@gajae-code/coding-agent 0.16.7 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +180 -1
- package/dist/types/capability/fs.d.ts +37 -4
- package/dist/types/capability/index.d.ts +19 -0
- package/dist/types/capability/types.d.ts +9 -0
- package/dist/types/cli/doctor/args.d.ts +36 -0
- package/dist/types/cli/doctor/checks.d.ts +18 -0
- package/dist/types/cli/doctor/config-repairs.d.ts +38 -0
- package/dist/types/cli/doctor/context.d.ts +89 -0
- package/dist/types/cli/doctor/files.d.ts +27 -0
- package/dist/types/cli/doctor/ids.d.ts +20 -0
- package/dist/types/cli/doctor/install-repairs.d.ts +94 -0
- package/dist/types/cli/doctor/journal.d.ts +43 -0
- package/dist/types/cli/doctor/managed-link.d.ts +39 -0
- package/dist/types/cli/doctor/native-probe.d.ts +2 -0
- package/dist/types/cli/doctor/permission-repairs.d.ts +25 -0
- package/dist/types/cli/doctor/plugin-quarantine.d.ts +77 -0
- package/dist/types/cli/doctor/plugin-restore.d.ts +40 -0
- package/dist/types/cli/doctor/plugin-targets.d.ts +11 -0
- package/dist/types/cli/doctor/probe-client.d.ts +9 -0
- package/dist/types/cli/doctor/probe-types.d.ts +18 -0
- package/dist/types/cli/doctor/probe.d.ts +3 -0
- package/dist/types/cli/doctor/projection-probe.d.ts +2 -0
- package/dist/types/cli/doctor/repairs.d.ts +28 -0
- package/dist/types/cli/doctor/report.d.ts +27 -0
- package/dist/types/cli/doctor/runner.d.ts +4 -0
- package/dist/types/cli/doctor/safety.d.ts +10 -0
- package/dist/types/cli/doctor/service-repairs.d.ts +8 -0
- package/dist/types/cli/doctor/service-targets.d.ts +41 -0
- package/dist/types/cli/doctor/types.d.ts +145 -0
- package/dist/types/cli/doctor-cli.d.ts +7 -0
- package/dist/types/cli/doctor-supervisor.d.ts +121 -0
- package/dist/types/cli/doctor-worker.d.ts +29 -0
- package/dist/types/cli/install-activation.d.ts +158 -0
- package/dist/types/cli/macos-community-app.d.ts +41 -0
- package/dist/types/cli/mcp-cli.d.ts +0 -11
- package/dist/types/cli/update-cli.d.ts +41 -4
- package/dist/types/cli-main.d.ts +174 -0
- package/dist/types/cli.d.ts +1 -171
- package/dist/types/commands/doctor.d.ts +7 -0
- package/dist/types/commands/sdk.d.ts +17 -8
- package/dist/types/config/autorouting-tier-map.d.ts +19 -0
- package/dist/types/config/file-lock.d.ts +27 -3
- package/dist/types/config/model-preset-registry.d.ts +1 -0
- package/dist/types/config/model-registry.d.ts +12 -5
- package/dist/types/config/model-resolver.d.ts +16 -3
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +1 -1
- package/dist/types/coordinator-mcp/question-gate-codec.d.ts +1 -1
- package/dist/types/coordinator-mcp/session-reaper.d.ts +15 -5
- package/dist/types/cursor.d.ts +9 -9
- package/dist/types/discovery/agents-md.d.ts +6 -1
- package/dist/types/discovery/helpers.d.ts +36 -7
- package/dist/types/discovery/index.d.ts +1 -1
- package/dist/types/discovery/mcp-json.d.ts +2 -0
- package/dist/types/extensibility/extensions/loader.d.ts +22 -1
- package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +14 -1
- package/dist/types/extensibility/gjc-plugins/paths.d.ts +2 -1
- package/dist/types/extensibility/gjc-plugins/types.d.ts +25 -0
- package/dist/types/extensibility/plugins/manager.d.ts +33 -4
- package/dist/types/extensibility/plugins/marketplace/cache.d.ts +6 -0
- package/dist/types/extensibility/plugins/marketplace/manager.d.ts +186 -0
- package/dist/types/extensibility/plugins/marketplace/registry.d.ts +27 -0
- package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +16 -1
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +16 -3
- package/dist/types/gjc-runtime/autoresearch-runtime.d.ts +6 -0
- package/dist/types/gjc-runtime/launch-worktree.d.ts +53 -0
- package/dist/types/gjc-runtime/session-layout.d.ts +8 -0
- package/dist/types/gjc-runtime/session-state-lock.d.ts +15 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +13 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +6 -0
- package/dist/types/main.d.ts +19 -1
- package/dist/types/modes/acp/acp-agent.d.ts +40 -0
- package/dist/types/modes/components/agent-dashboard.d.ts +1 -0
- package/dist/types/modes/components/model-selector.d.ts +2 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/runtime-mcp/config-writer.d.ts +47 -0
- package/dist/types/runtime-mcp/policy-json-edit.d.ts +60 -0
- package/dist/types/runtime-mcp/startup-policy.d.ts +4 -0
- package/dist/types/runtime-mcp/types.d.ts +2 -2
- package/dist/types/sdk/acp/adapter.d.ts +5 -1
- package/dist/types/sdk/broker/broker.d.ts +51 -0
- package/dist/types/sdk/broker/daemon-entry.d.ts +39 -0
- package/dist/types/sdk/broker/discovery.d.ts +38 -0
- package/dist/types/sdk/broker/doctor-restart.d.ts +79 -0
- package/dist/types/sdk/broker/endpoint-authority.d.ts +7 -0
- package/dist/types/sdk/broker/ensure.d.ts +14 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +2 -0
- package/dist/types/sdk/broker/process-incarnation.d.ts +50 -0
- package/dist/types/sdk/broker/runtime.d.ts +26 -0
- package/dist/types/sdk/broker/session-index.d.ts +13 -4
- package/dist/types/sdk/broker/worktree-occupancy.d.ts +14 -0
- package/dist/types/sdk/bus/chat-daemon-cli.d.ts +16 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +101 -6
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +16 -0
- package/dist/types/sdk/bus/daemon-startup-exclusion.d.ts +43 -0
- package/dist/types/sdk/bus/doctor-daemon-restart-client.d.ts +51 -0
- package/dist/types/sdk/bus/doctor-daemon-restart.d.ts +39 -0
- package/dist/types/sdk/bus/index.d.ts +2 -0
- package/dist/types/sdk/bus/notification-service.d.ts +3 -0
- package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +11 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
- package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -0
- package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +1 -0
- package/dist/types/sdk/bus/telegram-daemon.d.ts +36 -5
- package/dist/types/sdk/cli/session-cli.d.ts +1 -0
- package/dist/types/sdk/host/session-runtime.d.ts +4 -0
- package/dist/types/sdk/host/surface-policy.d.ts +3 -1
- package/dist/types/sdk/lifecycle/service.d.ts +44 -10
- package/dist/types/sdk/prompt-deadline-lease.d.ts +6 -3
- package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -2
- package/dist/types/sdk/prompt-failure.d.ts +47 -0
- package/dist/types/sdk/prompt-status.d.ts +19 -0
- package/dist/types/sdk/router/session-router.d.ts +3 -4
- package/dist/types/sdk/service-artifact-paths.d.ts +16 -0
- package/dist/types/sdk/session-authority.d.ts +9 -0
- package/dist/types/sdk/session.d.ts +3 -1
- package/dist/types/session/agent-session.d.ts +1 -1
- package/dist/types/session/blob-store.d.ts +1 -1
- package/dist/types/session/fallback-chain-controller.d.ts +3 -6
- package/dist/types/session/internal/managed-session-scope.d.ts +44 -0
- package/dist/types/session/primary-control-surface.d.ts +4 -0
- package/dist/types/session/session-manager.d.ts +6 -0
- package/dist/types/system-prompt.d.ts +6 -0
- package/dist/types/tools/ask.d.ts +25 -0
- package/dist/types/tools/image-gen.d.ts +0 -4
- package/dist/types/tools/skill-discovery.d.ts +7 -5
- package/dist/types/tools/ultragoal-ask-guard.d.ts +7 -4
- package/dist/types/utils/changelog.d.ts +0 -9
- package/dist/types/utils/mupdf-wasm.d.ts +1 -0
- package/package.json +9 -8
- package/scripts/compile-args.ts +8 -4
- package/src/capability/fs.ts +395 -17
- package/src/capability/index.ts +273 -10
- package/src/capability/types.ts +9 -0
- package/src/cli/customize-doctor.ts +18 -12
- package/src/cli/doctor/args.ts +236 -0
- package/src/cli/doctor/checks.ts +431 -0
- package/src/cli/doctor/config-repairs.ts +517 -0
- package/src/cli/doctor/context.ts +149 -0
- package/src/cli/doctor/files.ts +149 -0
- package/src/cli/doctor/ids.ts +115 -0
- package/src/cli/doctor/install-repairs.ts +335 -0
- package/src/cli/doctor/journal.ts +423 -0
- package/src/cli/doctor/managed-link.ts +514 -0
- package/src/cli/doctor/native-probe.ts +13 -0
- package/src/cli/doctor/permission-repairs.ts +242 -0
- package/src/cli/doctor/plugin-quarantine.ts +377 -0
- package/src/cli/doctor/plugin-restore.ts +59 -0
- package/src/cli/doctor/plugin-targets.ts +373 -0
- package/src/cli/doctor/probe-client.ts +195 -0
- package/src/cli/doctor/probe-types.ts +21 -0
- package/src/cli/doctor/probe.ts +42 -0
- package/src/cli/doctor/projection-probe.ts +249 -0
- package/src/cli/doctor/repairs.ts +1157 -0
- package/src/cli/doctor/report.ts +176 -0
- package/src/cli/doctor/runner.ts +342 -0
- package/src/cli/doctor/safety.ts +40 -0
- package/src/cli/doctor/service-repairs.ts +452 -0
- package/src/cli/doctor/service-targets.ts +274 -0
- package/src/cli/doctor/types.ts +164 -0
- package/src/cli/doctor-cli.ts +62 -0
- package/src/cli/doctor-supervisor.ts +571 -0
- package/src/cli/doctor-worker.ts +181 -0
- package/src/cli/install-activation.ts +666 -0
- package/src/cli/macos-community-app.ts +1449 -0
- package/src/cli/mcp-cli.ts +11 -21
- package/src/cli/nofile-limit.ts +5 -1
- package/src/cli/plugin-cli.ts +6 -1
- package/src/cli/update-cli.ts +362 -264
- package/src/cli-main.ts +517 -0
- package/src/cli.ts +64 -433
- package/src/commands/autoresearch.ts +11 -5
- package/src/commands/completion.ts +1 -1
- package/src/commands/doctor.ts +13 -0
- package/src/commands/sdk.ts +58 -10
- package/src/commands/ultragoal.ts +11 -5
- package/src/config/autorouting-tier-map.ts +7 -0
- package/src/config/file-lock.ts +736 -71
- package/src/config/mcp-schema.json +3 -3
- package/src/config/model-preset-registry.ts +1 -0
- package/src/config/model-registry.ts +80 -27
- package/src/config/model-resolver.ts +33 -4
- package/src/config/models-config-schema.ts +2 -0
- package/src/config/settings-schema.ts +6 -2
- package/src/coordinator-mcp/question-gate-codec.ts +1 -0
- package/src/coordinator-mcp/server.ts +534 -51
- package/src/coordinator-mcp/session-reaper.ts +64 -8
- package/src/cursor.ts +223 -53
- package/src/discovery/agents-md.ts +74 -8
- package/src/discovery/agents.ts +32 -7
- package/src/discovery/builtin.ts +184 -75
- package/src/discovery/claude-plugins.ts +85 -17
- package/src/discovery/cline.ts +38 -10
- package/src/discovery/cursor.ts +19 -6
- package/src/discovery/gemini.ts +62 -22
- package/src/discovery/github.ts +13 -3
- package/src/discovery/helpers.ts +483 -89
- package/src/discovery/index.ts +1 -0
- package/src/discovery/mcp-json.ts +36 -10
- package/src/discovery/opencode.ts +36 -19
- package/src/discovery/ssh.ts +11 -8
- package/src/discovery/windsurf.ts +12 -3
- package/src/exec/bash-executor.ts +10 -3
- package/src/exec/isolated-shell.ts +15 -2
- package/src/extensibility/extensions/loader.ts +88 -26
- package/src/extensibility/gjc-plugins/lifecycle.ts +189 -0
- package/src/extensibility/gjc-plugins/paths.ts +4 -1
- package/src/extensibility/gjc-plugins/types.ts +27 -0
- package/src/extensibility/plugins/manager.ts +200 -22
- package/src/extensibility/plugins/marketplace/cache.ts +55 -2
- package/src/extensibility/plugins/marketplace/manager.ts +1262 -162
- package/src/extensibility/plugins/marketplace/registry.ts +153 -0
- package/src/extensibility/plugins/marketplace/source-resolver.ts +116 -10
- package/src/extensibility/runtime-skill-discovery.ts +61 -9
- package/src/extensibility/skill-management.ts +7 -1
- package/src/gjc-runtime/autoresearch-runtime.ts +10 -1
- package/src/gjc-runtime/launch-worktree.test.ts +248 -0
- package/src/gjc-runtime/launch-worktree.ts +275 -38
- package/src/gjc-runtime/repository-binding.ts +26 -1
- package/src/gjc-runtime/session-layout.ts +10 -0
- package/src/gjc-runtime/session-state-lock.ts +330 -23
- package/src/gjc-runtime/session-state-sidecar.ts +328 -80
- package/src/gjc-runtime/ultragoal-runtime.ts +10 -1
- package/src/harness-control-plane/session-lease.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +28 -26
- package/src/main.ts +150 -29
- package/src/memories/index.ts +24 -2
- package/src/modes/acp/acp-agent.ts +522 -68
- package/src/modes/components/agent-dashboard.ts +3 -1
- package/src/modes/components/model-selector.ts +28 -19
- package/src/modes/components/plugin-settings.ts +2 -1
- package/src/modes/controllers/selector-controller.ts +15 -9
- package/src/modes/interactive-mode.ts +21 -3
- package/src/prompts/system/system-prompt.md +5 -1
- package/src/prompts/tools/browser.md +1 -1
- package/src/prompts/tools/move-session.md +4 -0
- package/src/prompts/tools/read.md +2 -1
- package/src/prompts/tools/skill-discovery.md +6 -5
- package/src/prompts/tools/task.md +1 -0
- package/src/runtime-mcp/config-writer.ts +228 -0
- package/src/runtime-mcp/oauth-discovery.ts +114 -14
- package/src/runtime-mcp/policy-json-edit.ts +129 -0
- package/src/runtime-mcp/startup-policy.ts +14 -0
- package/src/runtime-mcp/types.ts +2 -2
- package/src/sdk/acp/adapter.ts +27 -12
- package/src/sdk/broker/broker.ts +273 -44
- package/src/sdk/broker/daemon-entry.ts +119 -0
- package/src/sdk/broker/discovery.ts +173 -20
- package/src/sdk/broker/doctor-restart.ts +206 -0
- package/src/sdk/broker/endpoint-authority.ts +36 -0
- package/src/sdk/broker/ensure.ts +49 -14
- package/src/sdk/broker/lifecycle.ts +174 -42
- package/src/sdk/broker/process-incarnation.ts +86 -2
- package/src/sdk/broker/runtime.ts +145 -21
- package/src/sdk/broker/session-index.ts +136 -22
- package/src/sdk/broker/spawn-substrate.ts +4 -1
- package/src/sdk/broker/transport.ts +5 -0
- package/src/sdk/broker/worktree-occupancy.ts +21 -1
- package/src/sdk/bus/chat-daemon-cli.ts +63 -0
- package/src/sdk/bus/chat-daemon-control.ts +260 -64
- package/src/sdk/bus/chat-daemon-runtime.ts +141 -25
- package/src/sdk/bus/daemon-startup-exclusion.ts +119 -0
- package/src/sdk/bus/doctor-daemon-restart-client.ts +291 -0
- package/src/sdk/bus/doctor-daemon-restart.ts +92 -0
- package/src/sdk/bus/index.ts +252 -51
- package/src/sdk/bus/kind-aware-reconciliation.ts +76 -41
- package/src/sdk/bus/notification-service.ts +21 -3
- package/src/sdk/bus/reconciliation-store.ts +17 -11
- package/src/sdk/bus/telegram-daemon-cli.ts +91 -5
- package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
- package/src/sdk/bus/telegram-daemon-control.ts +47 -0
- package/src/sdk/bus/telegram-daemon-owner-registry.ts +1 -1
- package/src/sdk/bus/telegram-daemon.ts +178 -13
- package/src/sdk/cli/session-cli.ts +100 -12
- package/src/sdk/host/host.ts +2 -7
- package/src/sdk/host/session-runtime.test.ts +329 -8
- package/src/sdk/host/session-runtime.ts +202 -50
- package/src/sdk/host/surface-policy.ts +8 -1
- package/src/sdk/lifecycle/service.ts +199 -22
- package/src/sdk/mcp/server.ts +1 -1
- package/src/sdk/prompt-deadline-lease.ts +12 -4
- package/src/sdk/prompt-deadline-manager.ts +5 -7
- package/src/sdk/prompt-failure.ts +148 -0
- package/src/sdk/prompt-status.ts +30 -1
- package/src/sdk/prompt-watchdog.ts +11 -3
- package/src/sdk/protocol/operation-inventory.generated.json +18 -0
- package/src/sdk/protocol/operation-registry.ts +20 -8
- package/src/sdk/router/session-router.ts +8 -3
- package/src/sdk/service-artifact-paths.ts +26 -0
- package/src/sdk/session-authority.ts +10 -0
- package/src/sdk/session.ts +361 -194
- package/src/session/agent-session.ts +398 -93
- package/src/session/blob-store.ts +9 -9
- package/src/session/fallback-chain-controller.ts +3 -7
- package/src/session/internal/managed-session-scope.ts +445 -29
- package/src/session/internal/managed-session-storage.ts +38 -6
- package/src/session/primary-control-surface.ts +12 -0
- package/src/session/session-manager.ts +11 -3
- package/src/session/session-storage.ts +1 -1
- package/src/session-import/codex.ts +6 -1
- package/src/session-import/redact.ts +7 -0
- package/src/skill-state/workflow-mutation-guard.ts +645 -39
- package/src/slash-commands/builtin-registry.ts +7 -3
- package/src/system-prompt.ts +8 -0
- package/src/task/executor.ts +36 -3
- package/src/task/types.ts +27 -5
- package/src/tools/ask.ts +114 -34
- package/src/tools/browser/actions.ts +2 -2
- package/src/tools/browser/tab-worker.ts +11 -8
- package/src/tools/descriptors.ts +6 -1
- package/src/tools/fetch.ts +7 -2
- package/src/tools/image-gen.ts +33 -34
- package/src/tools/read.ts +78 -32
- package/src/tools/skill-discovery.ts +17 -7
- package/src/tools/tool-catalog.generated.ts +8 -8
- package/src/tools/ultragoal-ask-guard.ts +16 -26
- package/src/utils/changelog.ts +7 -1
- package/src/utils/git.ts +3 -1
- package/src/utils/markit.ts +24 -2
- package/src/utils/mupdf-wasm.ts +26 -0
- package/src/web/search/providers/openai-compatible.ts +191 -14
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,161 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.17.1] - 2026-09-17
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- The `pi-shell` owned-child absence test releases its child handle before asserting that a killed and reaped child observes as positively absent. `std::process::Child` closes the underlying handle only on drop, and Windows keeps a process object — with the creation-time identity `OpenProcess` and `from_pid` both read — alive for as long as any handle to it is open, so holding the child past the reap pinned the exact incarnation the test waits to see disappear and failed the Windows native CI job (`Present { incarnation: "windows:…" }` for the whole 2s poll budget). The assertion still demands a positive `Absent`, so this removes a fixture artifact rather than weakening the observation contract.
|
|
10
|
+
|
|
11
|
+
## [0.17.0] - 2026-09-17
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Interactive launches no longer wait for conventional MCP servers to handshake before the TUI paints. With `--mcp-config` or `.gjc/mcp.json` autoload servers configured, session creation returns immediately, the deferred starter connects after first paint (status: "Connecting MCP tools…"), and a startup turn barrier keeps the first prompt from racing tool registration. Sessions with plugin-bundle MCP servers still connect eagerly, because plugin connect evidence feeds the GJC runtime snapshot published during creation and a late failure would present a partial pass as a clear one. Persisted conventional MCP tool selections are preserved while the deferred catalog is pending, and a failed deferred connect releases the startup turn barrier instead of leaving the session unusable. ACP, print, and SDK sessions are unchanged.
|
|
16
|
+
- The embedded changelog is parsed once per process instead of on every lookup. Startup and each `/changelog` invocation re-split and re-scanned the full 710 KB embedded text; the text is immutable, so the first parse is now reused.
|
|
17
|
+
- The macOS file-descriptor preflight reads the inherited soft limit with a plain `sh -c` instead of a login shell, so launching no longer sources the user's shell profile on every start. The inherited limit is also the value the warning actually describes — a login-shell value could disagree with what the process is really running under.
|
|
18
|
+
- `GJC_TIMING` now measures the real cold start. The timing window is anchored at process start, exposing runtime bootstrap, static module link/eval, the runtime-globals install, the macOS nofile preflight, and the launch command's module graph that previously escaped measurement because the root span opened inside `main.ts`. The `cli:installRuntimeGlobals` / `cli:dispatch` / `interactive:init` / `interactive:firstPaint` spans break the boot down. `GJC_TIMING=x` boots interactive mode through the first transcript paint (`interactive:init` / `interactive:firstPaint` spans) before printing the tree and exiting, making the total a true time-to-first-render measure instead of a pre-TUI proxy.
|
|
19
|
+
|
|
20
|
+
- Release notes are now per-change fragments under `packages/<pkg>/changelog.d/` (#5491). Every pull request used to append to the same `## [Unreleased]` lines of the same `CHANGELOG.md`, so each merge dirtied every other open PR and the rebase that cleared it invalidated the head-bound approval that PR had already earned. Distinct fragment file names cannot conflict. `scripts/release.ts` folds pending fragments into the package changelog and consumes them as part of the release commit, `bun scripts/changelog-fragments.ts check` validates them locally, and Dev CI rejects a pull request that edits a guarded `## [Unreleased]` section directly or deletes a fragment.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- Devin CLI models are selectable through the ordinary provider/model path. When `devin acp` is installed and authenticated, `devin` models are discovered from the account (`gjc models`, `/model`), resolve without a GJC credential (authentication stays in the CLI), and can be pointed at a non-PATH executable with `GJC_DEVIN_CLI_PATH`. See `docs/devin-provider.md` for the agent-level boundary, permissions, and billing.
|
|
25
|
+
- `gjc doctor` diagnoses configuration, permissions, installation, plugins, and services, and repairs a fixed catalogue of nine actions under `--fix`. Diagnosis and `--dry-run` are strictly read-only: they never write product state, fetch, execute a plugin, or start a service. Every repair names one exact action and one exact target, and the two gates are independent: `--allow-risk` authorizes a risk class and `--yes` only skips interactive confirmation, so neither substitutes for the other or bypasses integrity, ownership, or occupancy verification. Artifact-replacing repairs additionally require an operator-supplied `--ref` and `--sha256` matched against recorded provenance.
|
|
26
|
+
- `gjc doctor --fix --repair service.restart-owned` restarts the SDK broker and Discord, Slack, and Telegram daemons through each owner's prepare/commit protocol. Restart success requires kernel-confirmed predecessor absence and a genuinely different successor process incarnation; matching PIDs are not accepted as proof.
|
|
27
|
+
|
|
28
|
+
- Successful macOS installs and updates can offer the optional experimental, third-party community Gajae Code App (#5140), defaulting to No. The shared installer requires canonical release checksums and a verified bundle/signature, skips installed apps and automation, and supports `GJC_NO_COMMUNITY_APP=1`; app failures leave GJC installed.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Coordinator runtime-state updates are no longer dropped when several gjc sessions write the same session-state projection. The state-file acquisition deadline was absolute rather than idle-based, so a contender gave up five seconds after it started waiting even while peers were taking and releasing the lock normally — and each of those writes runs inside the namespace transaction lock whose own budget is sixty seconds, so any critical section outlasting five seconds starved every waiter with `lock_owner_live_or_unverifiable` or `transition_claim_timeout`. A dropped update is permanent: nothing re-derives the snapshot, so the coordinator kept reporting stale lifecycle and tool activity for that session. The deadline now measures waiting without progress, restarting only on proof that the lock changed hands to a peer, and a separate ceiling still bounds total waiting. A change the contender's own stale reclaim caused is not counted as progress, so an endlessly recreated dead claim still fails on its original schedule, and a wedged lock is still refused promptly. Runtime-state persistence additionally retries a pure-contention refusal a bounded number of times; every other refusal is still reported on the first attempt.
|
|
33
|
+
- Cold startup refreshes missing explicitly selected models from supported dynamic providers. Explicit provider/model task selections now fail with an actionable error instead of silently using the parent model when unavailable or unauthenticated; configured selector chains and autorouting credential-unavailable advancement remain supported.
|
|
34
|
+
- The `gjc doctor` supervisor no longer writes to the worker's stdin after the worker has settled. A confirmation prompt could resolve after a deadline, SIGINT, or crash had already torn the child down, and the resulting write surfaced as an EPIPE/`ERR_STREAM_DESTROYED` that took the parent process with it. The protocol channel is now a one-way latch closed on `exit`, `close`, and stdin `error`, and every residual race is contained as a `worker_channel_closed` outcome instead of an exception.
|
|
35
|
+
- A `gjc doctor` worker report whose `selection` envelope is missing or malformed is now classified as `worker_report_invalid` instead of throwing. The plausibility gate only validated shallow fields while the protocol handler dereferenced `selection.repair` and `selection.targetId` directly, so a malformed report raised a `TypeError` inside the readline listener rather than degrading to a bounded report.
|
|
36
|
+
- Marketplace plugin sources are now contained by canonical path, not by a lexical check that can silently degrade. `pathIsWithin` falls back to comparing unresolved paths whenever `realpath` fails, so a catalog-supplied plugin directory that is a dangling or looping symlink out of the marketplace root passed the containment gate and was then followed by the existence probe. Relative and `git-subdir` sources now canonicalize both the root and the candidate before use, and an existing entry that cannot be canonicalized is refused as an untrusted source.
|
|
37
|
+
- Catalog-controlled marketplace plugin sources can no longer inject git options or dispatch a git remote helper. A `url`/`git-subdir` source must be an https/http/git/ssh/file URL, a `user@host:path` remote, or an absolute local path; values starting with `-` (`--upload-pack=<cmd>`) and `<helper>::<args>` remote-helper URLs (`ext::sh -c ...`) are refused. A `github` repo and the `owner/repo` shorthand must match a plain slug, and a `git-subdir` path must be relative and must not start with `-`. `git.clone` also passes `--` before the URL so no caller can reintroduce the option-parsing hole.
|
|
38
|
+
- `gjc doctor --fix` now refuses journal-backed repairs on Windows before any mutation instead of failing mid-action. The crash-recovery journal implements its durability primitives only under `#[cfg(unix)]`, so `config.set-validated`, `mcp.set-startup-policy`, `permissions.restrict-owned-config`, `install.repair-managed-link`, `plugin.quarantine-selected`, and `service.detach-owned-stale-artifact` are blocked with `unsupported_platform` on win32 and the limitation is documented in `gjc doctor --help`. Diagnosis and `--dry-run` are unaffected on every platform.
|
|
39
|
+
- Coordinator MCP now admits an authenticated workflow gate opened during an in-flight runtime turn while the sidecar is still `running`, preserving stable question bindings and live answer dispatch; terminal states without an accepted runtime receipt remain `terminal_uncertain` (#5513).
|
|
40
|
+
- SDK session CLI raw globals now expose an explicit `--page` mode that preserves one bounded Broker `session.list` page and its opaque continuation cursor without changing semantic all-pages listing. The public `session.lookup` lifecycle global reconciles a previously submitted `session.create` from its retained request key and target without replaying creation, returns credential-free found/pending/not-found/conflict/uncertain/terminal outcomes, and keeps lookup identity and certainty in nonzero CLI results.
|
|
41
|
+
- Quota, rate-limit, and OAuth account-specific model-rejection recovery now marks the credential before re-resolving it, avoiding backoff on the healthy replacement account. Model rejection retains its OAuth-only guard and default backoff rather than response retry-after. Replay requires known, different before/after stored row IDs and at least one unblocked replacement; when every row is blocked, recovery stops without replaying a blocked fallback. An unknown prior identity is not proof of rotation. This preserves the mark-time target and ordering, not dispatch-bound attribution across shared sessions (#5422).
|
|
42
|
+
- Session startup loads filesystem extension modules again. `createAgentSession` seeded its extension set from `options.preloadedExtensions` and otherwise used an empty set, so every documented install location — `<agentDir>/extensions/<name>/index.ts`, `<cwd>/.gjc/extensions/...`, the `extensions` setting, and `additionalExtensionPaths` — was ignored even though `disableExtensionDiscovery` defaulted to enabled discovery. The Ouroboros `ooo` bridge installs an `input` handler at exactly that location, so `ooo ...` reached the model as ordinary chat while `ouroboros setup --runtime gjc` reported success (#5497). Startup now calls `discoverAndLoadExtensions` with the explicit paths plus the `extensions` setting, applies `disabledExtensions`, and resolves user scope from the session's own agent directory. A discovered module that fails to import is logged and skipped, and the remaining modules still load, so one broken extension cannot take a session down; a discovery failure itself warns, records the failure in `extensionsResult.errors`, and degrades to the explicitly configured paths instead of failing session creation. A malformed, unresolvable, unreadable, or pathological configured entry no longer aborts the whole load; entry resolution inside a configured directory is recorded per entry and the other extensions still load. `disabledExtensions` now drops a disabled id in every form discovery reaches, not only for discovered directories; `disableExtensionDiscovery` still loads the explicit `additionalExtensionPaths` as given. `disableExtensionDiscovery` keeps its documented opt-in-to-explicit-paths-only semantics, and `gjc customize doctor` no longer claims startup skips these modules.
|
|
43
|
+
- Global session lookup no longer discards readable transcripts whose recorded workspace can no longer be resolved. `SessionManager.listAll` seeded every transcript under the sessions root, then rebuilt its result purely from managed-scope re-derivation keyed on each recorded `cwd`, so a session whose workspace was deleted, renamed, unmounted, or recorded by another platform's checkout was dropped from the global listing entirely. `--resume <id>` fell back to that listing and reported `Session "<id>" not found.` for a transcript sitting intact on disk, leaving the absolute `.jsonl` path as the only recovery route. Scope re-derivation is now an enrichment pass over the seeded set instead of an admission gate; staged transcripts stay excluded.
|
|
44
|
+
- Post-start provider stream failures no longer reach SDK callers as a submission rejection. A Responses stream that fails in an HTTP 200 envelope, throws a top-level `error` event, or ends without a terminal event now carries the bounded `upstream_stream_interrupted` classifier (never a retry-eligible transport fact), and the normalized prompt outcome exposes a stable `phase` (`submission`/`post_start`) plus an allowlisted `category` and phase-aware wording ("Provider failure after execution started.") while the legacy `agent_error` discriminator and provider-text redaction are preserved (#5477).
|
|
45
|
+
- File-lock release on a host whose AV/DRM minifilter rejects the native exact-removal primitive now retires the verified lock through a handle-bound detach-only `.removing` quarantine instead of recursively deleting the live pathname, and finishes that quarantine with an identity-checked filesystem removal. The previous fallback could delete a successor lock published after its last identity check, and its completion replayed the very primitive the host rejects, so release could still fail after parking the lock (#5434).
|
|
46
|
+
- File-lock acquisition against a lock whose owner is provably dead now appends the removal-failure cause instead of leaving the exhaustion message at `held by pid N (dead but not reaped)`. When the host's lock-removal path refuses the dead owner's directory, the exhaustion `FileLockAcquireError` carries a structured `removalFailure` (guarded-removal outcome, errno/native code, and cause) and names the host removal failure in its message, scoped to the owner generation it describes so a live successor is never blamed; refusals are recorded, never allowed to abort the contention loop, so the cause is no longer hidden behind the retry budget (#5434).
|
|
47
|
+
- The `opencode-go/muse-spark-1.3-contributor` catalog row added in #5485 is now declared in the autorouting tier-map skip list, so `check:autorouting-map` and its CI gate pass again instead of failing on the unlabeled new key.
|
|
48
|
+
- Image generation now sends the selected image-role model instead of silently substituting a provider default for Antigravity, Gemini, OpenRouter, and Alibaba.
|
|
49
|
+
- The Ultragoal Ask guard now binds only to the asking session's own id, so `ask` can no longer be blocked by another session's durable goal or have its nudge budget consumed by one (#5465). Active-skill metadata, `GJC_SESSION_ID`, and auto-detected sessions are no longer consulted: a state snapshot restored from a different session carries that session's id, and an auto-detected or environment session can be a dead session's abandoned run, which made `ask` unusable for every session in the repository. A caller with no session identity now fails open instead of inheriting an unrelated run.
|
|
50
|
+
- Completed coordinator runtime markers with the legacy `ready_for_input: true` shape now resume and self-heal on the next lifecycle write, while other contradictory readiness and liveness markers remain hard errors (#5471). This tolerance does not weaken the Coordinator sidecar signing fence: a launch that requires signing still refuses an unsigned predecessor, including the legacy shape.
|
|
51
|
+
- The macOS installer no longer swallows INT, TERM, or HUP arriving at the optional community-app offer's final signal check. Cancellation retains its signal-specific exit status while preserving the verified GJC installation (#5140).
|
|
52
|
+
- File-lock acquisition now classifies an aged zero-byte or malformed `.removing` transition as an `orphan_transition`, exposes that diagnosis through the typed public error code, and aborts without deleting it. Active parsed owners continue to wait, while dead parsed owners remain classified as abandoned for the existing recovery policy (#5474 stage 1).
|
|
53
|
+
- File-lock acquisition now finishes an aged `.removing` transition whose snapshot is the native payload-scrub residue (every file already truncated to zero bytes) instead of leaving the session mutation lock wedged forever. A process killed between the native detach/scrub and the caller's on-disk cleanup used to make every later write abort with `orphan_transition`; only that provably scrubbed residue is adopted and removed under the existing identity-bound primitive, while live owners, unscrubbed trees, successors, and every other refusal still keep the typed diagnostic (#5474 stage 2).
|
|
54
|
+
- An in-process role-agent/subagent fan-out no longer aims its own runtime-state writes at the parent session's coordinator-pinned marker (#5473). The process-wide `GJC_COORDINATOR_SESSION_STATE_FILE` pin describes exactly one session, but every nested session in the same process inherited it, so the runtime sidecar's identity fence refused each write with a bare `PreviousRuntimeStateReadError: Existing runtime state marker is invalid or unreadable; refusing to overwrite.` — 102 rejections in one 15-minute fan-out, with the parent's marker left perfectly valid and the message naming nothing. A nested session now owns a session-derived marker, and every refusal it can still produce names the failing field, bounds the received value so marker text can never reach an operator diagnostic, and pins the offending payload by SHA-256 digest; the sidecar also reads back the coordinator-only `prepared` lifecycle it shares the file with.
|
|
55
|
+
- Boundary-review follow-up to the #5473 marker-ownership fix: the runtime-state pin is now scoped by ownership everywhere, not only on the event path. A committed cwd move (`move_session`, `/move`, SDK/ACP `session.cwd.move`) re-read the raw `GJC_COORDINATOR_SESSION_STATE_FILE` pin inside the rescope family, so a nested in-process session read the parent's marker and its own committed move was refused as a session mismatch while its marker stayed stranded at the launch root; ownership now decides whether the marker is pinned or session-derived in `prepare`/`relocate`/`recover` and in the move listeners. Every refusal also binds the payload it refused — the identity fence and the shared lifecycle-consistency checks carry `payload sha256` where the raw bytes were read and `payload-content sha256` where only the parsed value is at hand — and a foreign marker's recorded workspace is stripped of control characters before it reaches the message (the exact value stays on `recordedCwd`/`currentCwd`), so a corrupt marker can no longer inject terminal control sequences into an operator's log.
|
|
56
|
+
- OpenAI-compatible web search now supports streaming-only servers, consuming SSE responses while preserving completed results, citations, cancellation, and the existing Responses-first routing and grounding checks (#5423).
|
|
57
|
+
- SessionIndex append prepares history parsing and checksumming outside the global lock, revalidates file identities and exact bytes under ownership, and strictly checks concurrent suffixes before committing. Durable ordering, corruption quarantine, sequence and registration authority, and retention remain intact while redundant row rereads and rotation replays are removed (#5438); this does not establish full standalone launch-load acceptance.
|
|
58
|
+
- `skill_discovery` zero-candidate results no longer pass as an empty catalog when the query itself filtered everything out. Query matching is conjunctive substring (every whitespace-separated term must appear in name/description/source/use-when, unless a term equals the exact skill name), so a single topic keyword that appears nowhere drops every skill; a query that matches nothing now carries a `notice` stating how many skills were scanned, the conjunctive-substring rule, and the retry guidance. The tool prompt and `query` schema description now document the semantics instead of implying relevance ranking, so a model can no longer answer "no such skill" from a filtered result. `discoverRuntimeSkills` results gained a `scanned` count backing the notice.
|
|
59
|
+
- A resident SDK broker whose own runtime executable disappeared or stopped being a regular file is now retired and replaced by the normal readiness path instead of accepting requests it can never serve. After a package upgrade removed the interpreter a live broker was started from (a Homebrew Bun Cellar path), the process kept heartbeating and answering, but every `session.create` failed with `SDK internal launch refused: runtime executable is not a readable regular file.` until the broker was restarted by hand. Brokers now publish the runtime image their internal spawns use, and `ensureBroker` retires an incumbent whose image is provably absent (`ENOENT`/`ENOTDIR`) or is no longer a regular file under the existing spawn lock. A broker whose image disappears between its own exec and its publication still publishes the path its runtime classification names, so the one broker that can never spawn cannot hide behind absent evidence. Filesystem probe errors do not retire a broker: records that carry no runtime evidence at all (written before the field existed, or by a publisher that could not classify its runtime), and images this caller merely cannot inspect (permissions, symlink loops, sandbox visibility, a probe that outruns its bound), keep the incumbent reusable.
|
|
60
|
+
- Headless ACP asks now abort their enclosing foreground turn when the remote client cancels the ask. Previously the ask tool rejected with a cancellation error without releasing foreground ownership, so the next client prompt could be rejected as already active.
|
|
61
|
+
|
|
62
|
+
- CLI startup now preserves saved account pins when handing authentication to the SDK. Catalog refreshes with a session use its effective credential pin, preventing a cached free OpenAI Codex account catalog from hiding Astra or Sol during paid-account profile startup. Generic injected SDK authentication keeps its existing isolation, and persisted session selections retain precedence over global pins.
|
|
63
|
+
|
|
64
|
+
- Managed migration-lock release now detects closed or reused Linux descriptors before native security verification and validates ownership through the recovered descriptor. Recovery still requires the original file identity, attempt id, and owner-only security; repeated release cannot change a successor. This fixes the retained-descriptor failure in #5399 without changing test timing or retry policy.
|
|
65
|
+
- Standalone binaries can convert PDFs again. Compiled releases marked `mupdf` as an external package, but compiled-Bun module resolution cannot satisfy markit's bare `mupdf` import, so every PDF conversion failed with a generic "PDF support requires 'mupdf'" note and the read tool fell back to raw bytes (#5433). `mupdf` is now bundled, its wasm asset is embedded and routed to the Emscripten loader via a `locateFile` hook, and a narrow `markit-ai` patch replaces its bundler-hostile `require("mupdf")` image-rendering call with a dynamic import. Conversion failures that still name `mupdf` now surface the real import error instead of the swallowed cause.
|
|
66
|
+
- Isolated-shell protocol send failures now retire unsent pending requests and their abort listeners before terminal cleanup. Callers still receive the original send error, while closing a worker with unavailable input no longer rejects an abandoned deferred later as an unhandled `Isolated shell worker closed` error.
|
|
67
|
+
- Bash cancellation now observes its owned abort acknowledgement immediately and joins it on every execution exit path. A run settling before its abort reply can no longer leave a rejected cleanup promise unobserved when a one-shot worker closes; public operation errors and existing bounded cleanup deadlines are unchanged.
|
|
68
|
+
- A headless `ask` no longer waits forever without a signal. An ask that only a remote answer source or a workflow gate can answer now has a documented answer deadline (`GJC_ASK_ANSWER_DEADLINE_MS`), and its expiry aborts with an origin-labelled error (`no answer was received within Ns of the headless ask answer deadline`) instead of degrading into the empty answer the model reads as "the user declined". The deadline is disabled by default because an attended remote responder may legitimately answer arbitrarily late, and a value beyond the runtime timer's range is treated as disabled rather than silently clamped to a 1 ms delay.
|
|
69
|
+
- Coordinator question reconciliation now reports a published workflow gate that no coordinator turn owns yet as a `pending_registration` diagnostic. Previously the gate was deferred silently, so `gjc_coordinator_list_questions` and `gjc_coordinator_read_coordination_status` answered a healthy empty snapshot for the whole deferral window while the agent was blocked on an ask no operator could see (#5475).
|
|
70
|
+
- Coordinator responses now preserve `error: null` instead of replacing it with an `unavailable` error. Non-null errors still use fixed public messages, and unknown error codes remain mapped to `unavailable`.
|
|
71
|
+
- Session-state locks now recover a settled same-process owner release failure, including an acquisition handoff whose transition cleanup fails, without replaying the callback or touching a successor owner.
|
|
72
|
+
- Session cwd moves now await `local://` initialization when an explicit `--session-dir` destination becomes managed storage, preserving local artifacts and preventing subsequent prompts from failing with `local:// legacy migration must complete before path resolution`; post-commit initialization failures recover coordinator state and settle pending persistence instead of leaving the rescope barrier blocked.
|
|
73
|
+
- Browser selector helpers now reject non-string and blank selectors with an actionable `ToolError` instead of a `startsWith` TypeError, directing numeric observation ids to `tab.id()`. Invalid optional selectors no longer fall through to unfocused key presses or page screenshots, including blank selectors passed through structured `act` press actions.
|
|
74
|
+
- Structural Read summaries now honor explicit `truncation: "last"` and `"both"` instead of rejecting the request. Directional byte budgeting preserves complete summary units, source anchors, and recovery guidance without falling back to raw source; omitted direction still defaults to `head`.
|
|
75
|
+
- Fresh-process CI harness output now records the configured worker/shard counts plus per-file wall, child, and spawn timing, making runner contention measurable without changing timeout or failure policy. Autorouting setup diagnostics retain an Error message when a loaded Bun process exposes a stack without its headline, and the chat-daemon replay regression waits for the router's explicit cursor-settlement boundary instead of a timing delay.
|
|
76
|
+
- Native SYSTEM.md, AGENTS.md, and RULES.md reads now reject symlinked user-scope leaves outside the selected agent directory while preserving contained profile-root and in-profile leaf symlinks; explicit-home reads remain bound to the preauthorized root identity. Executor diagnostics inspect only the stack headline before deciding that an Error message is already present. SDK lifecycle create replays retain endpoint file identity so same-key replays accept the live host without weakening same-generation replacement fencing.
|
|
77
|
+
- Non-admitted steering no longer schedules a duplicate queued continuation when its follow-up fallback is the first queued message; direct follow-up and nonempty-queue wake behavior remain unchanged.
|
|
78
|
+
- Fresh-process CI harness output now records the configured worker/shard counts plus per-file wall, child, and spawn timing, making runner contention measurable without changing timeout or failure policy. Autorouting setup diagnostics retain an Error message when a loaded Bun process exposes a stack without its headline, and the chat-daemon replay regression waits for the router's explicit cursor-settlement boundary instead of a timing delay.
|
|
79
|
+
- Native SYSTEM.md, AGENTS.md, and RULES.md reads now reject symlinked user-scope leaves outside the selected agent directory. SDK lifecycle create replays retain endpoint file identity so same-key replays accept the live host without weakening same-generation replacement fencing.
|
|
80
|
+
- Non-admitted steering no longer schedules a duplicate queued continuation when its follow-up fallback is the first queued message; direct follow-up and nonempty-queue wake behavior remain unchanged.
|
|
81
|
+
- Profile instruction containment retains the directory identity authorized at load setup and supports identity-bound aliases inside the selected profile without trusting replacement roots or external symlink targets.
|
|
82
|
+
- Dev CI metadata edits retain authoritative validation instead of publishing skipped aggregate checks, and state-gate planning includes runtime prompt Markdown in dependent workspaces. Git push preflight binds the actual push destination and fails closed when fork authority cannot be resolved.
|
|
83
|
+
- The G002 documentation gate now checks Exa policy in the corresponding embedded documents rather than treating unrelated statements denying MCP OAuth/reload as Exa fallback advertising. Generated corpus parsing is non-executing and fails closed on malformed or missing policy documents; all forbidden Exa patterns remain enforced.
|
|
84
|
+
- Session runtime caches avoid redundant sentinel scans, obsolete permission wrappers, and unnecessary blob-buffer copies; streaming-edit pre-cache reads can no longer publish after invalidation, and oversized IRC replies use bounded UTF-8 truncation.
|
|
85
|
+
- File-lock acquisition now fences retained `.removing` transitions on macOS as well as Linux, preventing successor publication from racing predecessor cleanup and wedging session-index locking with `quarantine_collision`. Raced publications roll back only after exact-identity verification; unowned transitions remain untouched and produce bounded contention diagnostics.
|
|
86
|
+
- Paseo's base ACP provider now inherits the active model preset when attaching to a live CLI session, including preset switching, without requiring a separately registered preset provider.
|
|
87
|
+
- Primary control now follows the session host's startup surface: Paseo attachments cannot take over a CLI host's permission/UI providers or close/delete authority, while Paseo/SDK hosts retain ACP ownership across reloads and reconnects.
|
|
88
|
+
- ACP now rejects legacy host capability responses that omit startup-surface provenance instead of attaching without provider or lifecycle ownership.
|
|
89
|
+
- ACP lifecycle authority for newly created and forked sessions now follows the host's authenticated startup provenance, including notification-backed SDK hosts: the launching connection owns the session until the host reports a CLI startup surface, which returns that authority to the terminal.
|
|
90
|
+
- `session/close` on a CLI-primary ACP session now releases the local attachment instead of returning success while leaving the adapter, its lease heartbeat, subscriptions, and pending prompt alive; a turn in flight settles as `cancelled` rather than hanging, and broker close/delete stays restricted to the owning connection. `session/delete` against a live session this connection does not own is refused explicitly rather than reporting a deletion that never happened.
|
|
91
|
+
- OpenAI Codex model binding no longer infers model eligibility from ChatGPT account-plan labels. Healthy OAuth credentials can bind selected models such as GPT-5.6 Sol, and a provider-confirmed account-specific rejection retries once with the next unpinned OAuth credential without hiding the provider's error evidence (#5410).
|
|
92
|
+
- Public MCP guidance now states the shipped boundary precisely: ordinary standalone interactive and ACP sessions do not expose `/mcp` OAuth, test, reconnect, or reload commands; `--mcp-config` and the SDK's `mcpConfigPath` consume trusted connection configs but do not initiate MCP OAuth authorization, while existing `auth` bindings remain runtime-owned for refresh. `gjc customize doctor` now reports that MCP changes require a new session instead of contradicting that startup-only contract.
|
|
93
|
+
- `gjc update` now distinguishes same-version package-manager migration from a version update and installed binaries from shell activation (#5432). Fresh and already-verified standalone targets share explicit launch and command-resolution guidance, including Bash `hash -r` / zsh `rehash` before conditional PATH advice; verified targets are reused without another binary download and Bun/npm shims remain untouched.
|
|
94
|
+
- MCP OAuth discovery parses failed connection error text in linear time. The challenge-parameter scan no longer retries long identifier runs at every offset, malformed JSON framing uses bounded first/last-brace slicing, and the redundant greedy `realm`/`token_url` fallback is removed. Oversized keys remain ignored as whole runs, so their suffixes cannot be reinterpreted as OAuth parameters.
|
|
95
|
+
|
|
96
|
+
- The default bash interceptor no longer rejects commands that never redirect to a file. Its `write` rule scanned the whole command string, so a redirection after `;`, `&&`, or `||` was attributed to a leading `echo`/`printf` and `2>/dev/null` was counted as a file write: `echo x; date 2>/dev/null` was blocked with "use the `write` tool" while the same two commands in the opposite order ran. A redirection must now belong to the leading command, fd redirections such as `2>/dev/null` are no longer treated as writes, and the heredoc spelling the rule exists for (`cat <<EOF > out.txt`, with no space after `<<`) is now detected instead of silently skipped.
|
|
97
|
+
- Memory consolidation, Codex/Claude session import, image-provider text, and subagent setup-failure summaries now redact the vendor token shapes `crash/upstream/envelope.ts` classifies as credential-like and refuses to transmit: npm, GitLab PAT, Stripe live/test keys, and Hugging Face tokens. Stripe and Hugging Face separate with `_`, so the existing `sk-`/`sk|rk|pk-` rules never matched them at any length, and a GitLab PAT and a Hugging Face token both fall under the image scrubber's 40-character catch-all. Setup-failure summaries additionally listed only `AKIA` of the four AWS access-key id prefixes and had no PEM rule, so `ASIA`, `ABIA`, `ACCA`, and whole private-key blocks survived into the diagnostic.
|
|
98
|
+
|
|
99
|
+
- File locks on WSL DrvFS no longer strand their live owner after a directory rename commits but native verification cannot see the destination while retaining its source handle. Acquisition and detached release reconcile only against their original complete tree identity and content evidence; ambiguous results, replaced trees, and foreign locks remain protected.
|
|
100
|
+
- File-lock publication now requires successful native receipts to name the exact invoked operation before admitting protected work. Recognized but inapplicable primitives cannot authorize acquisition or trigger a publication retry (#5437).
|
|
101
|
+
|
|
102
|
+
- `gjc doctor --fix` now refuses to plan a repair when a selected collector timed out or was cancelled and is therefore still writing to the shared diagnosis context. The action is reported as `blocked` with reason `incomplete_diagnostics` and exit 3, while the diagnosis still shows everything that was collected.
|
|
103
|
+
|
|
104
|
+
- SDK CLI operations no longer attach to every session host on the machine. `session tail`, `send`, `status`, `inspect`, and the raw control/query globals each address exactly one session id, but opened their Router unscoped, so every invocation dialled the whole fleet. Attaching is not free and is not invisible: each attachment registers as a live client on that host, which resets the host's abandonment window, so periodic single-session tooling kept every unrelated host alive indefinitely — observed as 37 session hosts held open by two polling clients, each host still pinning its language servers and MCP children. Row lookup is the same hazard one layer down: `inspect` and `tail` resolve their session through `session.list`, which the Broker answers over its own client and which therefore needs no session transport at all, yet it attached the whole fleet before the scoped operation ran. The Router scope is now a required argument rather than an omittable one, so a call site cannot silently fall back to fleet-wide: single-session paths pass `[sessionId]`, `search` passes its probed rows, and Broker-answered metadata passes the empty scope.
|
|
105
|
+
|
|
106
|
+
- Stop dead-ending explicit "use worktree" requests when `task.isolation.mode` is `none` (the shipped default). The routing guidance is now rendered from the session's actual isolation state: with isolation off the agent creates a dedicated `git worktree` instead of refusing over the `isolated` parameter the task schema does not advertise.
|
|
107
|
+
|
|
108
|
+
- A freshly created ACP session whose host accepts and starts the first turn before it has finished coming up, then fails it as `prompt_failed`, is retried a bounded number of times instead of ending the session on its first turn with an opaque `-32603` (issue #5574). The retry re-submits the first prompt as a new, independent `turn.prompt`, so it is gated to stay idempotent and correctly scoped: it fires only for a session's first logical prompt, only on a terminal the host classified as the startup-readiness class — a post-start `agent_failed` `prompt_failed` carrying a provider/transport classifier, never a provider rejection, an agent runtime failure or a deadline, however little output they produced — and never once the turn executed a tool or published assistant output — so a progressed, side-effecting turn is surfaced rather than re-run twice, and a re-submit can never stack a second answer on top of the failed attempt's text. A failed terminal that carries the whole answer as `finalText` with no preceding stream chunks counts as published output too, because that text reaches ACP consumers on an async tail after the attempt has already been rejected.
|
|
109
|
+
- `firstPromptDone` is preserved across endpoint reattachment (derived from the session's retained settled prompt correlations, and from a replayed prior user turn on load) so a prompt after a transport reconnect or `session/load` is never mistaken for a first prompt and given the retry path. A request rejected in preflight (empty/invalid prompt, auth/preflight failure, stale-state conflict, oversize frame, or provider bootstrap failure) no longer consumes the one-shot first-turn retry budget, so a later valid first prompt that hits the startup readiness race is still retried.
|
|
110
|
+
- The session is reserved for the duration of the retry's readiness backoff. After the failed attempt clears its active prompt, a concurrent ACP request can no longer slip into the backoff gap, steal the first turn, and force the authorized retry to fail with a conflict. A `session/cancel` arriving during that backoff is honored — the cancel intent is retained across the gap even when the adapter cancel is unacknowledged, and the retry re-checks it before resubmitting — and a `session/close` or `session/delete` that wins the gap now settles the parked retry with the teardown's own outcome, so a client-driven close or delete reports `stopReason: "cancelled"` instead of a `not_found` error raised against the record it just removed, or a `connection_closed` rejection that belongs to an involuntary transport loss. The retry also waits out the failed attempt's own final-text and failure-diagnostic publications before resubmitting, so a client slow to accept those updates can no longer make the authorized retry fail with a `conflict` raised by its own predecessor.
|
|
111
|
+
|
|
112
|
+
- Auto-compaction on a session whose reachable models are all agent-level providers (e.g. Devin over ACP) no longer reports a guaranteed `maintenanceCall` refusal as `Auto-compaction failed` on every threshold crossing. Agent-level providers own conversation history and cannot serve GJC maintenance calls by contract, so the maintenance is now a benign skip; the candidate chain also no longer spends an attempt on an agent-level model while a text-model candidate exists.
|
|
113
|
+
|
|
114
|
+
- The autoresearch research-only allowance no longer passes a mutation that names no target. It was keyed on `targets.paths.every(isAuthorized)`, which is vacuously true for an empty list, and it ran ahead of the fail-closed check, so an opaque interpreter write such as `python3 -c "open('src/product.ts','w').write('x')"` was returned as allowed on a research mission. The allowance now requires at least one named target and no unanalyzable mutation; `autoresearch.sh` stays writable.
|
|
115
|
+
|
|
116
|
+
- The bash mutation scanner no longer treats shell metacharacters in inert quoted values (`--evidence "p99 500ms -> 120ms"`, `"throughput > baseline"`) as redirections. Quoted mutator operands, quote-split command names, and live command substitutions remain subject to the planning mutation guard, including substitutions containing a quoted closing parenthesis. Quoted redirection operands remain visible to sink and bypass checks, in single- and double-quoted form alike (`> '/dev/null'`, `of='/dev/null'`).
|
|
117
|
+
- The planning mutation guard no longer fails open on mutators reached through a command position it did not model: root-level compound commands (`{ rm x; }`, `if …; then rm x; fi`, `for …; do rm x; done`), executable wrappers (`command`/`builtin`/`env`/`exec`/`nohup`/`nice`/`time` and friends), and ANSI-C or locale-quoted executable names (`$'rm'`, `$"rm"`) are now recognized as real writes. Constructs that still cannot be attributed statically (`case`, `select`, `function`) fail closed instead of scanning blind.
|
|
118
|
+
|
|
119
|
+
- `$(...)` and backtick command substitutions are scanned by the bash mutation guard. The mutation scanners anchor on statement boundaries, which never see inside a substitution, so `echo "$(rm -rf src/product.ts)"` passed the planning-phase guard while deleting the file. Substitution bodies are now rescanned like an `sh -c` payload under the same bounded depth, after syntax-aware masking removes inert data-heredoc bodies and shell comments; single-quoted spans stay inert because they suppress substitution.
|
|
120
|
+
|
|
121
|
+
- Preserve registered SDK endpoint file identity through host shutdown, conditional unregistration, and verified retirement so Coordinator MCP can verify completed session closure without a false `endpoint_stale` response. Stale successor identities remain rejected; historical incomplete records are not rewritten.
|
|
122
|
+
|
|
123
|
+
- Mark newly created `gjc_coordinator_start_session` sessions as coordinator-owned so they are eligible for the existing ephemeral stop and idle-reaper policy without force.
|
|
124
|
+
|
|
125
|
+
- The `customize doctor` read-only contract test compares canonical working-directory paths, so it no longer fails on every macOS host where `$TMPDIR` lives under the `/var` -> `/private/var` symlink and the report's path and the `mkdtemp` path name the same directory through different prefixes.
|
|
126
|
+
|
|
127
|
+
- `gjc doctor` no longer reports `projection.coverage: limit_exceeded` and an `inconclusive` verdict with exit 3 on a healthy machine. The projection probe emitted one check per discovered item — measured at 193 skills in an ordinary operator home — and each check costs roughly 300-400 bytes of digest id, target id, and evidence, so the serialized receipt crossed the 64 KiB probe transport budget. The transport then discarded the *entire* receipt and replaced it with a single blocked check carrying empty evidence, which silently dropped every real `load_error`, `invalid_config`, `rejected`, and `quarantined` finding the check exists to surface. A healthy item never carried anything its surface coverage count did not already state, and its digest id was never a repair target (plugin repairs resolve through the dedicated plugin collector), so only actionable items become item checks now: the same home reports `verdict: healthy`, exit 0, and 37 completed checks instead of 30 checks and an inconclusive verdict.
|
|
128
|
+
- The projection probe is also responsible for fitting inside the transport budget rather than letting the client drop the surface. Per-surface and aggregate coverage checks are always retained, and a surface with more genuine warnings and errors than the budget allows sheds item checks deterministically and reports the truncation on its own coverage check as `limit_exceeded` with emitted/omitted counts. The transport limit and the producer budget are now one shared constant instead of two independent literals.
|
|
129
|
+
- Read-only doctor diagnosis no longer leaks suppressed log records to stderr. The probe disables both logger transports so diagnosis cannot write `.gjc/logs/` product state, which left Winston with no transport at all; it then wrote its own `Attempt to write logs with no transports` warning — including scanned `SKILL.md` paths, their contents, and full stack traces — straight to the process stderr the receipt shares.
|
|
130
|
+
|
|
131
|
+
- The opportunistic file-lock staging reaper no longer throws `ENOENT` when a candidate directory is published by its winning acquirer between `readdir` and inspection. `inspectFileLockStagingDir` now treats a missing staging root as a normal `enoent_already_gone` non-removal result instead of propagating the error up through `reapOrphanedLockStagingDirs` and into the `Failed to reap orphaned file-lock staging directories` debug warning (observed ~154 times/day on `sessions/index.jsonl.lock`). The post-removal `detachedPath` observation and its `rmdir` are guarded the same way.
|
|
132
|
+
|
|
133
|
+
- A schema-invalid `extensions` setting (for example an object left in `config.yml` by a hand edit) no longer aborts extension discovery at session startup with `Failed to discover extension modules`: discovery now degrades to no extra extension paths while the canonical `<agentDir>/extensions` modules keep loading.
|
|
134
|
+
|
|
135
|
+
- Interactive `/exit` now handles a bounded session-disposal timeout without triggering the unhandled-rejection crash path. It restores the terminal, reports that persistence is incomplete, and exits through bounded cleanup with status 1. Underlying persistence ownership and lock safety are unchanged; an ownerless lock left by filesystem synchronization still requires verified recovery.
|
|
136
|
+
|
|
137
|
+
- Report a managed session lock already removed or replaced before release as `migration_busy`, preserving the successor file and existing descriptor-recovery security checks instead of masking ordinary ownership loss as a Linux security error.
|
|
138
|
+
|
|
139
|
+
- Dynamically discovered models (for example `google-antigravity/gemini-3.8-flash-tiered`) no longer disappear from a long-running session when the provider's OAuth token refreshes and the catalog is later rebuilt, such as after the models config changes. Provider auth evidence now follows the account-backed credential row instead of its rotating token, so cached discovery stays valid across refreshes; presets that reference those models no longer turn unavailable and their roles no longer drop out until restart. Swapping accounts, removing credentials, changing OAuth project or endpoint fields, and an expired credential that cannot refresh still invalidate the catalog.
|
|
140
|
+
|
|
141
|
+
- Treat a complete empty coordinator question snapshot as healthy while its authenticated turn is still running, without relaxing stale, replayed, cancelled, or raced authority fences.
|
|
142
|
+
|
|
143
|
+
- Treat declined cross-project `--resume` forks and missing `--resume`/`--fork` session ids as clean operator-facing startup failures without crash logs.
|
|
144
|
+
|
|
145
|
+
- Include bundled GJC workflow skills in runtime discovery results and explain zero-candidate searches when skills were observed or filtered.
|
|
146
|
+
|
|
147
|
+
- An explicit startup selector no longer lets a broken persisted profile block the run: `gjc --mpreset <profile> -p …` and `gjc --model <selector> -p …` now report a failing `modelProfile.default` as a warning and continue with the explicitly selected profile or model, instead of exiting before the override could apply. Without an explicit selector the fatal non-interactive contract is unchanged.
|
|
148
|
+
|
|
149
|
+
- Startup model resolution now refreshes runtime-descriptor providers named by an explicit `--model` selector or the configured default. `refreshMissingQualifiedModelProviders` only consulted `getDiscoverableProviders()` — the discovery-manager set (models.yml `discovery:` entries and local runtimes) — so descriptor-backed providers like `devin` never refreshed before resolution: a fresh `gjc -p --model devin/swe-2-max` failed with `Model "…" not found`, and a config default pointing at such a provider degraded to last-profile recovery with a different model silently serving, while interactive sessions resolved the same selector because their full startup discovery sweep populates the registry. The provider lookup now falls back to the static `PROVIDER_DESCRIPTORS` table, so the awaited startup `refreshProvider(provider, "online-if-uncached")` also runs for descriptor providers and the models.db discovery cache (or a live fetch) satisfies the selector before the session picks a model.
|
|
150
|
+
|
|
151
|
+
- Preserve bounded Telegram daemon stop causes in ownership records and surface them in status diagnostics. A missing ownership lock no longer implies that a dead daemon exited cleanly; records without a captured cause are reported as unknown.
|
|
152
|
+
- Prevent rebrand inventory false positives from PDF binary payloads while retaining strict checks on editable documentation sources.
|
|
153
|
+
|
|
154
|
+
- `gjc autoresearch <verb> --help` and `gjc ultragoal <verb> --help` reach the native help again. Both commands opt into `delegateHelp`, which exists so a command can route `cmd subcommand --help` itself, but each one then re-intercepted the help flags and printed the generic command summary — discarding the verb. The native help already documents every verb's flags, so `verdict --help` never showed `--status-json`, `--evidence`, `--evaluator`, or `--caveat`, and `ultragoal review --help` never showed its FLAGS block. Help still renders before the workflow-settings migration and without resolving a session.
|
|
155
|
+
|
|
156
|
+
### Performance
|
|
157
|
+
|
|
158
|
+
- Reuse unchanged transcript layout for all model-selector-originated render requests when the selector is mounted in the composer, including catalog/auth refreshes, view changes, smart-routing updates, and redraws when the selector remains open after an assignment. Keyboard input through TUI input handling, opening/closing, and controller actions retain their existing full-render behavior.
|
|
159
|
+
|
|
5
160
|
## [0.16.7] - 2026-09-13
|
|
6
161
|
### Fixed
|
|
7
162
|
|
|
@@ -19,12 +174,19 @@
|
|
|
19
174
|
- `gjc ultragoal succession offer|adopt|status` gives an approved Ultragoal an explicit, audited path from the repository it was planned in to the repository its implementation belongs to (#5353). Previously the repository-binding guard correctly refused to execute the plan from the second repository and the only ways forward — editing `repositoryBinding` or copying the runtime directory — both defeated that boundary and laundered verification provenance. `offer` records the source repository/session, the selected unfinished goal ids, verified source artifact digests, and the complete carryover (the source brief and each objective verbatim, plus the unresolved obligations recorded against those goals), then installs a durable outgoing ownership fence: the source run immediately refuses to schedule or checkpoint the handed-off goals, while goals outside the selection stay schedulable. The source `brief.md`, `goals.json` and `ledger.jsonl` are never written — not even appended to — so their recorded digests stay verifiable, and adoption performs no write to the source repository at all. `adopt` starts a fresh run under the target repository's own binding with new pending goals and no inherited receipts, quality gates, validation batches, steering, owner identity or activated objective; historical statuses, reviews and approvals travel as provenance only. Digests are integrity evidence, never authorization: adoption additionally requires the source fence, a bounded `--authorize`/`--authorized-by` statement, and an explicit goal selection. Because the fence deliberately leaves unselected goals schedulable, admission compares a snapshot of the offered work — the brief plus each selected goal's record and unresolved obligations — rather than whole-file digests, so ordinary source progress cannot permanently strand the handed-off work; whole-file digests remain recorded as provenance and observed drift is written into the adoption record. A selection that takes only part of a validation batch, or splits a review blocker from the goal it still blocks, is rejected rather than silently dropping that obligation, and dependency groups travel as explicit obligations with source-to-target id mapping while the source's batch metadata and receipts stay behind. Terminal-critic blockers are carried as unmet requirements even though the verdict itself is not inherited. Exclusion is a single repository-wide `O_EXCL` claim per operation rather than a directory scan, so two simultaneous sessions cannot both become owners, and adoption is pinned to the exact worktree the offer named because linked worktrees keep separate `.gjc` state. Until publication completes the target refuses to execute — a visible `goals.json` is not admission evidence, the adoption record is. Adoption fails closed on changed offered work, an altered or unfenced offer, an offer path that escapes the source worktree, a target the offer does not name, an occupied target session, and any duplicate or simultaneous adoption in the target repository. A retry reconciles only this operation's own partial bytes: a matching operation id is never authority to overwrite target work it did not write, and a published plan whose files have disappeared is refused rather than reconstructed. There is deliberately no `revoke` verb, because any read-then-delete of the fence races a concurrent adoption and could revive the source while the target is starting.
|
|
20
175
|
|
|
21
176
|
### Fixed
|
|
177
|
+
- Trusted Git projects can discover and load `.gjc/skills` root symlinks resolving inside their repository, including `.gjc/skills -> ../.agents/skills`. Repository, link, and target identities stay pinned through deferred body loading; external/dangling targets, replaced roots, hardlinked/non-regular skill files, and symlinked user/profile authority remain rejected. Management listing uses the same policy; creation/import destinations still refuse symlink roots.
|
|
178
|
+
- Cross-repository task rejection now explains the supported `gjc --cwd <approved-worktree>` fresh-session route instead of inviting binding payload changes. Declared task bindings revalidate their canonical worktree root, common Git directory, and supplied branch/HEAD snapshots before admission; runtime-owned isolation still stays within the originating repository family.
|
|
179
|
+
- `gjc mcp list` no longer tells operators to connect an `autoload: false` server "on demand via /mcp": no such command exists, and `--mcp-config` does not override the flag either. The runtime note and the `autoload` schema description now give the only working procedure (set `autoload` to true or remove the key, then start a new session) and keep `enabled: false`/`disabledServers` authoritative; the `oauth` description is corrected to describe the unexposed authorization flow rather than credential refresh, which uses the `auth` binding.
|
|
22
180
|
|
|
181
|
+
- SDK `turn.prompt` now fails closed when a provider returns structurally empty assistant output without independent activity evidence, including zero, omitted, null, or malformed usage, while preserving meaningful text or reasoning, complete tool calls, positive-token activity, and explicit cancellation. (#5015)
|
|
182
|
+
- Image-provider text passed back through errors and `responseText` no longer carries AWS access-key ids, Google API keys, GitHub tokens, PEM private-key blocks, or URL-embedded basic-auth credentials. The scrubber's last rule is a generic 40-character catch-all, so fixed-width credentials below that length were never reached: an AWS access-key id is 20 characters and a Google API key is exactly 39. Its prefix rule also listed `ghp`/`gho`/`github_pat` but required a `-` separator, while GitHub tokens use `_`, so it never matched one and short tokens fell through the catch-all as well. The text this scrubs includes raw provider response bodies.
|
|
183
|
+
- Memory consolidation no longer writes Google API keys, PEM private-key blocks, the `ABIA`/`ACCA` AWS access-key prefixes, Slack tokens, or URL-embedded basic-auth credentials into `MEMORY.md` and `memory_summary.md`. Each shape was already catalogued by `session-import/redact.ts` and `utils/crash-redaction.ts`, and this scrubber persists more than either: the summary is replayed into every later session. The JWT-shaped rule is also boundary-anchored so scanning stays linear; its first segment previously restarted at every offset of a long token-character run, costing about ten seconds on 200 KB of consolidation output containing no secret at all.
|
|
23
184
|
- Concurrent print-mode resumes rejected by the managed transcript append fence now exit with one retry diagnostic instead of crashing during disposal, including failures while persisting startup model overrides before print mode begins. A pre-write identity mismatch disowns the stale transcript without rewriting another process's successor; genuinely uncertain I/O closure still fails closed.
|
|
24
185
|
- Disk artifact GC and `gjc gc --empty-delete-receipts` now reclaim empty artifact `.removing` directories left by interrupted session deletion, including projects with no remaining transcripts. Only the two generated quarantine-name shapes qualify; no-follow directory snapshots prove emptiness, and non-recursive removal retains non-empty, symlinked, or raced entries with explicit reasons.
|
|
25
186
|
- SDK `session.spawn` now publishes the child PID/incarnation-bound lifecycle marker before waiting for host registration, so headless and managed-tmux children can become ready. Incomplete substrate proofs are rejected and released before seed handoff; registration failures include validated startup phase/reason diagnostics without task text.
|
|
26
187
|
- File-lock acquisition and GC now reclaim orphaned `.lock.pending.<pid>.<uuid>` directories after their owner dies, with a bounded acquisition sweep and exact-identity deletion. Live, unknown, in-process, malformed, symlinked, and host-qualified owners remain protected; cleanup failures cannot block acquisition (related #5198).
|
|
27
188
|
- File-lock acquisition timeouts now expose a typed error with the lock path, retry count, and holder description. Lease mutation and SDK shutdown classify contention without depending on operator-facing wording, and unrelated shutdown failures still propagate.
|
|
189
|
+
- The bash tool on macOS no longer kills its shell runtime (`Shell runtime exited with code 70.`) when a command spawns an entitlement-restricted or setuid executable such as `ps`, `top`, or `sudo`. The native process reference now reads process identity through `sysctl(KERN_PROC_PID)`, which the kernel answers for every visible process, instead of `proc_pidinfo(PROC_PIDTBSDINFO)`, which returns `EPERM` for those children and made the ownership ledger treat the shell's own child as untrackable.
|
|
28
190
|
- Broker `session.list` pagination cursors now evict the oldest entry when the 32-cursor budget is full instead of failing new paginations with `cursor capacity is exhausted` (#5370). Abandoned or partial paginations degrade gracefully (the evicted cursor reports `cursor is expired or invalid` on next use) so unrelated session ops never fail once the index exceeds one page; the obsolete capacity-exhausted path is removed.
|
|
29
191
|
- `session.delete` uncertain-cleanup fences are now identity-scoped: an unbound `terminal_uncertain` ledger entry no longer blanket-fences deletes for every other session id, and a delete refusal records its own target session so the fence it leaves is scoped to that session. Existing poisoned ledgers need no migration — unbound rows are ignored in place on the next read and stop amplifying (#5364).
|
|
30
192
|
- Runtime state persistence now identifies contradictory `ready_for_input`/`live` fields with their lifecycle state and expected value instead of reporting only a generic invalid/unreadable marker error. Invalid markers remain untouched; this does not migrate or repair old session state.
|
|
@@ -34,14 +196,23 @@
|
|
|
34
196
|
- The TUI working spinner and tool intent remain visible when a run continues after automatic context compaction, a compaction-hook veto, or a successful managed model retry. Temporary status replacement no longer marks the foreground run as finished; actual completion and cancellation still clear it.
|
|
35
197
|
- Coordinator delegates recover a creation-WAL crash before the initial prompt claim without recreating the session or replaying compacted requests. Recurring pin cleanup bounds each readiness pass to 32 session WALs and 32 pinned receipts, skips live caller-key locks, and revisits the namespace after clean scans so surviving coordinators discover later peer crashes as well as previously skipped pins.
|
|
36
198
|
- Session import no longer stalls on large credential-free content. The import redactor's URL-credential rule accepted an unbounded scheme before the literal `://`, so a long alphabetic run re-tried every prefix and scanning cost grew quadratically with the input (50k/100k/200k characters took 0.7s/2.7s/10.6s on text containing no credential at all). Every imported string crosses this fail-closed redactor, so one large transcript message was enough to stall an import of Claude Code or Codex history. The scheme is now length-bounded, which restores linear scanning while `https://`, `postgres://`, and `git+ssh://` credentials are still redacted.
|
|
37
|
-
- SDK saved-session resume now enforces a supplied transcript `sessionIdentity` for both live reattach and cold launch instead of silently replacing it with the broker's current snapshot.
|
|
199
|
+
- SDK saved-session resume now enforces a supplied transcript `sessionIdentity` for both live reattach and cold launch instead of silently replacing it with the broker's current snapshot. Public SDK session bindings and lifecycle create/resume/list projections expose the opaque `endpointIncarnation` alongside the generation, same-key replay refuses an endpoint replacement rather than refreshing success by session ID when a numeric generation is reused, and `SessionLifecycleService.close` rejects a partial endpoint authority so consumers can pass the exact `SessionRouter.bindingAuthority()` result without falling back to an unfenced session-ID close.
|
|
200
|
+
- Explicit SDK follow-ups admitted after the Agent loop emits `agent_end` but before prompt unwind finishes now schedule a queued-only successor instead of remaining executable but unconsumed after `waitForIdle()`. The embedding guide now distinguishes admission, dequeue/promotion, and terminal completion, including the fact that `waitForIdle()` is not a queue-drained receipt.
|
|
201
|
+
- Long-running SDK prompts are no longer terminalized as `prompt_deadline_exceeded` while they are still making progress on the notification/SDK bus host route. That route armed a single fixed timer from `sdk.promptDeadlineMs` at acceptance, so it ignored both progress and `sdk.promptMaxRuntimeMs`, while the SDK-only host route already applied the progress-aware lease. The bus route now uses the same bounded lease: attributable tool-execution boundaries correlated to the accepted prompt renew the terminal deadline, streaming updates and other chatter do not, and the hard maximum runtime stays anchored to the original acceptance. Setting names, defaults, bounds, and the published terminal outcome are unchanged.
|
|
38
202
|
- An ACP client that declares no MCP servers no longer loses `session/new`, `session/load`, and `session/fork` to the broker's bare readiness default. Only the MCP branch asked for a readiness budget, so an MCP-less launch kept the 10s default while a host cold start measurably crosses it whenever a second host starts alongside the first: the broker then returned `terminal_uncertain` ("Lifecycle startup could not be proven"), which Paseo recorded as a failed provider snapshot and left the GJC provider reading `error` instead of `available`, so imported terminal sessions attached to nothing and showed no transcript. Every ACP launch now requests the same budget the MCP path already used, independent of whether the client declared servers.
|
|
39
203
|
- `subagent await` now accepts integer heartbeat intervals up to 60,000 ms, including 10,000 ms, instead of rejecting them at an undocumented 5,000 ms schema limit. Zero still disables heartbeat updates and the default cadence is unchanged.
|
|
40
204
|
- Coordinator delegates recover a creation-WAL crash before the initial prompt claim without recreating the session or replaying compacted requests. Startup pin cleanup skips live observations without waiting on their caller-key locks, and revisits skipped pins so a surviving coordinator can clean up after a peer commits its response and crashes.
|
|
41
205
|
- Interrupted standalone-binary installs now reclaim an installer lock only when its recorded process ID is no longer running. Live or malformed locks remain protected and fail closed, so a cancelled `gjc update` no longer permanently blocks the next update while concurrent installers remain serialized.
|
|
206
|
+
- Managed session writers on macOS bind owner-only security checks to the open file descriptor and its retained path before truncation and at fsync/close, rejecting a substituted pathname instead of accepting security checks on a different file.
|
|
207
|
+
- Native SHA-256 hashing enables the library's assembly backend on Unix targets without changing SHA-256 digests or storage verification rules. Windows retains the standard backend because the assembly dependency does not support Windows builds.
|
|
42
208
|
- Disconnecting an MCP server during its initial connection now returns after cancelling the acquisition instead of waiting forever when an uncooperative transport ignores abort. The pool still owns and closes any late connection, retains cleanup failures for retry, and releases the manager's pending-cleanup fence after successful settlement (#5329).
|
|
43
209
|
- SDK session routing now uses the Broker's endpoint timestamp comparison, accepting sub-millisecond representation differences while retaining device/inode and exact file-replacement checks. Valid live sessions no longer become unavailable solely because timestamp conversions round differently.
|
|
44
210
|
- Paseo announcement now honors `PASEO_LISTEN` ahead of daemon pid metadata, uses `$PASEO_HOME` consistently in default path construction, and removes redundant target-selection and SDK frame-delivery indirection.
|
|
211
|
+
- Ordinary Agents, AGENTS.md, and Cline project discovery again walks parent directories when the working tree is outside the user home and has no detected repository root; explicit-home isolation remains bounded to its supplied home. The non-Linux isolation path now runs in the Windows affected CI lane (#4834 review).
|
|
212
|
+
- Explicit-home capability discovery now validates only the selected provider roots, isolates plugin-root caching from ordinary loads, and rejects configured extension paths that escape the canonical home.
|
|
213
|
+
- `loadCapabilityForHome` no longer falls back to the process-global agent directory when an explicit home is supplied. The user agent directory is derived from the supplied home (`<home>/<configDir>/agent`) unless the caller passes an explicit `agentDir`, and a non-absolute home fails closed instead of silently resolving against the process profile. Explicit-home loads can no longer read another profile's SYSTEM.md/RULES.md/AGENTS.md, skills, commands, hooks, settings, or custom-tool descriptors; a decoy-process-profile test instruments every filesystem read across all eight surfaces to prove zero reads escape the supplied home (#4834).
|
|
214
|
+
- An explicit `agentDir` redirect now applies uniformly to native user-scope surfaces instead of only to MCP: `loadCapability`/`loadCapabilityForHome` set the context user scope only for an explicit agent directory, and the native SYSTEM.md, RULES.md, skills, config-dir, and AGENTS.md loaders resolve user paths from it. The process-default (no explicit `agentDir`) layout is unchanged (#4834 review).
|
|
215
|
+
- `loadCapability` keeps `getAgentDir()` as the DEFAULT context user scope for native surfaces, so a process-selected non-default profile (GJC_CODING_AGENT_DIR / PI_CODING_AGENT_DIR / setAgentDir()) is never split across two directories: an explicit `options.agentDir` still wins, and `loadCapabilityForHome` still derives its scope from the supplied home (#4834 review).
|
|
45
216
|
- When every auto-compaction candidate fails, the reported error now leads with the first candidate's failure and lists each candidate that was tried with its own error. The chain starts at the session model and ends on a same-provider largest-context fallback, so surfacing only the final error named a model the user never chose (e.g. `openai-codex/gpt-5.4` on an `astra` preset session) and hid that their own model had already failed the same way.
|
|
46
217
|
- Registry fingerprints now enforce the existing regular-file and 32 MiB admission limits with bounded reads. Model activation, thinking overlay lookup, transcript navigation, slash autocomplete, and observer digest updates avoid repeated allocations; status lines without a git segment no longer request git status.
|
|
47
218
|
- Telegram `/session_recent` now distinguishes sessions currently connected to the notification daemon from saved history and prints a ready-to-copy resume command. Inside a session's existing topic, `/session_resume` and `/session_close` can omit the session ID, including after that topic became inactive.
|
|
@@ -54,6 +225,9 @@
|
|
|
54
225
|
|
|
55
226
|
### Fixed
|
|
56
227
|
|
|
228
|
+
- SDK `session.close` now accepts a native payload-durable zero-byte endpoint placeholder when cleaning up a dead host. The broker no longer retries that proven placeholder as JSON and falsely reports `terminal_uncertain`; unknown or replaced artifacts remain refused.
|
|
229
|
+
|
|
230
|
+
- Subagent setup-failure summaries and Codex session imports are scanned in linear time. `createSetupFailureSummary` had two quadratic patterns: its credential-name prefix nested an unbounded quantifier inside an unbounded quantified group, so the inner class ran to the end of a long identifier at every offset, and its URL rule accepted an unbounded scheme before `://`. Together they cost about eight seconds on 100 KB of text holding no credential at all. The Codex import scrubber carried the same URL defect behind its `://` guard, costing 1.3s on a 100 KB transcript that contains one URL. Neither input is length-bounded before it reaches the scrubber, and imported transcripts are external content.
|
|
57
231
|
- SDK submissions that reject during post-turn cleanup no longer publish a contradictory second terminal after their correlation has already settled.
|
|
58
232
|
- Paseo session imports discard unused CLI stdout instead of leaving an unread pipe.
|
|
59
233
|
- SDK live-attach streams preserve producer order across text deltas, final messages, and tool events even when asynchronous extension handlers are slow, without replaying or broadcasting turn content. Content observed while the correlated `agent_start` is still being durably recorded is held and released after the start frame, so no consumer sees turn content before the turn it belongs to; held content is delivered only to the owners that held the run when it was produced, and the hold is bounded (256 events, oldest dropped with one warning) so a wedged start write can neither invert the start/content boundary nor accumulate a whole response in memory.
|
|
@@ -182,6 +356,10 @@
|
|
|
182
356
|
- Coordinator projection consumers now retry a bounded number of fresh authoritative scans when concurrent session churn races a candidate. Cap exhaustion, owner disappearance, unsupported authority, and parse failures remain fail-closed, while settled concurrent SDK sessions no longer permanently starve the session reaper or coordinator mutations. (#5168)
|
|
183
357
|
|
|
184
358
|
- Coordinator session-state locks now reclaim an empty, identity-qualified released transition tombstone on POSIX after a short release grace period. Live, foreign, malformed, non-empty, or identity-changed claims remain fail-closed, while persistent macOS/File Provider debris no longer burns the full transition timeout on every state write. (#5159)
|
|
359
|
+
- Fresh SDK and print sessions now admit a matching credential- and endpoint-scoped discovered-model cache before validating an explicit provider/model, and revalidate pre-existing dynamic targets against the selected row; caller-supplied registries stay immutable while foreign credentials and unknown models remain fail-closed.
|
|
360
|
+
|
|
361
|
+
- `gjc auth-gateway serve` now requires `--provider=<id>`; existing unscoped invocations must choose the provider whose source-backed model catalog and broker credential the gateway should expose.
|
|
362
|
+
- `gjc auth-gateway serve` verifies an enabled broker credential before binding and reports only redacted provider-scoped status/check information.
|
|
185
363
|
|
|
186
364
|
- A runtime-state marker recorded against a different workspace path now reports that mismatch instead of claiming the file is unreadable, and a terminal, not-live marker that travelled into the current workspace with its session directory is adopted rather than refused. Live, non-terminal, and out-of-workspace markers are still refused untouched.
|
|
187
365
|
- An unavailable provider-qualified `modelRoles.default` selection now reports the requested model instead of silently starting on another provider's baseline. This keeps signed-registry omissions and failed catalog admission actionable rather than routing requests to an unrelated retired model. (#5144)
|
|
@@ -357,6 +535,7 @@
|
|
|
357
535
|
- `gjc setup hermes` no longer hardcodes the Hermes MCP client timeouts. New `--timeout` / `--connect-timeout` flags (whole seconds, 1–3600, exit 2 on anything else) override the 180/60 defaults, and `--install` now preserves existing numeric `timeout` / `connect_timeout` values from a GJC-marked block per field when the flag is omitted — a hand-set `timeout: 900` survives re-installs instead of being reset to 180 (#4878). The managed setup signature no longer pins those two operator knobs (hand-tuning keeps the block managed and `--check` no longer flags timeout drift), and unmarked blocks keep the existing refusal and `--force` full-overwrite behavior. Docs/help now state these are host MCP client call budgets — not GJC turn deadlines and not the coordinator per-call caps (`watch_events` 30000 ms; `await_turn` 30 minutes). Upgrading a pre-#4878 install: a block still matching its stored signature is re-signed on the next `--install`; a hand-tuned legacy block is refused with a dedicated stale-signature error pointing at `--force` (which preserves the tuned values); `--profile-dir` targets holding an older operator-instructions render need one `--force` because that file's digest pins its exact content. Unpreservable values (non-numeric or out of range) fall back to defaults with an explicit warning instead of being written through.
|
|
358
536
|
|
|
359
537
|
- Bumped Telegram daemon durable authority to generation 176 after the SDK lifecycle changes modified protected broker declarations. Older generation-175 daemons are now unattachable by this host, preserving fail-closed discovery and launch ownership across rolling upgrades (#4668).
|
|
538
|
+
- An SDK session host is no longer kept alive indefinitely by a broker that never adopted it. The orphan watchdog reset its absence window on *any* live broker publication, so the one event that actually strands a host — its broker dying and being replaced — also refreshed the only bound on its lifetime. Routing lives in the broker process and a replacement never adopts hosts from an earlier incarnation, so the host now pins the broker it was launched under (owner, pid, and start-time incarnation) and counts a successor's publication as absence rather than proof of reachability; a pid-reusing successor is rejected on incarnation. Hosts stranded this way accumulated indefinitely, each pinning its language servers — a JVM-backed server such as `kotlin-lsp` costs roughly 2 GB — and its MCP children, with no path back to a client.
|
|
360
539
|
- Gajae Pet now stays reachable in tmux and image-protocol-free SSH clients through a bounded two-row text-cell rendering. The fallback derives conservative Block Elements from the active skin, uses truecolor when available and ANSI-256 otherwise, reserves no extra transcript rows, and retains the pixel renderer unchanged for supported Kitty, Sixel, and iTerm2 terminals (#4867).
|
|
361
540
|
- `gjc setup hermes --gjc-command` now accepts the full server command instead of always appending `mcp-serve coordinator` (#4877). Omitted or single-token values stay executable-only and render byte-identically to previous output (`gjc`, `/opt/gjc` + `args: [mcp-serve, coordinator]`); a multi-token value is the complete command, split quote-aware (single/double quotes, backslash escapes) into controller argv and rendered verbatim with nothing appended — `--gjc-command 'python3 /tmp/gjc-wrapper.py'` now emits `command: python3`, `args: [/tmp/gjc-wrapper.py]`, exactly the shape a wrapper that already execs `gjc mcp-serve coordinator` needs instead of the doubled argv tail it previously received. Unbalanced quotes are rejected with an explicit error; the value is tokenized, never shell-evaluated. Setup signatures are computed from the rendered block, so existing installs and idempotent re-installs remain valid.
|
|
362
541
|
|
|
@@ -1,7 +1,40 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
export
|
|
2
|
+
/** Authority used when reading from an explicit-home discovery context. */
|
|
3
|
+
export type ReadScope = "project" | "user" | "native";
|
|
4
|
+
export interface FileIdentity {
|
|
5
|
+
readonly dev: number;
|
|
6
|
+
readonly ino: number;
|
|
7
|
+
}
|
|
8
|
+
export interface ReadFileOptions {
|
|
9
|
+
/** Canonicalize the file and enforce the supplied home/profile boundary. */
|
|
10
|
+
readonly isolatedHome?: boolean;
|
|
11
|
+
readonly home?: string;
|
|
12
|
+
readonly homeIdentity?: FileIdentity;
|
|
13
|
+
readonly userAgentDir?: string;
|
|
14
|
+
readonly userAgentIdentity?: FileIdentity | null;
|
|
15
|
+
/**
|
|
16
|
+
* Scope of the read. Foreign user/project providers are home-bound; only
|
|
17
|
+
* native/SSH user reads may use an explicitly external agent directory.
|
|
18
|
+
*/
|
|
19
|
+
readonly scope?: ReadScope;
|
|
20
|
+
/** Skip the shared lexical cache for this operation. */
|
|
21
|
+
readonly bypassCache?: boolean;
|
|
22
|
+
/** Optional physical root that the target must remain within for this read. */
|
|
23
|
+
readonly containmentRoot?: string;
|
|
24
|
+
/** Identity captured when the containment root was authorized. */
|
|
25
|
+
readonly containmentRootIdentity?: FileIdentity;
|
|
26
|
+
}
|
|
27
|
+
/** Reject hard-linked executable or configuration files in isolated discovery. */
|
|
28
|
+
export declare function isSingleLinkRegularFileAt(filePath: string): Promise<boolean>;
|
|
29
|
+
export declare function readFile(filePath: string, options?: ReadFileOptions): Promise<string | null>;
|
|
30
|
+
/** Capture a stable physical identity for an authorized containment root. */
|
|
31
|
+
export declare function capturePathIdentity(filePath: string): Promise<FileIdentity | null>;
|
|
32
|
+
/** Read one byte range through the same canonical authority as readFile. */
|
|
33
|
+
export declare function readFileSlice(filePath: string, start: number, end: number, options?: ReadFileOptions): Promise<Uint8Array | null>;
|
|
34
|
+
/** Read file size through the same canonical authority as readFile. */
|
|
35
|
+
export declare function readFileSize(filePath: string, options?: ReadFileOptions): Promise<number | null>;
|
|
36
|
+
export declare function readDirEntries(dirPath: string, options?: ReadFileOptions): Promise<fs.Dirent[]>;
|
|
37
|
+
export declare function readDir(dirPath: string, options?: ReadFileOptions): Promise<string[]>;
|
|
5
38
|
export declare function walkUp(startDir: string, name: string, opts?: {
|
|
6
39
|
file?: boolean;
|
|
7
40
|
dir?: boolean;
|
|
@@ -11,7 +44,7 @@ export declare function walkUp(startDir: string, name: string, opts?: {
|
|
|
11
44
|
* Returns the directory containing `.git` (the repo root), or null if not in a git repo.
|
|
12
45
|
* Results are based on the cached readDirEntries, so repeated calls are cheap.
|
|
13
46
|
*/
|
|
14
|
-
export declare function findRepoRoot(startDir: string): Promise<string | null>;
|
|
47
|
+
export declare function findRepoRoot(startDir: string, stopAt?: string, options?: ReadFileOptions): Promise<string | null>;
|
|
15
48
|
export declare function cacheStats(): {
|
|
16
49
|
content: number;
|
|
17
50
|
dir: number;
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability Registry
|
|
3
|
+
*
|
|
4
|
+
* Central registry for capabilities and providers. Provides the main API for:
|
|
5
|
+
* - Defining capabilities (what we're looking for)
|
|
6
|
+
* - Registering providers (where to find it)
|
|
7
|
+
* - Loading items for a capability across all providers
|
|
8
|
+
*/
|
|
1
9
|
import type { Settings } from "../config/settings";
|
|
2
10
|
import type { Capability, CapabilityInfo, CapabilityResult, LoadOptions, Provider, ProviderInfo } from "./types";
|
|
3
11
|
/**
|
|
@@ -12,6 +20,17 @@ export declare function registerProvider<T>(capabilityId: string, provider: Prov
|
|
|
12
20
|
* Load a capability by ID.
|
|
13
21
|
*/
|
|
14
22
|
export declare function loadCapability<T>(capabilityId: string, options?: LoadOptions): Promise<CapabilityResult<T>>;
|
|
23
|
+
/**
|
|
24
|
+
* Load a capability against an explicitly supplied home directory.
|
|
25
|
+
*
|
|
26
|
+
* Cross-profile authority contract: when an explicit `home` is supplied, the
|
|
27
|
+
* load must resolve every user-scope surface from that home and NEVER fall
|
|
28
|
+
* back to the process-global `getAgentDir()`. The agent directory is derived
|
|
29
|
+
* from the supplied home (`<home>/<configDir>/agent`) unless the caller
|
|
30
|
+
* supplies an explicit `agentDir`; there is no implicit process-profile
|
|
31
|
+
* fallback. Consumers that cannot derive a user scope must fail closed.
|
|
32
|
+
*/
|
|
33
|
+
export declare function loadCapabilityForHome<T>(capabilityId: string, home: string, options?: LoadOptions): Promise<CapabilityResult<T>>;
|
|
15
34
|
/**
|
|
16
35
|
* Initialize capability system with settings manager for persistence.
|
|
17
36
|
* Call this once on startup to enable persistent provider state.
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* and get back a unified array of MCP servers.
|
|
7
7
|
*/
|
|
8
8
|
import type { Settings } from "../config/settings";
|
|
9
|
+
import type { FileIdentity } from "./fs";
|
|
9
10
|
/**
|
|
10
11
|
* Context passed to every provider loader.
|
|
11
12
|
*/
|
|
@@ -30,8 +31,14 @@ export interface LoadContext {
|
|
|
30
31
|
userAgentDir?: string;
|
|
31
32
|
/** Resolver-owned classification for the selected user agent directory. */
|
|
32
33
|
profileAuthority?: "default" | "custom";
|
|
34
|
+
/** Device/inode identity captured for the explicit home root. */
|
|
35
|
+
homeIdentity?: FileIdentity;
|
|
36
|
+
/** Device/inode identity captured for the isolated native agent root. */
|
|
37
|
+
userAgentIdentity?: FileIdentity | null;
|
|
33
38
|
/** Git repository root (directory containing .git), or null if not in a repo */
|
|
34
39
|
repoRoot: string | null;
|
|
40
|
+
/** Whether discovery must remain isolated to the supplied home boundary. */
|
|
41
|
+
isolatedHome?: boolean;
|
|
35
42
|
/** Owning session settings for provider policy decisions. */
|
|
36
43
|
settings?: Settings;
|
|
37
44
|
}
|
|
@@ -99,6 +106,8 @@ export interface LoadOptions {
|
|
|
99
106
|
disabledExtensions?: string[];
|
|
100
107
|
/** Session settings whose provider policy applies to this load. */
|
|
101
108
|
settings?: Settings;
|
|
109
|
+
/** Internal: prevent explicit-home loads from consulting process-global policy. */
|
|
110
|
+
isolatedHome?: boolean;
|
|
102
111
|
}
|
|
103
112
|
/**
|
|
104
113
|
* Source metadata attached to every loaded item.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { DoctorMode, DoctorRepair, DoctorRiskClass, DoctorScope } from "./types";
|
|
2
|
+
export type DoctorAction = "config.set-validated" | "mcp.set-startup-policy" | "permissions.restrict-owned-config" | "install.restore-binary" | "install.repair-managed-link" | "plugin.restore-known-artifact" | "plugin.quarantine-selected" | "service.restart-owned" | "service.detach-owned-stale-artifact";
|
|
3
|
+
export interface DoctorCliOptions {
|
|
4
|
+
readonly mode: DoctorMode;
|
|
5
|
+
readonly json: boolean;
|
|
6
|
+
readonly help: boolean;
|
|
7
|
+
readonly checks: readonly string[];
|
|
8
|
+
readonly scope?: DoctorScope;
|
|
9
|
+
readonly timeoutMs?: number;
|
|
10
|
+
readonly repair?: DoctorAction;
|
|
11
|
+
readonly targetId?: string;
|
|
12
|
+
readonly setValue?: boolean;
|
|
13
|
+
readonly ref?: string;
|
|
14
|
+
readonly sha256?: string;
|
|
15
|
+
readonly allowRisks: readonly DoctorRiskClass[];
|
|
16
|
+
readonly yes: boolean;
|
|
17
|
+
readonly drainSeconds?: number;
|
|
18
|
+
}
|
|
19
|
+
export type DoctorConfirmationResult = "confirmed" | "confirmation_declined" | "confirmation_timeout" | "cancelled";
|
|
20
|
+
export interface DoctorOptions extends DoctorCliOptions {
|
|
21
|
+
readonly cwd?: string;
|
|
22
|
+
readonly tty?: boolean;
|
|
23
|
+
readonly signal?: AbortSignal;
|
|
24
|
+
readonly runId?: string;
|
|
25
|
+
readonly deadline?: number;
|
|
26
|
+
/** Internal supervisor channel; never populated from CLI data. */
|
|
27
|
+
readonly confirmRepair?: (repair: DoctorRepair) => Promise<DoctorConfirmationResult>;
|
|
28
|
+
/** Synchronous notification before entering an effect-capable transaction. */
|
|
29
|
+
readonly onRepairAdmitted?: () => void;
|
|
30
|
+
}
|
|
31
|
+
export interface DoctorParseResult {
|
|
32
|
+
readonly options?: DoctorOptions;
|
|
33
|
+
readonly error?: string;
|
|
34
|
+
}
|
|
35
|
+
export declare function isDoctorAction(value: unknown): value is DoctorAction;
|
|
36
|
+
export declare function parseDoctorArgs(argv: readonly string[]): DoctorParseResult;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DoctorContext } from "./context";
|
|
2
|
+
import type { DoctorCheck } from "./types";
|
|
3
|
+
export interface DoctorCollector {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly dependsOn: readonly string[];
|
|
6
|
+
readonly timeoutMs: number;
|
|
7
|
+
collect(context: DoctorContext): Promise<DoctorCheck[]>;
|
|
8
|
+
}
|
|
9
|
+
export declare function doctorCheck(id: string, targetId: string, result: Pick<DoctorCheck, "execution" | "health" | "evidenceLevel"> & Partial<DoctorCheck>): DoctorCheck;
|
|
10
|
+
export declare function collectRuntime(context: DoctorContext): Promise<DoctorCheck[]>;
|
|
11
|
+
export declare function collectConfig(context: DoctorContext): Promise<DoctorCheck[]>;
|
|
12
|
+
export declare function collectPermissions(context: DoctorContext): Promise<DoctorCheck[]>;
|
|
13
|
+
export declare function collectMcp(context: DoctorContext): Promise<DoctorCheck[]>;
|
|
14
|
+
export declare function collectCredentials(context: DoctorContext): Promise<DoctorCheck[]>;
|
|
15
|
+
export declare function collectInstallation(context: DoctorContext): Promise<DoctorCheck[]>;
|
|
16
|
+
/** Managed alias observation only: nothing on PATH is executed or resolved through the shell. */
|
|
17
|
+
export declare function collectManagedLinks(context: DoctorContext): Promise<DoctorCheck[]>;
|
|
18
|
+
export declare const BASIC_DOCTOR_COLLECTORS: readonly DoctorCollector[];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { NativeExactFileIdentity } from "@gajae-code/natives";
|
|
2
|
+
import { type CasReceipt } from "../../config/atomic-yaml-patch";
|
|
3
|
+
import type { DoctorCheck, DoctorRepair, DoctorScope } from "./types";
|
|
4
|
+
export interface DoctorConfigRepairRequest {
|
|
5
|
+
readonly filePath: string;
|
|
6
|
+
readonly rootPath: string;
|
|
7
|
+
readonly scope: DoctorScope;
|
|
8
|
+
readonly targetId: string;
|
|
9
|
+
readonly repairId: string;
|
|
10
|
+
readonly runId: string;
|
|
11
|
+
readonly mode: "dry-run" | "fix";
|
|
12
|
+
readonly authorization?: readonly string[];
|
|
13
|
+
readonly journalRoot: string;
|
|
14
|
+
readonly expected: {
|
|
15
|
+
readonly raw: string;
|
|
16
|
+
readonly observedValue?: unknown;
|
|
17
|
+
readonly identity: NativeExactFileIdentity;
|
|
18
|
+
};
|
|
19
|
+
readonly kind: "skill" | "mcp";
|
|
20
|
+
readonly schemaKey?: "skills.enabled" | "skills.enableSkillCommands";
|
|
21
|
+
readonly serverName?: string;
|
|
22
|
+
readonly field?: "autoload" | "enabled";
|
|
23
|
+
readonly value: boolean;
|
|
24
|
+
readonly collectAfterChecks: (input: {
|
|
25
|
+
readonly filePath: string;
|
|
26
|
+
readonly kind: "skill" | "mcp";
|
|
27
|
+
readonly value: boolean;
|
|
28
|
+
}) => Promise<readonly DoctorCheck[]>;
|
|
29
|
+
}
|
|
30
|
+
export interface DoctorConfigRepairResult {
|
|
31
|
+
readonly repair: DoctorRepair;
|
|
32
|
+
readonly receipt?: CasReceipt;
|
|
33
|
+
readonly before?: unknown;
|
|
34
|
+
readonly after?: unknown;
|
|
35
|
+
readonly journalPath?: string;
|
|
36
|
+
readonly afterChecks?: readonly DoctorCheck[];
|
|
37
|
+
}
|
|
38
|
+
export declare function applyDoctorConfigRepair(request: DoctorConfigRepairRequest): Promise<DoctorConfigRepairResult>;
|