@gajae-code/coding-agent 0.11.0 → 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 +63 -1
- package/dist/types/async/job-manager.d.ts +46 -7
- 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-receipt-freshness.d.ts +11 -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/command-controller.d.ts +2 -2
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -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 +21 -19
- 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 +21 -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 +22 -15
- 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/ensure.d.ts +9 -0
- 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/discord-daemon.d.ts +5 -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 +69 -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/tools/subagent-render.d.ts +1 -0
- package/dist/types/tools/subagent.d.ts +6 -1
- 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 +39 -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 +455 -69
- 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 +83 -12
- package/src/gjc-runtime/ultragoal-pipeline.ts +306 -0
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +102 -1
- package/src/gjc-runtime/ultragoal-runtime.ts +156 -1319
- 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/command-controller.ts +9 -15
- package/src/modes/controllers/event-controller.ts +3 -2
- package/src/modes/controllers/extension-ui-controller.ts +72 -25
- 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 +302 -1151
- 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 +78 -19
- 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 +47 -20
- 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 +21 -2
- package/src/sdk/broker/ensure.ts +85 -25
- 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 +14 -4
- 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/discord-daemon.ts +25 -8
- package/src/sdk/bus/html-format.ts +20 -3
- package/src/sdk/bus/index.ts +834 -113
- package/src/sdk/bus/lifecycle-control-runtime.ts +91 -33
- package/src/sdk/bus/native-runtime-compatibility.ts +1 -1
- 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 +1491 -247
- 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 +1901 -637
- 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 +62 -37
- 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/tools/subagent-render.ts +19 -8
- package/src/tools/subagent.ts +84 -32
- 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
package/src/cli/config-cli.ts
CHANGED
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
* Uses the settings schema as the source of truth for available settings.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import * as fs from "node:fs/promises";
|
|
9
|
+
import type * as path from "node:path";
|
|
8
10
|
import { APP_NAME, getAgentDir } from "@gajae-code/utils";
|
|
11
|
+
import { YAML } from "bun";
|
|
9
12
|
import chalk from "chalk";
|
|
10
13
|
import {
|
|
11
14
|
getDefault,
|
|
@@ -25,7 +28,7 @@ import { initXdg } from "./commands/init-xdg";
|
|
|
25
28
|
// Types
|
|
26
29
|
// =============================================================================
|
|
27
30
|
|
|
28
|
-
export type ConfigAction = "list" | "get" | "set" | "reset" | "path" | "init-xdg";
|
|
31
|
+
export type ConfigAction = "list" | "get" | "set" | "reset" | "path" | "doctor" | "init-xdg";
|
|
29
32
|
|
|
30
33
|
export interface ConfigCommandArgs {
|
|
31
34
|
action: ConfigAction;
|
|
@@ -111,7 +114,7 @@ function getSettingValues(def: CliSettingDef): readonly string[] | undefined {
|
|
|
111
114
|
// Argument Parser
|
|
112
115
|
// =============================================================================
|
|
113
116
|
|
|
114
|
-
const VALID_ACTIONS: ConfigAction[] = ["list", "get", "set", "reset", "path", "init-xdg"];
|
|
117
|
+
const VALID_ACTIONS: ConfigAction[] = ["list", "get", "set", "reset", "path", "doctor", "init-xdg"];
|
|
115
118
|
|
|
116
119
|
/**
|
|
117
120
|
* Parse config subcommand arguments.
|
|
@@ -299,6 +302,9 @@ export async function runConfigCommand(cmd: ConfigCommandArgs): Promise<void> {
|
|
|
299
302
|
case "path":
|
|
300
303
|
handlePath();
|
|
301
304
|
break;
|
|
305
|
+
case "doctor":
|
|
306
|
+
handleDoctor(cmd.flags);
|
|
307
|
+
break;
|
|
302
308
|
case "init-xdg":
|
|
303
309
|
await initXdg();
|
|
304
310
|
break;
|
|
@@ -443,6 +449,70 @@ function handlePath(): void {
|
|
|
443
449
|
console.log(getAgentDir());
|
|
444
450
|
}
|
|
445
451
|
|
|
452
|
+
function handleDoctor(flags: { json?: boolean }): void {
|
|
453
|
+
const report = settings.getSchemaReport();
|
|
454
|
+
if (flags.json) {
|
|
455
|
+
console.log(JSON.stringify(report, null, 2));
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
if (report.issues.length === 0) {
|
|
459
|
+
console.log(chalk.green("Settings schema is healthy."));
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
for (const issue of report.issues) console.log(`${issue.kind}\t${issue.path}\t${issue.detail}`);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
type ConfigDoctorReport = {
|
|
466
|
+
unknownKeys: string[];
|
|
467
|
+
invalidValues: Array<{ path: string; value: unknown }>;
|
|
468
|
+
legacyShapes: string[];
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
function flattenConfig(value: unknown, prefix = ""): Array<[string, unknown]> {
|
|
472
|
+
if (prefix && ALL_SETTING_PATHS.includes(prefix as SettingPath)) return [[prefix, value]];
|
|
473
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return prefix ? [[prefix, value]] : [];
|
|
474
|
+
return Object.entries(value).flatMap(([key, child]) => flattenConfig(child, prefix ? `${prefix}.${key}` : key));
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function matchesSettingType(path: SettingPath, value: unknown): boolean {
|
|
478
|
+
const definition = SETTINGS_SCHEMA[path];
|
|
479
|
+
switch (definition.type) {
|
|
480
|
+
case "string":
|
|
481
|
+
case "enum":
|
|
482
|
+
return (
|
|
483
|
+
typeof value === "string" && (definition.type !== "enum" || getEnumValues(path)?.includes(value) === true)
|
|
484
|
+
);
|
|
485
|
+
case "number":
|
|
486
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
487
|
+
case "boolean":
|
|
488
|
+
return typeof value === "boolean";
|
|
489
|
+
case "array":
|
|
490
|
+
return Array.isArray(value);
|
|
491
|
+
case "record":
|
|
492
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
export async function inspectConfigFile(configPath: string): Promise<ConfigDoctorReport> {
|
|
497
|
+
const report: ConfigDoctorReport = { unknownKeys: [], invalidValues: [], legacyShapes: [] };
|
|
498
|
+
try {
|
|
499
|
+
const raw = YAML.parse(await fs.readFile(configPath, "utf8"));
|
|
500
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
501
|
+
report.legacyShapes.push("config root is not a mapping");
|
|
502
|
+
return report;
|
|
503
|
+
}
|
|
504
|
+
for (const [settingPath, value] of flattenConfig(raw)) {
|
|
505
|
+
if (!ALL_SETTING_PATHS.includes(settingPath as SettingPath)) report.unknownKeys.push(settingPath);
|
|
506
|
+
else if (!matchesSettingType(settingPath as SettingPath, value))
|
|
507
|
+
report.invalidValues.push({ path: settingPath, value: redactConfigValue(settingPath, value) });
|
|
508
|
+
}
|
|
509
|
+
} catch (error) {
|
|
510
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT")
|
|
511
|
+
report.legacyShapes.push(`unable to parse config: ${String(error)}`);
|
|
512
|
+
}
|
|
513
|
+
return report;
|
|
514
|
+
}
|
|
515
|
+
|
|
446
516
|
// =============================================================================
|
|
447
517
|
// Help
|
|
448
518
|
// =============================================================================
|
|
@@ -455,8 +525,10 @@ ${chalk.bold("Commands:")}
|
|
|
455
525
|
get <key> Get a specific setting value
|
|
456
526
|
set <key> <value> Set a setting value
|
|
457
527
|
reset <key> Reset a setting to its default value
|
|
528
|
+
doctor Report unknown, invalid, and pending settings migrations
|
|
458
529
|
path Print the config directory path
|
|
459
530
|
init-xdg Initialize XDG Base Directory structure
|
|
531
|
+
doctor Report unknown, invalid, and legacy config entries
|
|
460
532
|
|
|
461
533
|
${chalk.bold("Options:")}
|
|
462
534
|
--json Output as JSON
|
|
@@ -472,6 +544,7 @@ ${chalk.bold("Examples:")}
|
|
|
472
544
|
${APP_NAME} config list --json
|
|
473
545
|
${APP_NAME} config get auth.broker.token --show-secrets
|
|
474
546
|
${APP_NAME} config init-xdg
|
|
547
|
+
${APP_NAME} config doctor --json
|
|
475
548
|
|
|
476
549
|
${chalk.bold("Boolean Values:")}
|
|
477
550
|
true, false, yes, no, on, off, 1, 0
|
package/src/cli/notify-cli.ts
CHANGED
|
@@ -75,6 +75,7 @@ export interface NotifyCommandDeps {
|
|
|
75
75
|
tokenPrompt?: () => Promise<string>;
|
|
76
76
|
setExitCode?: (code: number) => void;
|
|
77
77
|
exitProcess?: (code: number) => void;
|
|
78
|
+
valuePrompt?: (label: string, masked: boolean) => Promise<string>;
|
|
78
79
|
/** Optional daemon ownership facts collected by an embedding host. */
|
|
79
80
|
setupPreflight?: TelegramSetupPreflight;
|
|
80
81
|
/** Injectable timers and cancellation for setup pairing. */
|
|
@@ -99,6 +100,27 @@ export function parseNotifyArgs(args: string[]): NotifyCommandArgs | undefined {
|
|
|
99
100
|
const i = rest.indexOf(name);
|
|
100
101
|
return i >= 0 ? rest[i + 1] : undefined;
|
|
101
102
|
};
|
|
103
|
+
const valueFlags = [
|
|
104
|
+
"--token",
|
|
105
|
+
"--chat-id",
|
|
106
|
+
"--discord-bot-token",
|
|
107
|
+
"--discord-application-id",
|
|
108
|
+
"--discord-guild-id",
|
|
109
|
+
"--discord-parent-channel-id",
|
|
110
|
+
"--slack-bot-token",
|
|
111
|
+
"--slack-app-token",
|
|
112
|
+
"--slack-workspace-id",
|
|
113
|
+
"--slack-channel-id",
|
|
114
|
+
"--slack-authorized-user-id",
|
|
115
|
+
];
|
|
116
|
+
if (
|
|
117
|
+
valueFlags.some(name => {
|
|
118
|
+
const index = rest.indexOf(name);
|
|
119
|
+
const value = index >= 0 ? rest[index + 1] : undefined;
|
|
120
|
+
return index >= 0 && (!value || value.startsWith("--"));
|
|
121
|
+
})
|
|
122
|
+
)
|
|
123
|
+
return undefined;
|
|
102
124
|
const provider = rest[0]?.startsWith("--") ? undefined : rest[0];
|
|
103
125
|
if (provider !== undefined && provider !== "telegram" && provider !== "discord" && provider !== "slack") {
|
|
104
126
|
return undefined;
|
|
@@ -144,7 +166,7 @@ export function parseNotifyArgs(args: string[]): NotifyCommandArgs | undefined {
|
|
|
144
166
|
};
|
|
145
167
|
}
|
|
146
168
|
|
|
147
|
-
return
|
|
169
|
+
return undefined;
|
|
148
170
|
}
|
|
149
171
|
|
|
150
172
|
export async function runNotifyCommand(cmd: NotifyCommandArgs, deps: NotifyCommandDeps = {}): Promise<void> {
|
|
@@ -221,22 +243,41 @@ async function runSetup(cmd: NotifyCommandArgs, deps: NotifyCommandDeps): Promis
|
|
|
221
243
|
|
|
222
244
|
function requiredSetupValue(value: string | undefined, flag: string): string {
|
|
223
245
|
if (!value?.trim()) throw new Error(`${flag} is required for non-interactive setup.`);
|
|
246
|
+
if (value.trim().startsWith("--")) throw new Error(`${flag} must not start with --.`);
|
|
224
247
|
return value.trim();
|
|
225
248
|
}
|
|
226
249
|
|
|
250
|
+
async function promptSetupValue(
|
|
251
|
+
value: string | undefined,
|
|
252
|
+
flag: string,
|
|
253
|
+
masked: boolean,
|
|
254
|
+
deps: NotifyCommandDeps,
|
|
255
|
+
): Promise<string> {
|
|
256
|
+
if (value?.trim()) return requiredSetupValue(value, flag);
|
|
257
|
+
if (!resolveSetupInteractive(deps)) return requiredSetupValue(value, flag);
|
|
258
|
+
return requiredSetupValue(await (deps.valuePrompt ?? promptForValue)(`${flag.slice(2)}: `, masked), flag);
|
|
259
|
+
}
|
|
260
|
+
|
|
227
261
|
async function runDiscordSetup(cmd: NotifyCommandArgs, deps: NotifyCommandDeps): Promise<void> {
|
|
228
|
-
const botToken =
|
|
229
|
-
const applicationId =
|
|
230
|
-
const guildId =
|
|
231
|
-
const parentChannelId =
|
|
262
|
+
const botToken = await promptSetupValue(cmd.discordBotToken, "--discord-bot-token", true, deps);
|
|
263
|
+
const applicationId = await promptSetupValue(cmd.discordApplicationId, "--discord-application-id", false, deps);
|
|
264
|
+
const guildId = await promptSetupValue(cmd.discordGuildId, "--discord-guild-id", false, deps);
|
|
265
|
+
const parentChannelId = await promptSetupValue(
|
|
266
|
+
cmd.discordParentChannelId,
|
|
267
|
+
"--discord-parent-channel-id",
|
|
268
|
+
false,
|
|
269
|
+
deps,
|
|
270
|
+
);
|
|
232
271
|
const settings = await getSettings(deps);
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
272
|
+
const patches: SettingsAtomicPatch[] = [
|
|
273
|
+
{ path: "notifications.discord.botToken", op: "set", value: botToken },
|
|
274
|
+
{ path: "notifications.discord.applicationId", op: "set", value: applicationId },
|
|
275
|
+
{ path: "notifications.discord.guildId", op: "set", value: guildId },
|
|
276
|
+
{ path: "notifications.discord.parentChannelId", op: "set", value: parentChannelId },
|
|
277
|
+
{ path: "notifications.enabled", op: "set", value: true },
|
|
278
|
+
];
|
|
279
|
+
if (cmd.redact) patches.push({ path: "notifications.redact", op: "set", value: true });
|
|
280
|
+
await settings.commitAtomicBatch(patches);
|
|
240
281
|
const daemon = await ensureConfiguredProviderDaemon("discord", settings, deps);
|
|
241
282
|
process.stdout.write(
|
|
242
283
|
`Discord notifications enabled. botToken=${maskToken(botToken)} applicationId=${applicationId} guildId=${guildId} parentChannelId=${parentChannelId} daemon=${daemon}\n`,
|
|
@@ -244,20 +285,24 @@ async function runDiscordSetup(cmd: NotifyCommandArgs, deps: NotifyCommandDeps):
|
|
|
244
285
|
}
|
|
245
286
|
|
|
246
287
|
async function runSlackSetup(cmd: NotifyCommandArgs, deps: NotifyCommandDeps): Promise<void> {
|
|
247
|
-
const botToken =
|
|
248
|
-
const appToken =
|
|
249
|
-
const workspaceId =
|
|
250
|
-
const channelId =
|
|
288
|
+
const botToken = await promptSetupValue(cmd.slackBotToken, "--slack-bot-token", true, deps);
|
|
289
|
+
const appToken = await promptSetupValue(cmd.slackAppToken, "--slack-app-token", true, deps);
|
|
290
|
+
const workspaceId = await promptSetupValue(cmd.slackWorkspaceId, "--slack-workspace-id", false, deps);
|
|
291
|
+
const channelId = await promptSetupValue(cmd.slackChannelId, "--slack-channel-id", false, deps);
|
|
251
292
|
const authorizedUserId = cmd.slackAuthorizedUserId?.trim() || undefined;
|
|
252
293
|
const settings = await getSettings(deps);
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
294
|
+
const patches: SettingsAtomicPatch[] = [
|
|
295
|
+
{ path: "notifications.slack.botToken", op: "set", value: botToken },
|
|
296
|
+
{ path: "notifications.slack.appToken", op: "set", value: appToken },
|
|
297
|
+
{ path: "notifications.slack.workspaceId", op: "set", value: workspaceId },
|
|
298
|
+
{ path: "notifications.slack.channelId", op: "set", value: channelId },
|
|
299
|
+
authorizedUserId === undefined
|
|
300
|
+
? { path: "notifications.slack.authorizedUserId", op: "unset" }
|
|
301
|
+
: { path: "notifications.slack.authorizedUserId", op: "set", value: authorizedUserId },
|
|
302
|
+
{ path: "notifications.enabled", op: "set", value: true },
|
|
303
|
+
];
|
|
304
|
+
if (cmd.redact) patches.push({ path: "notifications.redact", op: "set", value: true });
|
|
305
|
+
await settings.commitAtomicBatch(patches);
|
|
261
306
|
const daemon = await ensureConfiguredProviderDaemon("slack", settings, deps);
|
|
262
307
|
process.stdout.write(
|
|
263
308
|
`Slack notifications enabled. botToken=${maskToken(botToken)} appToken=${maskToken(appToken)} workspaceId=${workspaceId} channelId=${channelId} authorizedUserId=${authorizedUserId ?? "(unset; inbound denied)"} daemon=${daemon}\n`,
|
|
@@ -437,7 +482,8 @@ type TokenPromptInput = NodeJS.ReadStream & {
|
|
|
437
482
|
|
|
438
483
|
type TokenPromptOutput = Pick<NodeJS.WriteStream, "write">;
|
|
439
484
|
|
|
440
|
-
|
|
485
|
+
async function promptForMaskedValue(
|
|
486
|
+
label: string,
|
|
441
487
|
input: TokenPromptInput = process.stdin,
|
|
442
488
|
output: TokenPromptOutput = process.stdout,
|
|
443
489
|
): Promise<string> {
|
|
@@ -448,7 +494,7 @@ export async function promptForToken(
|
|
|
448
494
|
throw new Error("notify setup requires a TTY with raw input support unless setupToken is injected.");
|
|
449
495
|
}
|
|
450
496
|
|
|
451
|
-
output.write(
|
|
497
|
+
output.write(label);
|
|
452
498
|
const wasRaw = input.isRaw === true;
|
|
453
499
|
input.setRawMode(true);
|
|
454
500
|
|
|
@@ -503,6 +549,26 @@ export async function promptForToken(
|
|
|
503
549
|
});
|
|
504
550
|
}
|
|
505
551
|
|
|
552
|
+
export async function promptForToken(
|
|
553
|
+
input: TokenPromptInput = process.stdin,
|
|
554
|
+
output: TokenPromptOutput = process.stdout,
|
|
555
|
+
): Promise<string> {
|
|
556
|
+
return await promptForMaskedValue("Telegram BotFather token: ", input, output);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
async function promptForValue(label: string, masked: boolean): Promise<string> {
|
|
560
|
+
if (masked) return await promptForMaskedValue(label);
|
|
561
|
+
if (!process.stdin.isTTY) {
|
|
562
|
+
throw new Error("notify setup requires an interactive TTY unless all setup values are supplied as flags.");
|
|
563
|
+
}
|
|
564
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: true });
|
|
565
|
+
try {
|
|
566
|
+
return (await rl.question(label)).trim();
|
|
567
|
+
} finally {
|
|
568
|
+
rl.close();
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
506
572
|
function resolveSetupInteractive(deps: NotifyCommandDeps): boolean {
|
|
507
573
|
if (deps.setupInteractive !== undefined) return deps.setupInteractive;
|
|
508
574
|
return Boolean(process.stdin.isTTY) && !deps.setupChatId?.trim();
|
|
@@ -1,13 +1,30 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
1
2
|
import { ProcessTerminal, TUI } from "@gajae-code/tui";
|
|
3
|
+
import { pathIsWithin } from "@gajae-code/utils";
|
|
2
4
|
import { type SessionSelectionResult, SessionSelectorComponent } from "../modes/components/session-selector";
|
|
3
5
|
import { type SessionInfo, SessionManager } from "../session/session-manager";
|
|
4
6
|
import { FileSessionStorage } from "../session/session-storage";
|
|
5
7
|
|
|
8
|
+
export async function deleteSessionPickerCandidate(sessionPath: string, explicitSessionDir?: string): Promise<void> {
|
|
9
|
+
if (!explicitSessionDir) {
|
|
10
|
+
await SessionManager.deleteManagedCandidate(sessionPath);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const root = path.resolve(explicitSessionDir);
|
|
14
|
+
const target = path.resolve(sessionPath);
|
|
15
|
+
if (!pathIsWithin(root, target))
|
|
16
|
+
throw new Error("Explicit session deletion escaped the configured session directory.");
|
|
17
|
+
await new FileSessionStorage().deleteSessionWithArtifacts(target);
|
|
18
|
+
}
|
|
19
|
+
|
|
6
20
|
/** Show the read-only TUI session picker and return the user's consent intent. */
|
|
7
|
-
export async function selectSession(
|
|
21
|
+
export async function selectSession(
|
|
22
|
+
sessions: SessionInfo[],
|
|
23
|
+
explicitSessionDir?: string,
|
|
24
|
+
): Promise<SessionSelectionResult> {
|
|
8
25
|
const { promise, resolve } = Promise.withResolvers<SessionSelectionResult>();
|
|
9
26
|
const ui = new TUI(new ProcessTerminal());
|
|
10
|
-
|
|
27
|
+
|
|
11
28
|
let settled = false;
|
|
12
29
|
const settle = (selection: SessionSelectionResult): void => {
|
|
13
30
|
if (settled) return;
|
|
@@ -21,7 +38,7 @@ export async function selectSession(sessions: SessionInfo[]): Promise<SessionSel
|
|
|
21
38
|
() => settle({ kind: "cancelled" }),
|
|
22
39
|
() => settle({ kind: "cancelled" }),
|
|
23
40
|
async session => {
|
|
24
|
-
await
|
|
41
|
+
await deleteSessionPickerCandidate(session.path, explicitSessionDir);
|
|
25
42
|
return true;
|
|
26
43
|
},
|
|
27
44
|
SessionManager.inspectSessionTailReadOnly,
|
package/src/cli/setup-cli.ts
CHANGED
|
@@ -564,7 +564,7 @@ async function confirmImport(count: number): Promise<boolean> {
|
|
|
564
564
|
*/
|
|
565
565
|
export interface CredentialsSetupDependencies {
|
|
566
566
|
openStore?: typeof SqliteAuthCredentialStore.open;
|
|
567
|
-
createAuthStorage?: (store:
|
|
567
|
+
createAuthStorage?: (store: SqliteAuthCredentialStore) => AuthStorage;
|
|
568
568
|
discover?: Parameters<typeof runExternalCredentialAutoImport>[0]["discover"];
|
|
569
569
|
}
|
|
570
570
|
|
package/src/cli.ts
CHANGED
|
@@ -9,7 +9,6 @@ import { Args, type CliConfig, Command, type CommandEntry, Flags, run } from "@g
|
|
|
9
9
|
import { APP_NAME, formatBunRuntimeError, MIN_BUN_VERSION, VERSION } from "@gajae-code/utils/dirs";
|
|
10
10
|
import { runFixtureReport } from "./cli/fixture-report";
|
|
11
11
|
import { isTmuxOwnerIsolationCliArgv, runTmuxOwnerIsolationCliFromStdin } from "./gjc-runtime/tmux-owner-isolation-cli";
|
|
12
|
-
import { runChatDaemonInternal } from "./sdk/bus/chat-daemon-cli";
|
|
13
12
|
|
|
14
13
|
if (Bun.semver.order(Bun.version, MIN_BUN_VERSION) < 0) {
|
|
15
14
|
process.stderr.write(
|
|
@@ -134,6 +133,7 @@ async function runChatDaemonInternalFastPath(argv: string[]): Promise<void> {
|
|
|
134
133
|
if (action !== "discord-internal" && action !== "slack-internal") {
|
|
135
134
|
throw new Error("invalid chat daemon internal fast path");
|
|
136
135
|
}
|
|
136
|
+
const { runChatDaemonInternal } = await import("./sdk/bus/chat-daemon-cli");
|
|
137
137
|
await runChatDaemonInternal(action === "discord-internal" ? "discord" : "slack", argv.slice(2));
|
|
138
138
|
}
|
|
139
139
|
|
package/src/commands/config.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Args, Command, Flags } from "@gajae-code/utils/cli";
|
|
|
5
5
|
import { type ConfigAction, type ConfigCommandArgs, runConfigCommand } from "../cli/config-cli";
|
|
6
6
|
import { initTheme } from "../modes/theme/theme";
|
|
7
7
|
|
|
8
|
-
const ACTIONS: ConfigAction[] = ["list", "get", "set", "reset", "path", "init-xdg"];
|
|
8
|
+
const ACTIONS: ConfigAction[] = ["list", "get", "set", "reset", "path", "init-xdg", "doctor"];
|
|
9
9
|
|
|
10
10
|
export default class Config extends Command {
|
|
11
11
|
static description = "Manage configuration settings";
|
package/src/commands/harness.ts
CHANGED
|
@@ -25,16 +25,25 @@ import {
|
|
|
25
25
|
classifyCgroup,
|
|
26
26
|
isExactScopedBootstrapSuccessReceipt,
|
|
27
27
|
isOwnerGenerationBaselineCurrentSync,
|
|
28
|
+
isSafeServerProof,
|
|
28
29
|
type OwnerGenerationBaseline,
|
|
29
30
|
type OwnerIsolationProbe,
|
|
30
31
|
observeOwnerTerminal,
|
|
31
32
|
ownerProcessStartTime,
|
|
32
33
|
planTmuxOwnerIsolation,
|
|
33
34
|
replaceOwnerGenerationSync,
|
|
35
|
+
sameServerIdentity,
|
|
34
36
|
type TmuxServerProof,
|
|
35
37
|
} from "../gjc-runtime/tmux-owner-isolation";
|
|
36
38
|
import { classifyRecovery } from "../harness-control-plane/classifier";
|
|
37
39
|
import { callEndpoint, EndpointUnreachableError } from "../harness-control-plane/control-endpoint";
|
|
40
|
+
import {
|
|
41
|
+
type CompletedTerminalEvent,
|
|
42
|
+
isOwnerLivenessBlocker,
|
|
43
|
+
needsVanishedOwnerBlock,
|
|
44
|
+
OWNER_STARTUP_BLOCKER,
|
|
45
|
+
reconcileOwnerLifecycle,
|
|
46
|
+
} from "../harness-control-plane/lifecycle-reconciliation";
|
|
38
47
|
import { type ResolvedOwner, RuntimeOwner, resolveOwner, resolveOwnerLive } from "../harness-control-plane/owner";
|
|
39
48
|
import { preserveDirtyWorktree } from "../harness-control-plane/preserve";
|
|
40
49
|
import { RECEIPT_SPOOL_DIR_ENV } from "../harness-control-plane/receipt-spool";
|
|
@@ -252,12 +261,6 @@ function pushUnique(out: string[], value: unknown): void {
|
|
|
252
261
|
if (typeof value === "string" && !out.includes(value)) out.push(value);
|
|
253
262
|
}
|
|
254
263
|
|
|
255
|
-
interface CompletedTerminalEvent {
|
|
256
|
-
cursor: number;
|
|
257
|
-
createdAt: string;
|
|
258
|
-
kind: string;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
264
|
function completedTerminalEvent(events: EventEnvelope[]): CompletedTerminalEvent | null {
|
|
262
265
|
for (const event of [...events].reverse()) {
|
|
263
266
|
const signal = (event.evidence as { signal?: unknown } | undefined)?.signal;
|
|
@@ -461,73 +464,21 @@ function updateStateWithRestoredOwner(state: SessionState, leasePath: string, re
|
|
|
461
464
|
state.updatedAt = nowIso();
|
|
462
465
|
}
|
|
463
466
|
|
|
464
|
-
function
|
|
465
|
-
return blocker === "detached-owner-not-live" || blocker.startsWith("owner-vanished:");
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
async function reconcileCompletedOwnerExited(
|
|
467
|
+
async function reconcileLifecycle(
|
|
469
468
|
root: string,
|
|
470
469
|
state: SessionState,
|
|
471
470
|
observation: Observation,
|
|
472
471
|
completedTerminal: CompletedTerminalEvent | null,
|
|
472
|
+
startupBlocked = false,
|
|
473
473
|
): Promise<SessionState> {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
function needsVanishedOwnerBlock(
|
|
484
|
-
state: SessionState,
|
|
485
|
-
observation: Observation,
|
|
486
|
-
completedTerminal: CompletedTerminalEvent | null,
|
|
487
|
-
): boolean {
|
|
488
|
-
if (observation.ownerLive || state.lifecycle !== "observing") return false;
|
|
489
|
-
if (completedTerminal || observation.observedSignals.includes("completed")) return false;
|
|
490
|
-
return observation.observedSignals.some(
|
|
491
|
-
signal => signal === "prompt-accepted" || signal === "tool-call" || signal === "streaming",
|
|
492
|
-
);
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
async function markVanishedOwnerBlocked(
|
|
496
|
-
root: string,
|
|
497
|
-
state: SessionState,
|
|
498
|
-
observation: Observation,
|
|
499
|
-
completedTerminal: CompletedTerminalEvent | null,
|
|
500
|
-
): Promise<SessionState> {
|
|
501
|
-
if (!needsVanishedOwnerBlock(state, observation, completedTerminal)) return state;
|
|
502
|
-
const blocker = `owner-vanished:${observation.gitDelta}`;
|
|
503
|
-
state.lifecycle = "blocked";
|
|
504
|
-
state.blockers = state.blockers.includes(blocker) ? state.blockers : [...state.blockers, blocker];
|
|
505
|
-
state.updatedAt = nowIso();
|
|
506
|
-
await writeSessionState(root, state);
|
|
507
|
-
return state;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
const OWNER_STARTUP_BLOCKER = "owner-died-before-first-prompt";
|
|
511
|
-
|
|
512
|
-
/**
|
|
513
|
-
* Persist an explicit startup blocker when an owner started, reported live, but died before
|
|
514
|
-
* accepting the first prompt. This makes the failure an actionable lifecycle state instead of a
|
|
515
|
-
* silent `owner-not-live` gate, so observe/recover surface it and recover can respawn the owner.
|
|
516
|
-
*/
|
|
517
|
-
async function markStartupOwnerBlocked(
|
|
518
|
-
root: string,
|
|
519
|
-
state: SessionState,
|
|
520
|
-
ownerExit: OwnerExitEvidence,
|
|
521
|
-
): Promise<SessionState> {
|
|
522
|
-
if (!ownerExit.startupBlocker) return state;
|
|
523
|
-
if (state.lifecycle === "completed" || state.lifecycle === "retired") return state;
|
|
524
|
-
state.lifecycle = "blocked";
|
|
525
|
-
state.blockers = state.blockers.includes(OWNER_STARTUP_BLOCKER)
|
|
526
|
-
? state.blockers
|
|
527
|
-
: [...state.blockers, OWNER_STARTUP_BLOCKER];
|
|
528
|
-
state.updatedAt = nowIso();
|
|
529
|
-
await writeSessionState(root, state);
|
|
530
|
-
return state;
|
|
474
|
+
return reconcileOwnerLifecycle({
|
|
475
|
+
state,
|
|
476
|
+
observation,
|
|
477
|
+
completedTerminal,
|
|
478
|
+
startupBlocked,
|
|
479
|
+
persist: async nextState => writeSessionState(root, nextState),
|
|
480
|
+
nowIso,
|
|
481
|
+
});
|
|
531
482
|
}
|
|
532
483
|
|
|
533
484
|
function resolveRetryBudget(input: Record<string, unknown>): RetryBudget {
|
|
@@ -562,29 +513,6 @@ function isBoundedNoServerDiagnostic(stderr: Uint8Array): boolean {
|
|
|
562
513
|
);
|
|
563
514
|
}
|
|
564
515
|
|
|
565
|
-
function sameServerIdentity(left: TmuxServerProof, right: TmuxServerProof): boolean {
|
|
566
|
-
return (
|
|
567
|
-
left.pid === right.pid &&
|
|
568
|
-
left.startTime === right.startTime &&
|
|
569
|
-
left.cgroup?.classification === right.cgroup?.classification &&
|
|
570
|
-
left.cgroup?.scope === right.cgroup?.scope &&
|
|
571
|
-
left.cgroup?.diagnostic === right.cgroup?.diagnostic
|
|
572
|
-
);
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
function isSafeServerProof(proof: TmuxServerProof): boolean {
|
|
576
|
-
return (
|
|
577
|
-
proof.state === "safe" &&
|
|
578
|
-
typeof proof.pid === "number" &&
|
|
579
|
-
Number.isSafeInteger(proof.pid) &&
|
|
580
|
-
proof.pid > 0 &&
|
|
581
|
-
typeof proof.startTime === "string" &&
|
|
582
|
-
proof.startTime.length > 0 &&
|
|
583
|
-
(proof.cgroup?.classification === "safe" ||
|
|
584
|
-
(process.platform !== "linux" && proof.cgroup?.classification === "not_applicable"))
|
|
585
|
-
);
|
|
586
|
-
}
|
|
587
|
-
|
|
588
516
|
function exactNativeTmuxSessionId(stdout: Uint8Array): string | null {
|
|
589
517
|
const value = new TextDecoder().decode(stdout);
|
|
590
518
|
const line = value.endsWith("\n") ? value.slice(0, -1) : value;
|
|
@@ -985,7 +913,9 @@ export default class Harness extends Command {
|
|
|
985
913
|
proof: TmuxServerProof | null,
|
|
986
914
|
probeServer: OwnerIsolationProbe["probeServer"],
|
|
987
915
|
): Promise<void> {
|
|
988
|
-
if (!nativeSessionId || !proof || !isSafeServerProof(proof
|
|
916
|
+
if (!nativeSessionId || !proof || !isSafeServerProof(proof, ownerIsolationPlatform()))
|
|
917
|
+
throw new Error("tmux-owner-cleanup_uncertain");
|
|
918
|
+
|
|
989
919
|
if (!(await this.#nativeSessionBoundToName(tmuxCommand, socketKey, nativeSessionId, sessionName)))
|
|
990
920
|
throw new Error("tmux-owner-cleanup_uncertain");
|
|
991
921
|
const current = await probeServer(socketKey, [tmuxCommand, "-L", socketKey]);
|
|
@@ -1141,7 +1071,7 @@ export default class Harness extends Command {
|
|
|
1141
1071
|
const postSpawnServer = await probeServer(socketKey, [tmuxCommand, "-L", socketKey]);
|
|
1142
1072
|
cleanupProof = postSpawnServer;
|
|
1143
1073
|
if (postSpawnServer.state === "unsafe") return fail("tmux-owner-server_unsafe");
|
|
1144
|
-
if (!isSafeServerProof(postSpawnServer)) return fail("tmux-owner-server_unverifiable");
|
|
1074
|
+
if (!isSafeServerProof(postSpawnServer, ownerIsolationPlatform())) return fail("tmux-owner-server_unverifiable");
|
|
1145
1075
|
if (
|
|
1146
1076
|
scopedReceipt &&
|
|
1147
1077
|
(scopedReceipt.sessionName !== sessionName ||
|
|
@@ -1441,14 +1371,10 @@ export default class Harness extends Command {
|
|
|
1441
1371
|
let state = await loadState(root, sessionId);
|
|
1442
1372
|
const ownerLive = ownerLiveFor(state);
|
|
1443
1373
|
const { observation, completedTerminalEvent } = await buildObservation(root, state, ownerLive);
|
|
1444
|
-
state = await reconcileCompletedOwnerExited(root, state, observation, completedTerminalEvent);
|
|
1445
1374
|
const vanishedOwnerBlock = needsVanishedOwnerBlock(state, observation, completedTerminalEvent);
|
|
1446
|
-
state = await markVanishedOwnerBlocked(root, state, observation, completedTerminalEvent);
|
|
1447
|
-
// Build owner-exit evidence whenever the owner is gone so a startup death (owner started,
|
|
1448
|
-
// reported live, then died before the first prompt) is detectable, not just vanish/completion.
|
|
1449
1375
|
const ownerExit = !ownerLive ? await buildOwnerExitEvidence(root, state) : null;
|
|
1450
1376
|
const startupBlocked = ownerExit?.startupBlocker ?? false;
|
|
1451
|
-
|
|
1377
|
+
state = await reconcileLifecycle(root, state, observation, completedTerminalEvent, startupBlocked);
|
|
1452
1378
|
const includeOwnerExit = Boolean(ownerExit && (vanishedOwnerBlock || completedTerminalEvent || startupBlocked));
|
|
1453
1379
|
writeJson(
|
|
1454
1380
|
buildResponse(state, ownerLive, {
|
|
@@ -1482,12 +1408,7 @@ export default class Harness extends Command {
|
|
|
1482
1408
|
if (!observation) {
|
|
1483
1409
|
const built = await buildObservation(root, stateView, ownerLive);
|
|
1484
1410
|
observation = built.observation;
|
|
1485
|
-
stateView = await
|
|
1486
|
-
root,
|
|
1487
|
-
stateView,
|
|
1488
|
-
built.observation,
|
|
1489
|
-
built.completedTerminalEvent,
|
|
1490
|
-
);
|
|
1411
|
+
stateView = await reconcileLifecycle(root, stateView, built.observation, built.completedTerminalEvent);
|
|
1491
1412
|
}
|
|
1492
1413
|
}
|
|
1493
1414
|
if (!observation) throw new Error("classify_requires_observation_or_session");
|
|
@@ -1548,7 +1469,14 @@ export default class Harness extends Command {
|
|
|
1548
1469
|
const ownerExit = await buildOwnerExitEvidence(root, state);
|
|
1549
1470
|
// An owner that started, reported live, then died before accepting the first prompt is a
|
|
1550
1471
|
// startup blocker, not a healthy `owner-not-live` gate — persist it and report it as such.
|
|
1551
|
-
|
|
1472
|
+
const built = await buildObservation(root, state, false);
|
|
1473
|
+
state = await reconcileLifecycle(
|
|
1474
|
+
root,
|
|
1475
|
+
state,
|
|
1476
|
+
built.observation,
|
|
1477
|
+
built.completedTerminalEvent,
|
|
1478
|
+
ownerExit.startupBlocker,
|
|
1479
|
+
);
|
|
1552
1480
|
const reason = ownerExit.startupBlocker ? ownerExit.reason : "owner-not-live";
|
|
1553
1481
|
writeJson(
|
|
1554
1482
|
buildResponse(
|
|
@@ -1614,7 +1542,7 @@ export default class Harness extends Command {
|
|
|
1614
1542
|
let state = await loadState(root, sessionId);
|
|
1615
1543
|
const beforeExit = await buildOwnerExitEvidence(root, state);
|
|
1616
1544
|
const { observation, completedTerminalEvent } = await buildObservation(root, state, false);
|
|
1617
|
-
state = await
|
|
1545
|
+
state = await reconcileLifecycle(root, state, observation, completedTerminalEvent);
|
|
1618
1546
|
const decision = classifyRecovery({
|
|
1619
1547
|
observation: { ...observation, lifecycle: state.lifecycle },
|
|
1620
1548
|
retryBudget: budget,
|
package/src/commands/launch.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { APP_NAME, setProjectDir } from "@gajae-code/utils";
|
|
|
9
9
|
import { Args, Command, Flags } from "@gajae-code/utils/cli";
|
|
10
10
|
import { parseArgs } from "../cli/args";
|
|
11
11
|
import { launchDefaultTmuxIfNeeded } from "../gjc-runtime/launch-tmux";
|
|
12
|
-
import { prepareLaunchWorktree } from "../gjc-runtime/launch-worktree";
|
|
12
|
+
import { type PreparedLaunchWorktree, prepareLaunchWorktree } from "../gjc-runtime/launch-worktree";
|
|
13
13
|
import {
|
|
14
14
|
GJC_COORDINATOR_SESSION_ID_ENV,
|
|
15
15
|
GJC_COORDINATOR_SESSION_STATE_FILE_ENV,
|
|
@@ -128,7 +128,8 @@ export default class Index extends Command {
|
|
|
128
128
|
description: "Resume a session (by ID prefix, path, or picker if omitted)",
|
|
129
129
|
}),
|
|
130
130
|
"session-dir": Flags.string({
|
|
131
|
-
description:
|
|
131
|
+
description:
|
|
132
|
+
"Explicit session storage directory and lookup override (default uses managed v2 workspace scope)",
|
|
132
133
|
}),
|
|
133
134
|
"no-session": Flags.boolean({
|
|
134
135
|
description: "Don't save session (ephemeral)",
|
|
@@ -199,7 +200,8 @@ export default class Index extends Command {
|
|
|
199
200
|
`# Pin a stored credential for this session\n ${APP_NAME} --credential email:me@example.com`,
|
|
200
201
|
`# Activate a model profile for this session\n ${APP_NAME} --mpreset codex-medium`,
|
|
201
202
|
`# Persist a model profile as the default\n ${APP_NAME} --mpreset opencodego --default`,
|
|
202
|
-
`# Export a session file to HTML\n ${APP_NAME} --export ~/.gjc/agent/sessions
|
|
203
|
+
`# Export a session file to HTML\n ${APP_NAME} --export ~/.gjc/agent/sessions/v2-<scope>/session.jsonl`,
|
|
204
|
+
`# Use an explicit session storage directory\n ${APP_NAME} --session-dir ./sessions`,
|
|
203
205
|
];
|
|
204
206
|
|
|
205
207
|
static strict = false;
|
|
@@ -212,7 +214,7 @@ export default class Index extends Command {
|
|
|
212
214
|
return;
|
|
213
215
|
}
|
|
214
216
|
|
|
215
|
-
let launch:
|
|
217
|
+
let launch: PreparedLaunchWorktree;
|
|
216
218
|
try {
|
|
217
219
|
launch = prepareLaunchWorktree(process.cwd(), args);
|
|
218
220
|
} catch (error) {
|