Commit Graph
23 Commits
Author SHA1 Message Date
SivanCola f882c708b5 refactor: satisfy session catalog ownership budgets
Problem:
The initial session catalog implementation exceeded incremental repository size and complexity budgets in several existing owner files, and Desktop CI reported stale helpers plus two modernization findings.

Root cause:
Catalog lifecycle, runtime projection, frontend topic presentation, mock bindings, plugin compatibility, and CLI wiring were colocated with already-large modules. Removing the eager project tree also left legacy runtime-tree helpers unused.

Fix:
- split catalog lifecycle from runtime projection and metadata mapping
- extract frontend catalog contracts, mock bridge, topic presentation, and count formatting
- isolate plugin compatibility, session projection, and CLI completion wiring
- remove obsolete eager-tree helpers and address CI modernization findings
- preserve behavior without changing repolint baselines

Verification:
- go run ./tools/repolint
- golangci-lint v2.12.2: 0 issues
- go test affected root packages
- focused Desktop catalog and workspace regression tests
- pnpm test:all
- pnpm build
2026-08-10 17:41:41 +08:00
SivanCola bf19574d3a feat(desktop): add resilient session catalog
Problem:
Desktop startup and project-tree queries could synchronously migrate and decode legacy session JSONL, blocking navigation, creation, and shutdown.

Root cause:
Session discovery, metadata repair, controller admission, and plugin startup shared UI-critical paths and broad lifecycle locks.

Fix:
- add a disposable SQLite session catalog with incremental reconciliation, repair checkpoints, corruption recovery, and memory fallback
- expose revisioned cursor pagination and migrate the desktop project tree to lazy loading
- move controller construction outside lifecycle admission and isolate incompatible plugin startup
- add session doctor and reindex commands while preserving authoritative JSONL and metadata
- retain CGO-free builds with platform-specific fallbacks

Verification:
- go test ./...
- cd desktop && go test ./...
- go test -race ./internal/sessioncatalog ./internal/agent
- cd desktop && go test -race .
- go vet ./... in root and desktop
- cd desktop/frontend && pnpm test:all && pnpm build
- CGO_ENABLED=0 cross-builds for supported macOS, Windows, and Linux targets
2026-08-10 17:16:26 +08:00
SivanCola 8cc7279c86 refactor(plugin): keep compatibility changes within lint budgets
Move Claude root-instruction helpers out of the oversized parser file and keep marketplace fixtures line-neutral while preserving the official skill-based coverage.

Verification: go run ./tools/repolint; go test ./...; ./scripts/cache-guard.sh.
2026-08-10 02:03:33 +08:00
SivanCola 1c6776d9d9 fix(plugin): align Claude root instructions with upstream
Problem: Reasonix synthesized a SessionStart context hook from a Claude plugin root CLAUDE.md, although Claude Code does not load that file as plugin project context.

Root cause: Claude manifests shared the Codex compatibility helper that always appended root instructions.

Fix: keep supported Claude convention imports without the synthetic root hook, document the distinction, and update install-source fixtures to use official skills.

Verification: go test ./...; ./scripts/cache-guard.sh; focused plugin and install-source tests; desktop plugin/theme tests.
2026-08-10 01:59:34 +08:00
SivanCola 500d21a283 Fix runtime ownership and v2 manifest boundaries
Problem:
Runtime publish gates, receipts, file priors, message deduplication, and stream cancellation were process-global, so rebuilding one session could drain or overwrite another session's lifecycle evidence. The v2 manifest path also still exposed migration behavior for versioned manifests.

Root cause:
Lifecycle state was wired through package globals instead of the controller/session lineage, and migration/parser compatibility retained assumptions from the unpublished manifest v1 design. Drain cancellation also allowed callbacks to register after a generation had already expired.

Fix:
Introduce an explicit RuntimeOwner carried through boot, controller, provider, UI, host streams, receipts, and file-write compensation. Reuse it only within a rebuild lineage, defer replacement publication until commit, reject draining turns, make late drain registrations cancel immediately, and enforce v2-only versioned manifests while limiting explicit migration to pre-extension manifests without apiVersion.

