@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
|
@@ -31,6 +31,8 @@ export interface CronJobView {
|
|
|
31
31
|
prompt: string;
|
|
32
32
|
recurring: boolean;
|
|
33
33
|
nextFireAt?: number;
|
|
34
|
+
/** A cron firing whose spawned job is currently running. */
|
|
35
|
+
firing?: boolean;
|
|
34
36
|
createdAt: number;
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -140,6 +142,7 @@ export class JobsObserver {
|
|
|
140
142
|
recurring: snapshot.recurring,
|
|
141
143
|
nextFireAt: snapshot.nextFireAt,
|
|
142
144
|
createdAt: snapshot.createdAt,
|
|
145
|
+
firing: snapshot.firing,
|
|
143
146
|
}))
|
|
144
147
|
.sort((a, b) => b.createdAt - a.createdAt);
|
|
145
148
|
const worstState: JobsWorstState = this.#failedUnacknowledged
|
|
@@ -248,6 +248,13 @@ export class PromptActionAutocompleteProvider implements AutocompleteProvider {
|
|
|
248
248
|
|
|
249
249
|
return this.#baseProvider.getSuggestions(lines, cursorLine, cursorCol);
|
|
250
250
|
}
|
|
251
|
+
getForceFileSuggestions(
|
|
252
|
+
lines: string[],
|
|
253
|
+
cursorLine: number,
|
|
254
|
+
cursorCol: number,
|
|
255
|
+
): Promise<{ items: AutocompleteItem[]; prefix: string } | null> {
|
|
256
|
+
return this.#baseProvider.getForceFileSuggestions(lines, cursorLine, cursorCol);
|
|
257
|
+
}
|
|
251
258
|
|
|
252
259
|
applyCompletion(
|
|
253
260
|
lines: string[],
|
|
@@ -66,6 +66,10 @@ export async function initializeExtensions(session: AgentSession, options: Initi
|
|
|
66
66
|
},
|
|
67
67
|
getActiveTools: () => session.getActiveToolNames(),
|
|
68
68
|
getAllTools: () => session.getAllToolNames(),
|
|
69
|
+
resolveTool: name => {
|
|
70
|
+
const tool = session.getToolByName(name);
|
|
71
|
+
return tool ? { safeSummary: tool.safeSummary, safeSummaryFields: tool.safeSummaryFields } : undefined;
|
|
72
|
+
},
|
|
69
73
|
setActiveTools: (toolNames: string[]) => session.setActiveToolsByName(toolNames),
|
|
70
74
|
getCommands: () => getSessionSlashCommands(session),
|
|
71
75
|
setModel: model => runExtensionSetModel(session, model),
|
|
@@ -100,6 +104,10 @@ export async function initializeExtensions(session: AgentSession, options: Initi
|
|
|
100
104
|
getQueuedMessages: () => session.getQueuedMessageEntries(),
|
|
101
105
|
getActiveTools: () => session.getActiveToolNames(),
|
|
102
106
|
getAllTools: () => session.getAllToolNames(),
|
|
107
|
+
resolveTool: name => {
|
|
108
|
+
const tool = session.getToolByName(name);
|
|
109
|
+
return tool ? { safeSummary: tool.safeSummary, safeSummaryFields: tool.safeSummaryFields } : undefined;
|
|
110
|
+
},
|
|
103
111
|
shutdown,
|
|
104
112
|
getContextUsage: () => session.getContextUsage(),
|
|
105
113
|
getSystemPrompt: () => session.systemPrompt,
|
|
@@ -11,19 +11,20 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import type { OpenGateInput } from "./workflow-gate-broker";
|
|
14
|
-
import
|
|
14
|
+
import {
|
|
15
|
+
type AskGateDeepInterviewState,
|
|
16
|
+
buildAskGateAnswerSchema,
|
|
17
|
+
buildAskGateStageState as buildCanonicalAskGateStageState,
|
|
18
|
+
type WorkflowGateKind,
|
|
19
|
+
type WorkflowStage,
|
|
20
|
+
} from "./workflow-gate-types";
|
|
15
21
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
round: number;
|
|
23
|
-
component: string;
|
|
24
|
-
dimension: string;
|
|
25
|
-
ambiguity: number;
|
|
26
|
-
}
|
|
22
|
+
export {
|
|
23
|
+
type AskGateDeepInterviewState,
|
|
24
|
+
buildAskGateAnswerSchema,
|
|
25
|
+
GATE_OTHER_OPTION,
|
|
26
|
+
validateAskGateStageState,
|
|
27
|
+
} from "./workflow-gate-types";
|
|
27
28
|
|
|
28
29
|
export interface AskGateWorkflowGateMeta {
|
|
29
30
|
stage: WorkflowStage;
|
|
@@ -95,7 +96,7 @@ function deepInterviewQuestionState(questionText: string): Record<string, unknow
|
|
|
95
96
|
const state: Record<string, unknown> = {};
|
|
96
97
|
if (roundMatch) {
|
|
97
98
|
const round = Number(roundMatch[1]);
|
|
98
|
-
if (Number.
|
|
99
|
+
if (Number.isSafeInteger(round) && round >= 0) state.round = round;
|
|
99
100
|
const mode = roundMatch[2]?.trim();
|
|
100
101
|
if (mode) {
|
|
101
102
|
state.mode = mode;
|
|
@@ -103,8 +104,9 @@ function deepInterviewQuestionState(questionText: string): Record<string, unknow
|
|
|
103
104
|
if (normalized.includes("topology")) state.topology_gate = true;
|
|
104
105
|
if (/(contrarian|simplifier|ontologist)/u.test(normalized)) state.challenge_mode = normalized;
|
|
105
106
|
}
|
|
106
|
-
const
|
|
107
|
-
|
|
107
|
+
const rawAmbiguity = roundMatch[3]?.trim();
|
|
108
|
+
const ambiguity = rawAmbiguity === "" || rawAmbiguity === undefined ? Number.NaN : Number(rawAmbiguity);
|
|
109
|
+
if (Number.isFinite(ambiguity) && ambiguity >= 0 && ambiguity <= 1) state.ambiguity = ambiguity;
|
|
108
110
|
}
|
|
109
111
|
if (/Round\s+0\s+\|\s+Topology confirmation/im.test(questionText)) {
|
|
110
112
|
state.round = 0;
|
|
@@ -114,91 +116,25 @@ function deepInterviewQuestionState(questionText: string): Record<string, unknow
|
|
|
114
116
|
return state;
|
|
115
117
|
}
|
|
116
118
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
...selectedBase,
|
|
128
|
-
...(multi ? {} : { maxItems: 0 }),
|
|
129
|
-
};
|
|
130
|
-
return {
|
|
131
|
-
type: "object",
|
|
132
|
-
properties: {
|
|
133
|
-
selected: selectedBase,
|
|
134
|
-
other: { type: "boolean", description: "set true to provide a free-text answer in `custom`" },
|
|
135
|
-
custom: {
|
|
136
|
-
type: "string",
|
|
137
|
-
minLength: 1,
|
|
138
|
-
pattern: "\\S",
|
|
139
|
-
description: "free-text answer; required when `other` is true",
|
|
140
|
-
},
|
|
141
|
-
action: {
|
|
142
|
-
type: "string",
|
|
143
|
-
enum: ["answer", "clarify"],
|
|
144
|
-
description: "set to `clarify` to ask about the choices without answering the round",
|
|
145
|
-
},
|
|
146
|
-
question: {
|
|
147
|
-
type: "string",
|
|
148
|
-
minLength: 1,
|
|
149
|
-
pattern: "\\S",
|
|
150
|
-
description: "clarification question; required when action is `clarify`",
|
|
151
|
-
},
|
|
119
|
+
/** Build and validate exact producer-compatible `stage_state` metadata for one ask question. */
|
|
120
|
+
export function buildAskGateStageState(question: AskGateQuestion, labels: string[]): Record<string, unknown> {
|
|
121
|
+
return buildCanonicalAskGateStageState(
|
|
122
|
+
{
|
|
123
|
+
id: question.id,
|
|
124
|
+
multi: question.multi,
|
|
125
|
+
allowEmpty: question.allowEmpty,
|
|
126
|
+
navigationLabel: question.navigationLabel,
|
|
127
|
+
deepInterview: question.deepInterview,
|
|
128
|
+
fallbackState: deepInterviewQuestionState(question.question),
|
|
152
129
|
},
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
{
|
|
156
|
-
type: "object",
|
|
157
|
-
properties: { selected: selectedOnly, other: { const: false }, action: { const: "answer" } },
|
|
158
|
-
required: ["selected"],
|
|
159
|
-
additionalProperties: false,
|
|
160
|
-
},
|
|
161
|
-
{
|
|
162
|
-
type: "object",
|
|
163
|
-
properties: {
|
|
164
|
-
selected: selectedWithOther,
|
|
165
|
-
other: { const: true },
|
|
166
|
-
custom: { type: "string", minLength: 1, pattern: "\\S" },
|
|
167
|
-
action: { const: "answer" },
|
|
168
|
-
},
|
|
169
|
-
required: ["selected", "other", "custom"],
|
|
170
|
-
additionalProperties: false,
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
type: "object",
|
|
174
|
-
properties: {
|
|
175
|
-
action: { const: "clarify" },
|
|
176
|
-
question: { type: "string", minLength: 1, pattern: "\\S" },
|
|
177
|
-
},
|
|
178
|
-
required: ["action", "question"],
|
|
179
|
-
additionalProperties: false,
|
|
180
|
-
},
|
|
181
|
-
],
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/** Build `stage_state` round metadata from the structured param (authoritative when present). */
|
|
186
|
-
function structuredDeepInterviewState(meta: AskGateDeepInterviewState): Record<string, unknown> {
|
|
187
|
-
const state: Record<string, unknown> = {
|
|
188
|
-
deep_interview_metadata: true,
|
|
189
|
-
round: meta.round,
|
|
190
|
-
component: meta.component,
|
|
191
|
-
dimension: meta.dimension,
|
|
192
|
-
ambiguity: meta.ambiguity,
|
|
193
|
-
};
|
|
194
|
-
if (meta.round_id !== undefined) state.round_id = meta.round_id;
|
|
195
|
-
return state;
|
|
130
|
+
labels,
|
|
131
|
+
);
|
|
196
132
|
}
|
|
197
133
|
|
|
198
134
|
/** Build the `workflow_gate` open-input for one ask question. */
|
|
199
135
|
export function questionToGate(question: AskGateQuestion): OpenGateInput {
|
|
200
136
|
const labels = question.options.map(o => o.label);
|
|
201
|
-
const schema =
|
|
137
|
+
const schema = buildAskGateAnswerSchema(question, labels);
|
|
202
138
|
return {
|
|
203
139
|
stage: question.workflowGate?.stage ?? "deep-interview",
|
|
204
140
|
kind: question.workflowGate?.kind ?? "question",
|
|
@@ -211,18 +147,7 @@ export function questionToGate(question: AskGateQuestion): OpenGateInput {
|
|
|
211
147
|
context: {
|
|
212
148
|
title: question.question,
|
|
213
149
|
prompt: question.question,
|
|
214
|
-
stage_state:
|
|
215
|
-
question_id: question.id,
|
|
216
|
-
multi: question.multi ?? false,
|
|
217
|
-
options: labels,
|
|
218
|
-
other_option: GATE_OTHER_OPTION,
|
|
219
|
-
clarification_action: "clarify",
|
|
220
|
-
allow_empty: question.allowEmpty === true,
|
|
221
|
-
navigation_label: question.navigationLabel,
|
|
222
|
-
...(question.deepInterview
|
|
223
|
-
? structuredDeepInterviewState(question.deepInterview)
|
|
224
|
-
: deepInterviewQuestionState(question.question)),
|
|
225
|
-
},
|
|
150
|
+
stage_state: buildAskGateStageState(question, labels),
|
|
226
151
|
},
|
|
227
152
|
};
|
|
228
153
|
}
|
|
@@ -28,7 +28,7 @@ import type {
|
|
|
28
28
|
WorkflowGateValidationError,
|
|
29
29
|
WorkflowStage,
|
|
30
30
|
} from "./workflow-gate-types";
|
|
31
|
-
import { RESERVED_WORKFLOW_STAGES } from "./workflow-gate-types";
|
|
31
|
+
import { RESERVED_WORKFLOW_STAGES, WORKFLOW_GATE_V1_STAGES } from "./workflow-gate-types";
|
|
32
32
|
|
|
33
33
|
export type PersistedSemanticDisposition = "commit" | "resolve_without_commit";
|
|
34
34
|
export type PersistedResolutionOrigin =
|
|
@@ -108,6 +108,10 @@ export interface WorkflowGateEmitter {
|
|
|
108
108
|
setAckRecoveryParticipant?(participant: AskSelectedAckRecoveryParticipant | null): void;
|
|
109
109
|
/** Explicit host hook for same-process accepted-but-unadvanced recovery. */
|
|
110
110
|
recoverAcceptedGates?(): Promise<string[]>;
|
|
111
|
+
/** Reads a durable completed resolution before any presentation claim. */
|
|
112
|
+
lookupCompletedResolution?(response: WorkflowGateResponse): WorkflowGateCompletedResolutionLookup;
|
|
113
|
+
/** Supplies the active runtime turn captured immediately before a gate is opened. */
|
|
114
|
+
setRuntimeTurnProvider?(provider: (() => string | undefined) | null): void;
|
|
111
115
|
/** Permanently revoke all in-process continuation authority and reject their waiters. */
|
|
112
116
|
fence?(): void;
|
|
113
117
|
/** Temporarily make this emitter unavailable while a session transition is reversible. */
|
|
@@ -139,6 +143,7 @@ export class BrokerWorkflowGateEmitter implements WorkflowGateEmitter {
|
|
|
139
143
|
readonly #runId: string;
|
|
140
144
|
readonly #store: GateStore;
|
|
141
145
|
readonly #emitterHooks: Pick<BrokerHooks, "advance">;
|
|
146
|
+
#runtimeTurnProvider: (() => string | undefined) | undefined;
|
|
142
147
|
|
|
143
148
|
constructor(runId: string, store: GateStore, emitterHooks: Pick<BrokerHooks, "advance"> = {}) {
|
|
144
149
|
this.#runId = runId;
|
|
@@ -158,20 +163,29 @@ export class BrokerWorkflowGateEmitter implements WorkflowGateEmitter {
|
|
|
158
163
|
isUnattended(): boolean {
|
|
159
164
|
return true;
|
|
160
165
|
}
|
|
166
|
+
setRuntimeTurnProvider(provider: (() => string | undefined) | null): void {
|
|
167
|
+
this.#runtimeTurnProvider = provider ?? undefined;
|
|
168
|
+
}
|
|
161
169
|
|
|
162
170
|
emitGate(input: OpenGateInput): Promise<unknown> {
|
|
163
171
|
if (this.#fenced || this.#suspended) return Promise.reject(new Error("workflow gate emitter is unavailable"));
|
|
164
172
|
const waiter = Promise.withResolvers<unknown>();
|
|
165
|
-
const gate = this.#broker.openGate(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const activeWaiter = this.#waiters.get(gateId);
|
|
170
|
-
if (!activeWaiter) return;
|
|
171
|
-
this.#waiters.delete(gateId);
|
|
172
|
-
activeWaiter.reject(new Error(`workflow gate ${gateId} continuation was fenced`));
|
|
173
|
+
const gate = this.#broker.openGate(
|
|
174
|
+
{
|
|
175
|
+
...input,
|
|
176
|
+
...(input.runtimeTurnId === undefined ? { runtimeTurnId: this.#runtimeTurnProvider?.() } : {}),
|
|
173
177
|
},
|
|
174
|
-
|
|
178
|
+
{
|
|
179
|
+
activate: opened => this.#waiters.set(opened.gate_id, waiter),
|
|
180
|
+
isLive: gateId => this.#waiters.has(gateId),
|
|
181
|
+
release: gateId => {
|
|
182
|
+
const activeWaiter = this.#waiters.get(gateId);
|
|
183
|
+
if (!activeWaiter) return;
|
|
184
|
+
this.#waiters.delete(gateId);
|
|
185
|
+
activeWaiter.reject(new Error(`workflow gate ${gateId} continuation was fenced`));
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
);
|
|
175
189
|
// A listener may answer synchronously while the broker emits. The durable
|
|
176
190
|
// record is the source of truth in that race; never strand its promise.
|
|
177
191
|
const persisted = this.#store.get(gate.gate_id);
|
|
@@ -192,6 +206,10 @@ export class BrokerWorkflowGateEmitter implements WorkflowGateEmitter {
|
|
|
192
206
|
throw error;
|
|
193
207
|
});
|
|
194
208
|
}
|
|
209
|
+
lookupCompletedResolution(response: WorkflowGateResponse): WorkflowGateCompletedResolutionLookup {
|
|
210
|
+
return this.#broker.lookupCompletedResolution(response);
|
|
211
|
+
}
|
|
212
|
+
|
|
195
213
|
prepareTerminalization(gateId: string, proof: WorkflowGateTerminalProof): boolean {
|
|
196
214
|
return this.#broker.prepareTerminalization(gateId, proof);
|
|
197
215
|
}
|
|
@@ -223,6 +241,7 @@ export class BrokerWorkflowGateEmitter implements WorkflowGateEmitter {
|
|
|
223
241
|
if (this.#fenced) return;
|
|
224
242
|
this.#fenced = true;
|
|
225
243
|
this.#suspended = false;
|
|
244
|
+
this.#runtimeTurnProvider = undefined;
|
|
226
245
|
if (this.#recoveryTimer) clearTimeout(this.#recoveryTimer);
|
|
227
246
|
this.#recoveryTimer = undefined;
|
|
228
247
|
if (this.#recoveryGraceTimer) clearTimeout(this.#recoveryGraceTimer);
|
|
@@ -467,8 +486,6 @@ export class BrokerWorkflowGateEmitter implements WorkflowGateEmitter {
|
|
|
467
486
|
}
|
|
468
487
|
}
|
|
469
488
|
|
|
470
|
-
const V1_STAGES: readonly WorkflowStage[] = ["deep-interview", "ralplan", "ultragoal"];
|
|
471
|
-
|
|
472
489
|
export interface PersistedGate {
|
|
473
490
|
gate: WorkflowGate;
|
|
474
491
|
status: "pending" | "accepted" | "quarantined";
|
|
@@ -760,7 +777,7 @@ function assertFileState(value: unknown, filePath: string): asserts value is Fil
|
|
|
760
777
|
invalidFileState(filePath);
|
|
761
778
|
for (const [stage, counter] of Object.entries(value.counters)) {
|
|
762
779
|
if (
|
|
763
|
-
!
|
|
780
|
+
!WORKFLOW_GATE_V1_STAGES.includes(stage as WorkflowStage) ||
|
|
764
781
|
typeof counter !== "number" ||
|
|
765
782
|
!Number.isSafeInteger(counter) ||
|
|
766
783
|
counter < 0
|
|
@@ -805,7 +822,7 @@ function assertPersistedGate(
|
|
|
805
822
|
if (
|
|
806
823
|
gate.type !== "workflow_gate" ||
|
|
807
824
|
!isNonEmptyString(gate.gate_id) ||
|
|
808
|
-
!
|
|
825
|
+
!WORKFLOW_GATE_V1_STAGES.includes(stage) ||
|
|
809
826
|
!["question", "approval", "execution"].includes(gate.kind as string) ||
|
|
810
827
|
!isObject(gate.schema) ||
|
|
811
828
|
!isNonEmptyString(gate.schema_hash) ||
|
|
@@ -814,6 +831,7 @@ function assertPersistedGate(
|
|
|
814
831
|
gate.required !== true
|
|
815
832
|
)
|
|
816
833
|
invalidFileState(filePath);
|
|
834
|
+
if (gate.runtime_turn_id !== undefined && !isNonEmptyString(gate.runtime_turn_id)) invalidFileState(filePath);
|
|
817
835
|
const id = new RegExp(`^wg_[A-Za-z0-9]+_${gate.stage}_(\\d{6,})$`).exec(gate.gate_id);
|
|
818
836
|
if (
|
|
819
837
|
!id ||
|
|
@@ -1149,11 +1167,24 @@ export interface OpenGateInput {
|
|
|
1149
1167
|
context?: WorkflowGateContext;
|
|
1150
1168
|
/** Optional diagnostic gate replaced by this newly persisted gate. */
|
|
1151
1169
|
supersedesGateId?: string;
|
|
1170
|
+
/** Optional immutable runtime turn captured by the emitter before broker persistence. */
|
|
1171
|
+
runtimeTurnId?: string;
|
|
1152
1172
|
}
|
|
1153
1173
|
|
|
1174
|
+
/** Durable resolution state used to safely replay direct control after presentation retirement. */
|
|
1175
|
+
export type WorkflowGateCompletedResolutionLookup =
|
|
1176
|
+
| { kind: "none" }
|
|
1177
|
+
| { kind: "completed"; resolution: WorkflowGateResolution }
|
|
1178
|
+
| { kind: "accepted_incomplete" };
|
|
1179
|
+
|
|
1154
1180
|
export class WorkflowGateBrokerError extends Error {
|
|
1155
1181
|
constructor(
|
|
1156
|
-
readonly code:
|
|
1182
|
+
readonly code:
|
|
1183
|
+
| "unknown_gate"
|
|
1184
|
+
| "already_resolved"
|
|
1185
|
+
| "idempotency_conflict"
|
|
1186
|
+
| "invalid_workflow_stage"
|
|
1187
|
+
| "invalid_runtime_turn",
|
|
1157
1188
|
message: string,
|
|
1158
1189
|
) {
|
|
1159
1190
|
super(message);
|
|
@@ -1212,6 +1243,27 @@ export class WorkflowGateBroker {
|
|
|
1212
1243
|
this.store.put({ ...record, ackPolicy });
|
|
1213
1244
|
}
|
|
1214
1245
|
|
|
1246
|
+
lookupCompletedResolution(response: WorkflowGateResponse): WorkflowGateCompletedResolutionLookup {
|
|
1247
|
+
const record = this.store.get(response.gate_id);
|
|
1248
|
+
if (!record) return { kind: "none" };
|
|
1249
|
+
const responseHash = answerHashOf({ gate_id: response.gate_id, answer: response.answer });
|
|
1250
|
+
if (record.status !== "accepted" && record.status !== "quarantined") return { kind: "none" };
|
|
1251
|
+
if (record.responseHash === undefined) return { kind: "none" };
|
|
1252
|
+
const sameBody = record.responseHash === responseHash;
|
|
1253
|
+
const sameKey = record.idempotencyKey === response.idempotency_key;
|
|
1254
|
+
if (response.idempotency_key !== undefined && sameKey && !sameBody)
|
|
1255
|
+
throw new WorkflowGateBrokerError(
|
|
1256
|
+
"idempotency_conflict",
|
|
1257
|
+
`idempotency_conflict: gate ${response.gate_id} resolved with a different body`,
|
|
1258
|
+
);
|
|
1259
|
+
if (response.idempotency_key !== undefined && sameKey && sameBody) {
|
|
1260
|
+
if (record.terminalized === true && record.advanced === true && record.resolution)
|
|
1261
|
+
return { kind: "completed", resolution: record.resolution };
|
|
1262
|
+
return { kind: "accepted_incomplete" };
|
|
1263
|
+
}
|
|
1264
|
+
throw new WorkflowGateBrokerError("already_resolved", `already_resolved: gate ${response.gate_id}`);
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1215
1267
|
async #terminalize(record: PersistedGate): Promise<void> {
|
|
1216
1268
|
const proof = this.#terminalProofs.get(record.gate.gate_id) ?? (await this.hooks.terminalizeAccepted?.(record));
|
|
1217
1269
|
this.#terminalProofs.delete(record.gate.gate_id);
|
|
@@ -1350,12 +1402,14 @@ export class WorkflowGateBroker {
|
|
|
1350
1402
|
|
|
1351
1403
|
/** Open and emit a gate. The pending record is persisted BEFORE emission. */
|
|
1352
1404
|
openGate(input: OpenGateInput, continuation?: GateContinuation): WorkflowGate {
|
|
1353
|
-
if (RESERVED_WORKFLOW_STAGES.includes(input.stage) || !
|
|
1405
|
+
if (RESERVED_WORKFLOW_STAGES.includes(input.stage) || !WORKFLOW_GATE_V1_STAGES.includes(input.stage)) {
|
|
1354
1406
|
throw new WorkflowGateBrokerError(
|
|
1355
1407
|
"invalid_workflow_stage",
|
|
1356
1408
|
`stage "${input.stage}" is not a v1 workflow stage`,
|
|
1357
1409
|
);
|
|
1358
1410
|
}
|
|
1411
|
+
if (input.runtimeTurnId !== undefined && !isNonEmptyString(input.runtimeTurnId))
|
|
1412
|
+
throw new WorkflowGateBrokerError("invalid_runtime_turn", "runtime turn id must be a nonempty string");
|
|
1359
1413
|
// Asserts schema shape (throws WorkflowGateSchemaError on unsupported keywords).
|
|
1360
1414
|
compileGateSchema(input.schema);
|
|
1361
1415
|
const seq = this.store.nextSeq(input.stage).toString().padStart(6, "0");
|
|
@@ -1371,6 +1425,7 @@ export class WorkflowGateBroker {
|
|
|
1371
1425
|
context: input.context ?? {},
|
|
1372
1426
|
created_at: new Date().toISOString(),
|
|
1373
1427
|
required: true,
|
|
1428
|
+
...(input.runtimeTurnId === undefined ? {} : { runtime_turn_id: input.runtimeTurnId }),
|
|
1374
1429
|
};
|
|
1375
1430
|
if (!continuation) {
|
|
1376
1431
|
this.store.put({
|
|
@@ -3,11 +3,186 @@
|
|
|
3
3
|
/** Lifecycle stages that emit machine-addressable SDK workflow gates. */
|
|
4
4
|
export type WorkflowStage = "deep-interview" | "ralplan" | "ultragoal";
|
|
5
5
|
|
|
6
|
+
/** Lifecycle stages included in the v1 workflow-gate contract. */
|
|
7
|
+
export const WORKFLOW_GATE_V1_STAGES: readonly WorkflowStage[] = ["deep-interview", "ralplan", "ultragoal"];
|
|
8
|
+
|
|
6
9
|
/** Reserved stage names that are explicitly not part of the v1 contract. */
|
|
7
10
|
export const RESERVED_WORKFLOW_STAGES: readonly string[] = ["team"];
|
|
8
11
|
|
|
9
12
|
export type WorkflowGateKind = "question" | "approval" | "execution";
|
|
10
13
|
|
|
14
|
+
/** "Other (type your own)" sentinel, mirroring the interactive ask tool. */
|
|
15
|
+
export const GATE_OTHER_OPTION = "Other (type your own)";
|
|
16
|
+
|
|
17
|
+
export interface AskGateDeepInterviewState {
|
|
18
|
+
round_id?: string;
|
|
19
|
+
round: number;
|
|
20
|
+
component: string;
|
|
21
|
+
dimension: string;
|
|
22
|
+
ambiguity: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface AskGateStageStateInput {
|
|
26
|
+
id: string;
|
|
27
|
+
multi?: boolean;
|
|
28
|
+
allowEmpty?: boolean;
|
|
29
|
+
navigationLabel?: "Next" | "Done";
|
|
30
|
+
deepInterview?: AskGateDeepInterviewState;
|
|
31
|
+
fallbackState?: Record<string, unknown>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface AskGateSchemaInput {
|
|
35
|
+
multi?: boolean;
|
|
36
|
+
allowEmpty?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isBoundedAskGateString(value: unknown): value is string {
|
|
40
|
+
return typeof value === "string" && value.length > 0 && new TextEncoder().encode(value).byteLength <= 256;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Rejects stage state that is not exactly compatible with the generic ask-gate producer. */
|
|
44
|
+
export function validateAskGateStageState(value: unknown): asserts value is Record<string, unknown> {
|
|
45
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
46
|
+
throw new Error("ask gate stage_state must be an object");
|
|
47
|
+
const state = value as Record<string, unknown>;
|
|
48
|
+
const allowed = new Set([
|
|
49
|
+
"question_id",
|
|
50
|
+
"multi",
|
|
51
|
+
"allow_empty",
|
|
52
|
+
"options",
|
|
53
|
+
"other_option",
|
|
54
|
+
"clarification_action",
|
|
55
|
+
"navigation_label",
|
|
56
|
+
"deep_interview_metadata",
|
|
57
|
+
"round",
|
|
58
|
+
"round_id",
|
|
59
|
+
"component",
|
|
60
|
+
"dimension",
|
|
61
|
+
"mode",
|
|
62
|
+
"challenge_mode",
|
|
63
|
+
"ambiguity",
|
|
64
|
+
"topology_gate",
|
|
65
|
+
]);
|
|
66
|
+
if (Object.keys(state).some(key => !allowed.has(key))) throw new Error("ask gate stage_state has an unknown field");
|
|
67
|
+
if (
|
|
68
|
+
!isBoundedAskGateString(state.question_id) ||
|
|
69
|
+
typeof state.multi !== "boolean" ||
|
|
70
|
+
typeof state.allow_empty !== "boolean" ||
|
|
71
|
+
!Array.isArray(state.options) ||
|
|
72
|
+
state.options.some(option => !isBoundedAskGateString(option)) ||
|
|
73
|
+
state.other_option !== GATE_OTHER_OPTION ||
|
|
74
|
+
state.clarification_action !== "clarify"
|
|
75
|
+
)
|
|
76
|
+
throw new Error("ask gate stage_state has invalid required fields");
|
|
77
|
+
if (state.navigation_label !== undefined && state.navigation_label !== "Next" && state.navigation_label !== "Done")
|
|
78
|
+
throw new Error("ask gate stage_state has an invalid navigation label");
|
|
79
|
+
for (const key of ["round_id", "component", "dimension", "mode", "challenge_mode"])
|
|
80
|
+
if (state[key] !== undefined && !isBoundedAskGateString(state[key]))
|
|
81
|
+
throw new Error(`ask gate stage_state has an invalid ${key}`);
|
|
82
|
+
if (state.deep_interview_metadata !== undefined && typeof state.deep_interview_metadata !== "boolean")
|
|
83
|
+
throw new Error("ask gate stage_state has invalid deep interview metadata");
|
|
84
|
+
if (state.round !== undefined && (!Number.isSafeInteger(state.round) || (state.round as number) < 0))
|
|
85
|
+
throw new Error("ask gate stage_state has an invalid round");
|
|
86
|
+
if (
|
|
87
|
+
state.ambiguity !== undefined &&
|
|
88
|
+
(typeof state.ambiguity !== "number" ||
|
|
89
|
+
!Number.isFinite(state.ambiguity) ||
|
|
90
|
+
state.ambiguity < 0 ||
|
|
91
|
+
state.ambiguity > 1)
|
|
92
|
+
)
|
|
93
|
+
throw new Error("ask gate stage_state has an invalid ambiguity");
|
|
94
|
+
if (state.topology_gate !== undefined && typeof state.topology_gate !== "boolean")
|
|
95
|
+
throw new Error("ask gate stage_state has an invalid topology flag");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Builds the canonical generic ask answer schema. */
|
|
99
|
+
export function buildAskGateAnswerSchema(question: AskGateSchemaInput, labels: string[]): JsonSchema {
|
|
100
|
+
const multi = question.multi ?? false;
|
|
101
|
+
const selectedItems: JsonSchema = { type: "string", enum: labels };
|
|
102
|
+
const selectedBase: JsonSchema = { type: "array", items: selectedItems, uniqueItems: true };
|
|
103
|
+
const selectedOnly: JsonSchema = {
|
|
104
|
+
...selectedBase,
|
|
105
|
+
minItems: question.allowEmpty ? 0 : 1,
|
|
106
|
+
...(multi ? {} : { maxItems: 1 }),
|
|
107
|
+
};
|
|
108
|
+
const selectedWithOther: JsonSchema = { ...selectedBase, ...(multi ? {} : { maxItems: 0 }) };
|
|
109
|
+
return {
|
|
110
|
+
type: "object",
|
|
111
|
+
properties: {
|
|
112
|
+
selected: selectedBase,
|
|
113
|
+
other: { type: "boolean", description: "set true to provide a free-text answer in `custom`" },
|
|
114
|
+
custom: {
|
|
115
|
+
type: "string",
|
|
116
|
+
minLength: 1,
|
|
117
|
+
pattern: "\\S",
|
|
118
|
+
description: "free-text answer; required when `other` is true",
|
|
119
|
+
},
|
|
120
|
+
action: {
|
|
121
|
+
type: "string",
|
|
122
|
+
enum: ["answer", "clarify"],
|
|
123
|
+
description: "set to `clarify` to ask about the choices without answering the round",
|
|
124
|
+
},
|
|
125
|
+
question: {
|
|
126
|
+
type: "string",
|
|
127
|
+
minLength: 1,
|
|
128
|
+
pattern: "\\S",
|
|
129
|
+
description: "clarification question; required when action is `clarify`",
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
additionalProperties: false,
|
|
133
|
+
anyOf: [
|
|
134
|
+
{
|
|
135
|
+
type: "object",
|
|
136
|
+
properties: { selected: selectedOnly, other: { const: false }, action: { const: "answer" } },
|
|
137
|
+
required: ["selected"],
|
|
138
|
+
additionalProperties: false,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
type: "object",
|
|
142
|
+
properties: {
|
|
143
|
+
selected: selectedWithOther,
|
|
144
|
+
other: { const: true },
|
|
145
|
+
custom: { type: "string", minLength: 1, pattern: "\\S" },
|
|
146
|
+
action: { const: "answer" },
|
|
147
|
+
},
|
|
148
|
+
required: ["selected", "other", "custom"],
|
|
149
|
+
additionalProperties: false,
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
type: "object",
|
|
153
|
+
properties: { action: { const: "clarify" }, question: { type: "string", minLength: 1, pattern: "\\S" } },
|
|
154
|
+
required: ["action", "question"],
|
|
155
|
+
additionalProperties: false,
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Builds and validates exact generic ask stage-state metadata. */
|
|
162
|
+
export function buildAskGateStageState(input: AskGateStageStateInput, labels: string[]): Record<string, unknown> {
|
|
163
|
+
const state: Record<string, unknown> = {
|
|
164
|
+
question_id: input.id,
|
|
165
|
+
multi: input.multi ?? false,
|
|
166
|
+
options: labels,
|
|
167
|
+
other_option: GATE_OTHER_OPTION,
|
|
168
|
+
clarification_action: "clarify",
|
|
169
|
+
allow_empty: input.allowEmpty === true,
|
|
170
|
+
...(input.navigationLabel === undefined ? {} : { navigation_label: input.navigationLabel }),
|
|
171
|
+
...(input.deepInterview
|
|
172
|
+
? {
|
|
173
|
+
deep_interview_metadata: true,
|
|
174
|
+
round: input.deepInterview.round,
|
|
175
|
+
component: input.deepInterview.component,
|
|
176
|
+
dimension: input.deepInterview.dimension,
|
|
177
|
+
ambiguity: input.deepInterview.ambiguity,
|
|
178
|
+
...(input.deepInterview.round_id === undefined ? {} : { round_id: input.deepInterview.round_id }),
|
|
179
|
+
}
|
|
180
|
+
: (input.fallbackState ?? {})),
|
|
181
|
+
};
|
|
182
|
+
validateAskGateStageState(state);
|
|
183
|
+
return state;
|
|
184
|
+
}
|
|
185
|
+
|
|
11
186
|
/** The documented JSON Schema 2020-12 subset supported by the gate validator. */
|
|
12
187
|
export interface JsonSchema {
|
|
13
188
|
type?: "string" | "number" | "integer" | "boolean" | "object" | "array" | "null";
|
|
@@ -60,6 +235,8 @@ export interface WorkflowGate {
|
|
|
60
235
|
context: WorkflowGateContext;
|
|
61
236
|
created_at: string;
|
|
62
237
|
required: true;
|
|
238
|
+
/** Immutable runtime turn correlation captured before durable gate visibility. */
|
|
239
|
+
runtime_turn_id?: string;
|
|
63
240
|
}
|
|
64
241
|
|
|
65
242
|
/** Non-actionable durable-gate state retained for restart diagnostics. */
|