@gajae-code/coding-agent 0.11.1 → 0.11.3
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 +64 -0
- package/dist/types/cli/config-cli.d.ts +11 -1
- package/dist/types/cli/launch-disposition.d.ts +23 -0
- 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 +141 -11
- 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 +4 -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/prompt-action-autocomplete.d.ts +4 -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 +29 -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/sdk/session.d.ts +2 -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 +5 -0
- package/dist/types/tools/search-tool-bm25.d.ts +3 -4
- package/dist/types/tools/subagent.d.ts +1 -0
- package/dist/types/utils/event-bus.d.ts +1 -1
- package/dist/types/utils/file-mentions.d.ts +3 -3
- 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/launch-disposition.ts +42 -0
- 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 +214 -12
- 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 +327 -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 +127 -30
- 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/prompt-action-autocomplete.ts +7 -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 +782 -94
- 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 +44 -2
- 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 +462 -480
- 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 +19 -7
- package/src/tools/read.ts +219 -64
- package/src/tools/resource-gc.ts +2 -2
- package/src/tools/search-tool-bm25.ts +11 -74
- package/src/tools/subagent.ts +43 -2
- package/src/utils/event-bus.ts +9 -4
- package/src/utils/file-mentions.ts +4 -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
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { CustomMessageEntry, SessionEntry } from "./session-manager";
|
|
2
|
+
|
|
3
|
+
const SUPERSEDED_VOLATILE_CONTEXT_NOTICE = "[superseded volatile context pruned]";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Custom messages whose producer maintains one current singleton state:
|
|
7
|
+
* - todo-write-error-reminder: a later todo-write failure replaces the prior warning.
|
|
8
|
+
* - resolve-reminder: only the currently pending resolve preview can be applied.
|
|
9
|
+
* - eager-todo-prelude: the newest todo prelude reflects the current task state.
|
|
10
|
+
*/
|
|
11
|
+
const SUPERSEDED_SINGLETON_REMINDER_TYPES = new Set([
|
|
12
|
+
"todo-write-error-reminder",
|
|
13
|
+
"resolve-reminder",
|
|
14
|
+
"eager-todo-prelude",
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Volatile context is refreshed for every prompt. Only its newest copy is useful;
|
|
19
|
+
* replacing older copies at a maintenance boundary preserves the audit trail
|
|
20
|
+
* without repeatedly charging the model for stale workspace snapshots.
|
|
21
|
+
*/
|
|
22
|
+
export function pruneSupersededVolatileProjectContext(entries: readonly SessionEntry[]): {
|
|
23
|
+
changed: CustomMessageEntry[];
|
|
24
|
+
bytesSaved: number;
|
|
25
|
+
} {
|
|
26
|
+
let latest = -1;
|
|
27
|
+
entries.forEach((entry, index) => {
|
|
28
|
+
if (entry.type === "custom_message" && entry.customType === "volatile-project-context") latest = index;
|
|
29
|
+
});
|
|
30
|
+
if (latest < 0) return { changed: [], bytesSaved: 0 };
|
|
31
|
+
|
|
32
|
+
const changed: CustomMessageEntry[] = [];
|
|
33
|
+
let bytesSaved = 0;
|
|
34
|
+
entries.forEach((entry, index) => {
|
|
35
|
+
if (index >= latest || entry.type !== "custom_message" || entry.customType !== "volatile-project-context") return;
|
|
36
|
+
const content =
|
|
37
|
+
typeof entry.content === "string"
|
|
38
|
+
? entry.content
|
|
39
|
+
: entry.content.map(block => (block.type === "text" ? block.text : "")).join("\n");
|
|
40
|
+
if (!content) return;
|
|
41
|
+
entry.content = SUPERSEDED_VOLATILE_CONTEXT_NOTICE;
|
|
42
|
+
bytesSaved += Buffer.byteLength(content, "utf-8");
|
|
43
|
+
changed.push(entry as CustomMessageEntry);
|
|
44
|
+
});
|
|
45
|
+
return { changed, bytesSaved };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Retire superseded known singleton maintenance reminders without touching ordinary user context. */
|
|
49
|
+
export function pruneSupersededMaintenanceReminders(entries: readonly SessionEntry[]): {
|
|
50
|
+
changed: CustomMessageEntry[];
|
|
51
|
+
bytesSaved: number;
|
|
52
|
+
} {
|
|
53
|
+
const latest = new Map<string, number>();
|
|
54
|
+
entries.forEach((entry, index) => {
|
|
55
|
+
if (entry.type === "custom_message" && SUPERSEDED_SINGLETON_REMINDER_TYPES.has(entry.customType)) {
|
|
56
|
+
latest.set(entry.customType, index);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const changed: CustomMessageEntry[] = [];
|
|
60
|
+
let bytesSaved = 0;
|
|
61
|
+
entries.forEach((entry, index) => {
|
|
62
|
+
if (
|
|
63
|
+
entry.type !== "custom_message" ||
|
|
64
|
+
latest.get(entry.customType) === undefined ||
|
|
65
|
+
latest.get(entry.customType) === index
|
|
66
|
+
)
|
|
67
|
+
return;
|
|
68
|
+
const text =
|
|
69
|
+
typeof entry.content === "string"
|
|
70
|
+
? entry.content
|
|
71
|
+
: entry.content.map(block => (block.type === "text" ? block.text : "")).join("\n");
|
|
72
|
+
if (!text) return;
|
|
73
|
+
entry.content = SUPERSEDED_VOLATILE_CONTEXT_NOTICE;
|
|
74
|
+
bytesSaved += Buffer.byteLength(text, "utf-8");
|
|
75
|
+
changed.push(entry);
|
|
76
|
+
});
|
|
77
|
+
return { changed, bytesSaved };
|
|
78
|
+
}
|
|
@@ -211,7 +211,8 @@ export function isCredentialAutoImportStateResolvedForVersion(
|
|
|
211
211
|
version: string,
|
|
212
212
|
): boolean {
|
|
213
213
|
return (
|
|
214
|
-
state.initialImportResolution
|
|
214
|
+
state.initialImportResolution === "declined" ||
|
|
215
|
+
(state.initialImportResolution === "accepted" && state.lastImportVersion === undefined) ||
|
|
215
216
|
(state.lastImportVersion !== undefined && state.lastImportVersion === version)
|
|
216
217
|
);
|
|
217
218
|
}
|
|
@@ -11,7 +11,7 @@ These instructions teach a Hermes-style coordinator how to operate GJC through t
|
|
|
11
11
|
3. Store the returned `turn_id`.
|
|
12
12
|
4. Prefer `{{TOOL_PREFIX}}_watch_events` with the stored `latest_seq` for event-driven progress; fall back to `{{TOOL_PREFIX}}_read_turn` or `{{TOOL_PREFIX}}_await_turn` for a specific `turn_id` until terminal.
|
|
13
13
|
If a second task is needed while one turn is active, pass `queue: true`; the next queued turn is promoted after the active turn is reported terminal.
|
|
14
|
-
5. If GJC asks
|
|
14
|
+
5. If GJC asks structured questions, call `{{TOOL_PREFIX}}_list_questions` with `session_id`. It reconciles pending `workflow.gates.list` rows and returns bounded public questions, diagnostics, and reconciliation; `pending` is the current filter and `open` is a compatibility alias. Handle every pending row. Submit its `session_id`, `turn_id`, `question_id`, and `answer_binding` to `{{TOOL_PREFIX}}_submit_question_answer` with the advertised `answer`, a unique `idempotency_key`, and `allow_mutation: true`. That tool resolves through `workflow.gate_answer`, never generic `ask.answer`; re-list after restart, incomplete reconciliation is `terminal_uncertain`, stale/terminal rows are not answerable, identical replay is safe, and conflicting idempotency-key reuse fails. Never expect private gate payloads or raw values. This coordinator loop is separate from #2549/#2551 and unattended plain-CLI behavior.
|
|
15
15
|
6. Use `{{TOOL_PREFIX}}_report_status` for coordinator-visible status and final reports.
|
|
16
16
|
7. Use `{{TOOL_PREFIX}}_read_tail` only to inspect the latest assistant response through the SDK when structured turn state is insufficient; it never reads terminal output.
|
|
17
17
|
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import * as fs from "node:fs/promises";
|
|
2
3
|
import * as path from "node:path";
|
|
3
|
-
import { getAgentDir } from "@gajae-code/utils";
|
|
4
|
+
import { getAgentDbPath, getAgentDir } from "@gajae-code/utils";
|
|
4
5
|
import { YAML } from "bun";
|
|
5
6
|
import { type ModelsConfig, ModelsConfigSchema } from "../config/models-config-schema";
|
|
7
|
+
import { AuthStorage } from "../session/auth-storage";
|
|
8
|
+
import providerPresets from "./provider-presets.json";
|
|
6
9
|
|
|
7
10
|
export type ProviderCompatibility = "openai" | "anthropic";
|
|
8
11
|
export type ProviderSetupApi = "openai-responses" | "openai-completions" | "anthropic-messages";
|
|
@@ -52,63 +55,7 @@ interface ProviderPreset {
|
|
|
52
55
|
const PROVIDER_ID_PATTERN = /^[a-z0-9][a-z0-9._-]*$/;
|
|
53
56
|
const REDACT_PREFIX = 4;
|
|
54
57
|
const REDACT_SUFFIX = 4;
|
|
55
|
-
|
|
56
|
-
// Keep them aligned with provider descriptor behavior without importing descriptor internals into setup UX.
|
|
57
|
-
const MINIMAX_OPENAI_COMPAT: ProviderCompatConfig = {
|
|
58
|
-
supportsStore: false,
|
|
59
|
-
supportsDeveloperRole: false,
|
|
60
|
-
supportsReasoningEffort: false,
|
|
61
|
-
reasoningContentField: "reasoning_content",
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const GLM_OPENAI_COMPAT: ProviderCompatConfig = {
|
|
65
|
-
supportsDeveloperRole: false,
|
|
66
|
-
supportsReasoningEffort: false,
|
|
67
|
-
thinkingFormat: "zai",
|
|
68
|
-
reasoningContentField: "reasoning_content",
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
export const PROVIDER_PRESETS: readonly ProviderPreset[] = [
|
|
72
|
-
{
|
|
73
|
-
id: "minimax",
|
|
74
|
-
aliases: ["minimax-code"],
|
|
75
|
-
name: "MiniMax Coding Plan",
|
|
76
|
-
description: "OpenAI-compatible MiniMax Coding Plan endpoint",
|
|
77
|
-
compatibility: "openai",
|
|
78
|
-
api: "openai-completions",
|
|
79
|
-
providerId: "minimax-code",
|
|
80
|
-
baseUrl: "https://api.minimax.io/v1",
|
|
81
|
-
apiKeyEnv: "MINIMAX_CODE_API_KEY",
|
|
82
|
-
models: ["minimax-m3"],
|
|
83
|
-
compat: MINIMAX_OPENAI_COMPAT,
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
id: "minimax-cn",
|
|
87
|
-
aliases: ["minimax-code-cn", "minimaxi"],
|
|
88
|
-
name: "MiniMax Coding Plan (China)",
|
|
89
|
-
description: "OpenAI-compatible MiniMax China endpoint",
|
|
90
|
-
compatibility: "openai",
|
|
91
|
-
api: "openai-completions",
|
|
92
|
-
providerId: "minimax-code-cn",
|
|
93
|
-
baseUrl: "https://api.minimaxi.com/v1",
|
|
94
|
-
apiKeyEnv: "MINIMAX_CODE_CN_API_KEY",
|
|
95
|
-
models: ["minimax-m3"],
|
|
96
|
-
compat: MINIMAX_OPENAI_COMPAT,
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
id: "glm",
|
|
100
|
-
aliases: ["zai", "z-ai", "bigmodel"],
|
|
101
|
-
name: "GLM / zAI",
|
|
102
|
-
description: "OpenAI-compatible GLM endpoint from zAI/BigModel",
|
|
103
|
-
compatibility: "openai",
|
|
104
|
-
api: "openai-completions",
|
|
105
|
-
providerId: "glm-proxy",
|
|
106
|
-
baseUrl: "https://api.z.ai/api/paas/v4",
|
|
107
|
-
apiKeyEnv: "ZAI_API_KEY",
|
|
108
|
-
models: ["glm-4.6"],
|
|
109
|
-
compat: GLM_OPENAI_COMPAT,
|
|
110
|
-
},
|
|
111
|
-
];
|
|
58
|
+
export const PROVIDER_PRESETS: readonly ProviderPreset[] = providerPresets as ProviderPreset[];
|
|
112
59
|
|
|
113
60
|
export function getDefaultModelsPath(): string {
|
|
114
61
|
return path.join(getAgentDir(), "models.yml");
|
|
@@ -290,8 +237,31 @@ async function writeModelsConfig(modelsPath: string, config: ModelsConfig): Prom
|
|
|
290
237
|
const where = first?.path.length ? `/${first.path.map(String).join("/")}` : "root";
|
|
291
238
|
throw new Error(`Generated models config is invalid at ${where}: ${first?.message ?? "unknown schema error"}`);
|
|
292
239
|
}
|
|
293
|
-
|
|
294
|
-
await
|
|
240
|
+
const directory = path.dirname(modelsPath);
|
|
241
|
+
await fs.mkdir(directory, { recursive: true });
|
|
242
|
+
const tempPath = path.join(directory, `.${path.basename(modelsPath)}.${process.pid}.${randomUUID()}.tmp`);
|
|
243
|
+
try {
|
|
244
|
+
const tempHandle = await fs.open(tempPath, "wx", 0o600);
|
|
245
|
+
try {
|
|
246
|
+
await tempHandle.writeFile(YAML.stringify(checked.data, null, 2), "utf8");
|
|
247
|
+
await tempHandle.sync();
|
|
248
|
+
} finally {
|
|
249
|
+
await tempHandle.close();
|
|
250
|
+
}
|
|
251
|
+
await fs.rename(tempPath, modelsPath);
|
|
252
|
+
try {
|
|
253
|
+
const directoryHandle = await fs.open(directory, "r");
|
|
254
|
+
try {
|
|
255
|
+
await directoryHandle.sync();
|
|
256
|
+
} finally {
|
|
257
|
+
await directoryHandle.close();
|
|
258
|
+
}
|
|
259
|
+
} catch {
|
|
260
|
+
// Directory fsync is unavailable on some filesystems; the replacement succeeded.
|
|
261
|
+
}
|
|
262
|
+
} finally {
|
|
263
|
+
await fs.rm(tempPath, { force: true }).catch(() => undefined);
|
|
264
|
+
}
|
|
295
265
|
}
|
|
296
266
|
|
|
297
267
|
export async function addApiCompatibleProvider(input: ProviderSetupInput): Promise<ProviderSetupResult> {
|
|
@@ -311,7 +281,12 @@ export async function addApiCompatibleProvider(input: ProviderSetupInput): Promi
|
|
|
311
281
|
if (validated.credentialSource === "env") {
|
|
312
282
|
provider.apiKeyEnv = validated.apiKey;
|
|
313
283
|
} else {
|
|
314
|
-
|
|
284
|
+
const authStorage = await AuthStorage.create(getAgentDbPath());
|
|
285
|
+
try {
|
|
286
|
+
await authStorage.set(validated.providerId, { type: "api_key", key: validated.apiKey });
|
|
287
|
+
} finally {
|
|
288
|
+
authStorage.close();
|
|
289
|
+
}
|
|
315
290
|
}
|
|
316
291
|
const next: ModelsConfig = {
|
|
317
292
|
...existing,
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
[
|
|
2
|
+
{"id":"minimax","aliases":["minimax-code"],"name":"MiniMax Coding Plan","description":"OpenAI-compatible MiniMax Coding Plan endpoint","compatibility":"openai","api":"openai-completions","providerId":"minimax-code","baseUrl":"https://api.minimax.io/v1","apiKeyEnv":"MINIMAX_CODE_API_KEY","models":["minimax-m3"],"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"reasoningContentField":"reasoning_content"}},
|
|
3
|
+
{"id":"minimax-cn","aliases":["minimax-code-cn","minimaxi"],"name":"MiniMax Coding Plan (China)","description":"OpenAI-compatible MiniMax China endpoint","compatibility":"openai","api":"openai-completions","providerId":"minimax-code-cn","baseUrl":"https://api.minimaxi.com/v1","apiKeyEnv":"MINIMAX_CODE_CN_API_KEY","models":["minimax-m3"],"compat":{"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"reasoningContentField":"reasoning_content"}},
|
|
4
|
+
{"id":"glm","aliases":["zai","z-ai","bigmodel"],"name":"GLM / zAI","description":"OpenAI-compatible GLM endpoint from zAI/BigModel","compatibility":"openai","api":"openai-completions","providerId":"glm-proxy","baseUrl":"https://api.z.ai/api/paas/v4","apiKeyEnv":"ZAI_API_KEY","models":["glm-4.6"],"compat":{"supportsDeveloperRole":false,"supportsReasoningEffort":false,"thinkingFormat":"zai","reasoningContentField":"reasoning_content"}}
|
|
5
|
+
]
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
setActiveStateCacheInvalidator,
|
|
17
17
|
writeActiveEntry,
|
|
18
18
|
} from "../gjc-runtime/state-writer";
|
|
19
|
+
import { getSkillManifest } from "../gjc-runtime/workflow-manifest";
|
|
19
20
|
import { CANONICAL_GJC_WORKFLOW_SKILLS, type CanonicalGjcWorkflowSkill } from "./canonical-skills";
|
|
20
21
|
import type { WorkflowStateReceipt } from "./workflow-state-contract";
|
|
21
22
|
|
|
@@ -445,29 +446,18 @@ async function readModeStatePhase(
|
|
|
445
446
|
const record = parsed as Record<string, unknown>;
|
|
446
447
|
const phase = safeString(record.current_phase).trim();
|
|
447
448
|
if (!phase) return undefined;
|
|
448
|
-
if (record.active === false && !
|
|
449
|
+
if (record.active === false && !getSkillManifest("ralplan").canonicalOverrides.includes(phase)) return undefined;
|
|
449
450
|
return phase;
|
|
450
451
|
} catch {
|
|
451
452
|
return undefined;
|
|
452
453
|
}
|
|
453
454
|
}
|
|
454
455
|
|
|
455
|
-
const RALPLAN_CANONICAL_PHASE_OVERRIDES = new Set([
|
|
456
|
-
"final",
|
|
457
|
-
"handoff",
|
|
458
|
-
"complete",
|
|
459
|
-
"completed",
|
|
460
|
-
"failed",
|
|
461
|
-
"cancelled",
|
|
462
|
-
"canceled",
|
|
463
|
-
"inactive",
|
|
464
|
-
]);
|
|
465
|
-
|
|
466
456
|
function withCanonicalRalplanPhase(entry: SkillActiveEntry, canonicalPhase: string | undefined): SkillActiveEntry {
|
|
467
457
|
if (
|
|
468
458
|
entry.skill !== "ralplan" ||
|
|
469
459
|
!canonicalPhase ||
|
|
470
|
-
!
|
|
460
|
+
!getSkillManifest("ralplan").canonicalOverrides.includes(canonicalPhase) ||
|
|
471
461
|
entry.phase === canonicalPhase
|
|
472
462
|
) {
|
|
473
463
|
return entry;
|
|
@@ -7,6 +7,7 @@ import { expandApplyPatchToEntries } from "../edit/modes/apply-patch";
|
|
|
7
7
|
import { GJC_SESSION_PREFIX, modeStatePath as sessionModeStatePath } from "../gjc-runtime/session-layout";
|
|
8
8
|
import { resolveGjcSessionForRead } from "../gjc-runtime/session-resolution";
|
|
9
9
|
import { ModeStateSchema } from "../gjc-runtime/state-schema";
|
|
10
|
+
import { getSkillManifest } from "../gjc-runtime/workflow-manifest";
|
|
10
11
|
import { LocalProtocolHandler, resolveLocalUrlToPath } from "../internal-urls/local-protocol";
|
|
11
12
|
import { resolveToCwd } from "../tools/path-utils";
|
|
12
13
|
import { ToolError } from "../tools/tool-errors";
|
|
@@ -51,7 +52,7 @@ type ToolWithEditMode = AgentTool & {
|
|
|
51
52
|
customWireName?: unknown;
|
|
52
53
|
};
|
|
53
54
|
|
|
54
|
-
export interface
|
|
55
|
+
export interface WorkflowMutationGuardInput {
|
|
55
56
|
cwd: string;
|
|
56
57
|
sessionId?: string;
|
|
57
58
|
threadId?: string;
|
|
@@ -59,6 +60,7 @@ export interface DeepInterviewMutationGuardInput {
|
|
|
59
60
|
args: unknown;
|
|
60
61
|
forceOverride?: boolean;
|
|
61
62
|
enforceWorkflowState?: boolean;
|
|
63
|
+
guardContext?: WorkflowGuardContext;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
interface ExtractedTargets {
|
|
@@ -66,7 +68,7 @@ interface ExtractedTargets {
|
|
|
66
68
|
unknown: boolean;
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
export interface
|
|
71
|
+
export interface WorkflowMutationDecision {
|
|
70
72
|
blocked: boolean;
|
|
71
73
|
message?: string;
|
|
72
74
|
targets: string[];
|
|
@@ -74,6 +76,12 @@ export interface DeepInterviewMutationDecision {
|
|
|
74
76
|
command?: string;
|
|
75
77
|
}
|
|
76
78
|
|
|
79
|
+
export interface WorkflowGuardContext {
|
|
80
|
+
sessionId: string | null;
|
|
81
|
+
activeState: Awaited<ReturnType<typeof readVisibleSkillActiveState>>;
|
|
82
|
+
modeStates: ReadonlyMap<string, ModeState | null>;
|
|
83
|
+
}
|
|
84
|
+
|
|
77
85
|
interface ModeState {
|
|
78
86
|
active?: boolean;
|
|
79
87
|
current_phase?: string;
|
|
@@ -125,8 +133,23 @@ async function readValidatedModeState(filePath: string): Promise<ModeState | nul
|
|
|
125
133
|
}
|
|
126
134
|
return state;
|
|
127
135
|
}
|
|
128
|
-
|
|
129
|
-
|
|
136
|
+
|
|
137
|
+
export async function readWorkflowGuardContext(
|
|
138
|
+
cwd: string,
|
|
139
|
+
options: { sessionId?: string; threadId?: string } = {},
|
|
140
|
+
): Promise<WorkflowGuardContext> {
|
|
141
|
+
const sessionId = await resolveBoundarySessionId(cwd, options.sessionId);
|
|
142
|
+
if (!sessionId) return { sessionId: null, activeState: null, modeStates: new Map() };
|
|
143
|
+
const activeState = await readVisibleSkillActiveState(cwd, sessionId, { tier: "security" });
|
|
144
|
+
const skills = activeState ? [...new Set(listActiveSkills(activeState).map(entry => entry.skill))] : [];
|
|
145
|
+
const modeStates = new Map(
|
|
146
|
+
await Promise.all(
|
|
147
|
+
skills.map(
|
|
148
|
+
async skill => [skill, await readValidatedModeState(modeStatePath(cwd, skill, sessionId))] as const,
|
|
149
|
+
),
|
|
150
|
+
),
|
|
151
|
+
);
|
|
152
|
+
return { sessionId, activeState, modeStates };
|
|
130
153
|
}
|
|
131
154
|
|
|
132
155
|
/**
|
|
@@ -135,7 +158,6 @@ async function readVisibleModeState(cwd: string, skill: string, sessionId: strin
|
|
|
135
158
|
* absent so a handoff-required planning skill (deep-interview/ralplan) keeps
|
|
136
159
|
* blocking through its handoff/ask window until it is demoted or cleared.
|
|
137
160
|
*/
|
|
138
|
-
const WORKFLOW_FINISHED_PHASES = new Set(["complete", "completed", "failed", "cancelled", "canceled", "inactive"]);
|
|
139
161
|
|
|
140
162
|
function entryMatchesContext(entry: SkillActiveEntry, sessionId?: string, threadId?: string): boolean {
|
|
141
163
|
if (sessionId && entry.session_id && entry.session_id !== sessionId) return false;
|
|
@@ -165,7 +187,7 @@ function isPlanningSkill(skill: string): skill is "deep-interview" | "ralplan" |
|
|
|
165
187
|
function isBlockingPlanningPhase(skill: "deep-interview" | "ralplan" | "ultragoal", phase: string): boolean {
|
|
166
188
|
const normalized = phase.trim().toLowerCase();
|
|
167
189
|
if (skill === "ultragoal") return normalized === "goal-planning";
|
|
168
|
-
return !
|
|
190
|
+
return !getSkillManifest(skill).stopReleasingPhases.includes(normalized);
|
|
169
191
|
}
|
|
170
192
|
|
|
171
193
|
interface ActivePlanningSkill {
|
|
@@ -219,10 +241,13 @@ async function getActivePlanningSkill(
|
|
|
219
241
|
cwd: string,
|
|
220
242
|
sessionId?: string,
|
|
221
243
|
threadId?: string,
|
|
244
|
+
context?: WorkflowGuardContext,
|
|
222
245
|
): Promise<ActivePlanningSkill | null> {
|
|
223
|
-
const
|
|
246
|
+
const guardContext = context ?? (await readWorkflowGuardContext(cwd, { sessionId, threadId }));
|
|
247
|
+
const resolvedSessionId = guardContext.sessionId;
|
|
224
248
|
if (!resolvedSessionId) return null;
|
|
225
|
-
const skillState =
|
|
249
|
+
const skillState = guardContext.activeState;
|
|
250
|
+
|
|
226
251
|
if (!skillState) return null;
|
|
227
252
|
const activeEntries = listActiveSkills(skillState).filter(entry =>
|
|
228
253
|
entryMatchesContext(entry, resolvedSessionId, threadId),
|
|
@@ -230,7 +255,8 @@ async function getActivePlanningSkill(
|
|
|
230
255
|
if (activeEntries.length === 0) return null;
|
|
231
256
|
const current = resolveCurrentWorkflowEntry(activeEntries, safeString(skillState.skill).trim());
|
|
232
257
|
if (!isPlanningSkill(current.skill)) return null;
|
|
233
|
-
const modeState =
|
|
258
|
+
const modeState = guardContext.modeStates.get(current.skill) ?? null;
|
|
259
|
+
|
|
234
260
|
if (!modeState) return null;
|
|
235
261
|
if (modeState.active !== true) return null;
|
|
236
262
|
if (!modeStateMatchesContext(modeState, resolvedSessionId, threadId)) return null;
|
|
@@ -558,23 +584,25 @@ async function planningBlockedTargets(cwd: string, targets: ExtractedTargets): P
|
|
|
558
584
|
}
|
|
559
585
|
return blocked;
|
|
560
586
|
}
|
|
561
|
-
export async function
|
|
587
|
+
export async function assertWorkflowMutationRawPathsAllowed(input: {
|
|
562
588
|
cwd: string;
|
|
563
589
|
sessionId?: string;
|
|
564
590
|
threadId?: string;
|
|
565
591
|
rawPaths: string[];
|
|
566
592
|
forceOverride?: boolean;
|
|
593
|
+
guardContext?: WorkflowGuardContext;
|
|
567
594
|
}): Promise<void> {
|
|
568
595
|
const targets: ExtractedTargets = { paths: input.rawPaths, unknown: input.rawPaths.length === 0 };
|
|
569
|
-
// Always-on `.gjc/**` runtime-owned block,
|
|
570
|
-
//
|
|
596
|
+
// Always-on `.gjc/**` runtime-owned block, ahead of forceOverride.
|
|
597
|
+
// A deferred ast_edit apply must not reach `.gjc/**` either.
|
|
571
598
|
if (hasBlockedGjcTarget(input.cwd, targets)) {
|
|
572
599
|
const stateSkill = firstBlockedWorkflowStateSkill(input.cwd, targets);
|
|
573
600
|
const command = stateSkill ? sanctionedWorkflowStateCommand(stateSkill) : "gjc <workflow-command>";
|
|
574
601
|
throw new ToolError(`${WORKFLOW_STATE_MUTATION_BLOCK_MESSAGE}\nUse: ${command}`);
|
|
575
602
|
}
|
|
576
603
|
if (input.forceOverride) return;
|
|
577
|
-
const planning = await getActivePlanningSkill(input.cwd, input.sessionId, input.threadId);
|
|
604
|
+
const planning = await getActivePlanningSkill(input.cwd, input.sessionId, input.threadId, input.guardContext);
|
|
605
|
+
|
|
578
606
|
if (!planning) return;
|
|
579
607
|
const message = planningPhaseBlockMessage(planning.skill);
|
|
580
608
|
if (input.rawPaths.length === 0) throw new ToolError(message);
|
|
@@ -582,9 +610,9 @@ export async function assertDeepInterviewMutationRawPathsAllowed(input: {
|
|
|
582
610
|
if (blocked.length > 0) throw new ToolError(message);
|
|
583
611
|
}
|
|
584
612
|
|
|
585
|
-
export async function
|
|
586
|
-
input:
|
|
587
|
-
): Promise<
|
|
613
|
+
export async function getWorkflowMutationDecision(
|
|
614
|
+
input: WorkflowMutationGuardInput,
|
|
615
|
+
): Promise<WorkflowMutationDecision> {
|
|
588
616
|
if (!BLOCKED_TOOL_NAMES.has(input.tool.name)) return { blocked: false, targets: [] };
|
|
589
617
|
const targets = extractTargets(input.tool, input.args);
|
|
590
618
|
if (input.tool.name !== "bash" && input.enforceWorkflowState !== false && hasBlockedGjcTarget(input.cwd, targets)) {
|
|
@@ -598,7 +626,7 @@ export async function getDeepInterviewMutationDecision(
|
|
|
598
626
|
command,
|
|
599
627
|
};
|
|
600
628
|
}
|
|
601
|
-
const planning = await getActivePlanningSkill(input.cwd, input.sessionId, input.threadId);
|
|
629
|
+
const planning = await getActivePlanningSkill(input.cwd, input.sessionId, input.threadId, input.guardContext);
|
|
602
630
|
if (!planning) {
|
|
603
631
|
return { blocked: false, targets: [] };
|
|
604
632
|
}
|
|
@@ -627,17 +655,7 @@ export async function getDeepInterviewMutationDecision(
|
|
|
627
655
|
};
|
|
628
656
|
}
|
|
629
657
|
|
|
630
|
-
export async function
|
|
631
|
-
const decision = await
|
|
658
|
+
export async function assertWorkflowMutationAllowed(input: WorkflowMutationGuardInput): Promise<void> {
|
|
659
|
+
const decision = await getWorkflowMutationDecision(input);
|
|
632
660
|
if (decision.blocked) throw new ToolError(decision.message ?? DEEP_INTERVIEW_MUTATION_BLOCK_MESSAGE);
|
|
633
661
|
}
|
|
634
|
-
|
|
635
|
-
/*
|
|
636
|
-
* Generic cross-workflow names for this planning-phase mutation guard. The guard
|
|
637
|
-
* now governs deep-interview, ralplan, and ultragoal goal-planning, so new
|
|
638
|
-
* callers SHOULD use these names; the `*DeepInterview*` exports above remain as
|
|
639
|
-
* compatibility aliases (and are still what the test-suite imports).
|
|
640
|
-
*/
|
|
641
|
-
export const getWorkflowMutationDecision = getDeepInterviewMutationDecision;
|
|
642
|
-
export const assertWorkflowMutationAllowed = assertDeepInterviewMutationAllowed;
|
|
643
|
-
export const assertWorkflowMutationRawPathsAllowed = assertDeepInterviewMutationRawPathsAllowed;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
+
import { activeSnapshotPath, assertNonEmptyGjcSessionId, modeStatePath } from "../gjc-runtime/session-layout";
|
|
2
3
|
import { CANONICAL_GJC_WORKFLOW_SKILLS, type CanonicalGjcWorkflowSkill, SKILL_ACTIVE_STATE_FILE } from "./active-state";
|
|
3
4
|
import { WORKFLOW_STATE_RECEIPT_FRESH_MS, WORKFLOW_STATE_RECEIPT_VERSION } from "./workflow-state-version";
|
|
4
5
|
|
|
@@ -51,57 +52,21 @@ export interface AuditEntry {
|
|
|
51
52
|
paths: string[];
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
function safeString(value: unknown): string {
|
|
55
|
-
return typeof value === "string" ? value : "";
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function encodePathSegment(value: string): string {
|
|
59
|
-
return encodeURIComponent(value).replaceAll(".", "%2E");
|
|
60
|
-
}
|
|
61
|
-
|
|
62
55
|
export function workflowModeStateFileName(skill: CanonicalGjcWorkflowSkill): string {
|
|
63
56
|
return `${skill}-state.json`;
|
|
64
57
|
}
|
|
65
58
|
|
|
66
|
-
export function workflowStateStoragePath(cwd: string, skill: CanonicalGjcWorkflowSkill, sessionId?: string): string {
|
|
67
|
-
const normalizedSessionId = safeString(sessionId).trim();
|
|
68
|
-
if (normalizedSessionId) {
|
|
69
|
-
return path.join(
|
|
70
|
-
cwd,
|
|
71
|
-
".gjc",
|
|
72
|
-
"state",
|
|
73
|
-
"sessions",
|
|
74
|
-
encodePathSegment(normalizedSessionId),
|
|
75
|
-
workflowModeStateFileName(skill),
|
|
76
|
-
);
|
|
77
|
-
}
|
|
78
|
-
return path.join(cwd, ".gjc", "state", workflowModeStateFileName(skill));
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function workflowActiveStatePath(cwd: string, sessionId?: string): string {
|
|
82
|
-
const normalizedSessionId = safeString(sessionId).trim();
|
|
83
|
-
if (normalizedSessionId) {
|
|
84
|
-
return path.join(
|
|
85
|
-
cwd,
|
|
86
|
-
".gjc",
|
|
87
|
-
"state",
|
|
88
|
-
"sessions",
|
|
89
|
-
encodePathSegment(normalizedSessionId),
|
|
90
|
-
SKILL_ACTIVE_STATE_FILE,
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
return path.join(cwd, ".gjc", "state", SKILL_ACTIVE_STATE_FILE);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
59
|
export function buildWorkflowStateReceipt(input: {
|
|
97
60
|
cwd: string;
|
|
98
61
|
skill: CanonicalGjcWorkflowSkill;
|
|
99
62
|
owner: WorkflowStateMutationOwner;
|
|
100
63
|
command: string;
|
|
101
|
-
sessionId
|
|
64
|
+
sessionId: string;
|
|
102
65
|
nowIso?: string;
|
|
103
66
|
mutationId?: string;
|
|
104
67
|
}): WorkflowStateReceipt {
|
|
68
|
+
assertNonEmptyGjcSessionId(input.sessionId, "buildWorkflowStateReceipt");
|
|
69
|
+
const cwd = path.resolve(input.cwd);
|
|
105
70
|
const mutatedAt = input.nowIso ?? new Date().toISOString();
|
|
106
71
|
const freshUntil = new Date(Date.parse(mutatedAt) + WORKFLOW_STATE_RECEIPT_FRESH_MS).toISOString();
|
|
107
72
|
return {
|
|
@@ -109,8 +74,8 @@ export function buildWorkflowStateReceipt(input: {
|
|
|
109
74
|
skill: input.skill,
|
|
110
75
|
owner: input.owner,
|
|
111
76
|
command: input.command,
|
|
112
|
-
state_path:
|
|
113
|
-
storage_path:
|
|
77
|
+
state_path: activeSnapshotPath(cwd, input.sessionId),
|
|
78
|
+
storage_path: modeStatePath(cwd, input.sessionId, input.skill),
|
|
114
79
|
mutated_at: mutatedAt,
|
|
115
80
|
fresh_until: freshUntil,
|
|
116
81
|
status: "fresh",
|
|
@@ -18,12 +18,17 @@ import {
|
|
|
18
18
|
formatModelSelectorValue,
|
|
19
19
|
parseModelPattern,
|
|
20
20
|
parseModelString,
|
|
21
|
+
splitSelectorThinkingSuffix,
|
|
21
22
|
} from "../config/model-resolver";
|
|
22
23
|
import { clearPluginRootsAndCaches, resolveActiveProjectRegistryPath } from "../discovery/helpers.js";
|
|
23
24
|
import { resolveMemoryBackend } from "../memory-backend";
|
|
24
25
|
import { DynamicBorder } from "../modes/components/dynamic-border";
|
|
25
26
|
import { theme } from "../modes/theme/theme";
|
|
26
|
-
import
|
|
27
|
+
import {
|
|
28
|
+
type ComposerSubmissionOptions,
|
|
29
|
+
canApplyComposerSubmission,
|
|
30
|
+
type InteractiveModeContext,
|
|
31
|
+
} from "../modes/types";
|
|
27
32
|
import {
|
|
28
33
|
buildNotificationStatusReport,
|
|
29
34
|
checkNotificationHealth,
|
|
@@ -62,7 +67,13 @@ import type {
|
|
|
62
67
|
export type { BuiltinSlashCommand, SubcommandDef } from "./types";
|
|
63
68
|
|
|
64
69
|
/** TUI-specific runtime accepted by `executeBuiltinSlashCommand`. */
|
|
65
|
-
export type BuiltinSlashCommandRuntime = TuiSlashCommandRuntime
|
|
70
|
+
export type BuiltinSlashCommandRuntime = TuiSlashCommandRuntime & {
|
|
71
|
+
composer?: ComposerSubmissionOptions;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
function canClearComposer(runtime: BuiltinSlashCommandRuntime): boolean {
|
|
75
|
+
return canApplyComposerSubmission(runtime.composer, runtime.ctx.editor);
|
|
76
|
+
}
|
|
66
77
|
|
|
67
78
|
const PET_COMMAND_OPTIONS: ReadonlyArray<{ name: string; mode: PetMode; description: string }> = [
|
|
68
79
|
{ name: "off", mode: "off", description: "Hide the pet" },
|
|
@@ -243,12 +254,9 @@ function parseModelCommandArgs(args: string): ParsedModelCommandArgs {
|
|
|
243
254
|
|
|
244
255
|
function splitExplicitThinkingSelector(selector: string): { baseSelector: string; thinkingLevel?: ThinkingLevel } {
|
|
245
256
|
const trimmed = selector.trim();
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
250
|
-
const thinkingLevel = parseThinkingLevel(trimmed.slice(colonIndex + 1));
|
|
251
|
-
return thinkingLevel ? { baseSelector: trimmed.slice(0, colonIndex), thinkingLevel } : { baseSelector: trimmed };
|
|
257
|
+
const { selector: baseSelector, thinkingLevel } = splitSelectorThinkingSuffix(trimmed);
|
|
258
|
+
// Preserve the whole selector when the trailing suffix is not a valid thinking level.
|
|
259
|
+
return thinkingLevel ? { baseSelector, thinkingLevel } : { baseSelector: trimmed };
|
|
252
260
|
}
|
|
253
261
|
|
|
254
262
|
interface ModelCommandSelection {
|
|
@@ -625,7 +633,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
625
633
|
// — including the first-time `/goal set <objective>` case where goal
|
|
626
634
|
// mode was not yet active. A previous `wasGoalModeEnabled` guard dropped
|
|
627
635
|
// that first-time case from history (up/down-arrow recall).
|
|
628
|
-
await runtime.ctx.
|
|
636
|
+
await runtime.ctx.goalModeController.handleCommand(command.args || undefined);
|
|
629
637
|
if (command.args) {
|
|
630
638
|
runtime.ctx.editor.addToHistory(command.text);
|
|
631
639
|
}
|
|
@@ -1048,6 +1056,20 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
1048
1056
|
runtime.ctx.editor.setText("");
|
|
1049
1057
|
},
|
|
1050
1058
|
},
|
|
1059
|
+
{
|
|
1060
|
+
name: "transcript",
|
|
1061
|
+
description: "Browse the current session transcript",
|
|
1062
|
+
acpDescription: "Browse the current session transcript",
|
|
1063
|
+
handle: async (_command, runtime) => {
|
|
1064
|
+
await runtime.output("Transcript browsing is available in the interactive TUI.");
|
|
1065
|
+
return commandConsumed();
|
|
1066
|
+
},
|
|
1067
|
+
handleTui: (_command, runtime) => {
|
|
1068
|
+
if (runtime.ctx.isTranscriptViewerOpen()) return;
|
|
1069
|
+
runtime.ctx.showTranscriptViewer();
|
|
1070
|
+
runtime.ctx.editor.setText("");
|
|
1071
|
+
},
|
|
1072
|
+
},
|
|
1051
1073
|
{
|
|
1052
1074
|
name: "context",
|
|
1053
1075
|
description: "Show active context token usage breakdown",
|
|
@@ -1446,6 +1468,15 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
|
|
1446
1468
|
runtime.ctx.editor.setText("");
|
|
1447
1469
|
},
|
|
1448
1470
|
},
|
|
1471
|
+
{
|
|
1472
|
+
name: "sessions",
|
|
1473
|
+
priority: 91,
|
|
1474
|
+
description: "Show all persisted sessions (read-only)",
|
|
1475
|
+
handleTui: (_command, runtime) => {
|
|
1476
|
+
runtime.ctx.showSessionsDashboard();
|
|
1477
|
+
runtime.ctx.editor.setText("");
|
|
1478
|
+
},
|
|
1479
|
+
},
|
|
1449
1480
|
{
|
|
1450
1481
|
name: "btw",
|
|
1451
1482
|
description: "Ask an ephemeral side question using the current session context",
|
|
@@ -1688,7 +1719,9 @@ export async function executeBuiltinSlashCommand(
|
|
|
1688
1719
|
const diagnostic = formatUnknownBuiltinSlashCommandDiagnostic(parsed.name);
|
|
1689
1720
|
if (!diagnostic) return false;
|
|
1690
1721
|
runtime.ctx.showError(diagnostic);
|
|
1691
|
-
runtime
|
|
1722
|
+
if (canClearComposer(runtime)) {
|
|
1723
|
+
runtime.ctx.editor.setText("");
|
|
1724
|
+
}
|
|
1692
1725
|
return true;
|
|
1693
1726
|
}
|
|
1694
1727
|
if (parsed.args.length > 0 && !command.allowArgs) {
|
|
@@ -1703,7 +1736,9 @@ export async function executeBuiltinSlashCommand(
|
|
|
1703
1736
|
const ctx = runtime.ctx;
|
|
1704
1737
|
const adapted = toSlashCommandRuntime(runtime);
|
|
1705
1738
|
const result = await command.handle(parsed, adapted);
|
|
1706
|
-
|
|
1739
|
+
if (canClearComposer(runtime)) {
|
|
1740
|
+
ctx.editor.setText("");
|
|
1741
|
+
}
|
|
1707
1742
|
if (result && typeof result === "object" && "prompt" in result) return result.prompt;
|
|
1708
1743
|
return true;
|
|
1709
1744
|
}
|