Verification:
- go test -race ./internal/agent ./internal/boot ./internal/control ./internal/extension ./internal/extension/providerext ./internal/extension/uihub ./internal/tool/builtin -count=1
- go test ./internal/extension ./internal/pluginpkg ./internal/recovery ./internal/agent ./internal/control ./internal/boot -count=1
- go test ./... -count=1 (sdk/go)
- focused Desktop plugin lifecycle tests
2026-08-08 02:29:40 +08:00
SivanCola 3552822776 feat: add generation-safe runtime composition 2026-08-08 01:03:45 +08:00
SivanCola f2bc54fab3 fix(release): restore cross-platform v1.20 gates
Summary:
- make extension content eviction deterministic and plugin path checks portable
- stabilize the parallel-task cancellation coverage test
- keep POSIX mode assertions meaningful on Windows and serialize tmux fixtures safely

Verification:
- go test -covermode=atomic ./...
- go test -race on all changed packages
- go vet ./...
- Windows test binaries cross-compiled for all changed packages
2026-08-05 21:41:51 +08:00
SivanCola 727ac27608 feat(extension): Plugin Manifest v1 with prompts, plugin themes, and full-trust install display
Stage 4 of the unified extension kernel / Extension Protocol v1 plan.

Problem: reasonix-plugin.json had no way to declare prompts, themes, or a
code runtime, no strictness against typos, and no path-safety beyond
lexical checks; install previews gave no signal that a code extension runs
with full trust.

Fix:
- Manifest v1 (apiVersion reasonix.io/plugin/v1): strict decoding with
  DisallowUnknownFields at every level so typos fail with the field path;
  unknown major versions rejected. v1 may mix legacy top-level fields with
  contributes (skills/agents/commands/prompts/hooks/mcpServers/themes):
  identical paths dedupe, same-key-different-definition is a manifest
  error naming the key. Prompts are a new path-list resource exposed as
  /<plugin>:<name> via the existing plugin-command semantics; themes are
  root-confined globs matched against .reasonix-theme files. v1 path
  safety rejects traversal, absolute paths, symlink escapes, and
  non-regular theme files; missing paths are warnings. Manifests without
  apiVersion parse byte-for-byte as before (legacy compat gates green).
- runtime declaration: exec-form command/args/env (never shell-interpreted)
  with required/priority/intercepts/replaces/capabilities validated against
  the extension kernel's interceptor points, replacement slots, priority
  bounds, and {interceptors,strategies,providers,ui}. pluginpkg cannot
  import internal/extension (extension->hook->pluginpkg cycle), so the
  validator lists are duplicated with a sync test pinning them equal.
- Full-trust disclosure: install plans carry RiskHigh + a FULL TRUST
  reason plus omitempty RuntimePlanInfo (command, intercepts, replaces,
  capabilities) that old consumers ignore; CLI plugin show/doctor and
  capdiag render prompts/themes counts and the FULL TRUST block; the
  Desktop install preview renders a danger-styled FULL TRUST section with
  the command line, interceptors, replacement slots, capabilities, and the
  session/environment/permission risk statement. Install/update/replace/
  --link continue to imply full trust with no second confirmation.
- Desktop plugin themes: plugin themes are discovered from enabled v1
  packages, validated by the existing v2 theme validator, and shown
  read-only (never copied into the user theme dir) with IDs
  plugin:<plugin>:<theme>; the internal pack ID regex is unchanged.
  Activating a plugin theme persists the full ID; when the plugin is
  disabled or uninstalled, rendering falls back to the base style while
  the ID is preserved byte-for-byte in desktop-theme-state.json so a
  reinstall of the same plugin restores the theme (non-plugin unknown IDs
  keep the old clear-and-save behavior; legacy state files load
  unchanged). Theme assets serve through the existing content-addressed
  route with digest re-verification.

