@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
package/src/main.ts
CHANGED
|
@@ -23,6 +23,7 @@ import chalk from "chalk";
|
|
|
23
23
|
import type { Args } from "./cli/args";
|
|
24
24
|
import { processFileArguments } from "./cli/file-processor";
|
|
25
25
|
import { buildInitialMessage } from "./cli/initial-message";
|
|
26
|
+
import { resolveLaunchDisposition } from "./cli/launch-disposition";
|
|
26
27
|
import { runListModelsCommand } from "./cli/list-models";
|
|
27
28
|
import { selectSession } from "./cli/session-picker";
|
|
28
29
|
import { findConfigFile } from "./config";
|
|
@@ -57,6 +58,7 @@ import type { AgentSession } from "./session/agent-session";
|
|
|
57
58
|
import {
|
|
58
59
|
type ResumeSessionIdentity,
|
|
59
60
|
resolveResumableSession,
|
|
61
|
+
type SessionDirectoryMigrationPolicy,
|
|
60
62
|
type SessionInfo,
|
|
61
63
|
SessionManager,
|
|
62
64
|
type StrictSessionOpenResult,
|
|
@@ -281,7 +283,7 @@ export function resolveAcpStartupOptions(
|
|
|
281
283
|
}
|
|
282
284
|
|
|
283
285
|
async function readPipedInput(): Promise<string | undefined> {
|
|
284
|
-
if (process.stdin.isTTY
|
|
286
|
+
if (process.stdin.isTTY === true) return undefined;
|
|
285
287
|
try {
|
|
286
288
|
const text = await Bun.stdin.text();
|
|
287
289
|
if (text.trim().length === 0) return undefined;
|
|
@@ -291,6 +293,30 @@ async function readPipedInput(): Promise<string | undefined> {
|
|
|
291
293
|
}
|
|
292
294
|
}
|
|
293
295
|
|
|
296
|
+
async function readPipedInputIfReady(): Promise<string | undefined> {
|
|
297
|
+
if (process.stdin.isTTY === true) return undefined;
|
|
298
|
+
|
|
299
|
+
const ready = Promise.withResolvers<void>();
|
|
300
|
+
const onReadable = () => ready.resolve();
|
|
301
|
+
const onEnd = () => ready.resolve();
|
|
302
|
+
const onError = () => ready.resolve();
|
|
303
|
+
process.stdin.once("readable", onReadable);
|
|
304
|
+
process.stdin.once("end", onEnd);
|
|
305
|
+
process.stdin.once("error", onError);
|
|
306
|
+
await Promise.race([ready.promise, new Promise<void>(resolve => setImmediate(resolve))]);
|
|
307
|
+
process.stdin.removeListener("readable", onReadable);
|
|
308
|
+
process.stdin.removeListener("end", onEnd);
|
|
309
|
+
process.stdin.removeListener("error", onError);
|
|
310
|
+
|
|
311
|
+
const chunks: Buffer[] = [];
|
|
312
|
+
for (let chunk = process.stdin.read(); chunk !== null; chunk = process.stdin.read()) {
|
|
313
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
314
|
+
}
|
|
315
|
+
if (chunks.length === 0) return undefined;
|
|
316
|
+
const text = Buffer.concat(chunks).toString("utf8");
|
|
317
|
+
return text.trim() ? text : undefined;
|
|
318
|
+
}
|
|
319
|
+
|
|
294
320
|
export interface InteractiveModeNotify {
|
|
295
321
|
kind: "warn" | "error" | "info";
|
|
296
322
|
message: string;
|
|
@@ -510,6 +536,7 @@ type SelectResumeSession = (sessions: SessionInfo[]) => Promise<SessionSelection
|
|
|
510
536
|
type OpenExistingSessionStrict = (
|
|
511
537
|
identity: ResumeSessionIdentity,
|
|
512
538
|
sessionDir?: string,
|
|
539
|
+
migrationPolicy?: SessionDirectoryMigrationPolicy,
|
|
513
540
|
) => Promise<StrictSessionOpenResult>;
|
|
514
541
|
|
|
515
542
|
export const BARE_RESUME_CONFLICT_ERROR =
|
|
@@ -694,6 +721,7 @@ export async function createSessionManager(
|
|
|
694
721
|
cwd: string,
|
|
695
722
|
activeSettings: Settings = settings,
|
|
696
723
|
): Promise<SessionManager | undefined> {
|
|
724
|
+
const migrationPolicy = activeSettings.get("session.directoryMigration") === "disabled" ? "disabled" : "copy-retain";
|
|
697
725
|
if (parsed.resume === true) {
|
|
698
726
|
return undefined;
|
|
699
727
|
}
|
|
@@ -703,13 +731,13 @@ export async function createSessionManager(
|
|
|
703
731
|
}
|
|
704
732
|
const forkSource = parsed.fork;
|
|
705
733
|
if (forkSource.includes("/") || forkSource.includes("\\") || forkSource.endsWith(".jsonl")) {
|
|
706
|
-
return await SessionManager.forkFrom(forkSource, cwd, parsed.sessionDir);
|
|
734
|
+
return await SessionManager.forkFrom(forkSource, cwd, parsed.sessionDir, undefined, migrationPolicy);
|
|
707
735
|
}
|
|
708
736
|
const match = await resolveResumableSession(forkSource, cwd, parsed.sessionDir);
|
|
709
737
|
if (!match) {
|
|
710
738
|
throw new Error(`Session "${forkSource}" not found.`);
|
|
711
739
|
}
|
|
712
|
-
return await SessionManager.forkFrom(match.session.path, cwd, parsed.sessionDir);
|
|
740
|
+
return await SessionManager.forkFrom(match.session.path, cwd, parsed.sessionDir, undefined, migrationPolicy);
|
|
713
741
|
}
|
|
714
742
|
|
|
715
743
|
if (parsed.noSession) {
|
|
@@ -718,7 +746,7 @@ export async function createSessionManager(
|
|
|
718
746
|
if (typeof parsed.resume === "string") {
|
|
719
747
|
const sessionArg = parsed.resume;
|
|
720
748
|
if (sessionArg.includes("/") || sessionArg.includes("\\") || sessionArg.endsWith(".jsonl")) {
|
|
721
|
-
return await SessionManager.open(sessionArg, parsed.sessionDir);
|
|
749
|
+
return await SessionManager.open(sessionArg, parsed.sessionDir, undefined, migrationPolicy);
|
|
722
750
|
}
|
|
723
751
|
const match = await resolveResumableSession(sessionArg, cwd, parsed.sessionDir);
|
|
724
752
|
if (!match) {
|
|
@@ -732,13 +760,19 @@ export async function createSessionManager(
|
|
|
732
760
|
if (!shouldFork) {
|
|
733
761
|
throw new Error(`Session "${sessionArg}" is in another project (${match.session.cwd}).`);
|
|
734
762
|
}
|
|
735
|
-
return await SessionManager.forkFrom(
|
|
763
|
+
return await SessionManager.forkFrom(
|
|
764
|
+
match.session.path,
|
|
765
|
+
cwd,
|
|
766
|
+
parsed.sessionDir,
|
|
767
|
+
undefined,
|
|
768
|
+
migrationPolicy,
|
|
769
|
+
);
|
|
736
770
|
}
|
|
737
771
|
}
|
|
738
|
-
return await SessionManager.open(match.session.path, parsed.sessionDir);
|
|
772
|
+
return await SessionManager.open(match.session.path, parsed.sessionDir, undefined, migrationPolicy);
|
|
739
773
|
}
|
|
740
774
|
if (parsed.continue) {
|
|
741
|
-
return await SessionManager.continueRecent(cwd, parsed.sessionDir);
|
|
775
|
+
return await SessionManager.continueRecent(cwd, parsed.sessionDir, undefined, migrationPolicy);
|
|
742
776
|
}
|
|
743
777
|
// --resume without value is handled separately (needs picker UI)
|
|
744
778
|
// If --session-dir provided without --continue/--resume, create new session there
|
|
@@ -761,7 +795,7 @@ export async function createSessionManager(
|
|
|
761
795
|
// buildSessionOptions restores the session's model/thinking instead of
|
|
762
796
|
// overriding them with CLI defaults.
|
|
763
797
|
if (activeSettings.get("autoResume")) {
|
|
764
|
-
const manager = await SessionManager.continueRecent(cwd, parsed.sessionDir);
|
|
798
|
+
const manager = await SessionManager.continueRecent(cwd, parsed.sessionDir, undefined, migrationPolicy);
|
|
765
799
|
if (manager.getEntries().length > 0) {
|
|
766
800
|
parsed.continue = true;
|
|
767
801
|
}
|
|
@@ -1005,6 +1039,7 @@ export interface RunRootCommandDependencies {
|
|
|
1005
1039
|
startupUpdate?: { check: () => Promise<string | undefined> };
|
|
1006
1040
|
initTheme?: typeof initTheme;
|
|
1007
1041
|
readPipedInput?: typeof readPipedInput;
|
|
1042
|
+
stdinIsTTY?: boolean;
|
|
1008
1043
|
runStartupCredentialAutoImportIfNeeded?: typeof runStartupCredentialAutoImportIfNeeded;
|
|
1009
1044
|
getChangelogForDisplay?: typeof getChangelogForDisplay;
|
|
1010
1045
|
createInteractiveMode?: CreateInteractiveMode;
|
|
@@ -1014,6 +1049,7 @@ export interface RunRootCommandDependencies {
|
|
|
1014
1049
|
selectResumeSession?: SelectResumeSession;
|
|
1015
1050
|
openExistingSessionStrict?: OpenExistingSessionStrict;
|
|
1016
1051
|
initializeSettings?: typeof Settings.init;
|
|
1052
|
+
loadSettingsForScope?: typeof Settings.loadForScope;
|
|
1017
1053
|
}
|
|
1018
1054
|
|
|
1019
1055
|
export async function runRootCommand(
|
|
@@ -1054,15 +1090,25 @@ export async function runRootCommand(
|
|
|
1054
1090
|
process.stdout.write(`${chalk.dim("No sessions found")}\n`);
|
|
1055
1091
|
return;
|
|
1056
1092
|
}
|
|
1057
|
-
const selection =
|
|
1093
|
+
const selection = deps.selectResumeSession
|
|
1094
|
+
? await deps.selectResumeSession(sessions)
|
|
1095
|
+
: await selectSession(sessions, parsedArgs.sessionDir);
|
|
1058
1096
|
if (selection.kind === "cancelled") {
|
|
1059
1097
|
return;
|
|
1060
1098
|
}
|
|
1099
|
+
const resumeMigrationPolicy =
|
|
1100
|
+
(await (deps.loadSettingsForScope ?? Settings.loadForScope)({ cwd: resumeCwd })).get(
|
|
1101
|
+
"session.directoryMigration",
|
|
1102
|
+
) === "disabled"
|
|
1103
|
+
? "disabled"
|
|
1104
|
+
: "copy-retain";
|
|
1061
1105
|
let opened: StrictSessionOpenResult;
|
|
1062
1106
|
try {
|
|
1063
1107
|
opened = await (deps.openExistingSessionStrict ?? SessionManager.openExistingStrict)(
|
|
1064
1108
|
selection.identity,
|
|
1065
1109
|
parsedArgs.sessionDir,
|
|
1110
|
+
undefined,
|
|
1111
|
+
resumeMigrationPolicy,
|
|
1066
1112
|
);
|
|
1067
1113
|
} catch {
|
|
1068
1114
|
process.stderr.write(`${BARE_RESUME_OPEN_ERROR}\n`);
|
|
@@ -1144,8 +1190,16 @@ export async function runRootCommand(
|
|
|
1144
1190
|
if (parsedArgs.noTitle || parsedArgs.mode === "acp") {
|
|
1145
1191
|
Bun.env.PI_NO_TITLE = "1";
|
|
1146
1192
|
}
|
|
1193
|
+
const hasPreparedInput = parsedArgs.messages.length > 0 || parsedArgs.fileArgs.length > 0;
|
|
1147
1194
|
const { pipedInput, fileText, fileImages } = await logger.time("prepareInitialMessage", async () => {
|
|
1148
|
-
const pipedInput =
|
|
1195
|
+
const pipedInput =
|
|
1196
|
+
parsedArgs.mode === "acp"
|
|
1197
|
+
? undefined
|
|
1198
|
+
: deps.readPipedInput
|
|
1199
|
+
? await deps.readPipedInput()
|
|
1200
|
+
: hasPreparedInput
|
|
1201
|
+
? await readPipedInputIfReady()
|
|
1202
|
+
: await readPipedInput();
|
|
1149
1203
|
if (parsedArgs.fileArgs.length === 0) {
|
|
1150
1204
|
return { pipedInput, fileText: undefined, fileImages: undefined };
|
|
1151
1205
|
}
|
|
@@ -1160,14 +1214,25 @@ export async function runRootCommand(
|
|
|
1160
1214
|
fileImages,
|
|
1161
1215
|
stdinContent: pipedInput,
|
|
1162
1216
|
});
|
|
1163
|
-
const
|
|
1217
|
+
const disposition = resolveLaunchDisposition({
|
|
1218
|
+
stdinIsTTY: deps.stdinIsTTY ?? process.stdin.isTTY,
|
|
1219
|
+
pipedInput,
|
|
1220
|
+
hasPreparedInput,
|
|
1221
|
+
print: Boolean(parsedArgs.print),
|
|
1222
|
+
mode: parsedArgs.mode,
|
|
1223
|
+
});
|
|
1224
|
+
if (disposition.nonInteractiveError) {
|
|
1225
|
+
process.stderr.write(`${chalk.red(disposition.nonInteractiveError)}\n`);
|
|
1226
|
+
process.exit(1);
|
|
1227
|
+
}
|
|
1228
|
+
const autoPrint = disposition.autoPrint;
|
|
1164
1229
|
const startupUpdateRoute = classifyStartupUpdateRoute(parsedArgs, autoPrint);
|
|
1165
1230
|
const startupUpdate = new StartupUpdateOrchestrator(
|
|
1166
1231
|
startupUpdateRoute,
|
|
1167
1232
|
() => settingsInstance.get("startup.checkUpdate"),
|
|
1168
1233
|
deps.startupUpdate?.check ?? (() => checkForNewVersion(VERSION)),
|
|
1169
1234
|
);
|
|
1170
|
-
const isInteractive =
|
|
1235
|
+
const isInteractive = disposition.isInteractive;
|
|
1171
1236
|
const mode = parsedArgs.mode || "text";
|
|
1172
1237
|
|
|
1173
1238
|
// Initialize discovery system with settings for provider persistence
|
|
@@ -1299,6 +1364,7 @@ export async function runRootCommand(
|
|
|
1299
1364
|
sessionOptions.modelRegistry = modelRegistry;
|
|
1300
1365
|
sessionOptions.hasUI = isInteractive;
|
|
1301
1366
|
sessionOptions.notificationHostModeSupported = isInteractive;
|
|
1367
|
+
sessionOptions.sdkHostModeSupported = isInteractive;
|
|
1302
1368
|
sessionOptions.settings = settingsInstance;
|
|
1303
1369
|
const hasRootStartupProfile = Boolean(settingsInstance.get("modelProfile.default") || parsedArgs.mpreset);
|
|
1304
1370
|
|
|
@@ -1331,6 +1397,30 @@ export async function runRootCommand(
|
|
|
1331
1397
|
applyCliRuntimeApiKeyOverride(authStorage, parsedArgs.apiKey, sessionOptions.model);
|
|
1332
1398
|
}
|
|
1333
1399
|
|
|
1400
|
+
if (
|
|
1401
|
+
!deps.suppressProcessExit &&
|
|
1402
|
+
deps.createAgentSession === undefined &&
|
|
1403
|
+
parsedArgs.noSession === true &&
|
|
1404
|
+
!parsedArgs.continue &&
|
|
1405
|
+
parsedArgs.resume === undefined &&
|
|
1406
|
+
parsedArgs.fork === undefined &&
|
|
1407
|
+
!isInteractive &&
|
|
1408
|
+
mode !== "acp" &&
|
|
1409
|
+
!hasRootStartupProfile &&
|
|
1410
|
+
!sessionOptions.model &&
|
|
1411
|
+
!sessionOptions.modelPattern &&
|
|
1412
|
+
modelRegistry.getAvailable().length === 0
|
|
1413
|
+
) {
|
|
1414
|
+
process.stderr.write(`${chalk.red(`No models available. ${formatModelOnboardingGuidance()}`)}\n`);
|
|
1415
|
+
process.stderr.write(
|
|
1416
|
+
`${chalk.yellow(`\nAdvanced manual config remains available at ${ModelsConfigFile.path()}`)}\n`,
|
|
1417
|
+
);
|
|
1418
|
+
process.exitCode = 1;
|
|
1419
|
+
authStorage.close();
|
|
1420
|
+
stopThemeWatcher();
|
|
1421
|
+
await postmortem.cleanup();
|
|
1422
|
+
return;
|
|
1423
|
+
}
|
|
1334
1424
|
const createAgentSessionImpl = deps.createAgentSession ?? createAgentSession;
|
|
1335
1425
|
const createSession: CreateSessionForMain = async (options, context): Promise<CreateAgentSessionResult> => {
|
|
1336
1426
|
const result = await logger.time("createAgentSession", createAgentSessionImpl, options);
|
|
@@ -1345,10 +1435,16 @@ export async function runRootCommand(
|
|
|
1345
1435
|
};
|
|
1346
1436
|
|
|
1347
1437
|
if (mode === "acp") {
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1438
|
+
try {
|
|
1439
|
+
await (deps.runAcpMode ?? (await import("./modes/acp")).runAcpMode)({
|
|
1440
|
+
agentDir: settingsInstance.getAgentDir(),
|
|
1441
|
+
...(acpStartupOptions ? { startupOptions: acpStartupOptions } : {}),
|
|
1442
|
+
});
|
|
1443
|
+
} finally {
|
|
1444
|
+
authStorage.close();
|
|
1445
|
+
stopThemeWatcher();
|
|
1446
|
+
if (!deps.suppressProcessExit) await postmortem.cleanup();
|
|
1447
|
+
}
|
|
1352
1448
|
} else {
|
|
1353
1449
|
const { session, setToolUIContext, modelFallbackMessage, lspServers, mcpManager, eventBus } = await createSession(
|
|
1354
1450
|
sessionOptions,
|
|
@@ -1483,20 +1579,21 @@ export async function runRootCommand(
|
|
|
1483
1579
|
}
|
|
1484
1580
|
} else {
|
|
1485
1581
|
const runPrint = deps.runPrintMode ?? (await import("./modes/print-mode")).runPrintMode;
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1582
|
+
try {
|
|
1583
|
+
await runPrint(session, {
|
|
1584
|
+
mode,
|
|
1585
|
+
messages: parsedArgs.messages,
|
|
1586
|
+
initialMessage,
|
|
1587
|
+
initialImages,
|
|
1588
|
+
suppressProcessExit: deps.suppressProcessExit,
|
|
1589
|
+
});
|
|
1590
|
+
if ($env.PI_TIMING) {
|
|
1591
|
+
logger.printTimings();
|
|
1592
|
+
}
|
|
1593
|
+
} finally {
|
|
1594
|
+
stopThemeWatcher();
|
|
1595
|
+
authStorage.close();
|
|
1596
|
+
if (!deps.suppressProcessExit) await postmortem.cleanup();
|
|
1500
1597
|
}
|
|
1501
1598
|
}
|
|
1502
1599
|
}
|
package/src/memories/index.ts
CHANGED
|
@@ -249,6 +249,7 @@ async function runPhase1(options: {
|
|
|
249
249
|
|
|
250
250
|
const claims = claimStage1Jobs(db, {
|
|
251
251
|
nowSec,
|
|
252
|
+
cwd: session.sessionManager.getCwd(),
|
|
252
253
|
threadScanLimit: config.threadScanLimit,
|
|
253
254
|
maxRolloutsPerStartup: config.maxRolloutsPerStartup,
|
|
254
255
|
maxRolloutAgeDays: config.maxRolloutAgeDays,
|
package/src/memories/storage.ts
CHANGED
|
@@ -137,6 +137,7 @@ export function claimStage1Jobs(
|
|
|
137
137
|
db: Database,
|
|
138
138
|
params: {
|
|
139
139
|
nowSec: number;
|
|
140
|
+
cwd: string;
|
|
140
141
|
threadScanLimit: number;
|
|
141
142
|
maxRolloutsPerStartup: number;
|
|
142
143
|
maxRolloutAgeDays: number;
|
|
@@ -149,6 +150,7 @@ export function claimStage1Jobs(
|
|
|
149
150
|
): Stage1Claim[] {
|
|
150
151
|
const {
|
|
151
152
|
nowSec,
|
|
153
|
+
cwd,
|
|
152
154
|
threadScanLimit,
|
|
153
155
|
maxRolloutsPerStartup,
|
|
154
156
|
maxRolloutAgeDays,
|
|
@@ -168,8 +170,10 @@ export function claimStage1Jobs(
|
|
|
168
170
|
let runningCount = runningCountRow?.count ?? 0;
|
|
169
171
|
if (runningCount >= runningConcurrencyCap) return [];
|
|
170
172
|
const candidateRows = db
|
|
171
|
-
.prepare(
|
|
172
|
-
|
|
173
|
+
.prepare(
|
|
174
|
+
"SELECT id, updated_at, rollout_path, cwd, source_kind FROM threads WHERE cwd = ? ORDER BY updated_at DESC LIMIT ?",
|
|
175
|
+
)
|
|
176
|
+
.all(cwd, threadScanLimit) as Array<{
|
|
173
177
|
id: string;
|
|
174
178
|
updated_at: number;
|
|
175
179
|
rollout_path: string;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import type { AppKeybinding } from "../config/keybindings";
|
|
2
|
+
|
|
3
|
+
export type FocusDomain = "composer" | "selector" | "overlay" | "global";
|
|
4
|
+
|
|
5
|
+
export interface ActionMetadata {
|
|
6
|
+
id: AppKeybinding;
|
|
7
|
+
title: string;
|
|
8
|
+
category: string;
|
|
9
|
+
bindingId?: AppKeybinding;
|
|
10
|
+
domains: readonly FocusDomain[];
|
|
11
|
+
exclusiveGroup?: string | false;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const action = (
|
|
15
|
+
id: AppKeybinding,
|
|
16
|
+
title: string,
|
|
17
|
+
category: string,
|
|
18
|
+
domains: FocusDomain[],
|
|
19
|
+
exclusiveGroup?: string | false,
|
|
20
|
+
): ActionMetadata => ({
|
|
21
|
+
id,
|
|
22
|
+
title,
|
|
23
|
+
category,
|
|
24
|
+
bindingId: id,
|
|
25
|
+
domains,
|
|
26
|
+
exclusiveGroup,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
export const APP_ACTION_METADATA: readonly ActionMetadata[] = [
|
|
30
|
+
action("app.interrupt", "Interrupt", "Session", ["global"], false),
|
|
31
|
+
action("app.clear", "Clear", "Session", ["global"]),
|
|
32
|
+
action("app.exit", "Exit", "Session", ["global"]),
|
|
33
|
+
action("app.suspend", "Suspend", "Session", ["global"]),
|
|
34
|
+
action("app.thinking.cycle", "Cycle thinking level", "Thinking", ["composer"]),
|
|
35
|
+
action("app.thinking.toggle", "Toggle thinking", "Thinking", ["composer"]),
|
|
36
|
+
action("app.commandPalette.open", "Open command palette", "Navigation", ["composer"]),
|
|
37
|
+
action("app.model.cycleForward", "Next model", "Model", ["composer"]),
|
|
38
|
+
action("app.model.cycleBackward", "Previous model", "Model", ["composer"]),
|
|
39
|
+
action("app.model.select", "Select model", "Model", ["composer"]),
|
|
40
|
+
action("app.model.selectTemporary", "Select temporary model", "Model", ["composer"]),
|
|
41
|
+
action("app.tools.expand", "Toggle tool expansion", "Tools", ["composer"]),
|
|
42
|
+
action("app.tool.backgroundFold", "Fold foreground tool", "Tools", ["composer"]),
|
|
43
|
+
action("app.editor.external", "Open external editor", "Editor", ["composer"]),
|
|
44
|
+
action("app.message.followUp", "Send follow-up", "Messages", ["composer"]),
|
|
45
|
+
action("app.message.queue", "Queue message", "Messages", ["composer"]),
|
|
46
|
+
action("app.message.dequeue", "Edit queued message", "Messages", ["composer"]),
|
|
47
|
+
action("app.clipboard.pasteImage", "Paste image", "Clipboard", ["composer"]),
|
|
48
|
+
action("app.clipboard.copyLine", "Copy line", "Clipboard", ["composer"]),
|
|
49
|
+
action("app.clipboard.copyPrompt", "Copy prompt", "Clipboard", ["composer"]),
|
|
50
|
+
action("app.session.new", "New session", "Session", ["composer"]),
|
|
51
|
+
action("app.session.tree", "Session tree", "Session", ["composer"]),
|
|
52
|
+
action("app.session.fork", "Fork session", "Session", ["composer"]),
|
|
53
|
+
action("app.session.resume", "Resume session", "Session", ["composer"]),
|
|
54
|
+
action("app.session.observe", "Observe sessions", "Session", ["composer"]),
|
|
55
|
+
action("app.session.dashboard", "Show sessions dashboard", "Session", ["composer"]),
|
|
56
|
+
action("app.jobs.open", "Open jobs", "Jobs", ["composer"]),
|
|
57
|
+
action("app.session.togglePath", "Toggle session path", "Session", ["selector"]),
|
|
58
|
+
action("app.session.toggleSort", "Toggle session sort", "Session", ["selector"]),
|
|
59
|
+
action("app.session.rename", "Rename session", "Session", ["selector"]),
|
|
60
|
+
action("app.session.delete", "Delete session", "Session", ["selector"]),
|
|
61
|
+
action("app.session.deleteNoninvasive", "Delete selected session", "Session", ["selector"]),
|
|
62
|
+
action("app.tree.foldOrUp", "Fold tree item", "Session", ["selector"]),
|
|
63
|
+
action("app.tree.unfoldOrDown", "Unfold tree item", "Session", ["selector"]),
|
|
64
|
+
action("app.plan.toggle", "Toggle plan mode", "Mode", ["composer"]),
|
|
65
|
+
action("app.history.search", "Search history", "Navigation", ["composer"]),
|
|
66
|
+
action("app.stt.toggle", "Toggle speech-to-text", "Speech", ["composer"]),
|
|
67
|
+
action("app.irc.sidebar.toggle", "Toggle IRC sidebar", "IRC", ["composer"]),
|
|
68
|
+
action("app.transcript.browse", "Browse transcript", "Transcript", ["composer"]),
|
|
69
|
+
action("app.transcript.prevTurn", "Previous transcript turn", "Transcript", ["composer"]),
|
|
70
|
+
action("app.transcript.nextTurn", "Next transcript turn", "Transcript", ["composer"]),
|
|
71
|
+
action("app.mode.cycle", "Cycle mode", "Mode", ["composer"]),
|
|
72
|
+
action("app.tasks.toggle", "Toggle tasks pane", "Jobs", ["composer"]),
|
|
73
|
+
action("app.queue.togglePane", "Toggle queue pane", "Messages", ["composer"]),
|
|
74
|
+
action("app.message.sendNow", "Send message now", "Messages", ["composer"]),
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
export interface ActionDefinition<Context> extends ActionMetadata {
|
|
78
|
+
availability(context: Context): boolean;
|
|
79
|
+
execute(context: Context): void | Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface ActionRegistryOptions<Context> {
|
|
83
|
+
context: Context;
|
|
84
|
+
showError(error: string): void;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export class ActionRegistry<Context> {
|
|
88
|
+
readonly #actions = new Map<AppKeybinding, ActionDefinition<Context>>();
|
|
89
|
+
readonly #busy = new Set<AppKeybinding>();
|
|
90
|
+
readonly #busyGroups = new Set<string>();
|
|
91
|
+
readonly #availability = new Map<AppKeybinding, boolean>();
|
|
92
|
+
#availabilityResetQueued = false;
|
|
93
|
+
|
|
94
|
+
constructor(private readonly options: ActionRegistryOptions<Context>) {}
|
|
95
|
+
|
|
96
|
+
register(action: ActionDefinition<Context>): void {
|
|
97
|
+
if (this.#actions.has(action.id)) throw new Error(`Action already registered: ${action.id}`);
|
|
98
|
+
this.#actions.set(action.id, action);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
get(id: AppKeybinding): ActionDefinition<Context> | undefined {
|
|
102
|
+
return this.#actions.get(id);
|
|
103
|
+
}
|
|
104
|
+
all(): readonly ActionDefinition<Context>[] {
|
|
105
|
+
return [...this.#actions.values()];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#reportError(id: AppKeybinding, phase: "availability" | "execution", error: unknown): void {
|
|
109
|
+
const cause = error instanceof Error ? error.message : String(error);
|
|
110
|
+
try {
|
|
111
|
+
this.options.showError(`Action ${id} ${phase} failed: ${cause}`);
|
|
112
|
+
} catch {
|
|
113
|
+
// Error reporting must not escape an action dispatch.
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
#evaluateAvailability(id: AppKeybinding, action: ActionDefinition<Context>): boolean {
|
|
118
|
+
const cached = this.#availability.get(id);
|
|
119
|
+
if (cached !== undefined) return cached;
|
|
120
|
+
let available: boolean;
|
|
121
|
+
try {
|
|
122
|
+
available = Boolean(action.availability(this.options.context));
|
|
123
|
+
} catch (error) {
|
|
124
|
+
this.#reportError(id, "availability", error);
|
|
125
|
+
available = false;
|
|
126
|
+
}
|
|
127
|
+
this.#availability.set(id, available);
|
|
128
|
+
if (!this.#availabilityResetQueued) {
|
|
129
|
+
this.#availabilityResetQueued = true;
|
|
130
|
+
queueMicrotask(() => {
|
|
131
|
+
this.#availability.clear();
|
|
132
|
+
this.#availabilityResetQueued = false;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return available;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
#exclusiveGroup(action: ActionDefinition<Context>): string | undefined {
|
|
139
|
+
return action.exclusiveGroup === false ? undefined : (action.exclusiveGroup ?? "default");
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
isAvailable(id: AppKeybinding): boolean {
|
|
143
|
+
const action = this.#actions.get(id);
|
|
144
|
+
return action ? this.#evaluateAvailability(id, action) : false;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async execute(id: AppKeybinding): Promise<boolean> {
|
|
148
|
+
const current = this.#actions.get(id);
|
|
149
|
+
if (!current || this.#busy.has(id) || !this.#evaluateAvailability(id, current)) return false;
|
|
150
|
+
const group = this.#exclusiveGroup(current);
|
|
151
|
+
if (group && this.#busyGroups.has(group)) return false;
|
|
152
|
+
this.#busy.add(id);
|
|
153
|
+
if (group) this.#busyGroups.add(group);
|
|
154
|
+
try {
|
|
155
|
+
await current.execute(this.options.context);
|
|
156
|
+
return true;
|
|
157
|
+
} catch (error) {
|
|
158
|
+
this.#reportError(id, "execution", error);
|
|
159
|
+
return false;
|
|
160
|
+
} finally {
|
|
161
|
+
this.#busy.delete(id);
|
|
162
|
+
if (group) this.#busyGroups.delete(group);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Container, type SelectItem, SelectList, Text } from "@gajae-code/tui";
|
|
2
|
+
import { getSelectListTheme, theme } from "../../modes/theme/theme";
|
|
3
|
+
import { DynamicBorder } from "./dynamic-border";
|
|
4
|
+
|
|
5
|
+
export interface FramedSelectOptions {
|
|
6
|
+
maxVisible?: number;
|
|
7
|
+
selectedValue?: string;
|
|
8
|
+
onSelect?: (item: SelectItem) => void;
|
|
9
|
+
onCancel?: () => void;
|
|
10
|
+
onSelectionChange?: (item: SelectItem) => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface FramedSelect {
|
|
14
|
+
container: Container;
|
|
15
|
+
selectList: SelectList;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Build the shared border/list selector chrome used by compact mode selectors. */
|
|
19
|
+
export function FramedSelect(
|
|
20
|
+
title: string | undefined,
|
|
21
|
+
items: ReadonlyArray<SelectItem>,
|
|
22
|
+
opts: FramedSelectOptions = {},
|
|
23
|
+
): FramedSelect {
|
|
24
|
+
const container = new Container();
|
|
25
|
+
container.addChild(new DynamicBorder());
|
|
26
|
+
if (title) {
|
|
27
|
+
container.addChild(new Text(theme.bold(theme.fg("accent", title)), 0, 0));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const selectList = new SelectList(items, opts.maxVisible ?? Math.min(items.length, 10), getSelectListTheme());
|
|
31
|
+
const selectedIndex =
|
|
32
|
+
opts.selectedValue === undefined ? -1 : items.findIndex(item => item.value === opts.selectedValue);
|
|
33
|
+
if (selectedIndex !== -1) selectList.setSelectedIndex(selectedIndex);
|
|
34
|
+
selectList.onSelect = item => opts.onSelect?.(item);
|
|
35
|
+
selectList.onCancel = () => opts.onCancel?.();
|
|
36
|
+
if (opts.onSelectionChange) selectList.onSelectionChange = opts.onSelectionChange;
|
|
37
|
+
container.addChild(selectList);
|
|
38
|
+
container.addChild(new DynamicBorder());
|
|
39
|
+
return { container, selectList };
|
|
40
|
+
}
|