@gajae-code/coding-agent 0.17.1 → 0.17.4
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 +266 -0
- package/dist/types/async/job-manager.d.ts +7 -6
- package/dist/types/cli/daemon-cli.d.ts +3 -1
- package/dist/types/cli/github-release.d.ts +17 -0
- package/dist/types/cli/public-command-entry.d.ts +56 -0
- package/dist/types/cli/public-command-errors.d.ts +126 -0
- package/dist/types/cli/public-command-evidence.d.ts +99 -0
- package/dist/types/cli/public-command-help.d.ts +65 -0
- package/dist/types/cli/public-command-registry.d.ts +69 -0
- package/dist/types/cli/session-picker.d.ts +1 -1
- package/dist/types/cli/setup-cli.d.ts +1 -0
- package/dist/types/cli/skills-cli.d.ts +5 -0
- package/dist/types/cli.d.ts +3 -0
- package/dist/types/commands/daemon.d.ts +4 -50
- package/dist/types/commands/sdk.d.ts +20 -37
- package/dist/types/commands/setup.d.ts +3 -0
- package/dist/types/commands/skills.d.ts +9 -0
- package/dist/types/config/autorouting-tier-map.d.ts +24 -0
- package/dist/types/config/file-lock.d.ts +10 -1
- package/dist/types/config/model-profile-activation.d.ts +63 -4
- package/dist/types/config/model-registry.d.ts +20 -2
- package/dist/types/config/settings-schema.d.ts +11 -0
- package/dist/types/coordinator-mcp/question-state.d.ts +6 -1
- package/dist/types/coordinator-mcp/server.d.ts +3 -0
- package/dist/types/daemon/operator-contract.d.ts +5 -1
- package/dist/types/eval/js/worker-protocol.d.ts +2 -0
- package/dist/types/extensibility/extensions/types.d.ts +12 -0
- package/dist/types/extensibility/gjc-plugins/registry.d.ts +4 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +18 -0
- package/dist/types/extensibility/shared-events.d.ts +3 -1
- package/dist/types/gjc-runtime/session-state-lock.d.ts +61 -0
- package/dist/types/internal-urls/embedded-protocol.d.ts +9 -0
- package/dist/types/internal-urls/index.d.ts +1 -0
- package/dist/types/internal-urls/parse.d.ts +9 -1
- package/dist/types/main.d.ts +22 -0
- package/dist/types/modes/acp/acp-agent.d.ts +94 -1
- package/dist/types/modes/acp/startup-provenance.d.ts +16 -0
- package/dist/types/modes/components/custom-provider-wizard.d.ts +19 -1
- package/dist/types/modes/components/session-selector.d.ts +5 -2
- package/dist/types/modes/components/thinking-selector.d.ts +2 -1
- package/dist/types/modes/components/user-message-selector.d.ts +5 -2
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +11 -1
- package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +14 -1
- package/dist/types/modes/types.d.ts +2 -2
- package/dist/types/runtime/process-lifecycle.d.ts +2 -0
- package/dist/types/runtime-mcp/manager.d.ts +56 -0
- package/dist/types/runtime-mcp/pool.d.ts +17 -0
- package/dist/types/runtime-mcp/redaction.d.ts +20 -0
- package/dist/types/runtime-mcp/startup-policy.d.ts +6 -0
- package/dist/types/runtime-mcp/tool-bridge.d.ts +9 -0
- package/dist/types/runtime-mcp/transports/http.d.ts +11 -0
- package/dist/types/sdk/acp/adapter.d.ts +27 -0
- package/dist/types/sdk/acp/final-text.d.ts +8 -0
- package/dist/types/sdk/broker/broker.d.ts +13 -2
- package/dist/types/sdk/broker/ensure.d.ts +46 -1
- package/dist/types/sdk/broker/identity.d.ts +3 -1
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +23 -3
- package/dist/types/sdk/broker/lifecycle.d.ts +15 -8
- package/dist/types/sdk/broker/runtime.d.ts +1 -1
- package/dist/types/sdk/broker/session-index.d.ts +22 -3
- package/dist/types/sdk/broker/spawn-authority.d.ts +4 -0
- package/dist/types/sdk/broker/stderr-drainer.d.ts +13 -0
- package/dist/types/sdk/bus/index.d.ts +19 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +3 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +5 -0
- package/dist/types/sdk/cli/master-cli.d.ts +6 -10
- package/dist/types/sdk/cli/rows.d.ts +19 -1
- package/dist/types/sdk/cli/session-cli.d.ts +22 -5
- package/dist/types/sdk/client/client.d.ts +2 -0
- package/dist/types/sdk/guides/cli.d.ts +3 -4
- package/dist/types/sdk/guides/verify.d.ts +2 -0
- package/dist/types/sdk/host/host.d.ts +9 -0
- package/dist/types/sdk/host/session-runtime.d.ts +31 -0
- package/dist/types/sdk/host/types.d.ts +10 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/prompt-deadline-flush.d.ts +83 -0
- package/dist/types/sdk/prompt-deadline-manager.d.ts +38 -1
- package/dist/types/sdk/prompt-failure.d.ts +30 -1
- package/dist/types/sdk/prompt-status.d.ts +8 -0
- package/dist/types/sdk/prompt-tool-boundary.d.ts +73 -0
- package/dist/types/sdk/router/replay-retention-gap-cache.d.ts +13 -0
- package/dist/types/sdk/router/session-router.d.ts +2 -0
- package/dist/types/sdk/startup-capability.d.ts +2 -0
- package/dist/types/sdk/transport/relay.d.ts +1 -0
- package/dist/types/sdk/transport/serve-cli.d.ts +73 -2
- package/dist/types/sdk/transport/stdio.d.ts +5 -1
- package/dist/types/session/agent-session.d.ts +168 -21
- package/dist/types/session/fallback-chain-controller.d.ts +6 -6
- package/dist/types/session/fold-coordinator.d.ts +17 -3
- package/dist/types/session/internal/managed-session-storage.d.ts +7 -1
- package/dist/types/session/session-manager.d.ts +64 -1
- package/dist/types/session/session-work-lease.d.ts +14 -0
- package/dist/types/setup/model-onboarding-guidance.d.ts +1 -1
- package/dist/types/setup/provider-onboarding.d.ts +81 -1
- package/dist/types/thinking.d.ts +3 -1
- package/dist/types/tools/bash.d.ts +37 -11
- package/dist/types/tools/job.d.ts +1 -1
- package/dist/types/tools/steer-fold.d.ts +31 -0
- package/dist/types/utils/git.d.ts +28 -2
- package/dist/types/utils/mupdf-embedded.d.ts +2 -0
- package/dist/types/utils/mupdf-wasm-embedded.d.ts +2 -0
- package/dist/types/utils/mupdf.d.ts +4 -0
- package/dist/types/utils/session-title-generation.d.ts +6 -0
- package/dist/types/utils/title-generator.d.ts +11 -2
- package/dist/types/web/scrapers/types.d.ts +3 -0
- package/package.json +18 -10
- package/scripts/build-binary.ts +9 -3
- package/scripts/compile-args.ts +0 -9
- package/scripts/embed-mupdf.ts +52 -0
- package/scripts/generate-sdk-operation-inventory.ts +31 -1
- package/scripts/vendor-markit.ts +196 -0
- package/src/async/job-manager.ts +60 -9
- package/src/cli/daemon-cli.ts +53 -18
- package/src/cli/github-release.ts +87 -5
- package/src/cli/mcp-cli.ts +38 -4
- package/src/cli/public-command-entry.ts +450 -0
- package/src/cli/public-command-errors.ts +581 -0
- package/src/cli/public-command-evidence.ts +717 -0
- package/src/cli/public-command-help.ts +360 -0
- package/src/cli/public-command-registry.ts +535 -0
- package/src/cli/session-picker.ts +2 -1
- package/src/cli/setup-cli.ts +9 -1
- package/src/cli/skills-cli.ts +46 -2
- package/src/cli.ts +61 -1
- package/src/commands/daemon.ts +65 -69
- package/src/commands/sdk.ts +232 -100
- package/src/commands/setup.ts +2 -0
- package/src/commands/skills.ts +11 -0
- package/src/config/autorouting-tier-map.ts +16 -0
- package/src/config/file-lock.ts +199 -68
- package/src/config/model-profile-activation.ts +406 -53
- package/src/config/model-registry.ts +204 -25
- package/src/config/settings-schema.ts +26 -2
- package/src/coordinator-mcp/policy.ts +10 -5
- package/src/coordinator-mcp/question-gate-codec.ts +17 -0
- package/src/coordinator-mcp/question-state.ts +175 -8
- package/src/coordinator-mcp/server.ts +528 -87
- package/src/coordinator-mcp/session-reaper.ts +6 -4
- package/src/crash/record-loader.ts +6 -2
- package/src/daemon/operator-contract.ts +26 -12
- package/src/debug/report-bundle.ts +114 -24
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +1 -1
- package/src/eval/js/context-manager.ts +8 -8
- package/src/eval/js/worker-core.ts +9 -4
- package/src/eval/js/worker-protocol.ts +2 -0
- package/src/extensibility/extensions/runner.ts +52 -4
- package/src/extensibility/extensions/types.ts +10 -0
- package/src/extensibility/gjc-plugins/registry.ts +196 -37
- package/src/extensibility/runtime-skill-discovery.ts +61 -3
- package/src/extensibility/shared-events.ts +3 -1
- package/src/gjc-runtime/managed-owner-admission.ts +67 -50
- package/src/gjc-runtime/session-state-lock.ts +165 -24
- package/src/gjc-runtime/ultragoal-succession.ts +31 -3
- package/src/internal-urls/docs-index.generated.ts +21 -19
- package/src/internal-urls/embedded-protocol.ts +83 -0
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/parse.ts +21 -1
- package/src/internal-urls/router.ts +4 -2
- package/src/main.ts +123 -55
- package/src/modes/acp/acp-agent.ts +593 -47
- package/src/modes/acp/acp-event-mapper.ts +9 -0
- package/src/modes/acp/startup-provenance.ts +59 -0
- package/src/modes/components/custom-provider-wizard.ts +308 -7
- package/src/modes/components/model-selector.ts +31 -15
- package/src/modes/components/oauth-selector.ts +9 -0
- package/src/modes/components/session-selector.ts +47 -4
- package/src/modes/components/status-line/segments.ts +6 -1
- package/src/modes/components/thinking-selector.ts +7 -3
- package/src/modes/components/user-message-selector.ts +57 -15
- package/src/modes/controllers/command-controller.ts +58 -32
- package/src/modes/controllers/extension-ui-controller.ts +33 -7
- package/src/modes/controllers/input-controller.ts +4 -0
- package/src/modes/controllers/selector-controller.ts +177 -18
- package/src/modes/interactive-mode.ts +21 -7
- package/src/modes/runtime-init.ts +1 -0
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +124 -7
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +16 -2
- package/src/modes/types.ts +2 -2
- package/src/prompts/agent-fragments/browser-aside.md +1 -0
- package/src/prompts/system/title-system.md +1 -1
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/job.md +1 -1
- package/src/prompts/tools/read.md +2 -0
- package/src/runtime/network-prewarm-service.test.ts +36 -1
- package/src/runtime/network-prewarm-service.ts +28 -3
- package/src/runtime/process-lifecycle.ts +22 -11
- package/src/runtime-mcp/config.ts +16 -1
- package/src/runtime-mcp/manager.ts +689 -55
- package/src/runtime-mcp/pool.test.ts +31 -0
- package/src/runtime-mcp/pool.ts +304 -28
- package/src/runtime-mcp/redaction.ts +42 -0
- package/src/runtime-mcp/startup-policy.ts +7 -0
- package/src/runtime-mcp/tool-bridge.ts +71 -0
- package/src/runtime-mcp/transports/http.ts +108 -25
- package/src/sdk/acp/adapter.ts +90 -9
- package/src/sdk/acp/final-text.ts +19 -2
- package/src/sdk/broker/broker.ts +378 -52
- package/src/sdk/broker/ensure.ts +97 -19
- package/src/sdk/broker/identity.ts +9 -1
- package/src/sdk/broker/lifecycle-ledger.ts +95 -31
- package/src/sdk/broker/lifecycle.ts +690 -141
- package/src/sdk/broker/runtime.ts +1 -1
- package/src/sdk/broker/session-index.ts +97 -4
- package/src/sdk/broker/spawn-authority.ts +35 -7
- package/src/sdk/broker/stderr-drainer.ts +59 -0
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/chat-daemon-runtime.ts +1 -0
- package/src/sdk/bus/index.ts +721 -84
- package/src/sdk/bus/telegram-daemon-cli.ts +31 -2
- package/src/sdk/bus/telegram-daemon-contract.ts +3 -1
- package/src/sdk/bus/telegram-daemon.ts +10 -3
- package/src/sdk/cli/master-cli.ts +47 -36
- package/src/sdk/cli/rows.ts +30 -7
- package/src/sdk/cli/session-cli.ts +687 -184
- package/src/sdk/client/client.ts +18 -0
- package/src/sdk/guides/catalog.ts +2 -2
- package/src/sdk/guides/cli.ts +20 -62
- package/src/sdk/guides/verify.ts +14 -0
- package/src/sdk/host/host.ts +49 -5
- package/src/sdk/host/session-runtime.test.ts +636 -9
- package/src/sdk/host/session-runtime.ts +499 -118
- package/src/sdk/host/types.ts +12 -1
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +84 -0
- package/src/sdk/host/websocket-transport.ts +40 -6
- package/src/sdk/index.ts +11 -0
- package/src/sdk/prompt-deadline-flush.ts +334 -0
- package/src/sdk/prompt-deadline-manager.ts +136 -4
- package/src/sdk/prompt-failure.ts +43 -1
- package/src/sdk/prompt-status.ts +8 -0
- package/src/sdk/prompt-tool-boundary.ts +121 -0
- package/src/sdk/protocol/operation-inventory.generated.json +106 -0
- package/src/sdk/router/replay-retention-gap-cache.ts +27 -0
- package/src/sdk/router/session-router.ts +31 -4
- package/src/sdk/session.ts +194 -16
- package/src/sdk/startup-capability.ts +1 -1
- package/src/sdk/transport/relay.ts +71 -6
- package/src/sdk/transport/serve-cli.ts +494 -49
- package/src/sdk/transport/socket.ts +12 -11
- package/src/sdk/transport/stdio.ts +7 -3
- package/src/session/agent-session.ts +2437 -400
- package/src/session/fallback-chain-controller.ts +6 -7
- package/src/session/fold-coordinator.ts +24 -5
- package/src/session/internal/managed-session-scope.ts +58 -18
- package/src/session/internal/managed-session-storage.ts +304 -11
- package/src/session/session-manager.ts +382 -44
- package/src/session/session-work-lease.ts +34 -0
- package/src/session-import/codex.ts +12 -3
- package/src/setup/model-onboarding-guidance.ts +1 -1
- package/src/setup/provider-onboarding.ts +397 -24
- package/src/slash-commands/builtin-registry.ts +258 -14
- package/src/task/index.ts +14 -2
- package/src/thinking.ts +21 -2
- package/src/tools/bash.ts +98 -78
- package/src/tools/fetch.ts +119 -20
- package/src/tools/job.ts +151 -25
- package/src/tools/output-meta.ts +15 -2
- package/src/tools/path-utils.ts +27 -3
- package/src/tools/read.ts +3 -3
- package/src/tools/steer-fold.ts +107 -0
- package/src/tools/tool-catalog.generated.ts +29 -2
- package/src/tools/tool-errors.ts +4 -0
- package/src/utils/git.ts +53 -3
- package/src/utils/markit.ts +55 -41
- package/src/utils/mupdf-assets.d.ts +4 -0
- package/src/utils/mupdf-embedded.ts +4 -0
- package/src/utils/mupdf-wasm-embedded.ts +3 -0
- package/src/utils/mupdf-wasm.ts +24 -2
- package/src/utils/mupdf.ts +129 -0
- package/src/utils/session-title-generation.ts +29 -0
- package/src/utils/title-generator.ts +46 -2
- package/src/web/scrapers/types.ts +24 -3
- package/vendor/markit-ai/LICENSE +21 -0
- package/vendor/markit-ai/MANIFEST.json +412 -0
- package/vendor/markit-ai/dist/commands/config.d.ts +4 -0
- package/vendor/markit-ai/dist/commands/config.js +139 -0
- package/vendor/markit-ai/dist/commands/convert.d.ts +6 -0
- package/vendor/markit-ai/dist/commands/convert.js +113 -0
- package/vendor/markit-ai/dist/commands/formats.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/formats.js +92 -0
- package/vendor/markit-ai/dist/commands/init.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/init.js +29 -0
- package/vendor/markit-ai/dist/commands/onboard.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/onboard.js +61 -0
- package/vendor/markit-ai/dist/commands/plugin.d.ts +4 -0
- package/vendor/markit-ai/dist/commands/plugin.js +58 -0
- package/vendor/markit-ai/dist/config.d.ts +26 -0
- package/vendor/markit-ai/dist/config.js +42 -0
- package/vendor/markit-ai/dist/converters/audio.d.ts +7 -0
- package/vendor/markit-ai/dist/converters/audio.js +104 -0
- package/vendor/markit-ai/dist/converters/csv.d.ts +7 -0
- package/vendor/markit-ai/dist/converters/csv.js +83 -0
- package/vendor/markit-ai/dist/converters/docx.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/docx.js +57 -0
- package/vendor/markit-ai/dist/converters/epub.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/epub.js +128 -0
- package/vendor/markit-ai/dist/converters/github.d.ts +18 -0
- package/vendor/markit-ai/dist/converters/github.js +148 -0
- package/vendor/markit-ai/dist/converters/html.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/html.js +30 -0
- package/vendor/markit-ai/dist/converters/image.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/image.js +124 -0
- package/vendor/markit-ai/dist/converters/ipynb.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/ipynb.js +75 -0
- package/vendor/markit-ai/dist/converters/iwork.d.ts +20 -0
- package/vendor/markit-ai/dist/converters/iwork.js +391 -0
- package/vendor/markit-ai/dist/converters/json.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/json.js +21 -0
- package/vendor/markit-ai/dist/converters/pdf/columns.d.ts +35 -0
- package/vendor/markit-ai/dist/converters/pdf/columns.js +93 -0
- package/vendor/markit-ai/dist/converters/pdf/extract.d.ts +19 -0
- package/vendor/markit-ai/dist/converters/pdf/extract.js +514 -0
- package/vendor/markit-ai/dist/converters/pdf/grid.d.ts +25 -0
- package/vendor/markit-ai/dist/converters/pdf/grid.js +795 -0
- package/vendor/markit-ai/dist/converters/pdf/headers.d.ts +24 -0
- package/vendor/markit-ai/dist/converters/pdf/headers.js +108 -0
- package/vendor/markit-ai/dist/converters/pdf/index.d.ts +19 -0
- package/vendor/markit-ai/dist/converters/pdf/index.js +136 -0
- package/vendor/markit-ai/dist/converters/pdf/mupdf-loader.js +9 -0
- package/vendor/markit-ai/dist/converters/pdf/render.d.ts +24 -0
- package/vendor/markit-ai/dist/converters/pdf/render.js +513 -0
- package/vendor/markit-ai/dist/converters/pdf/types.d.ts +75 -0
- package/vendor/markit-ai/dist/converters/pdf/types.js +1 -0
- package/vendor/markit-ai/dist/converters/plain-text.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/plain-text.js +87 -0
- package/vendor/markit-ai/dist/converters/pptx.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/pptx.js +289 -0
- package/vendor/markit-ai/dist/converters/rss.d.ts +11 -0
- package/vendor/markit-ai/dist/converters/rss.js +138 -0
- package/vendor/markit-ai/dist/converters/wikipedia.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/wikipedia.js +33 -0
- package/vendor/markit-ai/dist/converters/xlsx.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/xlsx.js +147 -0
- package/vendor/markit-ai/dist/converters/xml.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/xml.js +18 -0
- package/vendor/markit-ai/dist/converters/yaml.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/yaml.js +17 -0
- package/vendor/markit-ai/dist/converters/zip.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/zip.js +57 -0
- package/vendor/markit-ai/dist/index.d.ts +30 -0
- package/vendor/markit-ai/dist/index.js +26 -0
- package/vendor/markit-ai/dist/main.d.ts +2 -0
- package/vendor/markit-ai/dist/main.js +191 -0
- package/vendor/markit-ai/dist/markit.d.ts +45 -0
- package/vendor/markit-ai/dist/markit.js +267 -0
- package/vendor/markit-ai/dist/plugins/api.d.ts +7 -0
- package/vendor/markit-ai/dist/plugins/api.js +42 -0
- package/vendor/markit-ai/dist/plugins/index.d.ts +4 -0
- package/vendor/markit-ai/dist/plugins/index.js +3 -0
- package/vendor/markit-ai/dist/plugins/installer.d.ts +25 -0
- package/vendor/markit-ai/dist/plugins/installer.js +176 -0
- package/vendor/markit-ai/dist/plugins/loader.d.ts +6 -0
- package/vendor/markit-ai/dist/plugins/loader.js +61 -0
- package/vendor/markit-ai/dist/plugins/types.d.ts +25 -0
- package/vendor/markit-ai/dist/plugins/types.js +1 -0
- package/vendor/markit-ai/dist/providers/anthropic.d.ts +2 -0
- package/vendor/markit-ai/dist/providers/anthropic.js +47 -0
- package/vendor/markit-ai/dist/providers/index.d.ts +21 -0
- package/vendor/markit-ai/dist/providers/index.js +56 -0
- package/vendor/markit-ai/dist/providers/openai.d.ts +2 -0
- package/vendor/markit-ai/dist/providers/openai.js +76 -0
- package/vendor/markit-ai/dist/providers/types.d.ts +26 -0
- package/vendor/markit-ai/dist/providers/types.js +1 -0
- package/vendor/markit-ai/dist/types.d.ts +36 -0
- package/vendor/markit-ai/dist/types.js +1 -0
- package/vendor/markit-ai/dist/utils/exit-codes.d.ts +4 -0
- package/vendor/markit-ai/dist/utils/exit-codes.js +4 -0
- package/vendor/markit-ai/dist/utils/output.d.ts +22 -0
- package/vendor/markit-ai/dist/utils/output.js +31 -0
- package/vendor/markit-ai/dist/utils/turndown.d.ts +8 -0
- package/vendor/markit-ai/dist/utils/turndown.js +70 -0
- package/vendor/markit-ai/package.json +74 -0
- package/vendor/markit-ai.patch +49 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import * as fs from "node:fs/promises";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import * as url from "node:url";
|
|
6
|
+
|
|
7
|
+
const outputPath = url.fileURLToPath(new URL("../src/utils/mupdf-embedded.ts", import.meta.url));
|
|
8
|
+
const sourceMapping = `// AUTOGENERATED FILE -- DO NOT EDIT DIRECTLY
|
|
9
|
+
// See scripts/embed-mupdf.ts. Source installs resolve the package lazily.
|
|
10
|
+
export const embeddedMuPdfWasm: string | undefined = undefined;
|
|
11
|
+
export const embeddedMuPdfModule: string | undefined = undefined;
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
export async function resetMuPdfAsset(): Promise<void> {
|
|
15
|
+
await Bun.write(outputPath, sourceMapping);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function generateMuPdfAsset(options: { wasmPath?: string } = {}): Promise<void> {
|
|
19
|
+
const temporaryPath = `${outputPath}.tmp`;
|
|
20
|
+
try {
|
|
21
|
+
const markitModule = url.fileURLToPath(new URL("../vendor/markit-ai/dist/index.js", import.meta.url));
|
|
22
|
+
const modulePath = Bun.resolveSync("mupdf", path.dirname(markitModule));
|
|
23
|
+
const resolvedWasmPath = options.wasmPath ?? path.join(path.dirname(modulePath), "mupdf-wasm.wasm");
|
|
24
|
+
await fs.access(resolvedWasmPath);
|
|
25
|
+
await Bun.write(
|
|
26
|
+
temporaryPath,
|
|
27
|
+
`// AUTOGENERATED FILE -- DO NOT EDIT DIRECTLY
|
|
28
|
+
// See scripts/embed-mupdf.ts. Reset after compiling.
|
|
29
|
+
import wasmAsset from ${JSON.stringify(resolvedWasmPath)} with { type: "file" };
|
|
30
|
+
|
|
31
|
+
export const embeddedMuPdfWasm: string | undefined = wasmAsset;
|
|
32
|
+
export const embeddedMuPdfModule: string | undefined = ${JSON.stringify(modulePath)};
|
|
33
|
+
`,
|
|
34
|
+
);
|
|
35
|
+
await fs.rename(temporaryPath, outputPath);
|
|
36
|
+
} catch (cause) {
|
|
37
|
+
await resetMuPdfAsset();
|
|
38
|
+
throw new Error(
|
|
39
|
+
"Unable to embed MuPDF WASM; check the source-built artifact or installed coding-agent dependency.",
|
|
40
|
+
{
|
|
41
|
+
cause,
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
} finally {
|
|
45
|
+
await fs.rm(temporaryPath, { force: true });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (import.meta.main) {
|
|
50
|
+
if (process.argv.includes("--reset")) await resetMuPdfAsset();
|
|
51
|
+
else await generateMuPdfAsset();
|
|
52
|
+
}
|
|
@@ -19,8 +19,12 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
19
19
|
"internal terminal-abort bus seam, threaded via terminalAbortSeams; not a user-facing SDK control seam",
|
|
20
20
|
"agent_session:abortPromptAndWaitWithTerminal":
|
|
21
21
|
"internal terminal-abort fencing seam, threaded via terminalAbortSeams; not a user-facing SDK control seam",
|
|
22
|
+
"agent_session:pendingToolExecutions":
|
|
23
|
+
"internal read-only run-resource-ledger view, threaded via terminalAbortSeams so the prompt deadline can find a tool-call boundary; not a user-facing SDK control seam",
|
|
22
24
|
"slash_command:routing":
|
|
23
25
|
"visual/local-only autorouting settings toggle and smart-routing panel entry, not a user-facing SDK control seam",
|
|
26
|
+
"slash_command:mcp":
|
|
27
|
+
"interactive exact-config MCP status and session control command; terminal-only handleTui surface is not dispatched through ACP or the public SDK",
|
|
24
28
|
"slash_command:settings": "visual/local-only command, not a user-facing SDK control seam",
|
|
25
29
|
"slash_command:theme": "visual/local-only command, not a user-facing SDK control seam",
|
|
26
30
|
"slash_command:language":
|
|
@@ -162,6 +166,10 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
162
166
|
"agent_session:refreshSshTool": "internal accessor/plumbing, not a user-facing control seam",
|
|
163
167
|
"agent_session:refreshBaseSystemPrompt": "internal accessor/plumbing, not a user-facing control seam",
|
|
164
168
|
"agent_session:refreshMCPTools": "internal accessor/plumbing, not a user-facing control seam",
|
|
169
|
+
"agent_session:getExactMcpStatusSnapshot":
|
|
170
|
+
"internal exact-config MCP status accessor used only by the terminal-only /mcp command; its capability is granted only to root interactive --mcp-config sessions, not a public SDK query",
|
|
171
|
+
"agent_session:controlExactMcpServer":
|
|
172
|
+
"internal session-local exact-config MCP suspend/resume/reconnect mutation used only by the terminal-only /mcp command; runtime suppression is not persistent user authority or a public SDK control",
|
|
165
173
|
"agent_session:refreshGjcSubskillTools": "internal accessor/plumbing, not a user-facing control seam",
|
|
166
174
|
"agent_session:buildDisplaySessionContext": "internal accessor/plumbing, not a user-facing control seam",
|
|
167
175
|
"agent_session:buildPreparedDisplaySessionContext": "internal accessor/plumbing, not a user-facing control seam",
|
|
@@ -279,6 +287,12 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
279
287
|
"internal profile and fallback-chain state, not a user-facing SDK control seam",
|
|
280
288
|
"agent_session:setDefaultFallbackRuntimeModel":
|
|
281
289
|
"internal fallback runtime bookkeeping, not a user-facing SDK control seam",
|
|
290
|
+
"agent_session:installRecoveredDefaultFallbackChain":
|
|
291
|
+
"internal recovered fallback-chain installation during session startup, not a user-facing SDK control seam",
|
|
292
|
+
"agent_session:markStartupRecoveryBindingsRequired":
|
|
293
|
+
"internal startup recovery binding marker, not a user-facing SDK control seam",
|
|
294
|
+
"agent_session:hasRecoveredDefaultFallbackChain":
|
|
295
|
+
"internal recovered fallback-chain state query, not a user-facing SDK control seam",
|
|
282
296
|
"agent_session:setCredentialPin":
|
|
283
297
|
"interactive session-scoped OAuth account selector mutation behind the locked /credential and OAuth selector surfaces; the public SDK has no credential-selection operation and must not gain credential authority implicitly",
|
|
284
298
|
"agent_session:setCredentialAuto":
|
|
@@ -287,6 +301,8 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
|
|
|
287
301
|
"internal fallback resolution bookkeeping, not a user-facing SDK control seam",
|
|
288
302
|
"agent_session:syncEagerDelegation":
|
|
289
303
|
"internal profile-derived eager delegation synchronization, not a user-facing SDK control seam",
|
|
304
|
+
"agent_session:submitUserMessage":
|
|
305
|
+
"public in-process embedder lifecycle API; direct handle surface, not an SDK transport operation",
|
|
290
306
|
};
|
|
291
307
|
/** Maps reviewed source seams to registry SDK operation IDs. */
|
|
292
308
|
const SEAM_TO_SDK: Readonly<Record<string, string>> = {
|
|
@@ -366,6 +382,10 @@ const SEAM_TO_SDK: Readonly<Record<string, string>> = {
|
|
|
366
382
|
"slash_command:login": "auth.login",
|
|
367
383
|
"slash_command:clear": "context.clear",
|
|
368
384
|
"slash_command:new": "session.new",
|
|
385
|
+
// `/fork` opens the user-prompt selector, which commits via
|
|
386
|
+
// `session.branch(entryId)` (selector-controller.ts). Despite the command and
|
|
387
|
+
// keybinding name, it is NOT the exact-state `session.fork` operation.
|
|
388
|
+
"slash_command:fork": "session.branch",
|
|
369
389
|
"slash_command:compact": "compaction.run",
|
|
370
390
|
"slash_command:handoff": "session.handoff",
|
|
371
391
|
"slash_command:resume": "session.resume",
|
|
@@ -811,10 +831,17 @@ export function scanAgentSessionMethods(sourceText: string): string[] {
|
|
|
811
831
|
throw new Error("SDK operation inventory scanner: AgentSession class body is unbalanced.");
|
|
812
832
|
|
|
813
833
|
const methods: string[] = [];
|
|
834
|
+
const seenMethods = new Set<string>();
|
|
814
835
|
for (let memberStart = bodyStart + 1; memberStart < bodyEnd; ) {
|
|
815
836
|
const declaration = scanMethodDeclaration(tokens, memberStart, bodyEnd);
|
|
816
837
|
if (declaration) {
|
|
817
|
-
if (declaration.name)
|
|
838
|
+
if (declaration.name) {
|
|
839
|
+
const sourceId = `agent_session:${declaration.name}`;
|
|
840
|
+
if (!seenMethods.has(sourceId)) {
|
|
841
|
+
seenMethods.add(sourceId);
|
|
842
|
+
methods.push(sourceId);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
818
845
|
memberStart = Math.max(memberStart + 1, declaration.end);
|
|
819
846
|
continue;
|
|
820
847
|
}
|
|
@@ -940,6 +967,7 @@ function validateRegistry(records: InventoryRecord[]): string[] {
|
|
|
940
967
|
const errors: string[] = [];
|
|
941
968
|
const ids = new Set<string>();
|
|
942
969
|
const sdkIds = new Set<string>();
|
|
970
|
+
const sourceIds = new Set<string>();
|
|
943
971
|
for (const operation of OPERATIONS) {
|
|
944
972
|
if (ids.has(operation.id)) errors.push(`Duplicate operation ID: ${operation.id}`);
|
|
945
973
|
ids.add(operation.id);
|
|
@@ -951,6 +979,8 @@ function validateRegistry(records: InventoryRecord[]): string[] {
|
|
|
951
979
|
if (operation.testIds.length === 0) errors.push(`${operation.id} is missing test IDs.`);
|
|
952
980
|
}
|
|
953
981
|
for (const record of records) {
|
|
982
|
+
if (sourceIds.has(record.sourceId)) errors.push(`Duplicate source seam: ${record.sourceId}`);
|
|
983
|
+
sourceIds.add(record.sourceId);
|
|
954
984
|
if (record.decision === "exclude") {
|
|
955
985
|
if (!record.rationale) errors.push(`${record.sourceId} exclusion lacks a locked rationale.`);
|
|
956
986
|
if (
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/** Reproduce the patched MIT converter; --check is strictly local and read-only. */
|
|
3
|
+
import * as crypto from "node:crypto";
|
|
4
|
+
import * as fs from "node:fs/promises";
|
|
5
|
+
import * as os from "node:os";
|
|
6
|
+
import * as path from "node:path";
|
|
7
|
+
import { $ } from "bun";
|
|
8
|
+
|
|
9
|
+
const packageRoot = path.resolve(import.meta.dir, "..");
|
|
10
|
+
const vendorRoot = path.join(packageRoot, "vendor");
|
|
11
|
+
const vendorDir = path.join(vendorRoot, "markit-ai");
|
|
12
|
+
const patchPath = path.join(vendorRoot, "markit-ai.patch");
|
|
13
|
+
const sourceUrl = "https://registry.npmjs.org/markit-ai/-/markit-ai-0.5.3.tgz";
|
|
14
|
+
const sourceIntegrity =
|
|
15
|
+
"sha512-h4nhn6a/SNXEdc3kLVtL37TspxjUNCNL0OM7LRWxd389ZByI/B7bjNNgxFdVAT0O+H7ZekSwLdVe/lws1l2AZQ==";
|
|
16
|
+
const provenanceName = "MANIFEST.json";
|
|
17
|
+
const maxArchiveBytes = 16 * 1024 * 1024;
|
|
18
|
+
|
|
19
|
+
interface FileHash {
|
|
20
|
+
path: string;
|
|
21
|
+
sha256: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function sha256(bytes: Uint8Array): string {
|
|
25
|
+
return crypto.createHash("sha256").update(bytes).digest("hex");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function selectedFile(name: string): boolean {
|
|
29
|
+
return name === "LICENSE" || name === "package.json" || name.startsWith("dist/");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function inventory(directory: string): Promise<FileHash[]> {
|
|
33
|
+
const files: FileHash[] = [];
|
|
34
|
+
async function walk(relative: string): Promise<void> {
|
|
35
|
+
const absolute = path.join(directory, relative);
|
|
36
|
+
const metadata = await fs.lstat(absolute);
|
|
37
|
+
if (metadata.isDirectory()) {
|
|
38
|
+
if (relative !== "" && relative !== "dist" && !relative.startsWith("dist/")) {
|
|
39
|
+
throw new Error(`Unexpected vendor directory: ${relative}`);
|
|
40
|
+
}
|
|
41
|
+
for (const name of (await fs.readdir(absolute)).sort()) {
|
|
42
|
+
await walk(relative ? `${relative}/${name}` : name);
|
|
43
|
+
}
|
|
44
|
+
} else if (metadata.isFile()) {
|
|
45
|
+
if (relative === provenanceName) return;
|
|
46
|
+
if (!selectedFile(relative)) throw new Error(`Unexpected vendor file: ${relative}`);
|
|
47
|
+
files.push({ path: relative, sha256: sha256(await Bun.file(absolute).bytes()) });
|
|
48
|
+
} else {
|
|
49
|
+
throw new Error(`Vendor entries must be regular files or directories: ${relative}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
await walk("");
|
|
53
|
+
for (const required of [
|
|
54
|
+
"LICENSE",
|
|
55
|
+
"package.json",
|
|
56
|
+
"dist/index.js",
|
|
57
|
+
"dist/index.d.ts",
|
|
58
|
+
"dist/converters/pdf/extract.js",
|
|
59
|
+
"dist/markit.js",
|
|
60
|
+
]) {
|
|
61
|
+
if (!files.some(file => file.path === required)) throw new Error(`Missing vendor file: ${required}`);
|
|
62
|
+
}
|
|
63
|
+
return files.sort((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function provenance(directory: string): Promise<string> {
|
|
67
|
+
return `${JSON.stringify(
|
|
68
|
+
{
|
|
69
|
+
schemaVersion: 1,
|
|
70
|
+
upstream: { name: "markit-ai", version: "0.5.3", license: "MIT", url: sourceUrl, integrity: sourceIntegrity },
|
|
71
|
+
patch: { path: "../markit-ai.patch", sha256: sha256(await Bun.file(patchPath).bytes()) },
|
|
72
|
+
files: await inventory(directory),
|
|
73
|
+
},
|
|
74
|
+
null,
|
|
75
|
+
"\t",
|
|
76
|
+
)}\n`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function verifyContents(directory: string): Promise<void> {
|
|
80
|
+
const upstream = await Bun.file(path.join(directory, "package.json")).json();
|
|
81
|
+
if (upstream.name !== "markit-ai" || upstream.version !== "0.5.3" || upstream.license !== "MIT") {
|
|
82
|
+
throw new Error("Vendored manifest must identify MIT markit-ai@0.5.3");
|
|
83
|
+
}
|
|
84
|
+
const manifest = await Bun.file(path.join(packageRoot, "package.json")).json();
|
|
85
|
+
for (const dependency of Object.keys(upstream.dependencies)) {
|
|
86
|
+
if (typeof manifest.dependencies?.[dependency] !== "string") {
|
|
87
|
+
throw new Error(`Missing direct converter runtime dependency: ${dependency}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (manifest.dependencies.mupdf !== "1.28.0" || manifest.dependencies["markit-ai"] !== undefined) {
|
|
91
|
+
throw new Error("Converter must use vendored Markit and pinned mupdf@1.28.0");
|
|
92
|
+
}
|
|
93
|
+
const extract = await Bun.file(path.join(directory, "dist/converters/pdf/extract.js")).text();
|
|
94
|
+
const mupdfLoader = await Bun.file(path.join(directory, "dist/converters/pdf/mupdf-loader.js")).text();
|
|
95
|
+
const markit = await Bun.file(path.join(directory, "dist/markit.js")).text();
|
|
96
|
+
if (
|
|
97
|
+
/require\(["']mupdf["']\)/u.test(extract) ||
|
|
98
|
+
!extract.includes("\nlet mupdf;\n") ||
|
|
99
|
+
!extract.includes('import { loadMuPdf } from "./mupdf-loader.js";') ||
|
|
100
|
+
!extract.includes("mupdf = await loadMuPdf()") ||
|
|
101
|
+
!mupdfLoader.includes('import("mupdf")') ||
|
|
102
|
+
!extract.includes('new Error("MuPDF module initialization failed", { cause })') ||
|
|
103
|
+
!markit.includes("new AggregateError(errors.map((entry) => entry.error)") ||
|
|
104
|
+
!markit.includes("{ cause: errors[0].error }")
|
|
105
|
+
)
|
|
106
|
+
throw new Error("Vendored Markit is missing the required MuPDF/diagnostics patch");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function check(): Promise<void> {
|
|
110
|
+
if (!(await fs.lstat(vendorRoot)).isDirectory()) throw new Error("Vendor root must be a real directory");
|
|
111
|
+
if (!(await fs.lstat(patchPath)).isFile()) throw new Error("Vendor patch must be a regular file");
|
|
112
|
+
// Inventory rejects symlinks before any content verification reads them.
|
|
113
|
+
const expected = await provenance(vendorDir);
|
|
114
|
+
if ((await Bun.file(path.join(vendorDir, provenanceName)).text()) !== expected) {
|
|
115
|
+
throw new Error("Markit vendor inventory or patch hash differs; regenerate from the pinned artifact");
|
|
116
|
+
}
|
|
117
|
+
await verifyContents(vendorDir);
|
|
118
|
+
process.stdout.write("Markit vendor verification passed (markit-ai@0.5.3, local hashes)\n");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function download(): Promise<Uint8Array> {
|
|
122
|
+
const response = await fetch(sourceUrl, { redirect: "error", signal: AbortSignal.timeout(60_000) });
|
|
123
|
+
if (!response.ok || !response.body) throw new Error(`Pinned Markit download failed: HTTP ${response.status}`);
|
|
124
|
+
const chunks: Uint8Array[] = [];
|
|
125
|
+
let length = 0;
|
|
126
|
+
for await (const chunk of response.body) {
|
|
127
|
+
length += chunk.byteLength;
|
|
128
|
+
if (length > maxArchiveBytes) throw new Error("Pinned Markit archive exceeds size limit");
|
|
129
|
+
chunks.push(chunk);
|
|
130
|
+
}
|
|
131
|
+
const bytes = Buffer.concat(chunks, length);
|
|
132
|
+
if (`sha512-${crypto.createHash("sha512").update(bytes).digest("base64")}` !== sourceIntegrity) {
|
|
133
|
+
throw new Error("Pinned Markit archive integrity mismatch");
|
|
134
|
+
}
|
|
135
|
+
return bytes;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function generate(): Promise<void> {
|
|
139
|
+
const temporaryRoot = await fs.mkdtemp(path.join(os.tmpdir(), "gjc-vendor-markit-"));
|
|
140
|
+
try {
|
|
141
|
+
const bytes = await download();
|
|
142
|
+
await Bun.write(path.join(temporaryRoot, "markit-ai-0.5.3.tgz"), bytes);
|
|
143
|
+
const source = path.join(temporaryRoot, "source");
|
|
144
|
+
await fs.mkdir(source);
|
|
145
|
+
// Read verified archive entries as data and create only regular files. Never
|
|
146
|
+
// ask an extractor to recreate upstream symlinks, permissions, or devices.
|
|
147
|
+
const entries = await new Bun.Archive(bytes).files();
|
|
148
|
+
let unpackedBytes = 0;
|
|
149
|
+
for (const [name, file] of entries) {
|
|
150
|
+
if (
|
|
151
|
+
!name.startsWith("package/") ||
|
|
152
|
+
name.includes("\\") ||
|
|
153
|
+
name.includes("\0") ||
|
|
154
|
+
name.split("/").some(part => part === "" || part === "." || part === "..")
|
|
155
|
+
) {
|
|
156
|
+
throw new Error(`Unsafe pinned archive entry: ${name}`);
|
|
157
|
+
}
|
|
158
|
+
unpackedBytes += file.size;
|
|
159
|
+
if (unpackedBytes > maxArchiveBytes) throw new Error("Pinned Markit unpacked files exceed size limit");
|
|
160
|
+
const relative = name.slice("package/".length);
|
|
161
|
+
if (!selectedFile(relative)) continue;
|
|
162
|
+
const destination = path.join(source, relative);
|
|
163
|
+
await Bun.write(destination, file);
|
|
164
|
+
await fs.chmod(destination, 0o644);
|
|
165
|
+
}
|
|
166
|
+
await $`git apply --check ${patchPath}`.cwd(source);
|
|
167
|
+
await $`git apply ${patchPath}`.cwd(source);
|
|
168
|
+
await verifyContents(source);
|
|
169
|
+
await Bun.write(path.join(source, provenanceName), await provenance(source));
|
|
170
|
+
if (!(await fs.lstat(vendorRoot)).isDirectory()) throw new Error("Vendor root must be a real directory");
|
|
171
|
+
const existing = await fs.lstat(vendorDir).catch((error: NodeJS.ErrnoException) => {
|
|
172
|
+
if (error.code === "ENOENT") return undefined;
|
|
173
|
+
throw error;
|
|
174
|
+
});
|
|
175
|
+
if (existing) {
|
|
176
|
+
// Refuse unrelated contents and symlinks rather than silently deleting them.
|
|
177
|
+
await inventory(vendorDir);
|
|
178
|
+
const oldManifest = await Bun.file(path.join(vendorDir, "package.json")).json();
|
|
179
|
+
if (oldManifest.name !== "markit-ai") throw new Error("Refusing to replace an unrelated vendor tree");
|
|
180
|
+
await fs.rm(vendorDir, { recursive: true });
|
|
181
|
+
}
|
|
182
|
+
await fs.cp(source, vendorDir, { recursive: true, force: false, errorOnExist: true });
|
|
183
|
+
await check();
|
|
184
|
+
} finally {
|
|
185
|
+
await fs.rm(temporaryRoot, { recursive: true, force: true });
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (import.meta.main) {
|
|
190
|
+
const args = process.argv.slice(2);
|
|
191
|
+
if (args.length !== 1 || (args[0] !== "--check" && args[0] !== "--generate")) {
|
|
192
|
+
throw new Error("Use exactly --check (offline verification) or --generate (pinned regeneration)");
|
|
193
|
+
}
|
|
194
|
+
if (args[0] === "--generate") await generate();
|
|
195
|
+
else await check();
|
|
196
|
+
}
|
package/src/async/job-manager.ts
CHANGED
|
@@ -569,14 +569,22 @@ export class AsyncJobManager {
|
|
|
569
569
|
* instead of the last-created process-global instance (review thread P1).
|
|
570
570
|
* Returns TRUE when the mapping was installed (or already held by this
|
|
571
571
|
* manager); returns FALSE when the endpoint id is already held by a
|
|
572
|
-
* FOREIGN
|
|
573
|
-
* resumed under that endpoint must then
|
|
574
|
-
* silently replacing the first manager, which
|
|
575
|
-
* session's tools resolve the second manager and let
|
|
576
|
-
* queried, registered, or cancelled across sessions
|
|
572
|
+
* FOREIGN manager whose authority has not fully settled — a second
|
|
573
|
+
* top-level session constructed or resumed under that endpoint must then
|
|
574
|
+
* fail construction instead of silently replacing the first manager, which
|
|
575
|
+
* would make the first session's tools resolve the second manager and let
|
|
576
|
+
* same-id jobs be queried, registered, or cancelled across sessions
|
|
577
|
+
* (review thread P1). */
|
|
577
578
|
static registerForEndpoint(endpointId: string, manager: AsyncJobManager): boolean {
|
|
578
579
|
const holder = AsyncJobManager.#byEndpoint.get(endpointId);
|
|
579
|
-
if (
|
|
580
|
+
if (manager.#disposed || manager.#registrationClosed) return false;
|
|
581
|
+
if (holder !== undefined && holder !== manager) {
|
|
582
|
+
// A manager remains the endpoint owner until all authority retained
|
|
583
|
+
// past its disposal deadline has physically settled. Logical shutdown
|
|
584
|
+
// alone must not admit a replacement while late callbacks can still run.
|
|
585
|
+
if (!holder.#disposed || !holder.#disposalSettled) return false;
|
|
586
|
+
AsyncJobManager.#byEndpoint.delete(endpointId);
|
|
587
|
+
}
|
|
580
588
|
AsyncJobManager.#byEndpoint.set(endpointId, manager);
|
|
581
589
|
return true;
|
|
582
590
|
}
|
|
@@ -586,7 +594,8 @@ export class AsyncJobManager {
|
|
|
586
594
|
return AsyncJobManager.#byEndpoint.get(endpointId);
|
|
587
595
|
}
|
|
588
596
|
|
|
589
|
-
static unregisterForEndpoint(endpointId: string): void {
|
|
597
|
+
static unregisterForEndpoint(endpointId: string, manager?: AsyncJobManager): void {
|
|
598
|
+
if (manager !== undefined && AsyncJobManager.#byEndpoint.get(endpointId) !== manager) return;
|
|
590
599
|
AsyncJobManager.#byEndpoint.delete(endpointId);
|
|
591
600
|
}
|
|
592
601
|
|
|
@@ -619,9 +628,13 @@ export class AsyncJobManager {
|
|
|
619
628
|
manager: AsyncJobManager | undefined,
|
|
620
629
|
): boolean {
|
|
621
630
|
if (!manager || predecessorEndpointId === successorEndpointId) return true;
|
|
631
|
+
if (manager.#disposed || manager.#registrationClosed) return false;
|
|
622
632
|
if (AsyncJobManager.#byEndpoint.get(predecessorEndpointId) !== manager) return true;
|
|
623
633
|
const successorOwner = AsyncJobManager.#byEndpoint.get(successorEndpointId);
|
|
624
|
-
if (successorOwner !== undefined && successorOwner !== manager)
|
|
634
|
+
if (successorOwner !== undefined && successorOwner !== manager) {
|
|
635
|
+
if (!successorOwner.#disposed || !successorOwner.#disposalSettled) return false;
|
|
636
|
+
AsyncJobManager.#byEndpoint.delete(successorEndpointId);
|
|
637
|
+
}
|
|
625
638
|
AsyncJobManager.#byEndpoint.delete(predecessorEndpointId);
|
|
626
639
|
AsyncJobManager.#byEndpoint.set(successorEndpointId, manager);
|
|
627
640
|
return true;
|
|
@@ -651,6 +664,7 @@ export class AsyncJobManager {
|
|
|
651
664
|
|
|
652
665
|
readonly #jobs = new Map<string, AsyncJob>();
|
|
653
666
|
#retainedDisposalCompletion: Promise<void> = Promise.resolve();
|
|
667
|
+
#disposePromise: Promise<boolean> | undefined;
|
|
654
668
|
readonly #deliveries: AsyncJobDelivery[] = [];
|
|
655
669
|
readonly #inFlightDeliveries: AsyncJobDelivery[] = [];
|
|
656
670
|
readonly #suppressedDeliveries = new Set<string>();
|
|
@@ -674,6 +688,8 @@ export class AsyncJobManager {
|
|
|
674
688
|
readonly #maxDeadLetterOverflowOwners: number;
|
|
675
689
|
#deliveryLoop: Promise<void> | undefined;
|
|
676
690
|
#disposed = false;
|
|
691
|
+
/** Set only after all authority retained past a disposal deadline settles. */
|
|
692
|
+
#disposalSettled = false;
|
|
677
693
|
#runningOwnerCleanups = false;
|
|
678
694
|
readonly #subagentRecords = new Map<string, SubagentRecord>();
|
|
679
695
|
readonly #terminalEvents = new Map<string, TerminalEvent>();
|
|
@@ -2697,7 +2713,28 @@ export class AsyncJobManager {
|
|
|
2697
2713
|
markBackgrounded(jobId: string, generation: string, reason: FoldReason): boolean {
|
|
2698
2714
|
const job = this.#jobs.get(jobId);
|
|
2699
2715
|
if (!job || job.generation !== generation) return false;
|
|
2700
|
-
if (job.metadata?.backgrounded === true)
|
|
2716
|
+
if (job.metadata?.backgrounded === true) {
|
|
2717
|
+
// A direct async start is already backgrounded, but a later `job` await
|
|
2718
|
+
// can still be folded by a steer. Preserve the existing background state
|
|
2719
|
+
// while recording the first fold reason and publishing its event.
|
|
2720
|
+
if (job.metadata.foldReason !== undefined) return true;
|
|
2721
|
+
job.metadata = { ...job.metadata, foldReason: reason };
|
|
2722
|
+
for (const delivery of [...this.#deliveries, ...this.#inFlightDeliveries]) {
|
|
2723
|
+
if (delivery.jobId === jobId && delivery.generation === generation) delivery.foldReason = reason;
|
|
2724
|
+
}
|
|
2725
|
+
this.#notifyChange();
|
|
2726
|
+
const event: JobFoldEvent = { jobId, generation, reason };
|
|
2727
|
+
for (const cb of this.#foldListeners) {
|
|
2728
|
+
try {
|
|
2729
|
+
cb(event);
|
|
2730
|
+
} catch (error) {
|
|
2731
|
+
logger.warn("Async job fold listener failed", {
|
|
2732
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2733
|
+
});
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
return true;
|
|
2737
|
+
}
|
|
2701
2738
|
job.metadata = { ...job.metadata, backgrounded: true, foldReason: reason };
|
|
2702
2739
|
for (const delivery of [...this.#deliveries, ...this.#inFlightDeliveries]) {
|
|
2703
2740
|
if (delivery.jobId === jobId && delivery.generation === generation) {
|
|
@@ -2773,6 +2810,13 @@ export class AsyncJobManager {
|
|
|
2773
2810
|
}
|
|
2774
2811
|
|
|
2775
2812
|
async dispose(options?: { timeoutMs?: number }): Promise<boolean> {
|
|
2813
|
+
if (this.#disposePromise) return this.#disposePromise;
|
|
2814
|
+
const disposal = this.#disposeInternal(options);
|
|
2815
|
+
this.#disposePromise = disposal;
|
|
2816
|
+
return disposal;
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2819
|
+
async #disposeInternal(options?: { timeoutMs?: number }): Promise<boolean> {
|
|
2776
2820
|
// Close registration FIRST, then run owner cleanups, and only then mark the
|
|
2777
2821
|
// manager disposed. Setting #disposed before the cleanups made
|
|
2778
2822
|
// #ensureDeliveryLoop a no-op, so a failure an owner cleanup settled through
|
|
@@ -2865,6 +2909,13 @@ export class AsyncJobManager {
|
|
|
2865
2909
|
this.#notifyChange();
|
|
2866
2910
|
this.#changeListeners.clear();
|
|
2867
2911
|
this.#foldListeners.clear();
|
|
2912
|
+
const releaseEndpointOwnership = (): void => {
|
|
2913
|
+
this.#disposalSettled = true;
|
|
2914
|
+
AsyncJobManager.unregisterManager(this);
|
|
2915
|
+
if (AsyncJobManager.instance() === this) AsyncJobManager.setInstance(undefined);
|
|
2916
|
+
};
|
|
2917
|
+
if (disposalCompleted) releaseEndpointOwnership();
|
|
2918
|
+
else void this.#retainedDisposalCompletion.then(releaseEndpointOwnership);
|
|
2868
2919
|
return disposalCompleted;
|
|
2869
2920
|
}
|
|
2870
2921
|
|
package/src/cli/daemon-cli.ts
CHANGED
|
@@ -12,26 +12,28 @@ import type {
|
|
|
12
12
|
DaemonKind,
|
|
13
13
|
DaemonOperationOptions,
|
|
14
14
|
DaemonOperationResult,
|
|
15
|
+
DaemonStatus,
|
|
15
16
|
} from "../daemon/control-types";
|
|
16
17
|
import {
|
|
17
18
|
DAEMON_ACTION_TOKENS,
|
|
18
|
-
|
|
19
|
+
daemonOperationOutcome,
|
|
19
20
|
formatDaemonResult,
|
|
20
21
|
formatDaemonStatus,
|
|
21
22
|
resolveDaemonAction,
|
|
22
23
|
} from "../daemon/operator-contract";
|
|
23
24
|
import { runChatDaemonInternal } from "../sdk/bus/chat-daemon-cli";
|
|
25
|
+
import { PublicCommandFailure, type PublicDaemonTargetOutcome } from "./public-command-errors";
|
|
24
26
|
|
|
25
27
|
export type DaemonCliAction = "list" | "status" | "stop" | "restart";
|
|
26
28
|
export type DaemonInternalCliAction = "discord-internal" | "slack-internal";
|
|
27
29
|
export type DaemonCommandAction = DaemonCliAction | DaemonInternalCliAction;
|
|
28
30
|
|
|
29
|
-
export class UnknownDaemonKindError extends
|
|
31
|
+
export class UnknownDaemonKindError extends PublicCommandFailure {
|
|
30
32
|
constructor(
|
|
31
33
|
readonly kinds: readonly string[],
|
|
32
34
|
readonly knownKinds: readonly DaemonKind[],
|
|
33
35
|
) {
|
|
34
|
-
super(
|
|
36
|
+
super({ kind: "operation_failed", proof: "pre-effect" });
|
|
35
37
|
this.name = "UnknownDaemonKindError";
|
|
36
38
|
}
|
|
37
39
|
}
|
|
@@ -60,6 +62,7 @@ export interface DaemonCommandArgs {
|
|
|
60
62
|
export interface DaemonCommandDeps {
|
|
61
63
|
settings?: Settings;
|
|
62
64
|
controllers?: BuiltInDaemonController[];
|
|
65
|
+
/** Internal update orchestration retains result rendering and failure aggregation. */
|
|
63
66
|
setExitCode?: (code: number) => void;
|
|
64
67
|
}
|
|
65
68
|
|
|
@@ -131,15 +134,36 @@ export async function runDaemonCommand(cmd: DaemonCommandArgs, deps: DaemonComma
|
|
|
131
134
|
}
|
|
132
135
|
const unknownKinds = cmd.kinds.filter(kind => !(KNOWN_KINDS as readonly string[]).includes(kind));
|
|
133
136
|
if (unknownKinds.length > 0) throw new UnknownDaemonKindError(unknownKinds, KNOWN_KINDS);
|
|
137
|
+
// Settings and controller construction failures are NOT an availability
|
|
138
|
+
// condition. Malformed configuration, permission/IO errors, and programming
|
|
139
|
+
// errors are permanent and each needs its own root cause: collapsing them into
|
|
140
|
+
// `unavailable` tells an operator (or an AI caller) to retry a failure that
|
|
141
|
+
// will never succeed. Let them propagate to the normal CLI error rendering,
|
|
142
|
+
// which is the pre-existing contract for this path.
|
|
134
143
|
const settings = deps.settings ?? (await Settings.init());
|
|
135
|
-
const controllers =
|
|
144
|
+
const controllers: BuiltInDaemonController[] =
|
|
145
|
+
deps.controllers ?? selectDaemonControllers(settings, cmd.kinds, cmd.all);
|
|
136
146
|
|
|
137
147
|
if (cmd.action === "list" || cmd.action === "status") {
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
148
|
+
const statusResults = await Promise.allSettled(controllers.map(controller => controller.status()));
|
|
149
|
+
const statuses: DaemonStatus[] = [];
|
|
150
|
+
const failedTargets: PublicDaemonTargetOutcome[] = [];
|
|
151
|
+
for (const [index, result] of statusResults.entries()) {
|
|
152
|
+
if (result.status === "fulfilled") statuses.push(result.value);
|
|
153
|
+
else failedTargets.push({ kind: controllers[index]!.kind, outcome: "unknown" });
|
|
154
|
+
}
|
|
155
|
+
if (failedTargets.length > 0) {
|
|
156
|
+
throw new PublicCommandFailure({
|
|
157
|
+
kind: "daemon_mixed",
|
|
158
|
+
proof: "pre-effect",
|
|
159
|
+
targets: failedTargets,
|
|
160
|
+
partialStatuses: statuses,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
if (statuses.length > 0) {
|
|
164
|
+
if (cmd.json) process.stdout.write(`${JSON.stringify(statuses, null, 2)}\n`);
|
|
165
|
+
else
|
|
166
|
+
process.stdout.write(`${statuses.map(s => formatDaemonStatus(s, { verbose: cmd.verbose })).join("\n")}\n`);
|
|
143
167
|
}
|
|
144
168
|
return;
|
|
145
169
|
}
|
|
@@ -152,19 +176,30 @@ export async function runDaemonCommand(cmd: DaemonCommandArgs, deps: DaemonComma
|
|
|
152
176
|
allowDisabledNoop: cmd.allowDisabledNoop,
|
|
153
177
|
};
|
|
154
178
|
const results: DaemonOperationResult[] = [];
|
|
155
|
-
|
|
156
|
-
|
|
179
|
+
const targets: PublicDaemonTargetOutcome[] = [];
|
|
180
|
+
for (const [index, controller] of controllers.entries()) {
|
|
181
|
+
let result: DaemonOperationResult;
|
|
182
|
+
try {
|
|
183
|
+
result = cmd.action === "restart" ? await controller.reload(opts) : await controller.stop(opts);
|
|
184
|
+
} catch {
|
|
185
|
+
targets.push({ kind: controller.kind, outcome: "unknown" });
|
|
186
|
+
for (const pending of controllers.slice(index + 1))
|
|
187
|
+
targets.push({ kind: pending.kind, outcome: "not-applied" });
|
|
188
|
+
// Completed targets keep their full results: the envelope warns against
|
|
189
|
+
// replaying applied mutations, so it must carry the resulting state the
|
|
190
|
+
// caller has to reconcile against.
|
|
191
|
+
throw new PublicCommandFailure({ kind: "daemon_mixed", targets, partialResults: results });
|
|
192
|
+
}
|
|
193
|
+
results.push(result);
|
|
194
|
+
targets.push({ kind: controller.kind, outcome: daemonOperationOutcome(result) });
|
|
157
195
|
}
|
|
196
|
+
const failed = results.some(result => !result.ok);
|
|
197
|
+
if (failed && !deps.setExitCode)
|
|
198
|
+
throw new PublicCommandFailure({ kind: "daemon_mixed", targets, partialResults: results });
|
|
158
199
|
if (cmd.json) {
|
|
159
200
|
process.stdout.write(`${JSON.stringify(results, null, 2)}\n`);
|
|
160
201
|
} else {
|
|
161
202
|
process.stdout.write(`${results.map(formatDaemonResult).join("\n")}\n`);
|
|
162
203
|
}
|
|
163
|
-
if (
|
|
164
|
-
(
|
|
165
|
-
deps.setExitCode ??
|
|
166
|
-
(code => {
|
|
167
|
-
process.exitCode = code;
|
|
168
|
-
})
|
|
169
|
-
)(DAEMON_EXIT.failure);
|
|
204
|
+
if (failed) deps.setExitCode?.(1);
|
|
170
205
|
}
|