Verification: go test ./internal/pluginpkg ./internal/installsource
./internal/capdiag ./internal/cli ./internal/extension pass (legacy
compat gates unmodified); cd desktop && go test . passes (plugin theme
discovery/fallback-preserve/restore/read-only/asset-route tests);
desktop frontend pnpm typecheck and pnpm test pass; docs/THEME_PACK.md
updated in both languages; gofmt/go vet clean; no new dependencies.
2026-08-03 18:22:10 +08:00
SivanCola 72a1e32b49 Fix cross-platform plugin Hook execution contracts / 修复跨平台插件 Hook 执行契约 (#6911)
* Fix plugin hook execution contracts

Problem: Windows plugin hooks with compound commands or nested quoting could still fail after the narrow quoted-batch compatibility fix, while explicit empty args could lose exec-form semantics across JSON round trips.

Root cause: Hook launch behavior was inferred from argument length and platform shell heuristics instead of preserving the manifest's exec-form or shell-form contract. CMD and PowerShell command strings also passed through incompatible quoting layers.

Fix: Preserve args field presence and shell selection through plugin parsing and loading, add explicit legacy/exec/shell execution modes, transport raw CMD and encoded PowerShell scripts without token re-rendering, retain the existing simple batch compatibility path, and document the cross-platform contract.

Verification: Focused Hook and plugin package tests, race and shuffled tests, fuzzing, root and Desktop full suites, go vet, and Windows/Linux cross-compilation.

* Fix Windows hook output regressions

Problem: The new compound CMD regression expected cmd.exe to strip quotes from %1, leaving the Windows job red. PowerShell hook scripts also preserved UTF-16LE input transport without forcing captured output to UTF-8.

Root cause: The test confused %1 with the dequoting %~1 form, and the Hook-specific EncodedCommand path did not reuse the shell runtime's existing PowerShell output-encoding prologue.

Fix: Align the CMD assertion with native batch semantics, share the PowerShell UTF-8 script wrapper across shell and Hook launchers, and exercise Chinese plus emoji output in the Windows runtime test.

Verification: Focused Hook/plugin/sandbox tests and vet; race/shuffle count 3; root and Desktop full suites; full vet; Windows amd64 test cross-compilation; PowerShell encoding fuzzing.
2026-07-24 23:07:09 +08:00
SivanCola 7fe7d2b3f3 Simplify MCP authorization for installed servers / 简化已安装 MCP 授权 (#6767)
* fix(mcp): trust installed readers in subagents

Problem:
User-installed MCP tools that declared readOnlyHint could be exposed as readers but then fail before dispatch in planners and read-only subagents. Users were told to configure a second per-tool reader policy after already installing or authorizing the server.

Root cause:
Strict reader trust did not treat explicit install or an exact project launch grant as authority for non-destructive server metadata. Direct, lazy, and on-demand paths also duplicated cached-to-live safety reconciliation, while trusted_read_only_tools remained wired through configuration and Desktop contracts.

Fix:
Authorize non-destructive readOnlyHint tools for installed or launch-authorized servers, carry reader intent only for trusted readers, and share one cached-to-live safety reconciliation boundary across lazy and on-demand adapters. Remove trusted_read_only_tools from runtime, Desktop, examples, and docs while accepting and dropping legacy input on the next save.

Verification:
- env -u DEEPSEEK_API_KEY go test -count=1 ./...
- cd desktop && go test -count=1 ./...
- cd desktop/frontend && pnpm test:typecheck
- cd desktop/frontend && pnpm exec tsx src/__tests__/capabilities-panel-actions.test.ts
- ./scripts/cache-guard.sh
- ./scripts/check-cache-impact.sh
- git diff --check

* refactor(mcp): simplify installed server authorization

Problem:
User-installed MCP servers still depended on official-catalog and per-tool reader trust layers, so direct, lazy, and on-demand paths could disagree and strict child sessions could reject an already authorized reader.

Root cause:
Server authorization, signed package status, cached reader trust, and legacy plan-mode allowlists were modeled as separate overlapping decisions.

Fix:
Remove the official MCP catalog, signature/revocation plumbing, package verification, per-tool cached trust, and obsolete reader settings. Use one server-level authorization source for user installs, host-session installs, and exact project grants while retaining live read-only, destructive, and capability-fingerprint checks.

Verification:
- go test ./internal/plugin ./internal/agent ./internal/boot ./internal/config ./internal/installsource ./internal/pluginpkg ./internal/mcplaunch ./internal/planmode
- go test ./internal/acp ./internal/agent ./internal/plugin ./internal/boot
- cd desktop && go test ./...
- ./scripts/cache-guard.sh
- git diff --check

* refactor(mcp): make install authorization final

Problem:
Installed MCP servers could still encounter server, per-tool, writer, or destructive approval branches, and users had to understand settings that duplicated the install decision.

Root cause:
MCP authorization, cached reader trust, approval policy, and process sandboxing evolved as separate paths across direct, lazy, and on-demand execution.

Fix:
Treat install or exact project identity confirmation as the server authorization boundary, keep only explicit global deny plus Plan/read-only and sandbox safety checks, remove catalog and approval configuration, and unify the persistent MCP process sandbox.

Verification:
env -u DEEPSEEK_API_KEY go test ./...
go build ./...
cd desktop && go test ./...
cd desktop/frontend && pnpm typecheck
cd desktop/frontend && pnpm exec tsx src/__tests__/capabilities-panel-actions.test.ts
cd desktop/frontend && pnpm exec tsx src/__tests__/decision-surface.test.tsx

* chore(mcp): remove retired cache helper

Problem:
CI lint found writeBoolKV left unused after per-tool reader trust was removed.

Root cause:
The cached reader-map fingerprint was deleted, but its serialization helper remained.

Fix:
Remove the dead helper.

Verification:
go test ./internal/plugin
go vet ./internal/plugin
go build ./...

* refactor(mcp): stop blocking schema-only drift

Problem:
Authorized MCP calls could be rejected when a cached tool schema differed from the live server even though authorization and safety classification were unchanged.

Root cause:
A capability fingerprint mixed schema compatibility with read-only and destructive execution safety across direct, lazy, and on-demand paths.

Fix:
Remove the tool-level schema fingerprint chain, keep live server authorization and read-only/destructive reclassification checks, and refresh changed schemas for the next session without interrupting the current authorized call.

Verification:
- go test ./internal/plugin ./internal/agent ./internal/tool
- env -u DEEPSEEK_API_KEY go test ./...
- go vet ./...
- go build ./...
- ./scripts/cache-guard.sh
- pnpm --dir site test
- cd desktop && go test ./...

* fix(mcp): preserve short Windows temp paths

Problem:
Windows stdio MCP servers inherited a deeply nested Reasonix private TEMP path. Servers such as MATLAB create watchdog Unix sockets below TEMP and exit before initialization when the path exceeds the platform limit.

Root cause:
MCP private-state preparation redirected TMP, TEMP, and TMPDIR below the workspace-scoped mcp-state directory on every platform even though Reasonix does not currently provide an OS sandbox on Windows.

Fix:
Keep the host temporary-directory environment for Windows stdio MCP processes while retaining private cache and state directories. Preserve the existing private temporary directory behavior on other platforms and add focused regression coverage for both branches.

Verification:
- go test ./internal/plugin -count=1
- GOOS=windows GOARCH=amd64 go test -c ./internal/plugin
- go test ./...
- go vet ./internal/plugin
- git diff --check

* Simplify MCP runtime authorization state

Use Spec.Authorized as the sole resolved server authorization result so installed and host-session MCP servers no longer depend on launch-manager presence.

Keep exact identity grants for project sources, align planner and strict read-only registries with non-destructive readOnlyHint metadata, and document the cooperative trust boundary.

Add source and agent-surface matrix coverage while preserving the main provider-visible MCP tool surface.

* Limit MCP identity digests to project servers

Problem: User-installed and host-session MCP servers still resolved and hashed their executable identity during every startup even though installation was already the authorization decision.

Root cause: Project launch authorization and schema-cache ownership shared generic fingerprint terminology, and start() computed the project identity before checking whether launch approval was required.

Fix: Skip project identity resolution for installed servers, remove dead and non-participating identity state, and rename the remaining concepts to ProjectLaunchIdentityDigest and SchemaCacheKey while preserving existing JSON keys and digest bytes.

Verification: go test ./internal/mcplaunch ./internal/plugin ./internal/capability ./internal/boot ./internal/control ./internal/agent; go test ./...; cd desktop && go test .; go vet ./...; ./scripts/cache-guard.sh; git diff --check.

* Restore MCP 0.53 compatibility surfaces

Problem: MCP authorization was simplified, but the current client still lacked four compatibility surfaces present in the 0.53 line: legacy SSE, workspace roots, progress notifications, and registry browsing/install.

Root cause: the Go transport abstraction dropped inbound notifications and rejected legacy SSE; runtime specs did not carry a separate workspace root; the registry UI and CLI had no official MCP Registry client.

Fix: add inbound request/progress routing across transports, implement legacy SSE with same-origin endpoint protection, advertise roots/list, and add an explicit cached official Registry marketplace to CLI and desktop. Remove stale approval documentation and the dead helper that broke lint.

Verification: go test ./...; focused go test -race for plugin/registry/CLI/control; go vet in root and desktop; desktop go test ./...; frontend production build and marketplace UI test; Windows amd64 cross-build; official Registry browse smoke test.

* Avoid MCP progress capacity overflow

* Align MCP authorization documentation

Problem: CLI help and Chinese documentation still contained ambiguous or obsolete wording that implied installed MCP writer or destructive calls could require per-call approval.

Root cause: The server-level authorization simplification removed MCP approval modes, but not every user-facing explanation was updated consistently.

Fix: State explicitly that install or exact project identity confirmation authorizes the server, that writer and destructive hints do not prompt per call, and that deny, Plan, and strict read-only filtering remain separate boundaries.

Verification: go test ./internal/cli; go vet ./internal/cli; reasonix mcp help smoke test; stale-wording scan; git diff --check.

* Harden MCP registry installs and SSE replies

Problem:
Registry cache freshness was shared across queries, cached entries could flow into install paths, and legacy SSE server requests spawned an unbounded reply goroutine per request.

Root cause:
The cache stored one global timestamp, Resolve reused Search's offline fallback, the desktop installed browse payloads directly, and the SSE reader delegated every reply to a new goroutine.

Fix:
Track freshness per Registry query with legacy-cache compatibility, require live resolution before CLI and desktop installs, and serialize SSE replies through a bounded single-worker queue with finite deadlines.

Verification:
- env -u DEEPSEEK_API_KEY go test -count=1 ./...
- env -u DEEPSEEK_API_KEY go test -race -count=1 ./internal/mcpregistry ./internal/plugin
- env -u DEEPSEEK_API_KEY go test -count=1 ./... (desktop)
- env -u DEEPSEEK_API_KEY go vet ./... (root and desktop)
- pnpm run test:all
- pnpm run build
- env -u DEEPSEEK_API_KEY ./scripts/cache-guard.sh
- git diff --check

* Reject unavailable live registry installs

Problem:
A Registry entry could become non-installable between browsing and the desktop's live re-resolution, leaving the generic add flow with an invalid empty connection. The SSE concurrency regression also used a fixed delay after routing the client response.

Root cause:
The desktop resolver verified freshness but not the resolved entry's installability, and the test inferred worker startup from elapsed time.

Fix:
Validate the live entry through PluginEntry before returning it to the installer, and synchronize the SSE test on the first reply POST instead of sleeping.

Verification:
- env -u DEEPSEEK_API_KEY go test -count=5 ./internal/plugin
- env -u DEEPSEEK_API_KEY go test -race -count=3 ./internal/plugin
- env -u DEEPSEEK_API_KEY go test -count=1 ./...
- cd desktop && env -u DEEPSEEK_API_KEY go test -count=1 ./...
- git diff --check
2026-07-22 01:58:43 +08:00
SivanCola c636f017a8 feat(mcp): enforce trusted execution boundaries 2026-07-15 13:55:34 +08:00
SivanCola 6506ba46b7 fix(plugins): honor Claude hook deny decisions and fix hook dedup
Review on #6434 found that an imported Claude PreToolUse/PermissionRequest
hook's deny decision was silently dropped: ParseOutput only ever extracted
additionalContext from hook stdout, and PermissionRequest's exit code 2 was
explicitly downgraded to a notification instead of a block. A Claude plugin
that relies on hooks to refuse dangerous commands or permissions would show
as fully compatible while the tool call still ran.

- honor Claude's JSON deny decision (hookSpecificOutput.permissionDecision
  for PreToolUse, hookSpecificOutput.decision.behavior for PermissionRequest)
  even on exit 0, and have exit code 2 block an imported PermissionRequest
  hook the same way Claude's own contract does. Scoped to PayloadFormat
  "claude" so native Reasonix hook semantics (PermissionRequest stays
  advisory-only) are unchanged.
- wire the PermissionRequest hook synchronously into the approval flow so a
  deny preempts the prompt instead of only notifying after the fact.
- fix hook dedup (appendUniqueHook) to also compare Env, Timeout, Async, and
  Cwd, so two hooks that share a command/matcher but differ in one of those
  no longer collapse into one.
- fix Windows path-separator mismatch: ${CLAUDE_PLUGIN_ROOT}/${CLAUDE_PROJECT_DIR}
  expansion left a mixed "C:\...\pkg/bin/server" string since the manifest's
  "/"-authored suffix was never converted to the host separator.
- lint: tagged switch (QF1003) and remove two functions orphaned by this PR's
  own refactor (appendClaudeSettingsHooks, pluginNameExists).

Co-authored-by: SivanCola <[email protected]>
2026-07-14 02:58:26 +08:00
SivanCola cfe2b80c5c feat(plugins): add Claude plugin compatibility 2026-07-14 01:25:22 +08:00
SivanCola feff9f4da5 fix(plugin): pin GitHub plugin installs to the approved commit
Round-3 review follow-ups on the commands mapping:

- P1: plan and apply each cloned the source separately, so a repo that
  moved between the approved plan and the apply resolution could install
  content the approval never covered (and the optional planId echo could
  not catch the apply call's own second clone). pluginSource now reports
  the resolved commit for git sources; the plan records it on the action
  — entering the plan ID, so approvals fingerprint the exact snapshot —
  and apply pins a diverged clone back to the approved commit via a
  full-SHA fetch + detached checkout, refusing with a re-plan error when
  the snapshot is no longer reachable. Regression covers the unpinnable
  drift refusal end to end.
- P2: the command-dir adoption gate capped recursion at 5 levels while
  the runtime loader walks unbounded, so a plugin whose only command sat
  deeper was never adopted. The gate now delegates to internal/command
  itself — adoption and runtime discovery share one implementation and
  cannot diverge; a six-level nesting regression pins it.
2026-07-11 04:58:20 +00:00
SivanCola 2ef71c8165 fix(plugin): plan GitHub plugin installs from the real source tree
Review follow-ups on the commands mapping:

- P1: planGitHubPluginPackage assembled a sparse temp dir holding only
  the fetched manifest, so convention-discovered capabilities (skills/,
  commands/) and their warnings were invisible at plan time while apply
  cloned the full repo — the approved plan under-described what actually
  got installed. Plan and apply now resolve the source through one
  shared pluginSource resolver (shallow clone for GitHub), making the
  approval contract hold by construction; a plan/apply consistency
  regression covers it.
- P2: dirContainsCommandMd only looked at the top level, so a plugin
  whose commands all live in namespace subdirs (commands/git/commit.md)
  was never adopted even though the runtime loader walks them. The
  adoption gate now recurses (bounded depth, hidden dirs skipped).
- P3: appendInventoryText's empty-inventory fallback ignored commands, so
  a commands-only plugin printed its command list followed by
  "capabilities: no detailed inventory available".

Verified: reviewer's repro now plans skills=6 commands=11 for
github.com/OthmanAdi/planning-with-files with zero warnings.
2026-07-11 04:19:24 +00:00
SivanCola d38945513c feat(plugin): map Claude plugin commands to custom slash commands
Claude plugins like planning-with-files ship their primary interface as
commands/ (flat <name>.md prompt templates invoked as /<name>), which
Reasonix previously dropped with a "does not map yet" warning — the
plugin installed but /plan, /pwf etc. never appeared, reading to users
as a failed install (discussion #5762).

A Claude command is exactly Reasonix's custom slash command shape
(internal/command: frontmatter description/argument-hint, $ARGUMENTS /
$1..$N substitution, subdir namespacing), so map the capability instead
of warning about it:

- pluginpkg: Manifest gains Commands (explicit "commands" list in any
  manifest kind; claude plugins adopt conventional commands/ and
  .claude/commands/ automatically, even alongside explicit skills).
  Inventory/CapabilityCounts/describe now report commands, loaded via
  internal/command so names can never drift from runtime behavior.
- config: CommandDirsForRoot prepends enabled plugin packages' command
  roots at the lowest priority — boot and hot ReloadCommands both pick
  them up, and a user- or project-authored command wins name clashes.
- cli/installsource: plugin verify checks command roots; install plans
  carry commands/commandCount; plugin show lists commands.
- desktop: plugin view exposes commands count + details; capabilities
  panel renders a Commands section (en/zh/zh-TW strings).
- docs: EN/zh-CN plugin docs describe the mapping; commands removed
  from the unmapped-capabilities warning list (agents, hooks/hooks.json,
  .mcp.json still warn).

Verified end-to-end against planning-with-files v3.4.0: installs with
zero warnings, 6 skills + 11 commands, /plan invocable.
2026-07-10 17:58:13 +00:00
Sivan 5078a1987f Fix Windows encoded config reads 2026-07-10 02:40:43 +08:00
SivanCola 6a68799e18 fix(pluginpkg): discover conventional Claude skill dirs and warn on unmapped capabilities
Review findings on the Claude manifest support:

- A standard Claude plugin ships a metadata-only plugin.json and relies
  on Claude's auto-discovery of the conventional skills/ directory (packs
  in the wild also use .claude/skills/). Reading only the explicit
  `skills` field installed such packages as zero capabilities with no
  warning — "install succeeded" while nothing usable landed. Claude-kind
  parsing now falls back to the conventional directories when the
  manifest declares none, adopting a directory only if it actually holds
  a <name>/SKILL.md. Explicit declarations disable the fallback; codex
  parsing is untouched.
- Conventional Claude capabilities Reasonix does not map yet (commands/,
  agents/, hooks/hooks.json, .mcp.json) now surface as install warnings
  instead of being silently dropped.
- Negative test pins the includeCodexSessionStartHook boundary: a
  claude-kind package shipping hooks/session-start-codex must not get it
  registered as an executable SessionStart hook.
- Docs: retitle the compatibility section to "Codex & Claude", document
  the fallback, the warnings, and that marketplace.json indexes are out
  of scope.

Fallback reverse-verified: removing the convention-dir call fails
TestParseClaudePluginConventionSkillDirs.
2026-07-07 15:58:05 +08:00
SivanCola c070dc7432 Support Claude plugin manifests 2026-07-07 15:25:59 +08:00
SivanCola bd7d0fcd67 fix(plugin): budget stdio waits and stop probing shells under the lock
withStderr reaped the child with an unbudgeted cmd.Wait while holding callMu:
a surviving grandchild that keeps the stderr pipe open wedged every future
call on the transport (close() already budgets exactly this wait). Share its
5s budget via waitWithBudget. cachedShellPATH ran up to ~6s of login-shell
probes under its lock and re-probed empty results on every spawn; probe
off-lock with an in-flight channel and cache completed empty results.
pluginpkg state RMW gets a process lock and atomic writes.
2026-07-04 23:28:50 +08:00
SivanCola 253faa132f feat: surface plugin package usage details 2026-07-03 11:39:17 +08:00
SivanCola ad3d06343d feat: expand Claude-style plugin compatibility 2026-07-03 11:01:47 +08:00
SivanCola 42ee48f214 feat(plugin): add unified plugin packages 2026-07-02 17:23:56 +08:00