@gajae-code/coding-agent 0.13.3 → 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 +184 -2
- 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 +9 -1
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +70 -6
- 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 +1 -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/gajae-pet-widget.d.ts +8 -30
- 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 +11 -25
- 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/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 +40 -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 +9 -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 +20 -1
- package/src/config/model-profiles.ts +29 -19
- package/src/config/model-registry.ts +132 -21
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/settings-schema.ts +76 -6
- 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/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 +40 -32
- package/src/main.ts +32 -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/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/gajae-pet-widget.ts +539 -213
- package/src/modes/components/irc-sidebar.ts +11 -0
- package/src/modes/components/iterm-pet-transport.ts +585 -0
- package/src/modes/components/oauth-selector.ts +277 -86
- package/src/modes/components/pet-capability.ts +39 -40
- package/src/modes/components/settings-selector.ts +9 -0
- package/src/modes/components/status-line/gh.ts +45 -1
- package/src/modes/components/status-line/segments.ts +16 -1
- 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 +177 -72
- 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/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 +2857 -582
- 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 +173 -12
- package/src/session/messages.ts +1 -1
- package/src/session/secure-token-file.ts +80 -0
- package/src/session/session-manager.ts +730 -58
- 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 +98 -16
- 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 +27 -16
- 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/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
|
@@ -261,11 +261,46 @@ FROM model_usage_legacy
|
|
|
261
261
|
key: row.key,
|
|
262
262
|
error: String(error),
|
|
263
263
|
});
|
|
264
|
+
// A malformed row must fail the whole read: the migration drains
|
|
265
|
+
// rows only after a fully successful read, and deleting a row that
|
|
266
|
+
// never decoded would permanently lose its value. Throwing keeps
|
|
267
|
+
// every row (including the malformed one) in place for repair.
|
|
268
|
+
throw error;
|
|
264
269
|
}
|
|
265
270
|
}
|
|
266
271
|
return settings as Settings;
|
|
267
272
|
}
|
|
268
273
|
|
|
274
|
+
/**
|
|
275
|
+
* @deprecated Settings are now stored in config.yml, not agent.db.
|
|
276
|
+
* Clears the legacy settings rows after they have been drained into
|
|
277
|
+
* config.yml so a later load never re-imports them (the database has no
|
|
278
|
+
* other one-time guard). Retries transient SQLITE_BUSY contention with
|
|
279
|
+
* exponential backoff and THROWS on persistent failure: the migration must
|
|
280
|
+
* not treat a failed drain as success while stale rows stay eligible for
|
|
281
|
+
* re-import on a later load.
|
|
282
|
+
*/
|
|
283
|
+
async clearSettings(): Promise<void> {
|
|
284
|
+
const maxRetries = 3;
|
|
285
|
+
const baseDelayMs = 100;
|
|
286
|
+
let lastError: Error | undefined;
|
|
287
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
288
|
+
try {
|
|
289
|
+
this.#db.run("DELETE FROM settings");
|
|
290
|
+
return;
|
|
291
|
+
} catch (error) {
|
|
292
|
+
const isSqliteBusy =
|
|
293
|
+
error && typeof error === "object" && (error as { code?: string }).code === "SQLITE_BUSY";
|
|
294
|
+
if (!isSqliteBusy) {
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
lastError = error as Error;
|
|
298
|
+
await Bun.sleep(baseDelayMs * 2 ** attempt);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
throw lastError ?? new Error("Failed to clear legacy settings after retries");
|
|
302
|
+
}
|
|
303
|
+
|
|
269
304
|
/**
|
|
270
305
|
* @deprecated Settings are now stored in config.yml, not agent.db.
|
|
271
306
|
* This method is kept for backward compatibility but does nothing.
|
|
@@ -388,10 +388,41 @@ function removeResidentCacheTreeNoFollow(pathname: string): void {
|
|
|
388
388
|
fs.unlinkSync(pathname);
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
+
/**
|
|
392
|
+
* Disposal-time parent authority is an *identity* contract: the retained descriptor
|
|
393
|
+
* must still name the same owned directory, so a substituted parent (rename, symlink,
|
|
394
|
+
* or a foreign directory moved into place) fails closed and keeps disposal retryable.
|
|
395
|
+
*
|
|
396
|
+
* It deliberately does not re-assert the parent's owner-only mode. Adoption and every
|
|
397
|
+
* read/write path already refuse an untrusted (group/other-accessible) cache root, and
|
|
398
|
+
* the instance directory itself stays fully verified here — owner, mode, `O_NOFOLLOW`
|
|
399
|
+
* open, and post-rename `dev`/`ino` identity. Requiring owner-only mode on the parent
|
|
400
|
+
* *at disposal time* would instead turn a widened root into permanent retention of the
|
|
401
|
+
* predecessor's resident session bytes, which is the leak disposal exists to prevent.
|
|
402
|
+
*/
|
|
403
|
+
function assertResidentCacheDisposalParentIdentity(pathname: string, descriptor: number, uid: number): void {
|
|
404
|
+
let current: fs.Stats;
|
|
405
|
+
try {
|
|
406
|
+
current = fs.lstatSync(pathname);
|
|
407
|
+
} catch (error) {
|
|
408
|
+
throw residentCacheTrustError("directory_unverifiable", pathname, error);
|
|
409
|
+
}
|
|
410
|
+
if (!current.isDirectory() || current.isSymbolicLink() || current.uid !== uid)
|
|
411
|
+
throw new ResidentCacheTrustError("directory_untrusted", pathname);
|
|
412
|
+
let opened: fs.Stats;
|
|
413
|
+
try {
|
|
414
|
+
opened = fs.fstatSync(descriptor);
|
|
415
|
+
} catch (error) {
|
|
416
|
+
throw residentCacheTrustError("directory_descriptor_unverifiable", pathname, error);
|
|
417
|
+
}
|
|
418
|
+
if (!opened.isDirectory() || opened.uid !== uid || !hasSameFilesystemIdentity(current, opened))
|
|
419
|
+
throw new ResidentCacheTrustError("directory_identity_changed", pathname);
|
|
420
|
+
}
|
|
421
|
+
|
|
391
422
|
function assertResidentCacheDisposalParent(instanceDir: string, parentDescriptor: number): void {
|
|
392
423
|
const parentDir = path.dirname(instanceDir);
|
|
393
424
|
try {
|
|
394
|
-
|
|
425
|
+
assertResidentCacheDisposalParentIdentity(parentDir, parentDescriptor, residentCacheOwnerUid(parentDir));
|
|
395
426
|
} catch (error) {
|
|
396
427
|
throw residentCacheTrustError("parent_authority_changed", instanceDir, error);
|
|
397
428
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { UNPROVEN_TOOL_LABEL } from "../gjc-runtime/session-state-sidecar";
|
|
2
|
+
import { TOOL_DESCRIPTORS } from "../tools/descriptors";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Proves whether the tool OBJECT that actually ran is one this session constructed from a
|
|
6
|
+
* built-in descriptor, before any extension, MCP, or dynamically registered tool could
|
|
7
|
+
* override that registry name.
|
|
8
|
+
*/
|
|
9
|
+
export type BuiltinToolProvenance = (tool: object) => boolean;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Canonical public label for the tool object a call was ACTUALLY dispatched to.
|
|
13
|
+
*
|
|
14
|
+
* The input is the object the producer bound to the event, never a name resolved here. A
|
|
15
|
+
* wire name is model text and the tool list behind it is mutable: a `setTools`, MCP
|
|
16
|
+
* reload, or tool refresh between dispatch and this call would otherwise publish whatever
|
|
17
|
+
* holds the name by now instead of what ran.
|
|
18
|
+
*
|
|
19
|
+
* Two independent facts must hold before a canonical label is published:
|
|
20
|
+
*
|
|
21
|
+
* 1. the producer bound a dispatched tool object at all (an unknown name the loop
|
|
22
|
+
* rejected, and a call aborted before dispatch, bind nothing), AND
|
|
23
|
+
* 2. that object carries built-in provenance and its canonical name is one of the closed
|
|
24
|
+
* built-in descriptors.
|
|
25
|
+
*
|
|
26
|
+
* The object check is what makes the label trustworthy. A registry name is not
|
|
27
|
+
* provenance: an SDK extension, MCP, or custom tool may register itself as `bash` or
|
|
28
|
+
* `edit`, or claim a built-in `customWireName`, and would otherwise be published under
|
|
29
|
+
* the built-in's label. Without proven provenance — including for a direct AgentSession
|
|
30
|
+
* construction that supplies none — the answer is `custom`.
|
|
31
|
+
*/
|
|
32
|
+
export function canonicalCoordinatorToolLabel(
|
|
33
|
+
dispatchedTool: object | undefined,
|
|
34
|
+
isBuiltinToolObject: BuiltinToolProvenance,
|
|
35
|
+
): string {
|
|
36
|
+
if (!dispatchedTool || !isBuiltinToolObject(dispatchedTool)) return UNPROVEN_TOOL_LABEL;
|
|
37
|
+
const name = (dispatchedTool as { name?: unknown }).name;
|
|
38
|
+
if (typeof name !== "string" || !Object.hasOwn(TOOL_DESCRIPTORS, name)) return UNPROVEN_TOOL_LABEL;
|
|
39
|
+
return name;
|
|
40
|
+
}
|
|
@@ -1090,6 +1090,10 @@ export function prepareManagedSessionScopeForWriteSync(
|
|
|
1090
1090
|
policy,
|
|
1091
1091
|
);
|
|
1092
1092
|
stage = "store";
|
|
1093
|
+
// This must precede the first managed-store mutation: binding publication
|
|
1094
|
+
// reconciles receipts with the normal 50k fail-closed bound, while an older
|
|
1095
|
+
// macOS scope can contain only proven, terminal zero-byte remnants above it.
|
|
1096
|
+
reapScrubbedProtocolRemnantsSync(scope.directoryPath);
|
|
1093
1097
|
let store: ManagedSessionDescendantStore;
|
|
1094
1098
|
const openManagedStore = (): ManagedSessionDescendantStore => {
|
|
1095
1099
|
const next = buildStore();
|
|
@@ -43,7 +43,7 @@ function nativeSessionStorage(): NativeManagedSessionStorage {
|
|
|
43
43
|
|
|
44
44
|
export const MANAGED_ARTIFACT_MAX_DEPTH = 32;
|
|
45
45
|
export const MANAGED_ARTIFACT_MAX_FILES = 50_000;
|
|
46
|
-
export const MANAGED_ARTIFACT_MAX_FILE_BYTES =
|
|
46
|
+
export const MANAGED_ARTIFACT_MAX_FILE_BYTES = 128 * 1024 * 1024;
|
|
47
47
|
export const MANAGED_ARTIFACT_MAX_TOTAL_BYTES = 512 * 1024 * 1024;
|
|
48
48
|
const REPLACEMENT_CLEANUP_RECEIPT_MAX_BYTES = 64 * 1024;
|
|
49
49
|
const REPLACEMENT_CLEANUP_RECEIPT_SCAN_LIMIT = MANAGED_ARTIFACT_MAX_FILES;
|
|
@@ -62,12 +62,14 @@ export class ManagedPublishError extends Error {
|
|
|
62
62
|
| "io_error"
|
|
63
63
|
| "durability_failed";
|
|
64
64
|
readonly diagnostic: string;
|
|
65
|
+
readonly stagingCleanupSafe: boolean;
|
|
65
66
|
|
|
66
67
|
constructor(classification: ManagedPublishError["classification"], outcome: NativePublishOutcome) {
|
|
67
68
|
super(classification);
|
|
68
69
|
this.name = "ManagedPublishError";
|
|
69
70
|
this.classification = classification;
|
|
70
71
|
this.diagnostic = formatNativePublishDiagnostic(outcome);
|
|
72
|
+
this.stagingCleanupSafe = mayCleanCurrentStaging(outcome);
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
75
|
export class ManagedReplaceError extends Error {
|
|
@@ -77,6 +79,9 @@ export class ManagedReplaceError extends Error {
|
|
|
77
79
|
readonly retainedSuccessorPath: string | undefined;
|
|
78
80
|
readonly retainedPlaceholderPath: string | undefined;
|
|
79
81
|
readonly retainedUnknownPath: string | undefined;
|
|
82
|
+
/** Path-free Windows NTSTATUS of the underlying pre-mutation failure, when
|
|
83
|
+
* the native layer preserved one (e.g. `0xC0000043` for a sharing violation). */
|
|
84
|
+
readonly windowsErrorCode: string | undefined;
|
|
80
85
|
readonly replacementCause: unknown;
|
|
81
86
|
|
|
82
87
|
constructor(result: NativeExactUnlinkResult, cleanupReceiptPath: string, replacementCause?: unknown) {
|
|
@@ -89,6 +94,7 @@ export class ManagedReplaceError extends Error {
|
|
|
89
94
|
this.retainedSuccessorPath = result.retainedSuccessorPath;
|
|
90
95
|
this.retainedPlaceholderPath = result.retainedPlaceholderPath;
|
|
91
96
|
this.retainedUnknownPath = result.retainedUnknownPath;
|
|
97
|
+
this.windowsErrorCode = result.windowsErrorCode;
|
|
92
98
|
this.replacementCause = replacementCause;
|
|
93
99
|
}
|
|
94
100
|
}
|
|
@@ -170,7 +176,7 @@ function sameDirectoryTreeSnapshotAfterRename(
|
|
|
170
176
|
);
|
|
171
177
|
}
|
|
172
178
|
|
|
173
|
-
class ManagedTreeMoveOutcomeError extends Error {
|
|
179
|
+
export class ManagedTreeMoveOutcomeError extends Error {
|
|
174
180
|
constructor(
|
|
175
181
|
message: string,
|
|
176
182
|
readonly stagingCleanupSafe: boolean,
|
|
@@ -260,6 +266,17 @@ export interface ManagedAppendReceipt {
|
|
|
260
266
|
identity: ManagedFileIdentity;
|
|
261
267
|
}
|
|
262
268
|
|
|
269
|
+
function sameManagedIdentity(left: ManagedFileIdentity, right: ManagedFileIdentity): boolean {
|
|
270
|
+
return (
|
|
271
|
+
left.dev === right.dev &&
|
|
272
|
+
left.ino === right.ino &&
|
|
273
|
+
left.nlink === right.nlink &&
|
|
274
|
+
left.size === right.size &&
|
|
275
|
+
left.mtimeNs === right.mtimeNs &&
|
|
276
|
+
left.ctimeNs === right.ctimeNs
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
263
280
|
export interface ManagedBoundedAppendExpectation {
|
|
264
281
|
readonly dev: string;
|
|
265
282
|
readonly ino: string;
|
|
@@ -516,28 +533,30 @@ function reportScrubbedProtocolRemnantReap(reaped: number, failures: number): Sc
|
|
|
516
533
|
});
|
|
517
534
|
return { reaped, failures };
|
|
518
535
|
}
|
|
536
|
+
|
|
519
537
|
/**
|
|
520
538
|
* Best-effort removal of scrubbed write-protocol remnants from one managed
|
|
521
539
|
* directory. Only zero-length, single-link, non-symlink regular files whose
|
|
522
540
|
* names carry a terminal remnant prefix and whose timestamps are older than
|
|
523
541
|
* the age gate are removed: a zero-length single-link entry is exactly what
|
|
524
542
|
* the scrub proof leaves behind, and non-zero entries (displaced predecessors
|
|
525
|
-
* or detached receipts retained as evidence) are never touched.
|
|
526
|
-
*
|
|
527
|
-
*
|
|
543
|
+
* or detached receipts retained as evidence) are never touched. A proven
|
|
544
|
+
* concurrent disappearance (ENOENT) is benign; all other I/O failures are
|
|
545
|
+
* returned and logged once without aborting scope preparation.
|
|
528
546
|
*/
|
|
529
547
|
export function reapScrubbedProtocolRemnantsSync(
|
|
530
548
|
directory: string,
|
|
531
549
|
minAgeMs: number = SCRUBBED_REMNANT_MIN_AGE_MS,
|
|
532
|
-
):
|
|
550
|
+
): ScrubbedProtocolRemnantReapResult {
|
|
533
551
|
let names: string[];
|
|
534
552
|
try {
|
|
535
553
|
names = fs.readdirSync(directory);
|
|
536
|
-
} catch {
|
|
537
|
-
return 0;
|
|
554
|
+
} catch (error) {
|
|
555
|
+
return reportScrubbedProtocolRemnantReap(0, isEnoent(error) ? 0 : 1);
|
|
538
556
|
}
|
|
539
557
|
const cutoff = Date.now() - minAgeMs;
|
|
540
558
|
let reaped = 0;
|
|
559
|
+
let failures = 0;
|
|
541
560
|
for (const name of names) {
|
|
542
561
|
if (!SCRUBBED_REMNANT_PREFIXES.some(prefix => name.startsWith(prefix))) continue;
|
|
543
562
|
const pathname = path.join(directory, name);
|
|
@@ -547,11 +566,11 @@ export function reapScrubbedProtocolRemnantsSync(
|
|
|
547
566
|
if (named.mtimeMs > cutoff) continue;
|
|
548
567
|
fs.unlinkSync(pathname);
|
|
549
568
|
reaped += 1;
|
|
550
|
-
} catch {
|
|
551
|
-
|
|
569
|
+
} catch (error) {
|
|
570
|
+
if (!isEnoent(error)) failures += 1;
|
|
552
571
|
}
|
|
553
572
|
}
|
|
554
|
-
return reaped;
|
|
573
|
+
return reportScrubbedProtocolRemnantReap(reaped, failures);
|
|
555
574
|
}
|
|
556
575
|
|
|
557
576
|
/** Number of candidate remnants inspected between event-loop yields. */
|
|
@@ -1480,6 +1499,72 @@ export class ManagedSessionDescendantStore {
|
|
|
1480
1499
|
this.#publishRetainedNoReplace(this.#relative(resolved), bytes);
|
|
1481
1500
|
this.#assertBound();
|
|
1482
1501
|
}
|
|
1502
|
+
/**
|
|
1503
|
+
* Atomically publishes an already-written managed staging file without
|
|
1504
|
+
* materializing its contents. The staging file and destination must be
|
|
1505
|
+
* descendants of this retained store.
|
|
1506
|
+
*/
|
|
1507
|
+
publishStagedFileNoReplace(
|
|
1508
|
+
sourceRelativePath: string,
|
|
1509
|
+
destinationRelativePath: string,
|
|
1510
|
+
expected: { bytes: number; sha256: string },
|
|
1511
|
+
): void {
|
|
1512
|
+
this.#beforeMutation();
|
|
1513
|
+
this.#assertBound();
|
|
1514
|
+
const source = this.#resolve(sourceRelativePath);
|
|
1515
|
+
const destination = this.#resolve(destinationRelativePath);
|
|
1516
|
+
const fd = fs.openSync(source, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
1517
|
+
let sourceIdentity: ManagedFileSnapshot["identity"] | undefined;
|
|
1518
|
+
try {
|
|
1519
|
+
const descriptorStat = fs.fstatSync(fd, { bigint: true });
|
|
1520
|
+
const before = identity(descriptorStat);
|
|
1521
|
+
const named = identity(fs.lstatSync(source, { bigint: true }));
|
|
1522
|
+
if (
|
|
1523
|
+
!descriptorStat.isFile() ||
|
|
1524
|
+
before.nlink !== 1n ||
|
|
1525
|
+
!sameIdentity(before, named) ||
|
|
1526
|
+
before.size !== expected.bytes
|
|
1527
|
+
)
|
|
1528
|
+
throw new Error("managed_publish_identity_mismatch");
|
|
1529
|
+
const digest = createHash("sha256");
|
|
1530
|
+
const chunk = Buffer.allocUnsafe(1024 * 1024);
|
|
1531
|
+
let offset = 0;
|
|
1532
|
+
for (;;) {
|
|
1533
|
+
const bytesRead = fs.readSync(fd, chunk, 0, chunk.length, offset);
|
|
1534
|
+
if (bytesRead === 0) break;
|
|
1535
|
+
digest.update(chunk.subarray(0, bytesRead));
|
|
1536
|
+
offset += bytesRead;
|
|
1537
|
+
}
|
|
1538
|
+
if (digest.digest("hex") !== expected.sha256) throw new Error("managed_publish_identity_mismatch");
|
|
1539
|
+
fs.fsyncSync(fd);
|
|
1540
|
+
const after = identity(fs.fstatSync(fd, { bigint: true }));
|
|
1541
|
+
const namedAfter = identity(fs.lstatSync(source, { bigint: true }));
|
|
1542
|
+
if (!sameIdentity(before, after) || !sameIdentity(after, namedAfter))
|
|
1543
|
+
throw new Error("managed_publish_identity_mismatch");
|
|
1544
|
+
sourceIdentity = after;
|
|
1545
|
+
} finally {
|
|
1546
|
+
fs.closeSync(fd);
|
|
1547
|
+
}
|
|
1548
|
+
if (!sourceIdentity) throw new Error("managed_publish_identity_unavailable");
|
|
1549
|
+
const relativeSource = this.#relative(source);
|
|
1550
|
+
const relativeDestination = this.#relative(destination);
|
|
1551
|
+
const published = this.#authority
|
|
1552
|
+
? this.#authority.renameManagedFileNoReplace(
|
|
1553
|
+
relativeSource,
|
|
1554
|
+
relativeDestination,
|
|
1555
|
+
sourceIdentity.dev.toString(),
|
|
1556
|
+
sourceIdentity.ino.toString(),
|
|
1557
|
+
sourceIdentity.size.toString(),
|
|
1558
|
+
sourceIdentity.mtimeNs.toString(),
|
|
1559
|
+
sourceIdentity.ctimeNs.toString(),
|
|
1560
|
+
expected.sha256,
|
|
1561
|
+
)
|
|
1562
|
+
: nativeSessionStorage().renameNoReplacePath(source, destination);
|
|
1563
|
+
const outcome = classifyNativePublishOutcome(published, this.#authority ? "retained_file" : "direct_rename");
|
|
1564
|
+
if (!outcome.ok) throw publishFailure(outcome);
|
|
1565
|
+
if (!this.#authority) fsyncDirectory(this.#baseDir);
|
|
1566
|
+
this.#assertBound();
|
|
1567
|
+
}
|
|
1483
1568
|
|
|
1484
1569
|
async replace(relativePath: string, bytes: Uint8Array): Promise<void> {
|
|
1485
1570
|
this.#beforeMutation();
|
|
@@ -1501,6 +1586,49 @@ export class ManagedSessionDescendantStore {
|
|
|
1501
1586
|
this.#assertBound();
|
|
1502
1587
|
}
|
|
1503
1588
|
|
|
1589
|
+
replaceExpectedIdentitySync(relativePath: string, bytes: Uint8Array, expected: ManagedFileIdentity): void {
|
|
1590
|
+
this.#beforeMutation();
|
|
1591
|
+
this.#assertBound();
|
|
1592
|
+
const resolved = this.#resolve(relativePath);
|
|
1593
|
+
if (!this.#authority) {
|
|
1594
|
+
const current = captureManagedFileIdentityStreamingNoFollow(resolved);
|
|
1595
|
+
if (!sameManagedIdentity(current, expected)) throw new Error("managed_replace_identity_mismatch");
|
|
1596
|
+
replaceManagedFileSync(resolved, bytes, this.#subtreeRoot, this.#policy, undefined, current);
|
|
1597
|
+
this.#assertBound();
|
|
1598
|
+
return;
|
|
1599
|
+
}
|
|
1600
|
+
const relative = this.#relative(resolved);
|
|
1601
|
+
const observed = this.#authority.stat(relative);
|
|
1602
|
+
if (!observed.ok || !observed.identity) {
|
|
1603
|
+
const rawCode =
|
|
1604
|
+
typeof (observed as { code?: unknown })?.code === "string" ? (observed as { code: string }).code : "";
|
|
1605
|
+
// Authority reports "not_found" for missing, non-authority uses ENOENT.
|
|
1606
|
+
// Normalize to ENOENT so callers' isEnoent() recovers via create.
|
|
1607
|
+
const err = new Error(rawCode || "managed_replace_missing") as NodeJS.ErrnoException;
|
|
1608
|
+
err.code = rawCode === "not_found" ? "ENOENT" : rawCode || "managed_replace_missing";
|
|
1609
|
+
throw err;
|
|
1610
|
+
}
|
|
1611
|
+
const current = managedFileIdentityFromNative(observed.identity);
|
|
1612
|
+
if (!sameManagedIdentity(current, expected)) throw new Error("managed_replace_identity_mismatch");
|
|
1613
|
+
const expectedSha256 =
|
|
1614
|
+
typeof observed.identity.sha256 === "string" && /^[0-9a-f]{64}$/i.test(observed.identity.sha256)
|
|
1615
|
+
? observed.identity.sha256.toLowerCase()
|
|
1616
|
+
: this.readExpected(relativePath)?.identity.sha256;
|
|
1617
|
+
if (!expectedSha256) throw new Error("managed_replace_identity_unavailable");
|
|
1618
|
+
const replaced = (this.#authority as RecoveryFsRoot & RetainedManagedReplacer).replaceManaged(
|
|
1619
|
+
relative,
|
|
1620
|
+
bytes,
|
|
1621
|
+
observed.identity.dev,
|
|
1622
|
+
observed.identity.ino,
|
|
1623
|
+
observed.identity.size,
|
|
1624
|
+
observed.identity.mtimeNs,
|
|
1625
|
+
observed.identity.ctimeNs,
|
|
1626
|
+
expectedSha256,
|
|
1627
|
+
);
|
|
1628
|
+
if (!replaced.ok) throw new Error(replaced.code ?? "managed_replace_failed");
|
|
1629
|
+
this.#assertBound();
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1504
1632
|
replaceExpected(relativePath: string, bytes: Uint8Array, expected: ManagedFileSnapshot): void {
|
|
1505
1633
|
this.#beforeMutation();
|
|
1506
1634
|
this.#assertBound();
|
|
@@ -1608,6 +1736,24 @@ export class ManagedSessionDescendantStore {
|
|
|
1608
1736
|
return managedAppendReceiptFromIdentity(managedFileIdentityFromNative(appended.identity));
|
|
1609
1737
|
}
|
|
1610
1738
|
|
|
1739
|
+
appendExpectedIdentitySync(
|
|
1740
|
+
relativePath: string,
|
|
1741
|
+
bytes: Uint8Array,
|
|
1742
|
+
expected: ManagedFileIdentity,
|
|
1743
|
+
): ManagedAppendReceipt {
|
|
1744
|
+
const bounded = this.captureBoundedAppendExpectation(relativePath);
|
|
1745
|
+
if (
|
|
1746
|
+
!bounded ||
|
|
1747
|
+
bounded.dev !== expected.dev.toString() ||
|
|
1748
|
+
bounded.ino !== expected.ino.toString() ||
|
|
1749
|
+
bounded.size !== String(expected.size) ||
|
|
1750
|
+
bounded.mtimeNs !== expected.mtimeNs.toString() ||
|
|
1751
|
+
bounded.ctimeNs !== expected.ctimeNs.toString()
|
|
1752
|
+
)
|
|
1753
|
+
throw new Error("managed_append_identity_mismatch");
|
|
1754
|
+
return this.appendExpectedSync(relativePath, bytes, bounded);
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1611
1757
|
appendSync(relativePath: string, bytes: Uint8Array): ManagedAppendReceipt {
|
|
1612
1758
|
this.#beforeMutation();
|
|
1613
1759
|
this.#assertBound();
|
|
@@ -1615,7 +1761,13 @@ export class ManagedSessionDescendantStore {
|
|
|
1615
1761
|
if (this.#authority) {
|
|
1616
1762
|
const relative = this.#relative(resolved);
|
|
1617
1763
|
const observed = this.#authority.stat(relative);
|
|
1618
|
-
if (!observed.ok || !observed.identity)
|
|
1764
|
+
if (!observed.ok || !observed.identity) {
|
|
1765
|
+
const rawCode =
|
|
1766
|
+
typeof (observed as { code?: unknown })?.code === "string" ? (observed as { code: string }).code : "";
|
|
1767
|
+
const err = new Error(rawCode || "managed_append_missing") as NodeJS.ErrnoException;
|
|
1768
|
+
err.code = rawCode === "not_found" ? "ENOENT" : rawCode || "managed_append_missing";
|
|
1769
|
+
throw err;
|
|
1770
|
+
}
|
|
1619
1771
|
const nativeSha256 = observed.identity.sha256;
|
|
1620
1772
|
const expectedSha256 =
|
|
1621
1773
|
typeof nativeSha256 === "string" && /^[0-9a-f]{64}$/i.test(nativeSha256)
|
|
@@ -2891,6 +3043,15 @@ function replaceManagedFileGeneratedSync(
|
|
|
2891
3043
|
identity: publishedReceiptIdentity,
|
|
2892
3044
|
predecessor: expectedDestination,
|
|
2893
3045
|
};
|
|
3046
|
+
// Transient Windows sharing violations (a concurrent holder denying delete
|
|
3047
|
+
// sharing on the destination, issue #4330) are retried at the narrow
|
|
3048
|
+
// pre-mutation syscall boundary inside the native `exactReplacePath`: the
|
|
3049
|
+
// destination open is retried a bounded number of times while nothing has
|
|
3050
|
+
// been renamed or unlinked, and only `sharing_violation`/`io_error` with no
|
|
3051
|
+
// detached/retained paths can ever reach this throw from that open. This
|
|
3052
|
+
// TypeScript layer deliberately never retries: once `exactReplacePath`
|
|
3053
|
+
// returns, any failure that carries a detached/retained path is
|
|
3054
|
+
// post-mutation evidence and must surface unchanged for receipt recovery.
|
|
2894
3055
|
const replaced = nativeSessionStorage().exactReplacePath(
|
|
2895
3056
|
staging,
|
|
2896
3057
|
destination,
|
package/src/session/messages.ts
CHANGED
|
@@ -122,7 +122,7 @@ export function readPendingDisplayTag(details: unknown): string | undefined {
|
|
|
122
122
|
* the CustomMessageEntry to disk. Scoped intentionally narrow: only fields
|
|
123
123
|
* declared here are stripped. Adding a new entry is a deliberate, reviewed
|
|
124
124
|
* change — unrelated future payload fields are never silently dropped. */
|
|
125
|
-
export const INTERNAL_DETAILS_FIELDS = ["__pendingDisplayTag"] as const;
|
|
125
|
+
export const INTERNAL_DETAILS_FIELDS = ["__pendingDisplayTag", "ownedCompletions"] as const;
|
|
126
126
|
|
|
127
127
|
/** Return a `details` copy with every key in `INTERNAL_DETAILS_FIELDS`
|
|
128
128
|
* removed. Returns the input unchanged when there is nothing to strip
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { isEnoent } from "@gajae-code/utils";
|
|
4
|
+
|
|
5
|
+
function isPosix(): boolean {
|
|
6
|
+
return process.platform !== "win32";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async function validateDirectory(directory: string): Promise<void> {
|
|
10
|
+
await fs.mkdir(directory, { recursive: true, mode: 0o700 });
|
|
11
|
+
const stat = await fs.lstat(directory);
|
|
12
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) throw new Error("Credential token directory is unsafe.");
|
|
13
|
+
if (isPosix()) {
|
|
14
|
+
if (typeof process.getuid === "function" && stat.uid !== process.getuid()) {
|
|
15
|
+
throw new Error("Credential token directory has an unexpected owner.");
|
|
16
|
+
}
|
|
17
|
+
if ((stat.mode & 0o077) !== 0) await fs.chmod(directory, 0o700);
|
|
18
|
+
const repaired = await fs.lstat(directory);
|
|
19
|
+
if ((repaired.mode & 0o077) !== 0) throw new Error("Credential token directory is not owner-only.");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function validateTokenPath(file: string): Promise<boolean> {
|
|
24
|
+
let stat: Awaited<ReturnType<typeof fs.lstat>>;
|
|
25
|
+
try {
|
|
26
|
+
stat = await fs.lstat(file);
|
|
27
|
+
} catch (error) {
|
|
28
|
+
if (isEnoent(error)) return false;
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
if (stat.isSymbolicLink() || !stat.isFile()) throw new Error("Credential token path is unsafe.");
|
|
32
|
+
if (isPosix()) {
|
|
33
|
+
if (typeof process.getuid === "function" && stat.uid !== process.getuid()) {
|
|
34
|
+
throw new Error("Credential token file has an unexpected owner.");
|
|
35
|
+
}
|
|
36
|
+
if ((stat.mode & 0o077) !== 0) await fs.chmod(file, 0o600);
|
|
37
|
+
const repaired = await fs.lstat(file);
|
|
38
|
+
if ((repaired.mode & 0o077) !== 0) throw new Error("Credential token file is not owner-only.");
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function readSecureTokenFile(file: string): Promise<string | null> {
|
|
44
|
+
await validateDirectory(path.dirname(file));
|
|
45
|
+
if (!(await validateTokenPath(file))) return null;
|
|
46
|
+
const handle = await fs.open(file, "r");
|
|
47
|
+
try {
|
|
48
|
+
const opened = await handle.stat();
|
|
49
|
+
if (!opened.isFile()) throw new Error("Credential token path is unsafe.");
|
|
50
|
+
const value = (await handle.readFile("utf8")).trim();
|
|
51
|
+
return value || null;
|
|
52
|
+
} finally {
|
|
53
|
+
await handle.close();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function writeSecureTokenFile(file: string, token: string): Promise<void> {
|
|
58
|
+
await validateDirectory(path.dirname(file));
|
|
59
|
+
if (await validateTokenPath(file)) {
|
|
60
|
+
await fs.writeFile(file, token, { mode: 0o600 });
|
|
61
|
+
} else {
|
|
62
|
+
await fs.writeFile(file, token, { flag: "wx", mode: 0o600 });
|
|
63
|
+
}
|
|
64
|
+
if (isPosix()) await fs.chmod(file, 0o600);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function createSecureTokenFileExclusive(file: string, token: string): Promise<boolean> {
|
|
68
|
+
await validateDirectory(path.dirname(file));
|
|
69
|
+
try {
|
|
70
|
+
await fs.writeFile(file, token, { flag: "wx", mode: 0o600 });
|
|
71
|
+
} catch (error) {
|
|
72
|
+
if ((error as NodeJS.ErrnoException).code === "EEXIST") {
|
|
73
|
+
await validateTokenPath(file);
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
if (isPosix()) await fs.chmod(file, 0o600);
|
|
79
|
+
return true;
|
|
80
|
+
}
|