@gajae-code/coding-agent 0.11.1 → 0.11.2
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 +54 -0
- package/dist/types/cli/config-cli.d.ts +11 -1
- package/dist/types/cli/notify-cli.d.ts +1 -0
- package/dist/types/cli/session-picker.d.ts +2 -1
- package/dist/types/cli/setup-cli.d.ts +1 -1
- package/dist/types/commands/mcp-serve.d.ts +33 -0
- package/dist/types/commands/mcp.d.ts +1 -1
- package/dist/types/commands/notify.d.ts +0 -2
- package/dist/types/commands/sdk.d.ts +1 -1
- package/dist/types/config/atomic-yaml-patch.d.ts +18 -0
- package/dist/types/config/file-lock.d.ts +14 -4
- package/dist/types/config/keybindings.d.ts +42 -1
- package/dist/types/config/model-auth.d.ts +3 -0
- package/dist/types/config/model-bindings-applier.d.ts +13 -0
- package/dist/types/config/model-discovery-manager.d.ts +49 -0
- package/dist/types/config/model-equivalence.d.ts +20 -0
- package/dist/types/config/model-registry.d.ts +16 -15
- package/dist/types/config/model-resolver.d.ts +28 -18
- package/dist/types/config/models-config-schema.d.ts +11 -0
- package/dist/types/config/settings-schema.d.ts +56 -1
- package/dist/types/config/settings.d.ts +14 -11
- package/dist/types/coordinator-mcp/policy.d.ts +5 -0
- package/dist/types/coordinator-mcp/question-gate-codec.d.ts +129 -0
- package/dist/types/coordinator-mcp/question-state.d.ts +356 -0
- package/dist/types/coordinator-mcp/server.d.ts +4 -0
- package/dist/types/discovery/helpers.d.ts +0 -6
- package/dist/types/edit/index.d.ts +3 -0
- package/dist/types/eval/py/env.d.ts +9 -0
- package/dist/types/extensibility/extensions/loader.d.ts +2 -1
- package/dist/types/extensibility/extensions/runner.d.ts +2 -2
- package/dist/types/extensibility/extensions/types.d.ts +34 -3
- package/dist/types/extensibility/hooks/runner.d.ts +1 -1
- package/dist/types/extensibility/shared-events.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +44 -0
- package/dist/types/gjc-runtime/goal-mode-request.d.ts +11 -1
- package/dist/types/gjc-runtime/launch-worktree.d.ts +4 -2
- package/dist/types/gjc-runtime/linux-proc.d.ts +29 -0
- package/dist/types/gjc-runtime/session-resolution.d.ts +2 -2
- package/dist/types/gjc-runtime/state-migrations.d.ts +1 -1
- package/dist/types/gjc-runtime/state-writer.d.ts +2 -1
- package/dist/types/gjc-runtime/team-launch.d.ts +59 -0
- package/dist/types/gjc-runtime/team-notify.d.ts +45 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +29 -121
- package/dist/types/gjc-runtime/team-store.d.ts +160 -0
- package/dist/types/gjc-runtime/team-workers.d.ts +78 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +8 -0
- package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +13 -0
- package/dist/types/gjc-runtime/ultragoal-evidence.d.ts +38 -0
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +7 -0
- package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +23 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +55 -33
- package/dist/types/gjc-runtime/workflow-cli-common.d.ts +8 -0
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -0
- package/dist/types/goals/continuation-timeout-guard.d.ts +22 -0
- package/dist/types/goals/runtime.d.ts +1 -0
- package/dist/types/goals/state.d.ts +8 -0
- package/dist/types/harness-control-plane/lifecycle-reconciliation.d.ts +17 -0
- package/dist/types/harness-control-plane/phase-rollup.d.ts +4 -7
- package/dist/types/harness-control-plane/receipt-ingest.d.ts +5 -0
- package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
- package/dist/types/hindsight/state.d.ts +11 -4
- package/dist/types/lsp/lspmux.d.ts +5 -3
- package/dist/types/lsp/path-trust.d.ts +1 -0
- package/dist/types/main.d.ts +3 -2
- package/dist/types/memories/storage.d.ts +1 -0
- package/dist/types/modes/action-registry.d.ts +29 -0
- package/dist/types/modes/components/chrome.d.ts +14 -0
- package/dist/types/modes/components/command-palette.d.ts +27 -0
- package/dist/types/modes/components/custom-provider-wizard.d.ts +1 -0
- package/dist/types/modes/components/index.d.ts +2 -1
- package/dist/types/modes/components/pet-selector.d.ts +1 -1
- package/dist/types/modes/components/plan-preview-overlay.d.ts +43 -0
- package/dist/types/modes/components/queue-mode-selector.d.ts +1 -1
- package/dist/types/modes/components/queue-pane.d.ts +12 -0
- package/dist/types/modes/components/read-tool-group.d.ts +6 -0
- package/dist/types/modes/components/session-observer-overlay.d.ts +3 -4
- package/dist/types/modes/components/sessions-dashboard.d.ts +32 -0
- package/dist/types/modes/components/settings-selector.d.ts +1 -1
- package/dist/types/modes/components/show-images-selector.d.ts +1 -1
- package/dist/types/modes/components/status-line/types.d.ts +1 -1
- package/dist/types/modes/components/status-line.d.ts +1 -94
- package/dist/types/modes/components/tasks-pane.d.ts +15 -0
- package/dist/types/modes/components/theme-selector.d.ts +1 -1
- package/dist/types/modes/components/tool-execution.d.ts +15 -0
- package/dist/types/modes/components/tool-status-header.d.ts +111 -0
- package/dist/types/modes/components/transcript-viewer-overlay.d.ts +42 -0
- package/dist/types/modes/controllers/goal-mode-controller.d.ts +62 -0
- package/dist/types/modes/controllers/input-controller.d.ts +8 -1
- package/dist/types/modes/controllers/mode-gate.d.ts +8 -0
- package/dist/types/modes/controllers/plan-mode-controller.d.ts +65 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +15 -3
- package/dist/types/modes/controllers/stt-controller.d.ts +26 -0
- package/dist/types/modes/interactive-mode.d.ts +19 -17
- package/dist/types/modes/jobs-observer.d.ts +2 -0
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +4 -11
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +20 -2
- package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +31 -0
- package/dist/types/modes/tasks-aggregator.d.ts +39 -0
- package/dist/types/modes/transcript-item-registry.d.ts +60 -0
- package/dist/types/modes/types.d.ts +20 -13
- package/dist/types/modes/utils/ui-helpers.d.ts +2 -2
- package/dist/types/runtime-mcp/manager.d.ts +1 -1
- package/dist/types/sdk/broker/broker.d.ts +78 -12
- package/dist/types/sdk/broker/lifecycle-codec.d.ts +4 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +15 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +6 -2
- package/dist/types/sdk/broker/process-incarnation.d.ts +2 -0
- package/dist/types/sdk/broker/session-index.d.ts +0 -1
- package/dist/types/sdk/broker/state-version.d.ts +2 -0
- package/dist/types/sdk/bus/chat-effect-journal.d.ts +1 -0
- package/dist/types/sdk/bus/config-commands.d.ts +1 -1
- package/dist/types/sdk/bus/config.d.ts +11 -0
- package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
- package/dist/types/sdk/bus/html-format.d.ts +3 -2
- package/dist/types/sdk/bus/index.d.ts +27 -0
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/notification-service.d.ts +20 -0
- package/dist/types/sdk/bus/rate-limit-pool.d.ts +13 -2
- package/dist/types/sdk/bus/recent-activity.d.ts +21 -12
- package/dist/types/sdk/bus/rich-document.d.ts +7 -0
- package/dist/types/sdk/bus/rich-render.d.ts +18 -41
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +9 -4
- package/dist/types/sdk/bus/telegram-daemon.d.ts +46 -3
- package/dist/types/sdk/bus/threaded-inbound.d.ts +1 -1
- package/dist/types/sdk/bus/threaded-render.d.ts +13 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +24 -2
- package/dist/types/sdk/host/control/operations.d.ts +1 -1
- package/dist/types/sdk/host/host.d.ts +2 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/session-directory.d.ts +56 -0
- package/dist/types/session/agent-session.d.ts +82 -47
- package/dist/types/session/agent-storage.d.ts +7 -0
- package/dist/types/session/fallback-chain-controller.d.ts +10 -2
- package/dist/types/session/internal/managed-session-scope.d.ts +102 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +38 -0
- package/dist/types/session/messages.d.ts +16 -0
- package/dist/types/session/session-manager-internal.d.ts +14 -0
- package/dist/types/session/session-manager.d.ts +82 -12
- package/dist/types/session/session-storage.d.ts +43 -3
- package/dist/types/session/volatile-context-pruning.d.ts +15 -0
- package/dist/types/skill-state/{deep-interview-mutation-guard.d.ts → workflow-mutation-guard.d.ts} +24 -8
- package/dist/types/skill-state/workflow-state-contract.d.ts +1 -3
- package/dist/types/slash-commands/builtin-registry.d.ts +4 -1
- package/dist/types/system-prompt.d.ts +2 -11
- package/dist/types/task/executor.d.ts +3 -1
- package/dist/types/thinking.d.ts +7 -0
- package/dist/types/tool-discovery/tool-index.d.ts +1 -50
- package/dist/types/tools/ask.d.ts +64 -2
- package/dist/types/tools/bash.d.ts +3 -0
- package/dist/types/tools/browser/dead-tab-recovery.d.ts +24 -0
- package/dist/types/tools/browser/tab-supervisor.d.ts +21 -0
- package/dist/types/tools/cron.d.ts +2 -0
- package/dist/types/tools/fetch.d.ts +1 -0
- package/dist/types/tools/index.d.ts +30 -15
- package/dist/types/tools/output-meta.d.ts +1 -0
- package/dist/types/tools/read.d.ts +3 -0
- package/dist/types/tools/search-tool-bm25.d.ts +3 -4
- package/dist/types/utils/event-bus.d.ts +1 -1
- package/dist/types/web/search/index.d.ts +3 -1
- package/package.json +21 -9
- package/scripts/build-sdk-package-smoke.ts +34 -1
- package/scripts/generate-hotkeys-docs.ts +74 -0
- package/scripts/generate-sdk-operation-inventory.ts +64 -20
- package/scripts/verify-gjc-sdk-canonicalization.ts +182 -2
- package/src/async/job-manager.ts +49 -6
- package/src/cli/config-cli.ts +75 -2
- package/src/cli/notify-cli.ts +92 -26
- package/src/cli/session-picker.ts +20 -3
- package/src/cli/setup-cli.ts +1 -1
- package/src/cli.ts +1 -1
- package/src/commands/config.ts +1 -1
- package/src/commands/harness.ts +34 -106
- package/src/commands/launch.ts +6 -4
- package/src/commands/mcp-serve.ts +85 -8
- package/src/commands/mcp.ts +2 -2
- package/src/commands/notify.ts +8 -4
- package/src/commands/sdk.ts +61 -40
- package/src/commands/ultragoal.ts +4 -1
- package/src/config/atomic-yaml-patch.ts +80 -13
- package/src/config/file-lock.ts +105 -43
- package/src/config/keybindings.ts +64 -20
- package/src/config/model-auth.ts +9 -0
- package/src/config/model-bindings-applier.ts +139 -0
- package/src/config/model-discovery-manager.ts +224 -0
- package/src/config/model-equivalence.ts +66 -0
- package/src/config/model-registry.ts +169 -302
- package/src/config/model-resolver.ts +361 -369
- package/src/config/models-config-schema.ts +5 -4
- package/src/config/settings-schema.ts +159 -2
- package/src/config/settings.ts +458 -482
- package/src/coordinator-mcp/policy.ts +76 -11
- package/src/coordinator-mcp/question-gate-codec.ts +274 -0
- package/src/coordinator-mcp/question-state.ts +778 -0
- package/src/coordinator-mcp/server.ts +1702 -238
- package/src/debug/index.ts +1 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +13 -1
- package/src/defaults/gjc/skills/team/SKILL.md +16 -0
- package/src/discovery/helpers.ts +1 -50
- package/src/edit/index.ts +64 -0
- package/src/eval/py/env.ts +26 -0
- package/src/eval/py/kernel.ts +5 -3
- package/src/extensibility/extensions/loader.ts +9 -1
- package/src/extensibility/extensions/runner.ts +12 -3
- package/src/extensibility/extensions/types.ts +39 -1
- package/src/extensibility/gjc-plugins/installer.ts +16 -16
- package/src/extensibility/hooks/runner.ts +2 -2
- package/src/extensibility/runtime-skill-discovery.ts +33 -13
- package/src/extensibility/shared-events.ts +2 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +63 -3
- package/src/gjc-runtime/deep-interview-runtime.ts +76 -27
- package/src/gjc-runtime/deep-interview-state.ts +317 -5
- package/src/gjc-runtime/goal-mode-request.ts +55 -8
- package/src/gjc-runtime/launch-tmux.ts +2 -5
- package/src/gjc-runtime/launch-worktree.ts +5 -5
- package/src/gjc-runtime/linux-proc.ts +71 -0
- package/src/gjc-runtime/ralplan-runtime.ts +74 -90
- package/src/gjc-runtime/session-resolution.ts +18 -3
- package/src/gjc-runtime/session-state-sidecar.ts +6 -107
- package/src/gjc-runtime/state-migrations.ts +1 -1
- package/src/gjc-runtime/state-runtime.ts +320 -249
- package/src/gjc-runtime/state-writer.ts +36 -40
- package/src/gjc-runtime/team-launch.ts +319 -0
- package/src/gjc-runtime/team-notify.ts +326 -0
- package/src/gjc-runtime/team-runtime.ts +1099 -1482
- package/src/gjc-runtime/team-store.ts +828 -0
- package/src/gjc-runtime/team-workers.ts +962 -0
- package/src/gjc-runtime/tmux-owner-isolation-cli.ts +2 -11
- package/src/gjc-runtime/tmux-owner-isolation.ts +14 -9
- package/src/gjc-runtime/tmux-sessions.ts +4 -21
- package/src/gjc-runtime/ultragoal-change-set.ts +172 -0
- package/src/gjc-runtime/ultragoal-evidence.ts +874 -0
- package/src/gjc-runtime/ultragoal-guard.ts +29 -5
- package/src/gjc-runtime/ultragoal-pipeline.ts +306 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +84 -1311
- package/src/gjc-runtime/workflow-cli-common.ts +30 -0
- package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
- package/src/gjc-runtime/workflow-manifest.ts +18 -0
- package/src/goals/continuation-timeout-guard.ts +79 -0
- package/src/goals/runtime.ts +7 -5
- package/src/goals/state.ts +18 -0
- package/src/harness-control-plane/lifecycle-reconciliation.ts +64 -0
- package/src/harness-control-plane/phase-rollup.ts +4 -7
- package/src/harness-control-plane/receipt-ingest.ts +5 -0
- package/src/harness-control-plane/receipt-spool.ts +51 -7
- package/src/harness-control-plane/session-lease.ts +12 -130
- package/src/hindsight/backend.ts +26 -27
- package/src/hindsight/state.ts +101 -32
- package/src/hooks/skill-state.ts +17 -11
- package/src/internal-urls/docs-index.generated.ts +21 -18
- package/src/lsp/client.ts +1 -1
- package/src/lsp/config.ts +145 -26
- package/src/lsp/index.ts +1 -1
- package/src/lsp/lspmux.ts +39 -10
- package/src/lsp/path-trust.ts +81 -0
- package/src/main.ts +28 -8
- package/src/memories/index.ts +1 -0
- package/src/memories/storage.ts +6 -2
- package/src/modes/action-registry.ts +165 -0
- package/src/modes/components/chrome.ts +40 -0
- package/src/modes/components/command-palette.ts +168 -0
- package/src/modes/components/custom-editor.ts +1 -1
- package/src/modes/components/custom-provider-wizard.ts +51 -14
- package/src/modes/components/index.ts +2 -1
- package/src/modes/components/pet-selector.ts +11 -17
- package/src/modes/components/plan-preview-overlay.ts +295 -0
- package/src/modes/components/queue-mode-selector.ts +10 -27
- package/src/modes/components/queue-pane.ts +79 -0
- package/src/modes/components/read-tool-group.ts +13 -0
- package/src/modes/components/session-observer-overlay.ts +207 -772
- package/src/modes/components/sessions-dashboard.ts +181 -0
- package/src/modes/components/settings-selector.ts +1 -1
- package/src/modes/components/show-images-selector.ts +10 -24
- package/src/modes/components/status-line/types.ts +1 -1
- package/src/modes/components/status-line.ts +1 -969
- package/src/modes/components/tasks-pane.ts +73 -0
- package/src/modes/components/theme-selector.ts +11 -31
- package/src/modes/components/tool-execution.ts +22 -0
- package/src/modes/components/tool-status-header.ts +1056 -0
- package/src/modes/components/transcript-viewer-overlay.ts +384 -0
- package/src/modes/controllers/btw-controller.ts +1 -0
- package/src/modes/controllers/event-controller.ts +3 -2
- package/src/modes/controllers/extension-ui-controller.ts +24 -1
- package/src/modes/controllers/goal-mode-controller.ts +474 -0
- package/src/modes/controllers/input-controller.ts +764 -229
- package/src/modes/controllers/mode-gate.ts +24 -0
- package/src/modes/controllers/plan-mode-controller.ts +517 -0
- package/src/modes/controllers/selector-controller.ts +225 -10
- package/src/modes/controllers/stt-controller.ts +125 -0
- package/src/modes/interactive-mode.ts +289 -1150
- package/src/modes/jobs-observer.ts +3 -0
- package/src/modes/runtime-init.ts +8 -0
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +31 -106
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +71 -16
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +177 -0
- package/src/modes/tasks-aggregator.ts +199 -0
- package/src/modes/transcript-item-registry.ts +229 -0
- package/src/modes/types.ts +45 -18
- package/src/modes/utils/ui-helpers.ts +17 -9
- package/src/prompts/agent-fragments/ralplan-persistence.md +6 -0
- package/src/prompts/agent-fragments/restricted-bash.md +1 -0
- package/src/prompts/agents/architect.md +2 -8
- package/src/prompts/agents/critic.md +2 -8
- package/src/prompts/agents/executor.md +3 -0
- package/src/prompts/agents/planner.md +4 -12
- package/src/prompts/system/custom-system-prompt.md +1 -23
- package/src/prompts/system/plan-mode-approved.md +8 -0
- package/src/prompts/system/system-prompt.md +17 -96
- package/src/prompts/tools/bash.md +4 -4
- package/src/prompts/tools/browser.md +15 -52
- package/src/prompts/tools/find.md +2 -2
- package/src/prompts/tools/hashline.md +13 -55
- package/src/prompts/tools/read.md +3 -6
- package/src/prompts/tools/search-tool-bm25.md +0 -2
- package/src/prompts/tools/search.md +2 -4
- package/src/prompts/tools/skill-discovery.md +1 -2
- package/src/prompts/tools/task.md +1 -1
- package/src/runtime-mcp/manager.ts +1 -1
- package/src/sdk/broker/broker.ts +206 -78
- package/src/sdk/broker/discovery.ts +1 -1
- package/src/sdk/broker/ensure.ts +3 -1
- package/src/sdk/broker/lifecycle-codec.ts +11 -0
- package/src/sdk/broker/lifecycle-ledger.ts +371 -74
- package/src/sdk/broker/lifecycle.ts +1399 -142
- package/src/sdk/broker/process-incarnation.ts +5 -13
- package/src/sdk/broker/session-index.ts +145 -56
- package/src/sdk/broker/state-version.ts +21 -0
- package/src/sdk/broker/transport.ts +1 -1
- package/src/sdk/bus/chat-daemon-cli.ts +2 -0
- package/src/sdk/bus/chat-daemon-control.ts +8 -28
- package/src/sdk/bus/chat-effect-journal.ts +10 -2
- package/src/sdk/bus/config-commands.ts +5 -4
- package/src/sdk/bus/config.ts +98 -0
- package/src/sdk/bus/conversation-store.ts +5 -29
- package/src/sdk/bus/daemon-paths.ts +2 -0
- package/src/sdk/bus/html-format.ts +20 -3
- package/src/sdk/bus/index.ts +778 -93
- package/src/sdk/bus/lifecycle-control-runtime.ts +91 -33
- package/src/sdk/bus/natives-augment.d.ts +26 -1
- package/src/sdk/bus/notification-service.ts +168 -20
- package/src/sdk/bus/rate-limit-pool.ts +58 -14
- package/src/sdk/bus/recent-activity.ts +188 -74
- package/src/sdk/bus/rich-document.ts +258 -0
- package/src/sdk/bus/rich-render.ts +62 -70
- package/src/sdk/bus/telegram-daemon-cli.ts +15 -59
- package/src/sdk/bus/telegram-daemon-contract.ts +9 -4
- package/src/sdk/bus/telegram-daemon.ts +1389 -237
- package/src/sdk/bus/threaded-inbound.ts +8 -3
- package/src/sdk/bus/threaded-render.ts +57 -1
- package/src/sdk/bus/topic-registry.ts +120 -13
- package/src/sdk/host/control/dispatch.ts +14 -2
- package/src/sdk/host/control/operations.ts +6 -1
- package/src/sdk/host/host.ts +31 -1
- package/src/sdk/host/query/handlers.ts +20 -22
- package/src/sdk/host/query/revision-store.ts +80 -57
- package/src/sdk/index.ts +1 -0
- package/src/sdk/protocol/operation-inventory.generated.json +943 -1907
- package/src/sdk/session-directory.ts +141 -0
- package/src/sdk/session.ts +458 -479
- package/src/session/agent-session.ts +1700 -583
- package/src/session/agent-storage.ts +18 -0
- package/src/session/cache-economics.ts +25 -8
- package/src/session/fallback-chain-controller.ts +53 -3
- package/src/session/internal/managed-session-scope.ts +2226 -0
- package/src/session/internal/managed-session-storage.ts +453 -0
- package/src/session/messages.ts +91 -2
- package/src/session/session-manager-internal.ts +33 -0
- package/src/session/session-manager.ts +1112 -333
- package/src/session/session-storage.ts +444 -39
- package/src/session/volatile-context-pruning.ts +78 -0
- package/src/setup/credential-auto-import.ts +2 -1
- package/src/setup/hermes/templates/operator-instructions.v1.md +1 -1
- package/src/setup/provider-onboarding.ts +36 -61
- package/src/setup/provider-presets.json +5 -0
- package/src/skill-state/active-state.ts +3 -13
- package/src/skill-state/{deep-interview-mutation-guard.ts → workflow-mutation-guard.ts} +47 -29
- package/src/skill-state/workflow-state-contract.ts +6 -41
- package/src/slash-commands/builtin-registry.ts +46 -11
- package/src/system-prompt.ts +37 -44
- package/src/task/agents.ts +19 -1
- package/src/task/executor.ts +90 -6
- package/src/task/index.ts +36 -21
- package/src/thinking.ts +21 -6
- package/src/tool-discovery/tool-index.ts +2 -134
- package/src/tools/ask.ts +157 -21
- package/src/tools/ast-edit.ts +1 -1
- package/src/tools/bash.ts +38 -0
- package/src/tools/browser/dead-tab-recovery.ts +78 -0
- package/src/tools/browser/tab-supervisor.ts +282 -36
- package/src/tools/computer.ts +10 -3
- package/src/tools/cron.ts +30 -16
- package/src/tools/eval.ts +1 -2
- package/src/tools/fetch.ts +11 -4
- package/src/tools/index.ts +76 -24
- package/src/tools/output-meta.ts +13 -5
- package/src/tools/read.ts +37 -1
- package/src/tools/resource-gc.ts +2 -2
- package/src/tools/search-tool-bm25.ts +11 -74
- package/src/utils/event-bus.ts +9 -4
- package/src/web/search/index.ts +3 -3
- package/dist/types/discovery/plugin-dir-roots.d.ts +0 -15
- package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +0 -7
- package/src/discovery/plugin-dir-roots.ts +0 -28
- package/src/runtime-mcp/discoverable-tool-metadata.ts +0 -25
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getAgentDir } from "@gajae-code/utils";
|
|
1
2
|
import { Args, Command, Flags } from "@gajae-code/utils/cli";
|
|
2
3
|
import {
|
|
3
4
|
COORDINATOR_MCP_PROTOCOL_VERSION,
|
|
@@ -5,12 +6,88 @@ import {
|
|
|
5
6
|
COORDINATOR_MCP_TOOL_NAMES,
|
|
6
7
|
} from "../coordinator/contract";
|
|
7
8
|
import { runCoordinatorMcpStdio } from "../coordinator-mcp/server";
|
|
9
|
+
import { type BrokerDiscovery, readBrokerDiscovery } from "../sdk/broker/discovery";
|
|
10
|
+
import { UnsupportedStateVersionError } from "../sdk/broker/state-version";
|
|
8
11
|
import { runSdkMcpStdio, SDK_MCP_TOOL_NAMES } from "../sdk/mcp/server";
|
|
9
12
|
|
|
10
13
|
function writeJson(value: unknown): void {
|
|
11
14
|
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
12
15
|
}
|
|
13
16
|
|
|
17
|
+
export type CoordinatorBrokerDiscoveryStatus = "ready" | "unavailable" | "error";
|
|
18
|
+
export type CoordinatorBrokerDiscoveryReason =
|
|
19
|
+
| null
|
|
20
|
+
| "absent_or_invalid"
|
|
21
|
+
| "unsupported_state_version"
|
|
22
|
+
| "discovery_access_denied"
|
|
23
|
+
| "discovery_read_failed";
|
|
24
|
+
|
|
25
|
+
export interface CoordinatorBrokerObservation {
|
|
26
|
+
discovery_status: CoordinatorBrokerDiscoveryStatus;
|
|
27
|
+
reason: CoordinatorBrokerDiscoveryReason;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface CoordinatorCheckProbe {
|
|
31
|
+
agentDir?: string;
|
|
32
|
+
readBrokerDiscovery?: (agentDir: string) => Promise<BrokerDiscovery | null>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface CoordinatorCheckPayload {
|
|
36
|
+
ok: true;
|
|
37
|
+
server: { name: typeof COORDINATOR_MCP_SERVER_NAME; protocolVersion: typeof COORDINATOR_MCP_PROTOCOL_VERSION };
|
|
38
|
+
readOnly: true;
|
|
39
|
+
tools: readonly string[];
|
|
40
|
+
catalog: { ready: true; reason: null };
|
|
41
|
+
broker: CoordinatorBrokerObservation & {
|
|
42
|
+
operational_ready: null;
|
|
43
|
+
bootstrap_supported: true;
|
|
44
|
+
bootstrap_attempted: false;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function discoveryErrorCode(error: unknown): unknown {
|
|
49
|
+
if (typeof error !== "object" || error === null || !("code" in error)) return undefined;
|
|
50
|
+
return error.code;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function probeCoordinatorBrokerCheck(
|
|
54
|
+
probe: CoordinatorCheckProbe = {},
|
|
55
|
+
): Promise<CoordinatorBrokerObservation> {
|
|
56
|
+
try {
|
|
57
|
+
const discovery = await (probe.readBrokerDiscovery ?? readBrokerDiscovery)(probe.agentDir ?? getAgentDir());
|
|
58
|
+
return discovery
|
|
59
|
+
? { discovery_status: "ready", reason: null }
|
|
60
|
+
: { discovery_status: "unavailable", reason: "absent_or_invalid" };
|
|
61
|
+
} catch (error) {
|
|
62
|
+
if (error instanceof UnsupportedStateVersionError)
|
|
63
|
+
return { discovery_status: "error", reason: "unsupported_state_version" };
|
|
64
|
+
const code = discoveryErrorCode(error);
|
|
65
|
+
if (code === "EACCES" || code === "EPERM")
|
|
66
|
+
return { discovery_status: "error", reason: "discovery_access_denied" };
|
|
67
|
+
return { discovery_status: "error", reason: "discovery_read_failed" };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function formatCoordinatorCheckPayload(observation: CoordinatorBrokerObservation): CoordinatorCheckPayload {
|
|
72
|
+
return {
|
|
73
|
+
ok: true,
|
|
74
|
+
server: { name: COORDINATOR_MCP_SERVER_NAME, protocolVersion: COORDINATOR_MCP_PROTOCOL_VERSION },
|
|
75
|
+
readOnly: true,
|
|
76
|
+
tools: [...COORDINATOR_MCP_TOOL_NAMES],
|
|
77
|
+
catalog: { ready: true, reason: null },
|
|
78
|
+
broker: {
|
|
79
|
+
...observation,
|
|
80
|
+
operational_ready: null,
|
|
81
|
+
bootstrap_supported: true,
|
|
82
|
+
bootstrap_attempted: false,
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export async function buildCoordinatorCheckPayload(probe?: CoordinatorCheckProbe): Promise<CoordinatorCheckPayload> {
|
|
88
|
+
return formatCoordinatorCheckPayload(await probeCoordinatorBrokerCheck(probe));
|
|
89
|
+
}
|
|
90
|
+
|
|
14
91
|
export function validateMcpServeSubcommandForTest(server: string | undefined): void {
|
|
15
92
|
if (server !== "coordinator" && server !== "hermes" && server !== "sdk")
|
|
16
93
|
throw new Error(`unknown_mcp_serve_subcommand:${server ?? ""}`);
|
|
@@ -46,17 +123,17 @@ export default class McpServe extends Command {
|
|
|
46
123
|
}
|
|
47
124
|
|
|
48
125
|
if (flags.check) {
|
|
126
|
+
if (!flags.json) {
|
|
127
|
+
const serverName = server === "sdk" ? "gjc-sdk-mcp" : COORDINATOR_MCP_SERVER_NAME;
|
|
128
|
+
const toolCount = server === "sdk" ? SDK_MCP_TOOL_NAMES.length : COORDINATOR_MCP_TOOL_NAMES.length;
|
|
129
|
+
process.stdout.write(`server: ${serverName}\ntools: ${toolCount}\n`);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
49
132
|
const payload =
|
|
50
133
|
server === "sdk"
|
|
51
134
|
? { ok: true, server: { name: "gjc-sdk-mcp" }, readOnly: false, tools: [...SDK_MCP_TOOL_NAMES] }
|
|
52
|
-
:
|
|
53
|
-
|
|
54
|
-
server: { name: COORDINATOR_MCP_SERVER_NAME, protocolVersion: COORDINATOR_MCP_PROTOCOL_VERSION },
|
|
55
|
-
readOnly: true,
|
|
56
|
-
tools: [...COORDINATOR_MCP_TOOL_NAMES],
|
|
57
|
-
};
|
|
58
|
-
if (flags.json) writeJson(payload);
|
|
59
|
-
else process.stdout.write(`server: ${payload.server.name}\ntools: ${payload.tools.length}\n`);
|
|
135
|
+
: await buildCoordinatorCheckPayload();
|
|
136
|
+
writeJson(payload);
|
|
60
137
|
return;
|
|
61
138
|
}
|
|
62
139
|
|
package/src/commands/mcp.ts
CHANGED
|
@@ -53,7 +53,7 @@ export default class MCP extends Command {
|
|
|
53
53
|
|
|
54
54
|
async run(): Promise<void> {
|
|
55
55
|
if (this.argv.includes("--help") || this.argv.includes("-h")) {
|
|
56
|
-
this
|
|
56
|
+
this.#printHelp();
|
|
57
57
|
return;
|
|
58
58
|
}
|
|
59
59
|
|
|
@@ -80,7 +80,7 @@ export default class MCP extends Command {
|
|
|
80
80
|
await runMCPCommand(cmd);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
#printHelp(): void {
|
|
84
84
|
process.stdout.write(`Store standalone MCP server definitions in GJC config without loading them at runtime
|
|
85
85
|
|
|
86
86
|
USAGE
|
package/src/commands/notify.ts
CHANGED
|
@@ -12,9 +12,8 @@ export default class Notify extends Command {
|
|
|
12
12
|
|
|
13
13
|
static args = {
|
|
14
14
|
action: Args.string({
|
|
15
|
-
description: "Notify action",
|
|
15
|
+
description: "Notify action (setup|status|health|test|recovery|daemon-internal)",
|
|
16
16
|
required: false,
|
|
17
|
-
options: ACTIONS,
|
|
18
17
|
}),
|
|
19
18
|
extra: Args.string({
|
|
20
19
|
description: "Provider or additional internal args",
|
|
@@ -49,7 +48,12 @@ export default class Notify extends Command {
|
|
|
49
48
|
|
|
50
49
|
async run(): Promise<void> {
|
|
51
50
|
const { args, flags } = await this.parse(Notify);
|
|
52
|
-
const action =
|
|
51
|
+
const action = args.action ?? "status";
|
|
52
|
+
if (!ACTIONS.includes(action as NotifyAction)) {
|
|
53
|
+
console.error(`Unknown notify action: ${action}`);
|
|
54
|
+
console.error(`Valid actions: ${ACTIONS.join(", ")}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
53
57
|
const extra = Array.isArray(args.extra) ? args.extra : args.extra ? [args.extra] : [];
|
|
54
58
|
const flagRec = flags as Record<string, unknown>;
|
|
55
59
|
const ownerId = flagRec["owner-id"] as string | undefined;
|
|
@@ -72,7 +76,7 @@ export default class Notify extends Command {
|
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
const cmd: NotifyCommandArgs = {
|
|
75
|
-
action,
|
|
79
|
+
action: action as NotifyAction,
|
|
76
80
|
smoke: flags.smoke,
|
|
77
81
|
rawArgs,
|
|
78
82
|
provider: provider === "telegram" || provider === "discord" || provider === "slack" ? provider : undefined,
|
package/src/commands/sdk.ts
CHANGED
|
@@ -3,6 +3,7 @@ import * as fs from "node:fs/promises";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { Args, Command, Flags } from "@gajae-code/utils/cli";
|
|
5
5
|
import type { Args as ParsedArgs } from "../cli/args";
|
|
6
|
+
import { Settings } from "../config/settings";
|
|
6
7
|
import { applyStartupModelProfiles, createSessionManager } from "../main";
|
|
7
8
|
import { initializeExtensions } from "../modes/runtime-init";
|
|
8
9
|
import { Broker } from "../sdk/broker/broker";
|
|
@@ -16,20 +17,28 @@ import {
|
|
|
16
17
|
} from "../sdk/broker/lifecycle";
|
|
17
18
|
import { processIncarnation } from "../sdk/broker/process-incarnation";
|
|
18
19
|
import { type CreateLifecycleAgentSessionResult, createLifecycleAgentSession } from "../sdk/lifecycle-session";
|
|
20
|
+
import { listManagedSessionCandidates, resolveManagedSessionScope } from "../sdk/session-directory";
|
|
19
21
|
import {
|
|
20
22
|
normalizeSdkStartupFailure,
|
|
21
23
|
type SdkStartupFailure,
|
|
22
24
|
type SdkStartupRollbackResult,
|
|
23
25
|
SdkStartupRollbackTracker,
|
|
24
26
|
} from "../sdk/startup-capability";
|
|
25
|
-
|
|
26
27
|
import {
|
|
27
28
|
type CapturedSessionTranscriptSnapshot,
|
|
28
29
|
type ResumeSessionIdentity,
|
|
29
30
|
SessionManager,
|
|
30
31
|
} from "../session/session-manager";
|
|
31
32
|
|
|
32
|
-
export function lifecycleArgs(
|
|
33
|
+
export async function lifecycleArgs(
|
|
34
|
+
request: SessionLifecycleLaunchRequest,
|
|
35
|
+
cwd: string,
|
|
36
|
+
agentDir: string,
|
|
37
|
+
): Promise<ParsedArgs> {
|
|
38
|
+
const targetScope = await resolveManagedSessionScope({ cwd, agentDir });
|
|
39
|
+
if (targetScope.kind !== "resolved") throw new Error(`Lifecycle session scope is invalid: ${targetScope.message}`);
|
|
40
|
+
const forkSessionDir =
|
|
41
|
+
request.operation === "session.fork" ? SessionManager.getDefaultSessionDir(cwd, agentDir) : undefined;
|
|
33
42
|
return {
|
|
34
43
|
messages: [],
|
|
35
44
|
fileArgs: [],
|
|
@@ -39,7 +48,7 @@ export function lifecycleArgs(request: SessionLifecycleLaunchRequest, cwd: strin
|
|
|
39
48
|
...(request.operation === "session.fork"
|
|
40
49
|
? {
|
|
41
50
|
fork: request.sourceSessionPath ?? request.sourceSessionId,
|
|
42
|
-
sessionDir:
|
|
51
|
+
sessionDir: forkSessionDir,
|
|
43
52
|
}
|
|
44
53
|
: {}),
|
|
45
54
|
};
|
|
@@ -53,7 +62,7 @@ type LifecycleTranscriptSource = {
|
|
|
53
62
|
};
|
|
54
63
|
|
|
55
64
|
function sameTranscriptIdentity(
|
|
56
|
-
actual: { dev: bigint; ino: bigint; size: number; mtimeMs: number; mtimeNs: bigint },
|
|
65
|
+
actual: { dev: bigint; ino: bigint; size: number; mtimeMs: number; mtimeNs: bigint; sha256: string },
|
|
57
66
|
expected: SessionLifecycleTranscriptIdentity,
|
|
58
67
|
): boolean {
|
|
59
68
|
return (
|
|
@@ -61,7 +70,8 @@ function sameTranscriptIdentity(
|
|
|
61
70
|
actual.ino.toString() === expected.ino &&
|
|
62
71
|
actual.size === expected.size &&
|
|
63
72
|
actual.mtimeMs === expected.mtimeMs &&
|
|
64
|
-
actual.mtimeNs.toString() === expected.mtimeNs
|
|
73
|
+
actual.mtimeNs.toString() === expected.mtimeNs &&
|
|
74
|
+
actual.sha256 === expected.sha256
|
|
65
75
|
);
|
|
66
76
|
}
|
|
67
77
|
|
|
@@ -85,26 +95,38 @@ function lifecycleTranscriptSource(request: SessionLifecycleLaunchRequest, cwd:
|
|
|
85
95
|
throw new Error("A new lifecycle session has no persisted transcript authority.");
|
|
86
96
|
}
|
|
87
97
|
|
|
88
|
-
function
|
|
98
|
+
async function captureLifecycleTranscript(
|
|
89
99
|
request: SessionLifecycleLaunchRequest,
|
|
90
100
|
cwd: string,
|
|
91
101
|
agentDir: string,
|
|
92
|
-
|
|
102
|
+
migrationPolicy: "copy-retain" | "disabled",
|
|
103
|
+
): Promise<CapturedSessionTranscriptSnapshot> {
|
|
93
104
|
const source = lifecycleTranscriptSource(request, cwd);
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
105
|
+
const scope = await resolveManagedSessionScope({ cwd: source.cwd, agentDir });
|
|
106
|
+
if (scope.kind !== "resolved")
|
|
107
|
+
throw new Error("Lifecycle saved session storage could not be verified for the requested workspace.");
|
|
108
|
+
const inventory = await listManagedSessionCandidates({ scope: scope.scope });
|
|
97
109
|
if (inventory.kind !== "complete")
|
|
98
110
|
throw new Error("Lifecycle saved session storage could not be verified for the requested workspace.");
|
|
99
|
-
const
|
|
111
|
+
const captured = SessionManager.captureTranscriptStrict(source.path);
|
|
112
|
+
if (
|
|
113
|
+
captured.kind !== "captured" ||
|
|
114
|
+
captured.snapshot.sourcePath !== path.resolve(source.path) ||
|
|
115
|
+
captured.snapshot.identity.sessionId !== source.id ||
|
|
116
|
+
!sameTranscriptIdentity(captured.snapshot.identity, source.identity)
|
|
117
|
+
)
|
|
118
|
+
throw new Error("Lifecycle saved session authority changed before the session host consumed it.");
|
|
119
|
+
const matches = inventory.owned.filter(
|
|
100
120
|
candidate =>
|
|
101
|
-
candidate.path ===
|
|
102
|
-
candidate.
|
|
103
|
-
|
|
121
|
+
candidate.path === captured.snapshot.sourcePath &&
|
|
122
|
+
candidate.sessionId === source.id &&
|
|
123
|
+
sameLifecycleTranscriptSnapshot(candidate.identity, captured.snapshot.identity),
|
|
104
124
|
);
|
|
105
125
|
if (matches.length !== 1)
|
|
106
126
|
throw new Error("Lifecycle saved session authority changed before the session host started.");
|
|
107
|
-
|
|
127
|
+
if (matches[0]!.provenance === "legacy" && migrationPolicy === "disabled")
|
|
128
|
+
throw new Error("Lifecycle legacy session migration is disabled by policy.");
|
|
129
|
+
return captured.snapshot;
|
|
108
130
|
}
|
|
109
131
|
|
|
110
132
|
function sameLifecycleTranscriptSnapshot(left: ResumeSessionIdentity, right: ResumeSessionIdentity): boolean {
|
|
@@ -120,23 +142,6 @@ function sameLifecycleTranscriptSnapshot(left: ResumeSessionIdentity, right: Res
|
|
|
120
142
|
);
|
|
121
143
|
}
|
|
122
144
|
|
|
123
|
-
function captureLifecycleTranscript(
|
|
124
|
-
request: SessionLifecycleLaunchRequest,
|
|
125
|
-
cwd: string,
|
|
126
|
-
agentDir: string,
|
|
127
|
-
): CapturedSessionTranscriptSnapshot {
|
|
128
|
-
const source = verifyLifecycleTranscript(request, cwd, agentDir);
|
|
129
|
-
const captured = SessionManager.captureTranscriptStrict(source.path);
|
|
130
|
-
if (
|
|
131
|
-
captured.kind !== "captured" ||
|
|
132
|
-
captured.snapshot.sourcePath !== path.resolve(source.path) ||
|
|
133
|
-
captured.snapshot.identity.sessionId !== source.id ||
|
|
134
|
-
!sameTranscriptIdentity(captured.snapshot.identity, source.identity)
|
|
135
|
-
)
|
|
136
|
-
throw new Error("Lifecycle saved session authority changed before the session host consumed it.");
|
|
137
|
-
return captured.snapshot;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
145
|
async function revalidateLifecycleTranscript(snapshot: ResumeSessionIdentity): Promise<void> {
|
|
141
146
|
const inspected = await SessionManager.inspectSessionTailReadOnly(snapshot.canonicalPath);
|
|
142
147
|
if (inspected.kind === "error" || !sameLifecycleTranscriptSnapshot(snapshot, inspected.identity))
|
|
@@ -149,14 +154,22 @@ export async function openLifecycleSessionManager(
|
|
|
149
154
|
cwd: string,
|
|
150
155
|
agentDir: string,
|
|
151
156
|
): Promise<{ parsed: ParsedArgs; sessionManager: SessionManager | undefined }> {
|
|
152
|
-
const parsed = lifecycleArgs(request, cwd, agentDir);
|
|
157
|
+
const parsed = await lifecycleArgs(request, cwd, agentDir);
|
|
158
|
+
const lifecycleSettings = await Settings.loadForScope({ cwd, agentDir });
|
|
159
|
+
const migrationPolicy =
|
|
160
|
+
lifecycleSettings.get("session.directoryMigration") === "disabled" ? "disabled" : "copy-retain";
|
|
153
161
|
if (request.operation === "session.create") {
|
|
154
|
-
return { parsed, sessionManager: await createSessionManager(parsed, cwd) };
|
|
162
|
+
return { parsed, sessionManager: await createSessionManager(parsed, cwd, lifecycleSettings) };
|
|
155
163
|
}
|
|
156
|
-
const snapshot = captureLifecycleTranscript(request, cwd, agentDir);
|
|
164
|
+
const snapshot = await captureLifecycleTranscript(request, cwd, agentDir, migrationPolicy);
|
|
157
165
|
let sessionManager: SessionManager | undefined;
|
|
158
166
|
if (request.operation === "session.resume") {
|
|
159
|
-
const opened = await SessionManager.openExistingStrict(
|
|
167
|
+
const opened = await SessionManager.openExistingStrict(
|
|
168
|
+
snapshot.identity,
|
|
169
|
+
parsed.sessionDir,
|
|
170
|
+
undefined,
|
|
171
|
+
migrationPolicy,
|
|
172
|
+
);
|
|
160
173
|
if (opened.kind === "error")
|
|
161
174
|
throw new Error("Lifecycle saved session authority changed while the session host opened it.");
|
|
162
175
|
sessionManager = opened.manager;
|
|
@@ -167,7 +180,7 @@ export async function openLifecycleSessionManager(
|
|
|
167
180
|
throw error;
|
|
168
181
|
}
|
|
169
182
|
} else {
|
|
170
|
-
const forked = await SessionManager.forkFromCaptured(snapshot, cwd, parsed.sessionDir);
|
|
183
|
+
const forked = await SessionManager.forkFromCaptured(snapshot, cwd, parsed.sessionDir, migrationPolicy);
|
|
171
184
|
if (forked.kind === "error")
|
|
172
185
|
throw new Error("Lifecycle saved session authority changed while the session host forked it.");
|
|
173
186
|
sessionManager = forked.manager;
|
|
@@ -302,21 +315,23 @@ export async function runSessionHost(
|
|
|
302
315
|
fs.readFile(transcriptPath),
|
|
303
316
|
fs.stat(transcriptPath, { bigint: true }),
|
|
304
317
|
]);
|
|
318
|
+
const digest = createHash("sha256").update(bytes).digest("hex");
|
|
305
319
|
return {
|
|
306
|
-
digest
|
|
320
|
+
digest,
|
|
307
321
|
identity: {
|
|
308
322
|
dev: stat.dev.toString(),
|
|
309
323
|
ino: stat.ino.toString(),
|
|
310
324
|
size: Number(stat.size),
|
|
311
325
|
mtimeMs: Number(stat.mtimeMs),
|
|
312
326
|
mtimeNs: stat.mtimeNs.toString(),
|
|
327
|
+
sha256: digest,
|
|
313
328
|
},
|
|
314
329
|
};
|
|
315
330
|
} catch {
|
|
316
331
|
return undefined;
|
|
317
332
|
}
|
|
318
333
|
})();
|
|
319
|
-
return disposal;
|
|
334
|
+
return disposal ?? Promise.resolve(undefined);
|
|
320
335
|
};
|
|
321
336
|
let failureRollback: Promise<void> | undefined;
|
|
322
337
|
const failAfterRollback = (failure: SdkStartupFailure): Promise<void> => {
|
|
@@ -415,7 +430,13 @@ export default class Sdk extends Command {
|
|
|
415
430
|
}
|
|
416
431
|
const agentDir = flags["agent-dir"] as string | undefined;
|
|
417
432
|
if (!agentDir) throw new Error("--agent-dir is required for sdk broker-internal.");
|
|
418
|
-
const broker = new Broker({
|
|
433
|
+
const broker = new Broker({
|
|
434
|
+
agentDir,
|
|
435
|
+
resolveDirectoryMigration: async cwd => {
|
|
436
|
+
const policy = (await Settings.loadForScope({ cwd, agentDir })).get("session.directoryMigration");
|
|
437
|
+
return policy === "disabled" ? "disabled" : "copy-retain";
|
|
438
|
+
},
|
|
439
|
+
});
|
|
419
440
|
await broker.start();
|
|
420
441
|
if (!broker.ownsDiscovery) return;
|
|
421
442
|
const stop = () => void broker.stop().finally(() => process.exit(0));
|
|
@@ -26,15 +26,18 @@ export default class Ultragoal extends Command {
|
|
|
26
26
|
if (isReviewStart && !result.createdReviewPlan && (result.reviewBlockerGoalIds?.length ?? 0) === 0) return;
|
|
27
27
|
|
|
28
28
|
const cwd = process.cwd();
|
|
29
|
-
const { objective, goalsPath } = await readUltragoalGjcObjective(cwd);
|
|
29
|
+
const { objective, goalsPath, provenance } = await readUltragoalGjcObjective(cwd);
|
|
30
|
+
|
|
30
31
|
await writeCurrentSessionGoalModeState({
|
|
31
32
|
sessionFile: process.env[GJC_SESSION_FILE_ENV],
|
|
32
33
|
objective,
|
|
34
|
+
provenance,
|
|
33
35
|
});
|
|
34
36
|
await writePendingGoalModeRequest({
|
|
35
37
|
cwd,
|
|
36
38
|
objective,
|
|
37
39
|
goalsPath,
|
|
40
|
+
provenance,
|
|
38
41
|
sessionId: process.env[GJC_SESSION_ID_ENV],
|
|
39
42
|
});
|
|
40
43
|
}
|
|
@@ -4,19 +4,40 @@ import * as path from "node:path";
|
|
|
4
4
|
import { YAML } from "bun";
|
|
5
5
|
import { withFileLock } from "./file-lock";
|
|
6
6
|
|
|
7
|
+
export interface AtomicYamlExpectedPrecondition {
|
|
8
|
+
path: string;
|
|
9
|
+
hash: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
7
12
|
export interface AtomicYamlSetPatch {
|
|
8
13
|
path: string;
|
|
9
14
|
op: "set";
|
|
10
15
|
value: unknown;
|
|
16
|
+
expected?: AtomicYamlExpectedPrecondition;
|
|
11
17
|
}
|
|
12
18
|
|
|
13
19
|
export interface AtomicYamlUnsetPatch {
|
|
14
20
|
path: string;
|
|
15
21
|
op: "unset";
|
|
22
|
+
expected?: AtomicYamlExpectedPrecondition;
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
export type AtomicYamlPatch = AtomicYamlSetPatch | AtomicYamlUnsetPatch;
|
|
19
26
|
|
|
27
|
+
/** Raised when a compare-and-swap precondition no longer matches durable YAML. */
|
|
28
|
+
export class AtomicYamlConflictError extends Error {
|
|
29
|
+
readonly code = "ATOMIC_YAML_CONFLICT";
|
|
30
|
+
|
|
31
|
+
constructor(
|
|
32
|
+
readonly path: string,
|
|
33
|
+
readonly expectedHash: string,
|
|
34
|
+
readonly actualHash: string,
|
|
35
|
+
) {
|
|
36
|
+
super(`Atomic YAML precondition failed for ${path}.`);
|
|
37
|
+
this.name = "AtomicYamlConflictError";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
20
41
|
export interface AtomicYamlPatchRevision {
|
|
21
42
|
path: string;
|
|
22
43
|
beforeHash: string;
|
|
@@ -53,6 +74,8 @@ export interface AtomicYamlPatchOptions {
|
|
|
53
74
|
sleep?: (ms: number) => Promise<void>;
|
|
54
75
|
/** Test seam for Windows rename retry behavior. */
|
|
55
76
|
platform?: NodeJS.Platform;
|
|
77
|
+
/** Called under the config lock before patches are applied. */
|
|
78
|
+
validateRoot?: (root: unknown, patches: readonly AtomicYamlPatch[]) => void | Promise<void>;
|
|
56
79
|
/** Called under the config lock after a successful CAS restore. */
|
|
57
80
|
onRestored?: (patches: readonly AtomicYamlPatch[]) => void | Promise<void>;
|
|
58
81
|
}
|
|
@@ -98,6 +121,16 @@ function assertPatch(patch: AtomicYamlPatch): void {
|
|
|
98
121
|
) {
|
|
99
122
|
throw new Error("Atomic YAML patches require a non-empty dotted path.");
|
|
100
123
|
}
|
|
124
|
+
if (
|
|
125
|
+
patch.expected &&
|
|
126
|
+
(typeof patch.expected.path !== "string" ||
|
|
127
|
+
patch.expected.path.length === 0 ||
|
|
128
|
+
patch.expected.path.split(".").some(part => !part) ||
|
|
129
|
+
typeof patch.expected.hash !== "string" ||
|
|
130
|
+
patch.expected.hash.length === 0)
|
|
131
|
+
) {
|
|
132
|
+
throw new Error("Atomic YAML patch preconditions require a non-empty dotted path and hash.");
|
|
133
|
+
}
|
|
101
134
|
if (patch.op === "set") {
|
|
102
135
|
if (patch.value === undefined) {
|
|
103
136
|
throw new TypeError(`Atomic YAML set patch for ${patch.path} cannot carry undefined; use unset instead.`);
|
|
@@ -148,6 +181,12 @@ export function deleteByPath(value: Record<string, unknown>, segments: readonly
|
|
|
148
181
|
}
|
|
149
182
|
|
|
150
183
|
function stableValue(value: unknown): string {
|
|
184
|
+
if (typeof value === "number") {
|
|
185
|
+
if (Number.isNaN(value)) return "NaN";
|
|
186
|
+
if (value === Infinity) return "Infinity";
|
|
187
|
+
if (value === -Infinity) return "-Infinity";
|
|
188
|
+
if (Object.is(value, -0)) return "-0";
|
|
189
|
+
}
|
|
151
190
|
if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "undefined";
|
|
152
191
|
if (Array.isArray(value)) return `[${value.map(stableValue).join(",")}]`;
|
|
153
192
|
const object = value as Record<string, unknown>;
|
|
@@ -167,12 +206,22 @@ function cloneState(state: PathState): PathState {
|
|
|
167
206
|
return state.exists ? { exists: true, value: structuredClone(state.value) } : state;
|
|
168
207
|
}
|
|
169
208
|
|
|
170
|
-
|
|
209
|
+
/** Hash a dotted YAML path state for an expected-hash patch precondition. */
|
|
210
|
+
export function atomicYamlPathHash(value: Record<string, unknown>, path: string): string {
|
|
211
|
+
return stateHash(stateAtPath(value, path.split(".")));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
type YamlReadResult = {
|
|
215
|
+
current: Record<string, unknown>;
|
|
216
|
+
root: unknown;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
async function readYaml(configPath: string): Promise<YamlReadResult> {
|
|
171
220
|
try {
|
|
172
|
-
const
|
|
173
|
-
return record(
|
|
221
|
+
const root = YAML.parse(await fs.readFile(configPath, "utf8"));
|
|
222
|
+
return { current: record(root) ?? {}, root };
|
|
174
223
|
} catch (error) {
|
|
175
|
-
if ((error as NodeJS.ErrnoException).code === "ENOENT") return {};
|
|
224
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return { current: {}, root: undefined };
|
|
176
225
|
throw error;
|
|
177
226
|
}
|
|
178
227
|
}
|
|
@@ -254,8 +303,9 @@ function createReceipt(
|
|
|
254
303
|
async restore(): Promise<CasRestoreResult> {
|
|
255
304
|
if (discarded) return { status: "discarded" };
|
|
256
305
|
return await enqueueAtomicYamlOperation(configPath, async canonicalPath => {
|
|
306
|
+
if (discarded) return { status: "discarded" };
|
|
257
307
|
return await withFileLock(canonicalPath, async () => {
|
|
258
|
-
const current = await readYaml(canonicalPath);
|
|
308
|
+
const { current, root } = await readYaml(canonicalPath);
|
|
259
309
|
const conflicts = changes
|
|
260
310
|
.filter(
|
|
261
311
|
change =>
|
|
@@ -269,6 +319,7 @@ function createReceipt(
|
|
|
269
319
|
? { path: change.path, op: "set", value: structuredClone(change.before.value) }
|
|
270
320
|
: { path: change.path, op: "unset" },
|
|
271
321
|
);
|
|
322
|
+
await options.validateRoot?.(root, restorePatches);
|
|
272
323
|
const receipt = await applyPatchesUnderLock(canonicalPath, current, restorePatches, options);
|
|
273
324
|
await options.onRestored?.(restorePatches);
|
|
274
325
|
return { status: "restored", receipt };
|
|
@@ -286,6 +337,14 @@ async function applyPatchesUnderLock(
|
|
|
286
337
|
): Promise<CasReceipt> {
|
|
287
338
|
if (patches.length === 0) return createReceipt(configPath, [], options);
|
|
288
339
|
|
|
340
|
+
for (const patch of patches) {
|
|
341
|
+
if (!patch.expected) continue;
|
|
342
|
+
const actualHash = stateHash(stateAtPath(current, patch.expected.path.split(".")));
|
|
343
|
+
if (actualHash !== patch.expected.hash) {
|
|
344
|
+
throw new AtomicYamlConflictError(patch.expected.path, patch.expected.hash, actualHash);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
289
348
|
const changesByPath = new Map<string, ReceiptChange>();
|
|
290
349
|
for (const patch of patches) {
|
|
291
350
|
const segments = patch.path.split(".");
|
|
@@ -329,9 +388,10 @@ export function applyAtomicYamlPatchesWithCurrent(
|
|
|
329
388
|
return enqueueAtomicYamlOperation(configPath, async canonicalPath => {
|
|
330
389
|
await fs.mkdir(path.dirname(canonicalPath), { recursive: true, mode: 0o700 });
|
|
331
390
|
return await withFileLock(canonicalPath, async () => {
|
|
332
|
-
const current = await readYaml(canonicalPath);
|
|
391
|
+
const { current, root } = await readYaml(canonicalPath);
|
|
333
392
|
const patches = await buildPatches(current);
|
|
334
393
|
for (const patch of patches) assertPatch(patch);
|
|
394
|
+
await options.validateRoot?.(root, patches);
|
|
335
395
|
return await applyPatchesUnderLock(canonicalPath, current, patches, options);
|
|
336
396
|
});
|
|
337
397
|
});
|
|
@@ -374,7 +434,8 @@ export function reserveAtomicYamlPatchSlot(
|
|
|
374
434
|
for (const patch of nextPatches) assertPatch(patch);
|
|
375
435
|
await fs.mkdir(path.dirname(canonicalPath), { recursive: true, mode: 0o700 });
|
|
376
436
|
return await withFileLock(canonicalPath, async () => {
|
|
377
|
-
const current = await readYaml(canonicalPath);
|
|
437
|
+
const { current, root } = await readYaml(canonicalPath);
|
|
438
|
+
await options.validateRoot?.(root, nextPatches);
|
|
378
439
|
return await applyPatchesUnderLock(canonicalPath, current, nextPatches, options);
|
|
379
440
|
});
|
|
380
441
|
});
|
|
@@ -393,7 +454,7 @@ export function reserveAtomicYamlUpdateSlot<T>(
|
|
|
393
454
|
const atomicUpdate = await update();
|
|
394
455
|
await fs.mkdir(path.dirname(canonicalPath), { recursive: true, mode: 0o700 });
|
|
395
456
|
return await withFileLock(canonicalPath, async () => {
|
|
396
|
-
const current = await readYaml(canonicalPath);
|
|
457
|
+
const { current } = await readYaml(canonicalPath);
|
|
397
458
|
const result = await atomicUpdate.apply(current);
|
|
398
459
|
if (atomicUpdate.shouldWrite?.(result) !== false) {
|
|
399
460
|
await writeAtomicYaml(canonicalPath, current, options);
|
|
@@ -414,10 +475,16 @@ export function applyAtomicYamlPatches(
|
|
|
414
475
|
options: AtomicYamlPatchOptions = {},
|
|
415
476
|
): Promise<CasReceipt> {
|
|
416
477
|
for (const patch of patches) assertPatch(patch);
|
|
417
|
-
const immutablePatches = patches.map(patch =>
|
|
418
|
-
patch.
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
478
|
+
const immutablePatches = patches.map(patch => {
|
|
479
|
+
const expected = patch.expected ? { ...patch.expected } : undefined;
|
|
480
|
+
return patch.op === "set"
|
|
481
|
+
? ({
|
|
482
|
+
path: patch.path,
|
|
483
|
+
op: "set",
|
|
484
|
+
value: structuredClone(patch.value),
|
|
485
|
+
...(expected ? { expected } : {}),
|
|
486
|
+
} as const)
|
|
487
|
+
: ({ path: patch.path, op: "unset", ...(expected ? { expected } : {}) } as const);
|
|
488
|
+
});
|
|
422
489
|
return reserveAtomicYamlPatchSlot(configPath, () => immutablePatches, options);
|
|
423
490
|
}
|