@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
|
@@ -45,6 +45,12 @@ export interface RateLimitItem<T = unknown> {
|
|
|
45
45
|
payload: T;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
export type RateLimitDisposition = "queued" | "sending" | "accepted" | "rejected" | "ambiguous" | "removed" | "expired";
|
|
49
|
+
export interface RateLimitHandle {
|
|
50
|
+
itemId: string;
|
|
51
|
+
settled: Promise<Exclude<RateLimitDisposition, "queued" | "sending">>;
|
|
52
|
+
}
|
|
53
|
+
|
|
48
54
|
/** Options for {@link RateLimitPool}. */
|
|
49
55
|
export interface RateLimitPoolOptions {
|
|
50
56
|
/** Burst capacity (max tokens). Default 20 (Telegram per-chat burst). */
|
|
@@ -87,6 +93,11 @@ export class RateLimitPool<T = unknown> {
|
|
|
87
93
|
|
|
88
94
|
private tokens: number;
|
|
89
95
|
private lastRefill: number;
|
|
96
|
+
private readonly settlements = new Map<
|
|
97
|
+
string,
|
|
98
|
+
PromiseWithResolvers<Exclude<RateLimitDisposition, "queued" | "sending">>
|
|
99
|
+
>();
|
|
100
|
+
|
|
90
101
|
private seqCounter = 0;
|
|
91
102
|
|
|
92
103
|
constructor(options: RateLimitPoolOptions = {}) {
|
|
@@ -116,22 +127,45 @@ export class RateLimitPool<T = unknown> {
|
|
|
116
127
|
* item in the same `(sessionId, lane)` replace its payload (latest wins)
|
|
117
128
|
* while preserving FIFO position; identified items are always appended.
|
|
118
129
|
*/
|
|
119
|
-
submit(item: RateLimitItem<T>):
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
130
|
+
submit(item: RateLimitItem<T>): RateLimitHandle {
|
|
131
|
+
const itemId = item.itemId ?? `rate-limit:${this.seqCounter++}`;
|
|
132
|
+
const identified = item.itemId === undefined ? { ...item, itemId } : item;
|
|
133
|
+
const queue = this.lanes.get(identified.lane);
|
|
134
|
+
if (!queue) throw new Error(`unknown rate-limit lane: ${identified.lane}`);
|
|
135
|
+
if (item.itemId === undefined && identified.coalesceKey !== undefined) {
|
|
123
136
|
const existing = queue.find(
|
|
124
|
-
q =>
|
|
125
|
-
q.item.itemId === undefined &&
|
|
126
|
-
q.item.sessionId === item.sessionId &&
|
|
127
|
-
q.item.coalesceKey === item.coalesceKey,
|
|
137
|
+
q => q.item.sessionId === identified.sessionId && q.item.coalesceKey === identified.coalesceKey,
|
|
128
138
|
);
|
|
129
139
|
if (existing) {
|
|
130
|
-
existing.item
|
|
131
|
-
|
|
140
|
+
this.settle(existing.item.itemId!, "removed");
|
|
141
|
+
existing.item = identified;
|
|
142
|
+
return this.handle(itemId);
|
|
132
143
|
}
|
|
133
144
|
}
|
|
134
|
-
queue.push({ item, seq: this.seqCounter++ });
|
|
145
|
+
queue.push({ item: identified, seq: item.itemId === undefined ? this.seqCounter - 1 : this.seqCounter++ });
|
|
146
|
+
return this.handle(itemId);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Settle a stable item after its external transport effect has a known outcome. */
|
|
150
|
+
settle(itemId: string, disposition: Exclude<RateLimitDisposition, "queued" | "sending">): void {
|
|
151
|
+
const deferred = this.settlements.get(itemId);
|
|
152
|
+
if (!deferred) return;
|
|
153
|
+
this.settlements.delete(itemId);
|
|
154
|
+
deferred.resolve(disposition);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Mark a granted item as owned by an external transport effect. */
|
|
158
|
+
markSending(itemId: string): void {
|
|
159
|
+
if (!this.settlements.has(itemId)) throw new Error(`unknown rate-limit item: ${itemId}`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
private handle(itemId: string): RateLimitHandle {
|
|
163
|
+
let deferred = this.settlements.get(itemId);
|
|
164
|
+
if (!deferred) {
|
|
165
|
+
deferred = Promise.withResolvers<Exclude<RateLimitDisposition, "queued" | "sending">>();
|
|
166
|
+
this.settlements.set(itemId, deferred);
|
|
167
|
+
}
|
|
168
|
+
return { itemId, settled: deferred.promise };
|
|
135
169
|
}
|
|
136
170
|
|
|
137
171
|
/**
|
|
@@ -149,7 +183,8 @@ export class RateLimitPool<T = unknown> {
|
|
|
149
183
|
*/
|
|
150
184
|
drainWithExpired(nowMs: number = this.now()): RateLimitDrainResult<T> {
|
|
151
185
|
this.refill(nowMs);
|
|
152
|
-
const expired = this.removeWhere(item => item.deadlineAt !== undefined && item.deadlineAt <= nowMs);
|
|
186
|
+
const expired = this.removeWhere(item => item.deadlineAt !== undefined && item.deadlineAt <= nowMs, "expired");
|
|
187
|
+
|
|
153
188
|
const granted: RateLimitItem<T>[] = [];
|
|
154
189
|
while (this.tokens >= 1) {
|
|
155
190
|
const next = this.takeNext();
|
|
@@ -161,7 +196,10 @@ export class RateLimitPool<T = unknown> {
|
|
|
161
196
|
}
|
|
162
197
|
|
|
163
198
|
/** Remove queued items matching `predicate` without consuming tokens. Returns removed items in lane/FIFO order. */
|
|
164
|
-
removeWhere(
|
|
199
|
+
removeWhere(
|
|
200
|
+
predicate: (item: RateLimitItem<T>) => boolean,
|
|
201
|
+
disposition: Exclude<RateLimitDisposition, "queued" | "sending"> = "removed",
|
|
202
|
+
): RateLimitItem<T>[] {
|
|
165
203
|
const removed: RateLimitItem<T>[] = [];
|
|
166
204
|
for (const lane of LANE_PRIORITY) {
|
|
167
205
|
const queue = this.lanes.get(lane)!;
|
|
@@ -170,6 +208,7 @@ export class RateLimitPool<T = unknown> {
|
|
|
170
208
|
const queued = queue[read]!;
|
|
171
209
|
if (predicate(queued.item)) {
|
|
172
210
|
removed.push(queued.item);
|
|
211
|
+
this.settle(queued.item.itemId!, disposition);
|
|
173
212
|
} else {
|
|
174
213
|
queue[write++] = queued;
|
|
175
214
|
}
|
|
@@ -184,7 +223,11 @@ export class RateLimitPool<T = unknown> {
|
|
|
184
223
|
for (const lane of LANE_PRIORITY) {
|
|
185
224
|
const queue = this.lanes.get(lane)!;
|
|
186
225
|
const index = queue.findIndex(queued => queued.item.itemId === itemId);
|
|
187
|
-
if (index >= 0)
|
|
226
|
+
if (index >= 0) {
|
|
227
|
+
const item = queue.splice(index, 1)[0]!.item;
|
|
228
|
+
this.settle(item.itemId!, "removed");
|
|
229
|
+
return item;
|
|
230
|
+
}
|
|
188
231
|
}
|
|
189
232
|
return undefined;
|
|
190
233
|
}
|
|
@@ -203,6 +246,7 @@ export class RateLimitPool<T = unknown> {
|
|
|
203
246
|
if (queue.length === 0) continue;
|
|
204
247
|
const picked = this.pickFairIndex(lane, queue);
|
|
205
248
|
const [removed] = queue.splice(picked, 1);
|
|
249
|
+
if (removed) this.markSending(removed.item.itemId!);
|
|
206
250
|
return removed?.item;
|
|
207
251
|
}
|
|
208
252
|
return undefined;
|
|
@@ -6,14 +6,24 @@
|
|
|
6
6
|
* pick a repo to create in or a recent session to resume without typing raw
|
|
7
7
|
* paths. Dependency-light + injectable so it is unit-testable over a temp dir.
|
|
8
8
|
*/
|
|
9
|
-
import
|
|
9
|
+
import { createHash } from "node:crypto";
|
|
10
|
+
import * as fs from "node:fs/promises";
|
|
10
11
|
import * as path from "node:path";
|
|
12
|
+
import { verifyOwnerOnlyPathSecurity } from "@gajae-code/natives";
|
|
13
|
+
import { getAgentDir, getSessionsDir } from "@gajae-code/utils";
|
|
14
|
+
import { FileSessionStorage } from "../../session/session-storage";
|
|
15
|
+
import {
|
|
16
|
+
type LogicalSessionCandidate,
|
|
17
|
+
listManagedSessionCandidates,
|
|
18
|
+
type ManagedSessionScope,
|
|
19
|
+
resolveManagedSessionScope,
|
|
20
|
+
} from "../session-directory";
|
|
11
21
|
|
|
12
22
|
/** One ranked recent-session entry surfaced to the picker. */
|
|
13
23
|
export interface RecentSessionEntry {
|
|
14
|
-
/** Session id
|
|
24
|
+
/** Session id from the validated managed candidate header. */
|
|
15
25
|
sessionId: string;
|
|
16
|
-
/**
|
|
26
|
+
/** Validated workspace path recorded by the managed candidate. */
|
|
17
27
|
path?: string;
|
|
18
28
|
/** Branch, when recoverable from the header. */
|
|
19
29
|
branch?: string;
|
|
@@ -30,39 +40,54 @@ export interface RecentSessionEntry {
|
|
|
30
40
|
}
|
|
31
41
|
|
|
32
42
|
export interface RecentActivityDeps {
|
|
33
|
-
/**
|
|
34
|
-
|
|
43
|
+
/** Workspace whose managed sessions will be listed readonly. */
|
|
44
|
+
cwd: string;
|
|
45
|
+
/** Agent directory used to resolve the managed session scope. */
|
|
46
|
+
agentDir?: string;
|
|
47
|
+
/** Explicit managed root for isolated tests. */
|
|
48
|
+
sessionsRoot?: string;
|
|
35
49
|
/** Optional breadcrumb session-file paths (current terminals). */
|
|
36
50
|
breadcrumbPaths?: string[];
|
|
37
51
|
/** Max entries to return (default 20). */
|
|
38
52
|
limit?: number;
|
|
39
53
|
/** Include internal helper/sub-agent sessions (default true). */
|
|
40
54
|
includeInternal?: boolean;
|
|
55
|
+
/** Search every validated v2 workspace scope below the session root (default false). */
|
|
56
|
+
allWorkspaces?: boolean;
|
|
41
57
|
/** Injection seam for tests. */
|
|
42
58
|
readInitialLines?: (file: string, maxLines: number) => string[];
|
|
43
59
|
}
|
|
44
60
|
|
|
45
|
-
function
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
61
|
+
function readCandidateInitialLines(
|
|
62
|
+
candidate: LogicalSessionCandidate,
|
|
63
|
+
readInitialLines: ((file: string, maxLines: number) => string[]) | undefined,
|
|
64
|
+
): string[] {
|
|
65
|
+
if (readInitialLines) return readInitialLines(candidate.path, 8);
|
|
66
|
+
if (candidate.provenance !== "legacy") {
|
|
67
|
+
const security = verifyOwnerOnlyPathSecurity(candidate.path, "file");
|
|
68
|
+
if (!security.ok) throw new Error(`Managed session metadata path is unsafe: ${security.code}`);
|
|
51
69
|
}
|
|
70
|
+
const snapshot = new FileSessionStorage().readSnapshotSync(candidate.path);
|
|
71
|
+
const digest = createHash("sha256").update(snapshot.bytes).digest("hex");
|
|
72
|
+
if (
|
|
73
|
+
snapshot.stat.dev !== candidate.identity.dev ||
|
|
74
|
+
snapshot.stat.ino !== candidate.identity.ino ||
|
|
75
|
+
snapshot.stat.size !== candidate.identity.size ||
|
|
76
|
+
snapshot.stat.mtimeNs !== candidate.identity.mtimeNs ||
|
|
77
|
+
digest !== candidate.identity.sha256
|
|
78
|
+
)
|
|
79
|
+
throw new Error("Managed session changed after ownership was verified.");
|
|
80
|
+
return Buffer.from(snapshot.bytes).toString("utf8").split("\n").slice(0, 8);
|
|
52
81
|
}
|
|
53
82
|
|
|
54
83
|
/** Best-effort header metadata extraction from a session file's first line. */
|
|
55
|
-
function headerMeta(line: string | undefined): {
|
|
84
|
+
function headerMeta(line: string | undefined): { branch?: string; title?: string } {
|
|
56
85
|
if (!line) return {};
|
|
57
86
|
try {
|
|
58
87
|
const obj = JSON.parse(line) as Record<string, unknown>;
|
|
59
|
-
// Session headers vary; pull common fields defensively.
|
|
60
|
-
const id = typeof obj.id === "string" ? obj.id : undefined;
|
|
61
|
-
const cwd =
|
|
62
|
-
typeof obj.cwd === "string" ? obj.cwd : typeof obj.projectDir === "string" ? obj.projectDir : undefined;
|
|
63
88
|
const branch = typeof obj.branch === "string" ? obj.branch : undefined;
|
|
64
89
|
const title = typeof obj.title === "string" ? obj.title : undefined;
|
|
65
|
-
return {
|
|
90
|
+
return { branch, title };
|
|
66
91
|
} catch {
|
|
67
92
|
return {};
|
|
68
93
|
}
|
|
@@ -84,73 +109,162 @@ function isInternalSession(lines: readonly string[]): boolean {
|
|
|
84
109
|
return false;
|
|
85
110
|
}
|
|
86
111
|
|
|
87
|
-
/**
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
*/
|
|
92
|
-
function sessionIdForFile(stem: string, headerId: string | undefined): string {
|
|
93
|
-
if (headerId) return headerId;
|
|
94
|
-
const m = stem.match(/^\d{4}-\d{2}-\d{2}T[\d:.-]+Z?_(.+)$/);
|
|
95
|
-
return m?.[1] ?? stem;
|
|
96
|
-
}
|
|
112
|
+
/** Lists readonly managed candidates, optionally across every validated v2 workspace scope, ranked by history-file mtime. */
|
|
113
|
+
export type ListRecentSessionsResult =
|
|
114
|
+
| { kind: "complete"; entries: RecentSessionEntry[]; warnings: readonly string[] }
|
|
115
|
+
| { kind: "error"; code: "scope_unavailable" | "managed_scan_failed"; message: string };
|
|
97
116
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
117
|
+
async function resolveRecentScopes(
|
|
118
|
+
deps: RecentActivityDeps,
|
|
119
|
+
): Promise<
|
|
120
|
+
| { kind: "complete"; scopes: ManagedSessionScope[]; warnings: string[] }
|
|
121
|
+
| { kind: "error"; code: "scope_unavailable"; message: string }
|
|
122
|
+
> {
|
|
123
|
+
const agentDir = deps.agentDir ?? getAgentDir();
|
|
124
|
+
const sessionsRoot = deps.sessionsRoot ?? getSessionsDir(agentDir);
|
|
125
|
+
const current = await resolveManagedSessionScope({
|
|
126
|
+
cwd: deps.cwd,
|
|
127
|
+
agentDir,
|
|
128
|
+
sessionsRoot,
|
|
129
|
+
});
|
|
130
|
+
if (!deps.allWorkspaces) {
|
|
131
|
+
if (current.kind !== "resolved") return { kind: "error", code: "scope_unavailable", message: current.message };
|
|
132
|
+
return { kind: "complete", scopes: [current.scope], warnings: [] };
|
|
133
|
+
}
|
|
112
134
|
try {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
135
|
+
const root = await fs.lstat(sessionsRoot);
|
|
136
|
+
if (!root.isDirectory() || root.isSymbolicLink() || !verifyOwnerOnlyPathSecurity(sessionsRoot, "directory").ok) {
|
|
137
|
+
return {
|
|
138
|
+
kind: "error",
|
|
139
|
+
code: "scope_unavailable",
|
|
140
|
+
message: "The managed sessions root is not a safe directory.",
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
} catch (error) {
|
|
144
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return { kind: "complete", scopes: [], warnings: [] };
|
|
145
|
+
return { kind: "error", code: "scope_unavailable", message: "The managed sessions root could not be inspected." };
|
|
119
146
|
}
|
|
147
|
+
const warnings: string[] = [];
|
|
148
|
+
const scopes = current.kind === "resolved" ? [current.scope] : [];
|
|
149
|
+
const seen = new Set(scopes.map(scope => scope.directoryPath));
|
|
120
150
|
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
151
|
+
const addResolvedScope = async (cwd: string, expectedDirectory?: string): Promise<void> => {
|
|
152
|
+
const resolved = await resolveManagedSessionScope({
|
|
153
|
+
cwd,
|
|
154
|
+
agentDir,
|
|
155
|
+
sessionsRoot,
|
|
156
|
+
});
|
|
157
|
+
if (
|
|
158
|
+
resolved.kind !== "resolved" ||
|
|
159
|
+
(expectedDirectory !== undefined && resolved.scope.directoryPath !== expectedDirectory)
|
|
160
|
+
) {
|
|
161
|
+
warnings.push("Ignored invalid managed session scope binding.");
|
|
162
|
+
return;
|
|
128
163
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
164
|
+
if (!seen.has(resolved.scope.directoryPath)) {
|
|
165
|
+
seen.add(resolved.scope.directoryPath);
|
|
166
|
+
scopes.push(resolved.scope);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
try {
|
|
170
|
+
const directories = await fs.readdir(sessionsRoot, { withFileTypes: true });
|
|
171
|
+
for (const directory of directories) {
|
|
172
|
+
if (!directory.isDirectory() || directory.isSymbolicLink() || !directory.name.startsWith("v2-")) continue;
|
|
173
|
+
try {
|
|
174
|
+
const binding = JSON.parse(
|
|
175
|
+
await fs.readFile(path.join(sessionsRoot, directory.name, ".gjc-managed-session-scope.v2.json"), "utf8"),
|
|
176
|
+
) as { canonicalPath?: unknown };
|
|
177
|
+
if (typeof binding.canonicalPath !== "string") {
|
|
178
|
+
warnings.push("Ignored invalid managed session scope binding.");
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
await addResolvedScope(binding.canonicalPath, path.join(sessionsRoot, directory.name));
|
|
182
|
+
} catch {
|
|
183
|
+
warnings.push("Ignored unreadable managed session scope binding.");
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
for (const directory of directories) {
|
|
187
|
+
if (!directory.isDirectory() || directory.isSymbolicLink() || directory.name.startsWith("v2-")) continue;
|
|
132
188
|
try {
|
|
133
|
-
|
|
189
|
+
const files = await fs.readdir(path.join(sessionsRoot, directory.name), {
|
|
190
|
+
withFileTypes: true,
|
|
191
|
+
});
|
|
192
|
+
for (const file of files) {
|
|
193
|
+
if (!file.isFile() || file.isSymbolicLink() || !file.name.endsWith(".jsonl")) continue;
|
|
194
|
+
try {
|
|
195
|
+
const snapshot = new FileSessionStorage().readSnapshotSync(
|
|
196
|
+
path.join(sessionsRoot, directory.name, file.name),
|
|
197
|
+
);
|
|
198
|
+
const newline = snapshot.bytes.indexOf(0x0a);
|
|
199
|
+
if (newline < 0) continue;
|
|
200
|
+
const header = JSON.parse(Buffer.from(snapshot.bytes.subarray(0, newline)).toString("utf8")) as {
|
|
201
|
+
cwd?: unknown;
|
|
202
|
+
type?: unknown;
|
|
203
|
+
};
|
|
204
|
+
if (header.type === "session" && typeof header.cwd === "string") await addResolvedScope(header.cwd);
|
|
205
|
+
} catch {
|
|
206
|
+
warnings.push("Ignored unreadable legacy managed session candidate.");
|
|
207
|
+
}
|
|
208
|
+
}
|
|
134
209
|
} catch {
|
|
135
|
-
|
|
210
|
+
warnings.push("Ignored unreadable legacy managed session directory.");
|
|
136
211
|
}
|
|
137
|
-
const initialLines = readInitialLines(file, 8);
|
|
138
|
-
const meta = headerMeta(initialLines[0]);
|
|
139
|
-
const internal = isInternalSession(initialLines);
|
|
140
|
-
if (internal && !includeInternal) continue;
|
|
141
|
-
entries.push({
|
|
142
|
-
sessionId: sessionIdForFile(name.slice(0, -".jsonl".length), meta.id),
|
|
143
|
-
path: meta.path,
|
|
144
|
-
branch: meta.branch,
|
|
145
|
-
title: meta.title,
|
|
146
|
-
sessionStateFile: file,
|
|
147
|
-
mtimeMs,
|
|
148
|
-
currentTerminal: breadcrumbs.has(path.resolve(file)) || undefined,
|
|
149
|
-
internal: internal || undefined,
|
|
150
|
-
});
|
|
151
212
|
}
|
|
213
|
+
} catch (error) {
|
|
214
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") return { kind: "complete", scopes, warnings };
|
|
215
|
+
return { kind: "error", code: "scope_unavailable", message: "The managed sessions root could not be read." };
|
|
216
|
+
}
|
|
217
|
+
return { kind: "complete", scopes, warnings };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export async function listRecentSessions(deps: RecentActivityDeps): Promise<ListRecentSessionsResult> {
|
|
221
|
+
const limit = deps.limit ?? 20;
|
|
222
|
+
const includeInternal = deps.includeInternal ?? true;
|
|
223
|
+
const readInitialLines = deps.readInitialLines;
|
|
224
|
+
const breadcrumbs = new Set((deps.breadcrumbPaths ?? []).map(candidate => path.resolve(candidate)));
|
|
225
|
+
const resolved = await resolveRecentScopes(deps);
|
|
226
|
+
if (resolved.kind === "error") return resolved;
|
|
227
|
+
const warnings = [...resolved.warnings];
|
|
228
|
+
const candidates: LogicalSessionCandidate[] = [];
|
|
229
|
+
for (const scope of resolved.scopes) {
|
|
230
|
+
const listed = await listManagedSessionCandidates({ scope });
|
|
231
|
+
if (listed.kind !== "complete") {
|
|
232
|
+
return { kind: "error", code: "managed_scan_failed", message: listed.message };
|
|
233
|
+
}
|
|
234
|
+
candidates.push(...listed.owned);
|
|
235
|
+
warnings.push(...listed.invalid.map(invalid => `Ignored invalid managed session candidate: ${invalid.code}`));
|
|
152
236
|
}
|
|
153
237
|
|
|
238
|
+
const entries: RecentSessionEntry[] = [];
|
|
239
|
+
for (const candidate of candidates) {
|
|
240
|
+
let initialLines: string[];
|
|
241
|
+
try {
|
|
242
|
+
initialLines = readCandidateInitialLines(candidate, readInitialLines);
|
|
243
|
+
} catch (error) {
|
|
244
|
+
return {
|
|
245
|
+
kind: "error",
|
|
246
|
+
code: "managed_scan_failed",
|
|
247
|
+
message: `Could not read managed session metadata: ${error instanceof Error ? error.message : String(error)}`,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
const meta = headerMeta(initialLines[0]);
|
|
251
|
+
const internal = isInternalSession(initialLines);
|
|
252
|
+
if (internal && !includeInternal) continue;
|
|
253
|
+
entries.push({
|
|
254
|
+
sessionId: candidate.sessionId,
|
|
255
|
+
path: candidate.cwd,
|
|
256
|
+
branch: meta.branch,
|
|
257
|
+
title: meta.title,
|
|
258
|
+
sessionStateFile: candidate.path,
|
|
259
|
+
mtimeMs: candidate.identity.mtimeMs,
|
|
260
|
+
currentTerminal: breadcrumbs.has(path.resolve(candidate.path)) || undefined,
|
|
261
|
+
internal: internal || undefined,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
154
264
|
entries.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
155
|
-
return
|
|
265
|
+
return {
|
|
266
|
+
kind: "complete",
|
|
267
|
+
entries: entries.slice(0, limit),
|
|
268
|
+
warnings,
|
|
269
|
+
};
|
|
156
270
|
}
|