@gajae-code/coding-agent 0.13.2 → 0.14.0
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 +215 -8
- package/README.md +2 -0
- package/bin/gajaessi.js +4 -0
- package/dist/types/async/job-manager.d.ts +55 -2
- package/dist/types/async/support.d.ts +14 -0
- package/dist/types/capability/mcp.d.ts +6 -0
- package/dist/types/capability/types.d.ts +6 -0
- package/dist/types/cli/accounts-cli.d.ts +19 -0
- package/dist/types/cli/args.d.ts +3 -0
- package/dist/types/cli/config-cli.d.ts +6 -0
- package/dist/types/cli/crash-cli.d.ts +10 -0
- package/dist/types/cli/customize-doctor.d.ts +145 -0
- package/dist/types/cli/daemon-cli.d.ts +3 -1
- package/dist/types/cli/mcp-cli.d.ts +11 -0
- package/dist/types/cli/notify-cli.d.ts +1 -1
- package/dist/types/cli/root-flags.d.ts +12 -0
- package/dist/types/cli/setup-cli.d.ts +3 -1
- package/dist/types/cli/skills-cli.d.ts +2 -1
- package/dist/types/cli/update-cli.d.ts +19 -1
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/commands/accounts.d.ts +40 -0
- package/dist/types/commands/crash.d.ts +24 -0
- package/dist/types/commands/customize.d.ts +22 -0
- package/dist/types/commands/daemon.d.ts +1 -1
- package/dist/types/commands/launch.d.ts +6 -0
- package/dist/types/commands/setup.d.ts +6 -0
- package/dist/types/commands/skills.d.ts +6 -1
- package/dist/types/commands/update.d.ts +7 -0
- package/dist/types/config/atomic-yaml-patch-worker.d.ts +25 -0
- package/dist/types/config/atomic-yaml-patch.d.ts +62 -2
- package/dist/types/config/config-schema-version.d.ts +10 -0
- package/dist/types/config/file-lock.d.ts +18 -0
- package/dist/types/config/model-profile-activation.d.ts +3 -1
- package/dist/types/config/model-registry.d.ts +10 -1
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +73 -9
- package/dist/types/config/settings.d.ts +63 -0
- package/dist/types/config/skill-settings-defaults.d.ts +26 -0
- package/dist/types/config/task-delegation.d.ts +39 -0
- package/dist/types/config/update-channel.d.ts +10 -0
- package/dist/types/coordinator-mcp/server.d.ts +5 -1
- package/dist/types/crash/index-store.d.ts +87 -0
- package/dist/types/crash/nudge.d.ts +50 -0
- package/dist/types/crash/record-loader.d.ts +17 -0
- package/dist/types/crash/report.d.ts +134 -0
- package/dist/types/crash/sanitize.d.ts +25 -0
- package/dist/types/cursor.d.ts +13 -2
- package/dist/types/customization/import.d.ts +37 -0
- package/dist/types/customization/index.d.ts +4 -0
- package/dist/types/customization/inventory.d.ts +25 -0
- package/dist/types/customization/mutations.d.ts +32 -0
- package/dist/types/customization/types.d.ts +115 -0
- package/dist/types/daemon/control-types.d.ts +8 -1
- package/dist/types/daemon/operator-contract.d.ts +4 -4
- package/dist/types/discovery/claude.d.ts +39 -1
- package/dist/types/discovery/codex.d.ts +39 -1
- package/dist/types/discovery/index.d.ts +2 -0
- package/dist/types/discovery/mcp-compat.d.ts +30 -0
- package/dist/types/edit/renderer.d.ts +23 -0
- package/dist/types/extensibility/extensions/runner.d.ts +3 -0
- package/dist/types/extensibility/extensions/types.d.ts +21 -4
- package/dist/types/extensibility/gjc-plugins/observability.d.ts +6 -1
- package/dist/types/extensibility/gjc-plugins/registry.d.ts +8 -1
- package/dist/types/extensibility/hooks/loader.d.ts +19 -5
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +22 -1
- package/dist/types/extensibility/skill-management.d.ts +107 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +3 -1
- package/dist/types/gjc-runtime/launch-worktree.d.ts +8 -0
- package/dist/types/gjc-runtime/linux-proc.d.ts +3 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +10 -6
- package/dist/types/gjc-runtime/session-state-lock.d.ts +104 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +120 -2
- package/dist/types/gjc-runtime/state-writer.d.ts +10 -1
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +4 -2
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -6
- package/dist/types/gjc-runtime/workflow-settings.d.ts +109 -0
- package/dist/types/hooks/events.d.ts +60 -0
- package/dist/types/hooks/normalize.d.ts +83 -0
- package/dist/types/hooks/skill-state.d.ts +9 -2
- package/dist/types/main.d.ts +2 -1
- package/dist/types/modes/acp/abort-scope.d.ts +13 -0
- package/dist/types/modes/acp/acp-agent.d.ts +7 -4
- package/dist/types/modes/components/customization/customization-dashboard.d.ts +44 -0
- package/dist/types/modes/components/customization/import-wizard.d.ts +21 -0
- package/dist/types/modes/components/customization/index.d.ts +1 -0
- package/dist/types/modes/components/dynamic-theme-text.d.ts +9 -0
- package/dist/types/modes/components/gajae-pet-widget.d.ts +6 -28
- package/dist/types/modes/components/irc-sidebar.d.ts +1 -0
- package/dist/types/modes/components/iterm-pet-transport.d.ts +122 -0
- package/dist/types/modes/components/oauth-selector.d.ts +10 -4
- package/dist/types/modes/components/pet-capability.d.ts +7 -21
- package/dist/types/modes/components/settings-selector.d.ts +5 -0
- package/dist/types/modes/components/status-line/gh.d.ts +6 -2
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +7 -8
- package/dist/types/modes/controllers/stt-controller.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/theme/defaults/index.d.ts +118 -0
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/modes/utils/injected-user-submission.d.ts +10 -0
- package/dist/types/runtime-mcp/config.d.ts +9 -0
- package/dist/types/runtime-mcp/manager.d.ts +26 -1
- package/dist/types/runtime-mcp/oauth-discovery.d.ts +4 -0
- package/dist/types/runtime-mcp/oauth-flow.d.ts +24 -1
- package/dist/types/runtime-mcp/pool-key.d.ts +2 -0
- package/dist/types/runtime-mcp/protocol.d.ts +278 -0
- package/dist/types/runtime-mcp/scope-config.d.ts +29 -0
- package/dist/types/runtime-mcp/tool-bridge.d.ts +15 -13
- package/dist/types/runtime-mcp/transports/http.d.ts +9 -0
- package/dist/types/runtime-mcp/types.d.ts +102 -10
- package/dist/types/sdk/acp/adapter.d.ts +26 -5
- package/dist/types/sdk/broker/broker.d.ts +3 -55
- package/dist/types/sdk/broker/lifecycle.d.ts +18 -12
- package/dist/types/sdk/broker/session-index.d.ts +14 -5
- package/dist/types/sdk/broker/startup-failure.d.ts +16 -1
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +51 -1
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -41
- package/dist/types/sdk/bus/config.d.ts +11 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +0 -1
- package/dist/types/sdk/bus/daemon-paths.d.ts +6 -0
- package/dist/types/sdk/bus/discord-conversation.d.ts +2 -0
- package/dist/types/sdk/bus/discord-daemon.d.ts +17 -12
- package/dist/types/sdk/bus/existing-thread-readiness.d.ts +4 -34
- package/dist/types/sdk/bus/inbound-reaction-ordering.d.ts +61 -0
- package/dist/types/sdk/bus/index.d.ts +85 -99
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +29 -7
- package/dist/types/sdk/bus/managed-daemon.d.ts +2 -32
- package/dist/types/sdk/bus/notification-service.d.ts +52 -0
- package/dist/types/sdk/bus/operator-runtime.d.ts +1 -1
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +16 -5
- package/dist/types/sdk/bus/reconciliation-store.d.ts +113 -5
- package/dist/types/sdk/bus/session-control.d.ts +25 -1
- package/dist/types/sdk/bus/slack-conversation.d.ts +4 -0
- package/dist/types/sdk/bus/slack-daemon.d.ts +9 -17
- package/dist/types/sdk/bus/slack-live-provider.d.ts +3 -1
- package/dist/types/sdk/bus/slack-provider.d.ts +4 -0
- package/dist/types/sdk/bus/slack-thread-binding.d.ts +6 -40
- package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +30 -104
- package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +10 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +262 -19
- package/dist/types/sdk/bus/telegram-daemon-orphan-reap.d.ts +125 -0
- package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +22 -0
- package/dist/types/sdk/bus/telegram-daemon.d.ts +119 -310
- package/dist/types/sdk/bus/telegram-reference.d.ts +1 -47
- package/dist/types/sdk/bus/threaded-render.d.ts +1 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +33 -17
- package/dist/types/sdk/cli/rows.d.ts +2 -11
- package/dist/types/sdk/cli/session-cli.d.ts +15 -25
- package/dist/types/sdk/client/client.d.ts +97 -1
- package/dist/types/sdk/host/control/dispatch.d.ts +0 -7
- package/dist/types/sdk/host/control/index.d.ts +1 -1
- package/dist/types/sdk/host/control/operations.d.ts +18 -5
- package/dist/types/sdk/host/control/runtime-gate.d.ts +19 -0
- package/dist/types/sdk/host/host.d.ts +15 -1
- package/dist/types/sdk/host/query/handlers.d.ts +5 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
- package/dist/types/sdk/host/session-runtime.d.ts +127 -7
- package/dist/types/sdk/host/types.d.ts +1 -1
- package/dist/types/sdk/host/websocket-transport.d.ts +1 -1
- package/dist/types/sdk/index.d.ts +2 -1
- package/dist/types/sdk/lifecycle/broker-client.d.ts +8 -0
- package/dist/types/sdk/lifecycle/client.d.ts +59 -0
- package/dist/types/sdk/lifecycle/index.d.ts +3 -0
- package/dist/types/sdk/lifecycle/service.d.ts +232 -0
- package/dist/types/sdk/mcp/server.d.ts +9 -6
- package/dist/types/sdk/prompt-deadline-lease.d.ts +43 -0
- package/dist/types/sdk/prompt-deadline-manager.d.ts +28 -0
- package/dist/types/sdk/prompt-status.d.ts +10 -3
- package/dist/types/sdk/protocol/operation-registry.d.ts +5 -0
- package/dist/types/sdk/receipt-state.d.ts +17 -0
- package/dist/types/sdk/reconciliation-extensions.d.ts +2 -0
- package/dist/types/sdk/router/index.d.ts +1 -0
- package/dist/types/sdk/router/session-router.d.ts +152 -0
- package/dist/types/sdk/session-list.d.ts +22 -0
- package/dist/types/sdk/session-reconnect.d.ts +43 -1
- package/dist/types/sdk/session.d.ts +34 -1
- package/dist/types/sdk/transport/serve-cli.d.ts +1 -4
- package/dist/types/session/account-inventory.d.ts +86 -0
- package/dist/types/session/agent-session.d.ts +145 -6
- package/dist/types/session/agent-storage.d.ts +10 -0
- package/dist/types/session/coordinator-tool-label.d.ts +28 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +23 -4
- package/dist/types/session/messages.d.ts +1 -1
- package/dist/types/session/secure-token-file.d.ts +3 -0
- package/dist/types/session/session-manager.d.ts +47 -1
- package/dist/types/session/startup-auth-config.d.ts +44 -0
- package/dist/types/session/terminal-abort.d.ts +378 -0
- package/dist/types/session/yield-queue.d.ts +7 -0
- package/dist/types/session-import/claude.d.ts +26 -0
- package/dist/types/session-import/codex.d.ts +88 -0
- package/dist/types/session-import/command.d.ts +35 -0
- package/dist/types/session-import/detect.d.ts +22 -0
- package/dist/types/session-import/index.d.ts +7 -0
- package/dist/types/session-import/provider-codex.d.ts +22 -0
- package/dist/types/session-import/provider-service.d.ts +38 -0
- package/dist/types/session-import/redact.d.ts +23 -0
- package/dist/types/session-import/service.d.ts +47 -0
- package/dist/types/session-import/types.d.ts +120 -0
- package/dist/types/setup/paseo/check.d.ts +16 -0
- package/dist/types/setup/paseo/install-saga.d.ts +115 -0
- package/dist/types/setup/paseo/json-publisher.d.ts +76 -0
- package/dist/types/setup/paseo/orchestration-preferences.d.ts +24 -0
- package/dist/types/setup/paseo/paseo-ownership.d.ts +87 -0
- package/dist/types/setup/paseo/paseo-setup.d.ts +29 -0
- package/dist/types/setup/paseo/provider-config.d.ts +35 -0
- package/dist/types/setup/paseo/remove.d.ts +14 -0
- package/dist/types/setup/paseo/result-types.d.ts +59 -0
- package/dist/types/setup/paseo/setup-deps.d.ts +73 -0
- package/dist/types/setup/paseo/skills-bridge.d.ts +44 -0
- package/dist/types/skill-state/active-state.d.ts +5 -1
- package/dist/types/slash-commands/acp-builtins.d.ts +5 -1
- package/dist/types/slash-commands/builtin-registry.d.ts +2 -0
- package/dist/types/slash-commands/helpers/credential-switch.d.ts +12 -0
- package/dist/types/slash-commands/helpers/usage-report.d.ts +5 -6
- package/dist/types/slash-commands/types.d.ts +7 -1
- package/dist/types/task/executor.d.ts +10 -0
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/tools/ask-answer-registry.d.ts +6 -3
- package/dist/types/tools/bash-sleep-advisory.d.ts +14 -0
- package/dist/types/tools/bash.d.ts +2 -6
- package/dist/types/tools/browser/attach.d.ts +11 -0
- package/dist/types/tools/browser/launch.d.ts +20 -0
- package/dist/types/tools/browser/profile-discovery.d.ts +6 -0
- package/dist/types/tools/browser/render.d.ts +1 -0
- package/dist/types/tools/browser.d.ts +3 -1
- package/dist/types/tools/image-gen.d.ts +10 -2
- package/dist/types/tools/index.d.ts +8 -0
- package/dist/types/tools/monitor.d.ts +1 -1
- package/dist/types/tools/skill-discovery.d.ts +8 -1
- package/dist/types/tools/subagent.d.ts +2 -0
- package/dist/types/tools/ultragoal-ask-guard.d.ts +2 -2
- package/dist/types/utils/herdr-pane.d.ts +76 -0
- package/package.json +19 -9
- package/scripts/build-binary.ts +2 -1
- package/scripts/build-sdk-package-smoke.ts +2 -13
- package/scripts/capture-sticky-viewport-showcase.ts +0 -1
- package/scripts/compile-args.ts +2 -0
- package/scripts/generate-sdk-adapter-parity-manifest.ts +31 -16
- package/scripts/generate-sdk-operation-inventory.ts +28 -0
- package/scripts/generate-telegram-baseline-manifest.ts +1 -0
- package/scripts/generate-tool-catalog.ts +6 -4
- package/scripts/verify-gjc-sdk-canonicalization.ts +5 -39
- package/src/async/job-manager.ts +352 -17
- package/src/async/support.ts +25 -0
- package/src/autoresearch/dashboard.ts +28 -13
- package/src/capability/index.ts +3 -1
- package/src/capability/mcp.ts +6 -0
- package/src/capability/types.ts +6 -0
- package/src/cli/accounts-cli.ts +395 -0
- package/src/cli/args.ts +23 -0
- package/src/cli/auth-broker-cli.ts +136 -66
- package/src/cli/auth-gateway-cli.ts +94 -70
- package/src/cli/config-cli.ts +27 -2
- package/src/cli/crash-cli.ts +78 -0
- package/src/cli/customize-doctor.ts +1605 -0
- package/src/cli/daemon-cli.ts +12 -3
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/mcp-cli.ts +128 -60
- package/src/cli/notify-cli.ts +8 -14
- package/src/cli/root-flags.ts +8 -0
- package/src/cli/setup-cli.ts +145 -0
- package/src/cli/skills-cli.ts +38 -2
- package/src/cli/update-cli.ts +167 -12
- package/src/cli.ts +4 -0
- package/src/commands/accounts.ts +71 -0
- package/src/commands/crash.ts +35 -0
- package/src/commands/customize.ts +84 -0
- package/src/commands/daemon.ts +2 -2
- package/src/commands/deep-interview.ts +2 -0
- package/src/commands/launch.ts +1 -0
- package/src/commands/mcp.ts +12 -7
- package/src/commands/ralplan.ts +2 -0
- package/src/commands/sdk.ts +65 -32
- package/src/commands/setup.ts +5 -0
- package/src/commands/skills.ts +14 -4
- package/src/commands/ultragoal.ts +10 -1
- package/src/commands/update.ts +26 -15
- package/src/config/atomic-yaml-patch-worker.ts +57 -0
- package/src/config/atomic-yaml-patch.ts +769 -29
- package/src/config/config-schema-version.ts +10 -0
- package/src/config/file-lock.ts +70 -1
- package/src/config/mcp-schema.json +52 -14
- package/src/config/model-profile-activation.ts +23 -2
- package/src/config/model-profiles.ts +88 -21
- package/src/config/model-registry.ts +147 -21
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/settings-schema.ts +77 -7
- package/src/config/settings.ts +4038 -199
- package/src/config/skill-settings-defaults.ts +41 -3
- package/src/config/task-delegation.ts +87 -0
- package/src/config/update-channel.ts +23 -0
- package/src/coordinator-mcp/server.ts +377 -308
- package/src/crash/index-store.ts +723 -0
- package/src/crash/nudge.ts +89 -0
- package/src/crash/record-loader.ts +149 -0
- package/src/crash/report.ts +551 -0
- package/src/crash/sanitize.ts +129 -0
- package/src/cursor.ts +36 -10
- package/src/customization/import.ts +946 -0
- package/src/customization/index.ts +4 -0
- package/src/customization/inventory.ts +335 -0
- package/src/customization/mutations.ts +141 -0
- package/src/customization/types.ts +223 -0
- package/src/daemon/control-types.ts +8 -1
- package/src/daemon/operator-contract.ts +6 -6
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +31 -6
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +11 -22
- package/src/defaults/gjc/skills/ralplan/SKILL.md +36 -23
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +16 -0
- package/src/discovery/claude-hooks.ts +38 -0
- package/src/discovery/claude.ts +142 -209
- package/src/discovery/codex-hooks.ts +38 -0
- package/src/discovery/codex.ts +132 -198
- package/src/discovery/helpers.ts +8 -1
- package/src/discovery/index.ts +2 -0
- package/src/discovery/mcp-compat.ts +234 -0
- package/src/discovery/mcp-json.ts +6 -0
- package/src/edit/renderer.ts +40 -0
- package/src/edit/streaming.ts +4 -2
- package/src/exec/bash-executor.ts +24 -20
- package/src/export/html/index.ts +51 -2
- package/src/extensibility/extensions/loader.ts +9 -1
- package/src/extensibility/extensions/runner.ts +17 -4
- package/src/extensibility/extensions/types.ts +31 -6
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +33 -0
- package/src/extensibility/gjc-plugins/installer.ts +9 -5
- package/src/extensibility/gjc-plugins/observability.ts +8 -2
- package/src/extensibility/gjc-plugins/registry.ts +13 -2
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +3 -1
- package/src/extensibility/gjc-plugins/schema.ts +222 -39
- package/src/extensibility/hooks/loader.ts +154 -10
- package/src/extensibility/runtime-skill-discovery.ts +257 -60
- package/src/extensibility/skill-management.ts +368 -0
- package/src/extensibility/skills.ts +52 -16
- package/src/gjc-runtime/deep-interview-runtime.ts +45 -61
- package/src/gjc-runtime/launch-worktree.ts +56 -2
- package/src/gjc-runtime/linux-proc.ts +7 -1
- package/src/gjc-runtime/ralplan-runtime.ts +100 -164
- package/src/gjc-runtime/session-state-lock.ts +992 -0
- package/src/gjc-runtime/session-state-sidecar.ts +644 -142
- package/src/gjc-runtime/state-writer.ts +39 -14
- package/src/gjc-runtime/tmux-owner-isolation.ts +5 -4
- package/src/gjc-runtime/ultragoal-guard.ts +11 -4
- package/src/gjc-runtime/ultragoal-runtime.ts +44 -41
- package/src/gjc-runtime/workflow-settings.ts +596 -0
- package/src/goals/tools/goal-tool.ts +6 -1
- package/src/hooks/events.ts +291 -0
- package/src/hooks/native-skill-hook.ts +4 -0
- package/src/hooks/normalize.ts +369 -0
- package/src/hooks/skill-state.ts +165 -46
- package/src/internal-urls/docs-index.generated.ts +41 -32
- package/src/main.ts +36 -5
- package/src/migrate/mcp-mapper.ts +25 -2
- package/src/modes/acp/abort-scope.ts +29 -0
- package/src/modes/acp/acp-agent.ts +423 -98
- package/src/modes/components/assistant-message.ts +6 -1
- package/src/modes/components/chrome.ts +4 -3
- package/src/modes/components/customization/customization-dashboard.ts +443 -0
- package/src/modes/components/customization/import-wizard.ts +372 -0
- package/src/modes/components/customization/index.ts +1 -0
- package/src/modes/components/dynamic-theme-text.ts +22 -0
- package/src/modes/components/gajae-pet-widget.ts +607 -193
- package/src/modes/components/irc-sidebar.ts +11 -0
- package/src/modes/components/iterm-pet-transport.ts +585 -0
- package/src/modes/components/model-selector.ts +1 -6
- package/src/modes/components/oauth-selector.ts +277 -86
- package/src/modes/components/pet-capability.ts +35 -31
- package/src/modes/components/settings-selector.ts +29 -5
- package/src/modes/components/status-line/gh.ts +45 -1
- package/src/modes/components/status-line/segments.ts +19 -4
- package/src/modes/components/tool-status-header.ts +13 -3
- package/src/modes/controllers/command-controller.ts +20 -8
- package/src/modes/controllers/extension-ui-controller.ts +56 -257
- package/src/modes/controllers/input-controller.ts +10 -0
- package/src/modes/controllers/runtime-mcp-command-controller.ts +16 -3
- package/src/modes/controllers/selector-controller.ts +238 -77
- package/src/modes/controllers/stt-controller.ts +3 -3
- package/src/modes/interactive-mode.ts +88 -16
- package/src/modes/print-mode.ts +35 -6
- package/src/modes/runtime-init.ts +21 -68
- package/src/modes/theme/defaults/index.ts +2 -0
- package/src/modes/theme/defaults/ouroboros.json +118 -0
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/injected-user-submission.ts +25 -0
- package/src/modes/utils/terminal-bell.ts +15 -1
- package/src/prompts/agent-fragments/ralplan-persistence.md +1 -1
- package/src/prompts/agent-fragments/restricted-bash.md +1 -1
- package/src/prompts/agents/critic.md +1 -1
- package/src/prompts/system/rlm-research.md +1 -1
- package/src/prompts/system/system-prompt.md +0 -2
- package/src/prompts/tools/bash.md +7 -1
- package/src/prompts/tools/browser.md +1 -1
- package/src/prompts/tools/cron.md +6 -6
- package/src/prompts/tools/read.md +0 -2
- package/src/prompts/tools/skill-discovery.md +4 -2
- package/src/runtime-mcp/client.ts +427 -23
- package/src/runtime-mcp/config.ts +37 -5
- package/src/runtime-mcp/manager-pool.test.ts +56 -0
- package/src/runtime-mcp/manager.ts +52 -2
- package/src/runtime-mcp/oauth-discovery.ts +13 -0
- package/src/runtime-mcp/oauth-flow.ts +46 -1
- package/src/runtime-mcp/pool-key.ts +5 -1
- package/src/runtime-mcp/pool.test.ts +9 -0
- package/src/runtime-mcp/protocol.test.ts +353 -0
- package/src/runtime-mcp/protocol.ts +624 -0
- package/src/runtime-mcp/scope-config.ts +78 -0
- package/src/runtime-mcp/tool-bridge.ts +44 -10
- package/src/runtime-mcp/transports/http.ts +84 -13
- package/src/runtime-mcp/types.ts +123 -12
- package/src/sdk/acp/adapter.ts +328 -97
- package/src/sdk/broker/broker.ts +160 -741
- package/src/sdk/broker/ensure.ts +9 -1
- package/src/sdk/broker/lifecycle.ts +510 -116
- package/src/sdk/broker/operation-receipt-ledger.ts +11 -2
- package/src/sdk/broker/process-incarnation.ts +19 -0
- package/src/sdk/broker/session-index.ts +516 -117
- package/src/sdk/broker/startup-failure.ts +28 -5
- package/src/sdk/broker/transport.ts +1 -13
- package/src/sdk/bus/chat-daemon-cli.ts +4 -2
- package/src/sdk/bus/chat-daemon-control.ts +67 -6
- package/src/sdk/bus/chat-daemon-runtime.ts +183 -859
- package/src/sdk/bus/config.ts +13 -0
- package/src/sdk/bus/conversation-store.ts +59 -171
- package/src/sdk/bus/daemon-paths.ts +20 -0
- package/src/sdk/bus/discord-conversation.ts +2 -0
- package/src/sdk/bus/discord-daemon.ts +524 -126
- package/src/sdk/bus/discord-live-provider.ts +206 -79
- package/src/sdk/bus/existing-thread-readiness.ts +4 -97
- package/src/sdk/bus/inbound-reaction-ordering.ts +122 -0
- package/src/sdk/bus/index.ts +2480 -456
- package/src/sdk/bus/kind-aware-reconciliation.ts +204 -34
- package/src/sdk/bus/lifecycle-commands.ts +2 -2
- package/src/sdk/bus/managed-daemon.ts +2 -145
- package/src/sdk/bus/notification-service.ts +196 -0
- package/src/sdk/bus/operator-runtime.ts +1 -1
- package/src/sdk/bus/prompt-reconciliation.ts +24 -15
- package/src/sdk/bus/reconciliation-store.ts +553 -24
- package/src/sdk/bus/session-control.ts +49 -3
- package/src/sdk/bus/slack-conversation.ts +4 -0
- package/src/sdk/bus/slack-daemon.ts +733 -134
- package/src/sdk/bus/slack-live-provider.ts +65 -15
- package/src/sdk/bus/slack-provider.ts +4 -0
- package/src/sdk/bus/slack-thread-binding.ts +9 -104
- package/src/sdk/bus/telegram-adoption-intent.ts +299 -209
- package/src/sdk/bus/telegram-daemon-cli.ts +194 -7
- package/src/sdk/bus/telegram-daemon-contract.ts +265 -19
- package/src/sdk/bus/telegram-daemon-control.ts +3 -13
- package/src/sdk/bus/telegram-daemon-orphan-reap.ts +498 -0
- package/src/sdk/bus/telegram-daemon-owner-registry.ts +176 -0
- package/src/sdk/bus/telegram-daemon.ts +2552 -2280
- package/src/sdk/bus/telegram-reference.ts +1 -226
- package/src/sdk/bus/telegram-setup.ts +2 -2
- package/src/sdk/bus/threaded-render.ts +1 -0
- package/src/sdk/bus/topic-registry.ts +279 -146
- package/src/sdk/cli/rows.ts +2 -35
- package/src/sdk/cli/session-cli.ts +776 -700
- package/src/sdk/client/client.ts +892 -1
- package/src/sdk/host/control/dispatch.ts +93 -58
- package/src/sdk/host/control/index.ts +1 -1
- package/src/sdk/host/control/operations.ts +18 -10
- package/src/sdk/host/control/runtime-gate.ts +40 -0
- package/src/sdk/host/host.ts +63 -12
- package/src/sdk/host/query/handlers.ts +66 -7
- package/src/sdk/host/reverse-leases.ts +2 -2
- package/src/sdk/host/sdk-surface-parity.test.ts +1 -1
- package/src/sdk/host/session-runtime.test.ts +2787 -34
- package/src/sdk/host/session-runtime.ts +1489 -101
- package/src/sdk/host/surface-policy.ts +12 -8
- package/src/sdk/host/types.ts +1 -1
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +31 -59
- package/src/sdk/host/websocket-transport.ts +85 -50
- package/src/sdk/index.ts +2 -1
- package/src/sdk/lifecycle/broker-client.ts +53 -0
- package/src/sdk/lifecycle/client.ts +234 -0
- package/src/sdk/lifecycle/index.ts +3 -0
- package/src/sdk/{bus/recent-activity.ts → lifecycle/recent-sessions.ts} +5 -2
- package/src/sdk/lifecycle/service.ts +720 -0
- package/src/sdk/mcp/server.ts +226 -188
- package/src/sdk/prompt-deadline-lease.ts +55 -0
- package/src/sdk/prompt-deadline-manager.ts +148 -0
- package/src/sdk/prompt-status.ts +11 -3
- package/src/sdk/protocol/operation-inventory.generated.json +272 -129
- package/src/sdk/protocol/operation-registry.ts +71 -8
- package/src/sdk/receipt-state.ts +43 -0
- package/src/sdk/reconciliation-extensions.ts +14 -0
- package/src/sdk/router/index.ts +1 -0
- package/src/sdk/router/session-router.ts +1658 -0
- package/src/sdk/session-list.ts +93 -0
- package/src/sdk/session-reconnect.ts +45 -1
- package/src/sdk/session.ts +716 -120
- package/src/sdk/transport/serve-cli.ts +18 -34
- package/src/session/account-inventory.ts +603 -0
- package/src/session/agent-session.ts +2873 -559
- package/src/session/agent-storage.ts +35 -0
- package/src/session/blob-store.ts +32 -1
- package/src/session/coordinator-tool-label.ts +40 -0
- package/src/session/internal/managed-session-scope.ts +4 -0
- package/src/session/internal/managed-session-storage.ts +199 -31
- package/src/session/messages.ts +1 -1
- package/src/session/secure-token-file.ts +80 -0
- package/src/session/session-manager.ts +757 -57
- package/src/session/session-storage.ts +25 -16
- package/src/session/startup-auth-config.ts +297 -0
- package/src/session/terminal-abort.ts +1253 -0
- package/src/session/yield-queue.ts +57 -15
- package/src/session-import/claude.ts +334 -0
- package/src/session-import/codex.ts +1033 -0
- package/src/session-import/command.ts +77 -0
- package/src/session-import/detect.ts +133 -0
- package/src/session-import/index.ts +7 -0
- package/src/session-import/provider-codex.ts +327 -0
- package/src/session-import/provider-service.ts +457 -0
- package/src/session-import/redact.ts +128 -0
- package/src/session-import/service.ts +1264 -0
- package/src/session-import/types.ts +148 -0
- package/src/setup/paseo/check.ts +213 -0
- package/src/setup/paseo/install-saga.ts +293 -0
- package/src/setup/paseo/json-publisher.ts +263 -0
- package/src/setup/paseo/orchestration-preferences.ts +86 -0
- package/src/setup/paseo/paseo-ownership.ts +224 -0
- package/src/setup/paseo/paseo-setup.ts +253 -0
- package/src/setup/paseo/provider-config.ts +139 -0
- package/src/setup/paseo/remove.ts +183 -0
- package/src/setup/paseo/result-types.ts +79 -0
- package/src/setup/paseo/setup-deps.ts +175 -0
- package/src/setup/paseo/skills-bridge.ts +260 -0
- package/src/skill-state/active-state.ts +21 -11
- package/src/slash-commands/acp-builtins.ts +9 -1
- package/src/slash-commands/builtin-registry.ts +117 -19
- package/src/slash-commands/helpers/credential-switch.ts +143 -0
- package/src/slash-commands/helpers/mcp.ts +9 -3
- package/src/slash-commands/helpers/usage-report.ts +61 -56
- package/src/slash-commands/types.ts +7 -2
- package/src/task/executor.ts +30 -11
- package/src/task/index.ts +66 -7
- package/src/task/render.ts +23 -9
- package/src/tools/ask-answer-registry.ts +23 -7
- package/src/tools/ask.ts +8 -4
- package/src/tools/bash-sleep-advisory.ts +115 -0
- package/src/tools/bash.ts +98 -18
- package/src/tools/browser/attach.ts +71 -3
- package/src/tools/browser/launch.ts +86 -13
- package/src/tools/browser/profile-discovery.ts +57 -7
- package/src/tools/browser/render.ts +8 -1
- package/src/tools/browser.ts +130 -21
- package/src/tools/computer.enforcement.test.ts +1 -1
- package/src/tools/computer.ts +3 -2
- package/src/tools/cron.ts +12 -1
- package/src/tools/image-gen.ts +349 -142
- package/src/tools/index.ts +8 -0
- package/src/tools/job.ts +33 -6
- package/src/tools/monitor.ts +41 -2
- package/src/tools/skill-discovery.ts +21 -29
- package/src/tools/subagent.ts +142 -24
- package/src/tools/todo-contract.ts +55 -3
- package/src/tools/todo-write.ts +4 -3
- package/src/tools/tool-catalog.generated.ts +6 -6
- package/src/tools/ultragoal-ask-guard.ts +10 -3
- package/src/utils/herdr-pane.ts +345 -0
- package/src/utils/title-generator.ts +2 -0
- package/src/web/scrapers/index.ts +6 -4
- package/dist/types/cli/malloc-env-guard.test.d.ts +0 -1
- package/dist/types/defaults/gjc-defaults.test.d.ts +0 -1
- package/dist/types/memory-backend/lazy-loading.test.d.ts +0 -1
- package/dist/types/runtime/boot-ordering.test.d.ts +0 -1
- package/dist/types/runtime/lazy-service.test.d.ts +0 -1
- package/dist/types/runtime/network-prewarm-service.test.d.ts +0 -1
- package/dist/types/runtime/workspace-tree-service.test.d.ts +0 -1
- package/dist/types/runtime-mcp/config.test.d.ts +0 -1
- package/dist/types/runtime-mcp/http.test.d.ts +0 -1
- package/dist/types/runtime-mcp/manager-pool.test.d.ts +0 -1
- package/dist/types/runtime-mcp/pool-key.test.d.ts +0 -1
- package/dist/types/runtime-mcp/pool.test.d.ts +0 -1
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +0 -117
- package/dist/types/sdk/bus/lifecycle-orchestrator.d.ts +0 -141
- package/dist/types/sdk/bus/telegram-cli.d.ts +0 -31
- package/dist/types/sdk/elevation/allowlist.d.ts +0 -20
- package/dist/types/sdk/elevation/audit.d.ts +0 -93
- package/dist/types/sdk/elevation/capability.d.ts +0 -3
- package/dist/types/sdk/elevation/digest.d.ts +0 -72
- package/dist/types/sdk/elevation/dispatch-receipt.d.ts +0 -85
- package/dist/types/sdk/elevation/grant-ledger.d.ts +0 -163
- package/dist/types/sdk/elevation/owner.d.ts +0 -48
- package/dist/types/sdk/host/import-graph.test.d.ts +0 -1
- package/dist/types/sdk/host/sdk-surface-parity.test.d.ts +0 -1
- package/dist/types/sdk/host/session-runtime.test.d.ts +0 -1
- package/dist/types/sdk/host/websocket-transport.lifecycle.test.d.ts +0 -1
- package/dist/types/session/auth-broker-config.d.ts +0 -13
- package/dist/types/session/heap-eviction-artifacts.test.d.ts +0 -1
- package/dist/types/skills/skills.test.d.ts +0 -1
- package/dist/types/slash-commands/notify-command.test.d.ts +0 -1
- package/dist/types/task/token-log.test.d.ts +0 -1
- package/dist/types/tools/computer.enforcement.test.d.ts +0 -1
- package/dist/types/tools/descriptors.test.d.ts +0 -1
- package/scripts/g005-daemon-smoke.ts +0 -180
- package/scripts/g011-daemon-path-smoke.ts +0 -153
- package/src/sdk/bus/lifecycle-control-runtime.ts +0 -1733
- package/src/sdk/bus/lifecycle-orchestrator.ts +0 -489
- package/src/sdk/bus/telegram-cli.ts +0 -212
- package/src/sdk/elevation/allowlist.ts +0 -54
- package/src/sdk/elevation/audit.ts +0 -208
- package/src/sdk/elevation/capability.ts +0 -41
- package/src/sdk/elevation/digest.ts +0 -129
- package/src/sdk/elevation/dispatch-receipt.ts +0 -184
- package/src/sdk/elevation/grant-ledger.ts +0 -1142
- package/src/sdk/elevation/owner.ts +0 -109
- package/src/session/auth-broker-config.ts +0 -109
- /package/dist/types/{ai-core-import-gate.test.d.ts → discovery/claude-hooks.d.ts} +0 -0
- /package/dist/types/{cli/fixture-report.test.d.ts → discovery/codex-hooks.d.ts} +0 -0
- /package/dist/types/sdk/{bus/recent-activity.d.ts → lifecycle/recent-sessions.d.ts} +0 -0
package/src/tools/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { AgentTelemetryConfig, AgentTool } from "@gajae-code/agent-core";
|
|
2
2
|
import type { Model, ServiceTier, ToolChoice } from "@gajae-code/ai/core";
|
|
3
3
|
import { $env, logger } from "@gajae-code/utils";
|
|
4
|
+
import type { AsyncJobManager } from "../async";
|
|
4
5
|
import type { PromptTemplate } from "../config/prompt-templates";
|
|
5
6
|
import type { Settings } from "../config/settings";
|
|
6
7
|
import type { Skill } from "../extensibility/skills";
|
|
@@ -217,6 +218,8 @@ export interface ToolSession {
|
|
|
217
218
|
hasForegroundBashBackgroundRequestHandler?: () => boolean;
|
|
218
219
|
/** Request that the active managed foreground bash call fold into a background job, if supported. */
|
|
219
220
|
requestForegroundBashBackground?: () => boolean;
|
|
221
|
+
/** Get the session-owned or inherited async job manager. */
|
|
222
|
+
getAsyncJobManager?: () => AsyncJobManager | undefined;
|
|
220
223
|
/** Get session ID */
|
|
221
224
|
getSessionId?: () => string | null;
|
|
222
225
|
/** Get credential-selection session identity. */
|
|
@@ -279,6 +282,11 @@ export interface ToolSession {
|
|
|
279
282
|
agentOutputManager?: AgentOutputManager;
|
|
280
283
|
/** Settings instance for passing to subagents */
|
|
281
284
|
settings: Settings;
|
|
285
|
+
/**
|
|
286
|
+
* The session's REQUESTED effective agent directory, independent of the
|
|
287
|
+
* global Settings singleton (which can be reused across sessions).
|
|
288
|
+
*/
|
|
289
|
+
getSessionAgentDir?: () => string;
|
|
282
290
|
/** Live service-tier intent of the parent session, inherited by `inherit` subagents. */
|
|
283
291
|
serviceTier?: ServiceTier;
|
|
284
292
|
/** Whether the effective subagent tier grants fast mode for a resolved provider. */
|
package/src/tools/job.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { type AsyncJob, AsyncJobManager, isBackgroundJobSupportEnabled, jobElaps
|
|
|
7
7
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
8
8
|
import type { Theme } from "../modes/theme/theme";
|
|
9
9
|
import jobDescription from "../prompts/tools/job.md" with { type: "text" };
|
|
10
|
+
import { lookupOwnedRegistration, unregisterOwnedRegistration } from "../session/terminal-abort";
|
|
10
11
|
import { Ellipsis, Hasher, type RenderCache, renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
|
|
11
12
|
import type { ToolSession } from "./index";
|
|
12
13
|
import {
|
|
@@ -100,7 +101,10 @@ export class JobTool implements AgentTool<typeof jobSchema, JobToolDetails> {
|
|
|
100
101
|
onUpdate?: AgentToolUpdateCallback<JobToolDetails>,
|
|
101
102
|
_context?: AgentToolContext,
|
|
102
103
|
): Promise<AgentToolResult<JobToolDetails>> {
|
|
103
|
-
const manager =
|
|
104
|
+
const manager =
|
|
105
|
+
this.session.getAsyncJobManager?.() ??
|
|
106
|
+
AsyncJobManager.forEndpoint(this.session.getSessionId?.() ?? undefined) ??
|
|
107
|
+
AsyncJobManager.instance();
|
|
104
108
|
if (!manager) {
|
|
105
109
|
return {
|
|
106
110
|
content: [{ type: "text", text: "Async execution is disabled; no background jobs are available." }],
|
|
@@ -237,7 +241,7 @@ export class JobTool implements AgentTool<typeof jobSchema, JobToolDetails> {
|
|
|
237
241
|
const PROGRESS_INTERVAL_MS = 500;
|
|
238
242
|
const emitProgress = () => {
|
|
239
243
|
if (!onUpdate) return;
|
|
240
|
-
const snapshot = this.#snapshotJobs(allTrackedJobs);
|
|
244
|
+
const snapshot = this.#snapshotJobs(manager, allTrackedJobs);
|
|
241
245
|
onUpdate({
|
|
242
246
|
content: [{ type: "text", text: "" }],
|
|
243
247
|
details: {
|
|
@@ -318,6 +322,7 @@ export class JobTool implements AgentTool<typeof jobSchema, JobToolDetails> {
|
|
|
318
322
|
}
|
|
319
323
|
|
|
320
324
|
#snapshotJobs(
|
|
325
|
+
manager: AsyncJobManager,
|
|
321
326
|
jobs: {
|
|
322
327
|
id: string;
|
|
323
328
|
type: "bash" | "task";
|
|
@@ -331,7 +336,7 @@ export class JobTool implements AgentTool<typeof jobSchema, JobToolDetails> {
|
|
|
331
336
|
): JobSnapshot[] {
|
|
332
337
|
const now = Date.now();
|
|
333
338
|
return jobs.map(j => {
|
|
334
|
-
const current =
|
|
339
|
+
const current = manager.getJob(j.id);
|
|
335
340
|
const latest = current ?? j;
|
|
336
341
|
return {
|
|
337
342
|
id: latest.id,
|
|
@@ -366,9 +371,31 @@ export class JobTool implements AgentTool<typeof jobSchema, JobToolDetails> {
|
|
|
366
371
|
seen.add(j.id);
|
|
367
372
|
return true;
|
|
368
373
|
});
|
|
369
|
-
const jobResults = this.#snapshotJobs(uniqueJobs);
|
|
370
|
-
|
|
371
|
-
|
|
374
|
+
const jobResults = this.#snapshotJobs(manager, uniqueJobs);
|
|
375
|
+
|
|
376
|
+
// Only COMPLETED/FAILED/CANCELLED jobs are terminal for ownership
|
|
377
|
+
// retirement: a paused subagent is not quiescent (settleOwnedWork
|
|
378
|
+
// cancels paused jobs before it can claim stopped_owned), so its
|
|
379
|
+
// ownership tuple must stay registered until it is actually cancelled
|
|
380
|
+
// — otherwise a scope:"owned" abort could find an empty causal set and
|
|
381
|
+
// report stopped_owned while the job remains visibly paused (review
|
|
382
|
+
// thread P2).
|
|
383
|
+
const terminalJobs = jobResults.filter(
|
|
384
|
+
j => j.status === "completed" || j.status === "failed" || j.status === "cancelled",
|
|
385
|
+
);
|
|
386
|
+
manager.acknowledgeDeliveries(terminalJobs.map(j => j.id));
|
|
387
|
+
// A terminal job whose deliveries were just acknowledged is
|
|
388
|
+
// synchronously consumed: its owned registration is settled and must
|
|
389
|
+
// not occupy the registry, otherwise the retained-policy tombstone
|
|
390
|
+
// treats it as a live policy occupant forever and its FIFO fallback can
|
|
391
|
+
// evict a genuinely running job's policy (review thread P2).
|
|
392
|
+
for (const job of terminalJobs) {
|
|
393
|
+
const generation = manager.getJob?.(job.id)?.generation;
|
|
394
|
+
if (!generation) continue;
|
|
395
|
+
// The endpoint disambiguates concurrent sessions' same job ids (review P1).
|
|
396
|
+
const registration = lookupOwnedRegistration(job.id, generation, this.session.getSessionId?.() ?? "local");
|
|
397
|
+
if (registration) unregisterOwnedRegistration(registration);
|
|
398
|
+
}
|
|
372
399
|
|
|
373
400
|
const completed = jobResults.filter(j => j.status !== "running");
|
|
374
401
|
const running = jobResults.filter(j => j.status === "running");
|
package/src/tools/monitor.ts
CHANGED
|
@@ -4,6 +4,7 @@ import * as z from "zod/v4";
|
|
|
4
4
|
import { AsyncJobManager, isBackgroundJobSupportEnabled } from "../async";
|
|
5
5
|
import monitorDescription from "../prompts/tools/monitor.md" with { type: "text" };
|
|
6
6
|
import { truncateTail } from "../session/streaming-output";
|
|
7
|
+
import { lookupOwnedRegistration } from "../session/terminal-abort";
|
|
7
8
|
import { BashTool } from "./bash";
|
|
8
9
|
import type { ToolSession } from "./index";
|
|
9
10
|
import { ToolError } from "./tool-errors";
|
|
@@ -106,13 +107,20 @@ export class MonitorTool implements AgentTool<typeof monitorSchema, MonitorToolD
|
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
async execute(
|
|
109
|
-
|
|
110
|
+
toolCallId: string,
|
|
110
111
|
params: MonitorParams,
|
|
111
112
|
_signal?: AbortSignal,
|
|
112
113
|
_onUpdate?: AgentToolUpdateCallback<MonitorToolDetails>,
|
|
113
114
|
context?: AgentToolContext,
|
|
114
115
|
): Promise<AgentToolResult<MonitorToolDetails>> {
|
|
115
|
-
|
|
116
|
+
// The session's ENDPOINT-owned manager first: the monitor job is created
|
|
117
|
+
// in it, its generation is read from it, and non-persistent cancel must
|
|
118
|
+
// stop that exact job — the process-global instance may belong to a
|
|
119
|
+
// different concurrent top-level session (review thread P1).
|
|
120
|
+
const manager =
|
|
121
|
+
this.session.getAsyncJobManager?.() ??
|
|
122
|
+
AsyncJobManager.forEndpoint(this.session.getSessionId?.() ?? undefined) ??
|
|
123
|
+
AsyncJobManager.instance();
|
|
116
124
|
if (!manager) {
|
|
117
125
|
throw new ToolError("Async execution is disabled; the monitor tool is unavailable in this session.");
|
|
118
126
|
}
|
|
@@ -169,8 +177,38 @@ export class MonitorTool implements AgentTool<typeof monitorSchema, MonitorToolD
|
|
|
169
177
|
const suffix = count > 0 ? `\n(+${count} earlier lines)` : "";
|
|
170
178
|
const notificationLine = formatMonitorNotificationLine(line);
|
|
171
179
|
const content = `<task-notification>\nMonitor task ${jobId} (${params.kind}: ${params.description}) emitted latest state:\n${notificationLine.content}${suffix}\n</task-notification>`;
|
|
180
|
+
// Route the notification through the SAME owned-completion envelope
|
|
181
|
+
// and fresh-admission path as async results: a scope:"turn" abort
|
|
182
|
+
// that left this monitor running must resume the agent with a FRESH
|
|
183
|
+
// lineage (never the aborted attempt's), and scope:"owned" must drop
|
|
184
|
+
// it. The envelope is built from the tool-call lineage binding and
|
|
185
|
+
// the exact registered tuple; monitors without a registration stay
|
|
186
|
+
// ordinary. The standalone generation is NOT persisted — it lives in
|
|
187
|
+
// the envelope, which INTERNAL_DETAILS_FIELDS strips (review threads
|
|
188
|
+
// P1/P2).
|
|
189
|
+
const generation = manager.getJob(jobId)?.generation;
|
|
190
|
+
// Build the envelope from the RETAINED registration (which carries the
|
|
191
|
+
// complete lineage tuple), not the tool-call binding: the binding map
|
|
192
|
+
// is separately bounded and can evict a long-lived monitor's entry,
|
|
193
|
+
// but the registration keeps the lineage for owned classification
|
|
194
|
+
// (review thread P2).
|
|
195
|
+
// The lookup is ENDPOINT-scoped to THIS monitor's session: concurrent
|
|
196
|
+
// sessions have monitors with the same manager-local job id, and an
|
|
197
|
+
// endpoint-less fallback scan could attach a foreign session's
|
|
198
|
+
// registration (review thread P2).
|
|
199
|
+
const registration = generation
|
|
200
|
+
? lookupOwnedRegistration(jobId, generation, this.session.getSessionId?.() ?? "local")
|
|
201
|
+
: undefined;
|
|
202
|
+
const ownedCompletion = registration
|
|
203
|
+
? {
|
|
204
|
+
lineageIdHash: registration.lineageIdHash,
|
|
205
|
+
promptAttemptEpoch: registration.promptAttemptEpoch,
|
|
206
|
+
registration,
|
|
207
|
+
}
|
|
208
|
+
: undefined;
|
|
172
209
|
const details = {
|
|
173
210
|
taskId: jobId,
|
|
211
|
+
...(ownedCompletion ? { ownedCompletions: [ownedCompletion] } : {}),
|
|
174
212
|
kind: params.kind,
|
|
175
213
|
description: params.description,
|
|
176
214
|
monitor: true,
|
|
@@ -219,6 +257,7 @@ export class MonitorTool implements AgentTool<typeof monitorSchema, MonitorToolD
|
|
|
219
257
|
ownerId,
|
|
220
258
|
label,
|
|
221
259
|
ctx: context,
|
|
260
|
+
toolCallId,
|
|
222
261
|
shouldAcceptRawLine: () => !controller.closed,
|
|
223
262
|
lifecycle: {
|
|
224
263
|
onCancel: () => closeMonitor("purge"),
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { AgentTool, AgentToolResult } from "@gajae-code/agent-core";
|
|
2
2
|
import { prompt, untilAborted } from "@gajae-code/utils";
|
|
3
3
|
import * as z from "zod/v4";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
describeDisabledSkillScopes,
|
|
6
|
+
discoverRuntimeSkills,
|
|
7
|
+
type RuntimeSkillDiscoveryCandidate,
|
|
8
|
+
} from "../extensibility/runtime-skill-discovery";
|
|
5
9
|
import skillDiscoveryDescription from "../prompts/tools/skill-discovery.md" with { type: "text" };
|
|
6
10
|
import type { ToolSession } from ".";
|
|
7
11
|
|
|
@@ -23,11 +27,18 @@ export interface SkillDiscoveryToolDetails {
|
|
|
23
27
|
count: number;
|
|
24
28
|
/**
|
|
25
29
|
* Present only when zero candidates were returned AND discovery config gates
|
|
26
|
-
* (`skills.enabled` / `skills.
|
|
30
|
+
* (`skills.enabled` / `skills.trustProjectSkills` / `skills.trustUserSkills`)
|
|
27
31
|
* prevented some or all of the requested scope from being searched. Without
|
|
28
32
|
* this, a disabled config is indistinguishable from "no skills exist".
|
|
29
33
|
*/
|
|
30
34
|
notice?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Human-readable diagnostics for skills that were scanned but not
|
|
37
|
+
* advertised (protected-name collisions with bundled workflow skills,
|
|
38
|
+
* include/ignore/disable policy filters, invalid frontmatter, shadowing,
|
|
39
|
+
* scan failures). Bounded; empty when nothing was filtered.
|
|
40
|
+
*/
|
|
41
|
+
diagnostics?: string[];
|
|
31
42
|
}
|
|
32
43
|
|
|
33
44
|
export class SkillDiscoveryTool implements AgentTool<typeof skillDiscoverySchema, SkillDiscoveryToolDetails> {
|
|
@@ -65,16 +76,20 @@ export class SkillDiscoveryTool implements AgentTool<typeof skillDiscoverySchema
|
|
|
65
76
|
): Promise<AgentToolResult<SkillDiscoveryToolDetails>> {
|
|
66
77
|
return untilAborted(signal, async () => {
|
|
67
78
|
const source = input.source ?? "all";
|
|
68
|
-
const
|
|
79
|
+
const result = await discoverRuntimeSkills({
|
|
69
80
|
cwd: this.#session.cwd,
|
|
70
81
|
query: input.query,
|
|
71
82
|
source,
|
|
72
83
|
limit: input.limit,
|
|
73
84
|
policy: this.#getRuntimeSkillPolicy(),
|
|
74
85
|
});
|
|
75
|
-
const details: SkillDiscoveryToolDetails = {
|
|
76
|
-
|
|
77
|
-
|
|
86
|
+
const details: SkillDiscoveryToolDetails = {
|
|
87
|
+
candidates: result.candidates,
|
|
88
|
+
count: result.candidates.length,
|
|
89
|
+
};
|
|
90
|
+
if (result.diagnostics.messages.length > 0) details.diagnostics = result.diagnostics.messages;
|
|
91
|
+
if (result.candidates.length === 0) {
|
|
92
|
+
const notice = describeDisabledSkillScopes(source, this.#getRuntimeSkillPolicy());
|
|
78
93
|
if (notice) details.notice = notice;
|
|
79
94
|
}
|
|
80
95
|
return {
|
|
@@ -83,27 +98,4 @@ export class SkillDiscoveryTool implements AgentTool<typeof skillDiscoverySchema
|
|
|
83
98
|
};
|
|
84
99
|
});
|
|
85
100
|
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Explain an empty result that is caused by disabled discovery config rather
|
|
89
|
-
* than by an actually empty skill catalog.
|
|
90
|
-
*/
|
|
91
|
-
#disabledPolicyNotice(source: "all" | "project" | "user"): string | undefined {
|
|
92
|
-
const policy = this.#getRuntimeSkillPolicy();
|
|
93
|
-
if (policy.enabled !== true) {
|
|
94
|
-
return "Runtime skill discovery is disabled: `skills.enabled` is false, so no skill directories were searched. Enable it with `gjc config set skills.enabled true` (project and user scopes additionally require `skills.enablePiProject` / `skills.enablePiUser`).";
|
|
95
|
-
}
|
|
96
|
-
const skipped: string[] = [];
|
|
97
|
-
const commands: string[] = [];
|
|
98
|
-
if ((source === "all" || source === "project") && policy.enablePiProject !== true) {
|
|
99
|
-
skipped.push("project (`skills.enablePiProject` is false)");
|
|
100
|
-
commands.push("`gjc config set skills.enablePiProject true`");
|
|
101
|
-
}
|
|
102
|
-
if ((source === "all" || source === "user") && policy.enablePiUser !== true) {
|
|
103
|
-
skipped.push("user (`skills.enablePiUser` is false)");
|
|
104
|
-
commands.push("`gjc config set skills.enablePiUser true`");
|
|
105
|
-
}
|
|
106
|
-
if (skipped.length === 0) return undefined;
|
|
107
|
-
return `Skill discovery skipped disabled scope(s): ${skipped.join(", ")}. Enable them with ${commands.join(" and ")}.`;
|
|
108
|
-
}
|
|
109
101
|
}
|
package/src/tools/subagent.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@gajae-code/agent-core";
|
|
3
|
-
import { prompt } from "@gajae-code/utils";
|
|
3
|
+
import { formatDuration, logger, prompt } from "@gajae-code/utils";
|
|
4
4
|
import * as z from "zod/v4";
|
|
5
5
|
import { type AsyncJob, AsyncJobManager, jobElapsedMs, type SubagentRecord } from "../async";
|
|
6
6
|
import subagentDescription from "../prompts/tools/subagent.md" with { type: "text" };
|
|
@@ -12,6 +12,15 @@ import { ToolError } from "./tool-errors";
|
|
|
12
12
|
|
|
13
13
|
const DEFAULT_AWAIT_TIMEOUT_MS = 30_000;
|
|
14
14
|
const MAX_AWAIT_TIMEOUT_MS = 60 * 60 * 1000;
|
|
15
|
+
/**
|
|
16
|
+
* Bounded cadence for await liveness: even when the rendered-state signature is
|
|
17
|
+
* stable (a running subagent emitting no new progress), the await panel re-emits
|
|
18
|
+
* so a healthy wait never looks like a hung session (issue #4465). Derived from
|
|
19
|
+
* `heartbeat_ms` so callers keep one knob, floor-bounded so a small heartbeat
|
|
20
|
+
* cannot turn liveness into transcript spam, and injected for tests.
|
|
21
|
+
*/
|
|
22
|
+
const AWAIT_LIVENESS_MULTIPLIER = 30;
|
|
23
|
+
const AWAIT_LIVENESS_MIN_INTERVAL_MS = 15_000;
|
|
15
24
|
const DEFAULT_LIST_LIMIT = 10;
|
|
16
25
|
const MAX_LIST_LIMIT = 50;
|
|
17
26
|
const RECEIPT_PREVIEW_WIDTH = 280;
|
|
@@ -123,6 +132,22 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
123
132
|
readonly parameters = subagentSchema;
|
|
124
133
|
readonly strict = true;
|
|
125
134
|
readonly loadMode = "discoverable";
|
|
135
|
+
/**
|
|
136
|
+
* Injected monotonic clock for await-liveness tests. Production callers leave
|
|
137
|
+
* this undefined and the await falls back to `Date.now`; tests substitute a
|
|
138
|
+
* virtual clock so a 15s+ liveness interval is exercised without any real
|
|
139
|
+
* multi-minute sleep (#4465).
|
|
140
|
+
*/
|
|
141
|
+
#livenessNowMs?: () => number;
|
|
142
|
+
|
|
143
|
+
/** Test-only seam: substitute the liveness clock. Returns a restore function. */
|
|
144
|
+
withLivenessClock(nowMs: () => number): () => void {
|
|
145
|
+
const prior = this.#livenessNowMs;
|
|
146
|
+
this.#livenessNowMs = nowMs;
|
|
147
|
+
return () => {
|
|
148
|
+
this.#livenessNowMs = prior;
|
|
149
|
+
};
|
|
150
|
+
}
|
|
126
151
|
|
|
127
152
|
constructor(private readonly session: ToolSession) {
|
|
128
153
|
this.description = prompt.render(subagentDescription);
|
|
@@ -135,7 +160,16 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
135
160
|
onUpdate?: AgentToolUpdateCallback<SubagentToolDetails>,
|
|
136
161
|
_context?: AgentToolContext,
|
|
137
162
|
): Promise<AgentToolResult<SubagentToolDetails>> {
|
|
138
|
-
|
|
163
|
+
// The session's ENDPOINT-owned manager first: concurrent top-level
|
|
164
|
+
// sessions register their manager under their endpoint (sdk/session.ts),
|
|
165
|
+
// so list/pause/resume/message/cancel/await must inspect THIS session's
|
|
166
|
+
// manager — the process-global instance belongs to the last-created
|
|
167
|
+
// session, where this session's subagent records and jobs are absent
|
|
168
|
+
// or belong to a same-id subagent of another session (review thread P1).
|
|
169
|
+
const manager =
|
|
170
|
+
this.session.getAsyncJobManager?.() ??
|
|
171
|
+
AsyncJobManager.forEndpoint(this.session.getSessionId?.() ?? undefined) ??
|
|
172
|
+
AsyncJobManager.instance();
|
|
139
173
|
if (!manager) {
|
|
140
174
|
return {
|
|
141
175
|
content: [{ type: "text", text: "No subagent manager is available in this session." }],
|
|
@@ -241,7 +275,7 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
241
275
|
records.push(record);
|
|
242
276
|
terminalGuidanceIds.add(record.subagentId);
|
|
243
277
|
} else {
|
|
244
|
-
const result = manager.resumeSubagent(record.subagentId, ownerFilter, params.message);
|
|
278
|
+
const result = manager.resumeSubagent(record.subagentId, ownerFilter, params.message, _toolCallId);
|
|
245
279
|
if (!result.ok && result.reason === "context_unavailable") throw new ToolError("context unavailable");
|
|
246
280
|
if (!result.ok && result.reason === "not_found") {
|
|
247
281
|
missing.push(this.#missingSnapshot(id, "not_found", "No visible detached subagent matches this id."));
|
|
@@ -293,7 +327,7 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
293
327
|
records.push(manager.getSubagentRecord(record.subagentId, ownerFilter) ?? record);
|
|
294
328
|
steerStates.set(record.subagentId, "queued");
|
|
295
329
|
} else {
|
|
296
|
-
const result = manager.resumeSubagent(record.subagentId, ownerFilter, message);
|
|
330
|
+
const result = manager.resumeSubagent(record.subagentId, ownerFilter, message, _toolCallId);
|
|
297
331
|
if (!result.ok && result.reason === "not_found") {
|
|
298
332
|
missing.push(this.#missingSnapshot(id, "not_found", "No visible detached subagent matches this id."));
|
|
299
333
|
} else if (!result.ok) {
|
|
@@ -402,23 +436,71 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
402
436
|
});
|
|
403
437
|
}
|
|
404
438
|
const watchedJobIds = targets.map(target => target.jobId).filter((jobId): jobId is string => jobId !== null);
|
|
405
|
-
manager.
|
|
439
|
+
const watchHandle = manager.watchJobGenerations(watchedJobIds);
|
|
406
440
|
const heartbeatMs = params.heartbeat_ms === undefined ? 500 : params.heartbeat_ms;
|
|
441
|
+
// Liveness interval: force a re-emit even when the rendered-state signature
|
|
442
|
+
// is stable so a healthy wait never looks like a hung session (#4465). The
|
|
443
|
+
// `#livenessNowMs` clock is injected for deterministic tests; `Date.now`
|
|
444
|
+
// is the production fallback. The interval is floor-bounded so a caller who
|
|
445
|
+
// sets a tiny `heartbeat_ms` cannot turn liveness into transcript spam.
|
|
446
|
+
const livenessIntervalMs = Math.max(AWAIT_LIVENESS_MIN_INTERVAL_MS, heartbeatMs * AWAIT_LIVENESS_MULTIPLIER);
|
|
447
|
+
const nowMs = this.#livenessNowMs ?? Date.now;
|
|
448
|
+
let lastEmitMs = nowMs();
|
|
407
449
|
let lastEmittedSignature: string | undefined;
|
|
450
|
+
let streamingDisabled = false;
|
|
451
|
+
let stopProgressTimer = (): void => {};
|
|
452
|
+
const disableStreaming = (error: unknown): void => {
|
|
453
|
+
if (streamingDisabled) return;
|
|
454
|
+
streamingDisabled = true;
|
|
455
|
+
stopProgressTimer();
|
|
456
|
+
try {
|
|
457
|
+
logger.warn("Subagent await progress update failed; streaming disabled for this wait", {
|
|
458
|
+
error: safeThrownValue(error),
|
|
459
|
+
});
|
|
460
|
+
} catch {
|
|
461
|
+
// Diagnostics must never turn a recoverable progress-channel failure
|
|
462
|
+
// into an await or process-lifecycle failure.
|
|
463
|
+
}
|
|
464
|
+
};
|
|
408
465
|
const emitIfChanged = (force: boolean): void => {
|
|
409
|
-
if (!onUpdate) return;
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
466
|
+
if (!onUpdate || streamingDisabled) return;
|
|
467
|
+
try {
|
|
468
|
+
const result = this.#progressResult(manager, records, true);
|
|
469
|
+
const signature = subagentAwaitRenderedStateSignature(result.details?.subagents ?? []);
|
|
470
|
+
const t = nowMs();
|
|
471
|
+
const livenessDue = force || t - lastEmitMs >= livenessIntervalMs;
|
|
472
|
+
if (!livenessDue && signature === lastEmittedSignature) return;
|
|
473
|
+
lastEmittedSignature = signature;
|
|
474
|
+
lastEmitMs = t;
|
|
475
|
+
// A TypeScript void-return callback may still be implemented by an
|
|
476
|
+
// async function. Observe its runtime result so a rejected promise or
|
|
477
|
+
// thenable cannot become an unhandled rejection outside this span.
|
|
478
|
+
const updateResult = (onUpdate as (update: AgentToolResult<SubagentToolDetails>) => unknown)(result);
|
|
479
|
+
if (isPromiseLike(updateResult)) void Promise.resolve(updateResult).catch(disableStreaming);
|
|
480
|
+
} catch (error) {
|
|
481
|
+
// The liveness timer fires outside this function's promise chain, so a
|
|
482
|
+
// throwing progress consumer would otherwise escape `setInterval` as an
|
|
483
|
+
// uncaught exception, leave the wait's cleanup unreached, and let the
|
|
484
|
+
// interval keep firing and rethrowing for the rest of the await. Retire
|
|
485
|
+
// the streaming channel instead and keep waiting: losing progress output
|
|
486
|
+
// is recoverable, losing the timer and the watch registration is not.
|
|
487
|
+
disableStreaming(error);
|
|
488
|
+
}
|
|
415
489
|
};
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
490
|
+
// The initial emission and the timer own process-lifetime resources together
|
|
491
|
+
// with the watch registration and the terminal-wait handle, so they all live
|
|
492
|
+
// inside one guarded span rather than straddling it.
|
|
493
|
+
let progressTimer: Timer | undefined;
|
|
419
494
|
let waitOutcome: "completed" | "timed_out_wait" | "interrupted";
|
|
420
495
|
let onAbort: (() => void) | undefined;
|
|
496
|
+
let terminalJobIds: string[] | undefined;
|
|
421
497
|
try {
|
|
498
|
+
progressTimer = onUpdate && heartbeatMs > 0 ? setInterval(() => emitIfChanged(false), heartbeatMs) : undefined;
|
|
499
|
+
stopProgressTimer = () => {
|
|
500
|
+
if (progressTimer) clearInterval(progressTimer);
|
|
501
|
+
progressTimer = undefined;
|
|
502
|
+
};
|
|
503
|
+
emitIfChanged(true);
|
|
422
504
|
const abortPromise = new Promise<"interrupted">(resolve => {
|
|
423
505
|
onAbort = () => resolve("interrupted");
|
|
424
506
|
if (signal?.aborted) onAbort();
|
|
@@ -432,14 +514,16 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
432
514
|
Bun.sleep(timeoutMs).then(() => "timed_out_wait" as const),
|
|
433
515
|
abortPromise,
|
|
434
516
|
]);
|
|
517
|
+
if (waitOutcome === "completed") {
|
|
518
|
+
terminalJobIds = (await handle.result).terminalJobIds;
|
|
519
|
+
handle.acknowledge(terminalJobIds);
|
|
520
|
+
}
|
|
435
521
|
} finally {
|
|
436
522
|
if (signal && onAbort) signal.removeEventListener("abort", onAbort);
|
|
437
|
-
|
|
523
|
+
stopProgressTimer();
|
|
524
|
+
watchHandle.close();
|
|
525
|
+
handle.close();
|
|
438
526
|
}
|
|
439
|
-
const waitResult = waitOutcome === "completed" ? await handle.result : undefined;
|
|
440
|
-
if (waitOutcome === "completed") handle.acknowledge(waitResult?.terminalJobIds);
|
|
441
|
-
manager.unwatchJobs(watchedJobIds);
|
|
442
|
-
handle.close();
|
|
443
527
|
const awaitOutcome: SubagentAwaitOutcome =
|
|
444
528
|
waitOutcome === "completed" ? "completed" : waitOutcome === "timed_out_wait" ? "timed_out" : "interrupted";
|
|
445
529
|
const finalRecords = this.#visibleRecordsByIds(
|
|
@@ -456,7 +540,7 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
456
540
|
awaitOutcome,
|
|
457
541
|
waitOutcome,
|
|
458
542
|
condition,
|
|
459
|
-
terminalIds:
|
|
543
|
+
terminalIds: terminalJobIds,
|
|
460
544
|
});
|
|
461
545
|
}
|
|
462
546
|
|
|
@@ -558,11 +642,10 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
558
642
|
records: SubagentRecord[],
|
|
559
643
|
attachLiveProgress = false,
|
|
560
644
|
): AgentToolResult<SubagentToolDetails> {
|
|
645
|
+
const subagents = this.#recordSnapshots(manager, records, false, "receipt", new Set(), attachLiveProgress);
|
|
561
646
|
return {
|
|
562
|
-
content: [{ type: "text", text:
|
|
563
|
-
details: {
|
|
564
|
-
subagents: this.#recordSnapshots(manager, records, false, "receipt", new Set(), attachLiveProgress),
|
|
565
|
-
},
|
|
647
|
+
content: [{ type: "text", text: awaitProgressSummary(subagents) }],
|
|
648
|
+
details: { subagents },
|
|
566
649
|
};
|
|
567
650
|
}
|
|
568
651
|
|
|
@@ -810,6 +893,41 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
810
893
|
}
|
|
811
894
|
}
|
|
812
895
|
|
|
896
|
+
/**
|
|
897
|
+
* Human-readable line for streamed `await` progress.
|
|
898
|
+
*
|
|
899
|
+
* Consumers that render structured content (ACP) previously received an empty
|
|
900
|
+
* text block here, which made `extractStructuredText` fail and the mapper fall
|
|
901
|
+
* back to serializing the whole result object as the human-readable content. A
|
|
902
|
+
* real sentence keeps the elapsed time legible there and in any log that only
|
|
903
|
+
* shows tool text.
|
|
904
|
+
*/
|
|
905
|
+
function awaitProgressSummary(subagents: readonly SubagentSnapshot[]): string {
|
|
906
|
+
const waiting = subagents.filter(snapshot => !isTerminalStatus(snapshot.status));
|
|
907
|
+
if (waiting.length === 0) return "";
|
|
908
|
+
// Accumulate rather than spreading into Math.max: explicit `ids` are not
|
|
909
|
+
// capped by MAX_LIST_LIMIT, so a large await would hit the argument limit.
|
|
910
|
+
let longestMs = 0;
|
|
911
|
+
for (const snapshot of waiting) if (snapshot.durationMs > longestMs) longestMs = snapshot.durationMs;
|
|
912
|
+
return `Awaiting ${waiting.length} subagent(s) for ${formatDuration(longestMs)}: ${waiting
|
|
913
|
+
.map(snapshot => snapshot.id)
|
|
914
|
+
.join(", ")}`;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
function isPromiseLike(value: unknown): value is PromiseLike<unknown> {
|
|
918
|
+
if ((typeof value !== "object" || value === null) && typeof value !== "function") return false;
|
|
919
|
+
return typeof (value as { then?: unknown }).then === "function";
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
function safeThrownValue(error: unknown): string {
|
|
923
|
+
try {
|
|
924
|
+
if (error instanceof Error) return error.message;
|
|
925
|
+
return String(error);
|
|
926
|
+
} catch {
|
|
927
|
+
return "[unprintable thrown value]";
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
813
931
|
function isTerminalStatus(status: SubagentStatus): boolean {
|
|
814
932
|
return status === "completed" || status === "failed" || status === "cancelled";
|
|
815
933
|
}
|
|
@@ -50,6 +50,8 @@ const TODO_OP_KEYS = new Set(["op", "list", "task", "phase", "items", "text"]);
|
|
|
50
50
|
const TODO_INIT_ENTRY_KEYS = new Set(["phase", "items"]);
|
|
51
51
|
/** `content` is accepted only as a synonym the schema rewrites to `task`. */
|
|
52
52
|
const TODO_OP_KEYS_WITH_ALIASES = new Set([...TODO_OP_KEYS, "content"]);
|
|
53
|
+
const MAX_REJECTED_KEYS = 8;
|
|
54
|
+
const POSITIONAL_HANDLE_KEYS = new Set(["id", "ids", "index", "taskId", "task_id"]);
|
|
53
55
|
|
|
54
56
|
/**
|
|
55
57
|
* Exact key corrections. `note` is the one repeatable confusion: it is an `op`
|
|
@@ -60,11 +62,27 @@ const TODO_OP_KEYS_WITH_ALIASES = new Set([...TODO_OP_KEYS, "content"]);
|
|
|
60
62
|
* an entry here when the replacement is unambiguous — never from fuzzy or
|
|
61
63
|
* edit-distance matching, because a wrong suggestion costs more turns than no
|
|
62
64
|
* suggestion.
|
|
65
|
+
*
|
|
66
|
+
* The positional-handle family (`id`, `index`, and spellings of them) is the
|
|
67
|
+
* other repeatable confusion: the tool result renders tasks as a list, so a
|
|
68
|
+
* caller assumes the list is addressable by ordinal. No op has ever taken a
|
|
69
|
+
* handle - a task is addressed by its verbatim content - and the executor
|
|
70
|
+
* already says so, but on the validated model-facing path this validator
|
|
71
|
+
* rejects the key first, so that message never gets its turn. One shared
|
|
72
|
+
* correction keeps both layers telling the same story.
|
|
63
73
|
*/
|
|
74
|
+
const POSITIONAL_HANDLE_CORRECTION =
|
|
75
|
+
'tasks have no id or index; target a task with "task" set to its exact content, or a whole phase with "phase"';
|
|
76
|
+
|
|
64
77
|
const TODO_KEY_CORRECTIONS = new Map<string, string>([
|
|
65
78
|
["note", 'note is an op, not a key; note operations require both "task" and "text"'],
|
|
66
79
|
["newTask", "there is no rename op; re-run init with the corrected list to rename a task"],
|
|
67
80
|
["tasks", 'tasks is not a key; append operations take "items"'],
|
|
81
|
+
["id", POSITIONAL_HANDLE_CORRECTION],
|
|
82
|
+
["ids", POSITIONAL_HANDLE_CORRECTION],
|
|
83
|
+
["index", POSITIONAL_HANDLE_CORRECTION],
|
|
84
|
+
["taskId", POSITIONAL_HANDLE_CORRECTION],
|
|
85
|
+
["task_id", POSITIONAL_HANDLE_CORRECTION],
|
|
68
86
|
]);
|
|
69
87
|
|
|
70
88
|
function unknownKeys(value: object, allowed: Set<string>): string[] {
|
|
@@ -72,15 +90,42 @@ function unknownKeys(value: object, allowed: Set<string>): string[] {
|
|
|
72
90
|
}
|
|
73
91
|
|
|
74
92
|
function keyRejectionDetail(keys: readonly string[], location?: string): RawArgumentRejectionDetail {
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
93
|
+
const rejectedKeys = keys.slice(0, MAX_REJECTED_KEYS);
|
|
94
|
+
// Distinct corrections only. A family that shares one correction (every
|
|
95
|
+
// positional handle) would otherwise repeat it once per rejected key and blow
|
|
96
|
+
// past the caller's hint clamp, which truncates the advice mid-sentence.
|
|
97
|
+
const hints = [
|
|
98
|
+
...new Set(
|
|
99
|
+
keys
|
|
100
|
+
.map(key => TODO_KEY_CORRECTIONS.get(key) ?? TODO_KEY_CORRECTIONS.get(key.split(".").at(-1) ?? ""))
|
|
101
|
+
.filter((hint): hint is string => hint !== undefined),
|
|
102
|
+
),
|
|
103
|
+
];
|
|
104
|
+
const omitted = keys.length - rejectedKeys.length;
|
|
105
|
+
const parts = [
|
|
106
|
+
...(location === undefined ? [] : [location]),
|
|
107
|
+
...hints,
|
|
108
|
+
...(omitted > 0 ? [`${omitted} additional rejected keys omitted`] : []),
|
|
109
|
+
];
|
|
110
|
+
return parts.length > 0 ? { rejectedKeys, hint: parts.join("; ") } : { rejectedKeys };
|
|
78
111
|
}
|
|
79
112
|
|
|
80
113
|
function isPlainRecord(value: unknown): value is Record<string, unknown> {
|
|
81
114
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
82
115
|
}
|
|
83
116
|
|
|
117
|
+
function nestedPositionalHandleKeys(entry: Record<string, unknown>): string[] {
|
|
118
|
+
const keys: string[] = [];
|
|
119
|
+
for (const alias of ["task", "content"] as const) {
|
|
120
|
+
const value = entry[alias];
|
|
121
|
+
if (!isPlainRecord(value)) continue;
|
|
122
|
+
for (const key of Object.keys(value)) {
|
|
123
|
+
if (POSITIONAL_HANDLE_KEYS.has(key)) keys.push(`${alias}.${key}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return keys;
|
|
127
|
+
}
|
|
128
|
+
|
|
84
129
|
/**
|
|
85
130
|
* Single source of truth for todo_write pre-coercion validation. Every
|
|
86
131
|
* rejection carries a code so the caller can surface an actionable correction
|
|
@@ -119,6 +164,13 @@ export function validateRawTodoArguments(arguments_: Record<string, unknown>): R
|
|
|
119
164
|
code: "todo-write-unknown-op-entry-key",
|
|
120
165
|
detail: keyRejectionDetail(unknownEntryKeys, location),
|
|
121
166
|
};
|
|
167
|
+
const nestedHandles = nestedPositionalHandleKeys(entry);
|
|
168
|
+
if (nestedHandles.length > 0)
|
|
169
|
+
return {
|
|
170
|
+
outcome: "reject",
|
|
171
|
+
code: "todo-write-unknown-op-entry-key",
|
|
172
|
+
detail: keyRejectionDetail(nestedHandles, location),
|
|
173
|
+
};
|
|
122
174
|
const target = entry.task ?? entry.content;
|
|
123
175
|
if ((op === "done" || op === "drop") && !target && !entry.phase) {
|
|
124
176
|
return { outcome: "reject", code: "todo-write-done-drop-requires-target", detail: { hint: location } };
|
package/src/tools/todo-write.ts
CHANGED
|
@@ -539,9 +539,10 @@ export class TodoWriteTool implements AgentTool<typeof todoWriteSchema, TodoWrit
|
|
|
539
539
|
entry => (entry.op === "done" || entry.op === "drop") && !entry.task && !entry.phase,
|
|
540
540
|
);
|
|
541
541
|
if (missingTarget) {
|
|
542
|
-
//
|
|
543
|
-
//
|
|
544
|
-
//
|
|
542
|
+
// Model-issued calls never arrive here with a positional handle (`id: "1"`,
|
|
543
|
+
// `index: 2`): raw validation rejects the key first and carries the same
|
|
544
|
+
// correction. Bridges that call execute directly (eval's callSessionTool)
|
|
545
|
+
// skip that validation, so this still has to name what actually works.
|
|
545
546
|
const errors = [
|
|
546
547
|
`Missing task or phase for ${missingTarget.op} operation. ` +
|
|
547
548
|
`Pass "task" with the task's exact content, or "phase" with the phase name; ` +
|