@sayknow-cli/coding-agent 0.4.7 → 0.5.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 +97 -0
- package/dist/types/capability/index.d.ts +10 -20
- package/dist/types/capability/types.d.ts +3 -0
- package/dist/types/cli/args.d.ts +0 -2
- package/dist/types/cli/read-cli.d.ts +1 -0
- package/dist/types/cli.d.ts +9 -1
- package/dist/types/commands/daemon.d.ts +2 -2
- package/dist/types/commands/deep-interview.d.ts +9 -0
- package/dist/types/commands/harness.d.ts +22 -0
- package/dist/types/commands/read.d.ts +6 -0
- package/dist/types/commands/sdk.d.ts +20 -2
- package/dist/types/config/keybindings.d.ts +34 -4
- package/dist/types/config/model-profile-contract.d.ts +40 -0
- package/dist/types/config/model-profiles.d.ts +2 -3
- package/dist/types/config/model-registry.d.ts +5 -0
- package/dist/types/config/provider-auth-health.d.ts +14 -0
- package/dist/types/config/provider-ranking.d.ts +59 -0
- package/dist/types/config/settings-schema.d.ts +156 -10
- package/dist/types/config/settings.d.ts +3 -0
- package/dist/types/edit/modes/patch.d.ts +13 -0
- package/dist/types/edit/path-mutation-lock.d.ts +15 -0
- package/dist/types/eval/py/executor.d.ts +1 -1
- package/dist/types/eval/py/runner-artifact.d.ts +8 -0
- package/dist/types/eval/py/tool-bridge.d.ts +1 -2
- package/dist/types/extensibility/extensions/types.d.ts +43 -2
- package/dist/types/extensibility/shared-events.d.ts +6 -0
- package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
- package/dist/types/main.d.ts +33 -2
- package/dist/types/memories/index.d.ts +2 -0
- package/dist/types/modes/acp/acp-agent.d.ts +22 -9
- package/dist/types/modes/components/assistant-message.d.ts +3 -1
- package/dist/types/modes/components/btw-panel.d.ts +1 -0
- package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
- package/dist/types/modes/components/queue-pane.d.ts +8 -0
- package/dist/types/modes/components/queued-message-selector.d.ts +6 -0
- package/dist/types/modes/components/read-tool-group.d.ts +4 -4
- package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +2 -1
- package/dist/types/modes/components/session-observer-overlay.d.ts +4 -0
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +8 -0
- package/dist/types/modes/components/tool-status-header.d.ts +4 -2
- package/dist/types/modes/components/welcome.d.ts +5 -0
- package/dist/types/modes/controllers/btw-controller.d.ts +5 -0
- package/dist/types/modes/controllers/command-controller.d.ts +2 -0
- package/dist/types/modes/controllers/event-controller.d.ts +3 -0
- package/dist/types/modes/interactive-mode.d.ts +13 -2
- package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
- package/dist/types/modes/prompt-action-autocomplete.d.ts +6 -1
- package/dist/types/modes/prompt-suggestion-controller.d.ts +35 -0
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +2 -2
- package/dist/types/modes/types.d.ts +6 -0
- package/dist/types/modes/utils/hotkeys-markdown.d.ts +2 -1
- package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
- package/dist/types/runtime/memory-domain.d.ts +9 -0
- package/dist/types/runtime/memory-guard-contract.d.ts +71 -0
- package/dist/types/runtime/memory-guard.d.ts +39 -0
- package/dist/types/runtime/memory-limit.d.ts +11 -0
- package/dist/types/runtime-mcp/content-limits.d.ts +7 -0
- package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +1 -1
- package/dist/types/runtime-mcp/manager.d.ts +9 -1
- package/dist/types/runtime-mcp/oauth-flow.d.ts +0 -5
- package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +14 -0
- package/dist/types/runtime-mcp/redaction.d.ts +2 -0
- package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
- package/dist/types/sdk/acp/final-text.d.ts +19 -0
- package/dist/types/sdk/acp/mcp.d.ts +23 -0
- package/dist/types/sdk/broker/broker.d.ts +2 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +13 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +9 -1
- package/dist/types/sdk/bus/config-commands.d.ts +2 -2
- package/dist/types/sdk/bus/config.d.ts +2 -0
- package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +1 -0
- package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
- package/dist/types/sdk/bus/index.d.ts +52 -4
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +37 -0
- package/dist/types/sdk/bus/lifecycle-commands.d.ts +5 -4
- package/dist/types/sdk/bus/notification-orchestration.d.ts +1 -0
- package/dist/types/sdk/bus/notification-service.d.ts +34 -0
- package/dist/types/sdk/bus/operator-runtime.d.ts +1 -0
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +106 -0
- package/dist/types/sdk/bus/rate-limit-pool.d.ts +2 -0
- package/dist/types/sdk/bus/reconciliation-store.d.ts +65 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +33 -9
- package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +286 -12
- package/dist/types/sdk/bus/telegram-reference.d.ts +2 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +88 -2
- package/dist/types/sdk/client/discovery.d.ts +2 -0
- package/dist/types/sdk/client/liveness.d.ts +7 -0
- package/dist/types/sdk/host/control/operations.d.ts +3 -2
- package/dist/types/sdk/host/host.d.ts +3 -1
- package/dist/types/sdk/host/query/handlers.d.ts +14 -0
- package/dist/types/sdk/index.d.ts +2 -0
- package/dist/types/sdk/lifecycle-session.d.ts +10 -1
- package/dist/types/sdk/prompt-status.d.ts +88 -0
- package/dist/types/sdk/session-directory.d.ts +1 -1
- package/dist/types/sdk/session.d.ts +7 -0
- package/dist/types/sdk/startup-capability.d.ts +9 -0
- package/dist/types/sdk/transport/auth-preface.d.ts +9 -0
- package/dist/types/sdk/transport/index.d.ts +12 -0
- package/dist/types/sdk/transport/relay.d.ts +43 -0
- package/dist/types/sdk/transport/serve-cli.d.ts +4 -0
- package/dist/types/sdk/transport/socket.d.ts +7 -0
- package/dist/types/sdk/transport/stdio.d.ts +3 -0
- package/dist/types/session/agent-session.d.ts +83 -24
- package/dist/types/session/btw-contract.d.ts +16 -0
- package/dist/types/session/fallback-chain-controller.d.ts +18 -2
- package/dist/types/session/internal/managed-session-scope.d.ts +70 -10
- package/dist/types/session/internal/managed-session-storage.d.ts +34 -12
- package/dist/types/session/internal/native-publish-outcome.d.ts +48 -0
- package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
- package/dist/types/session/session-manager.d.ts +89 -18
- package/dist/types/session/session-storage.d.ts +31 -0
- package/dist/types/session/streaming-output.d.ts +60 -5
- package/dist/types/setup/credential-import.d.ts +5 -1
- package/dist/types/setup/provider-onboarding.d.ts +2 -0
- package/dist/types/skc-runtime/deep-interview-runtime.d.ts +1 -1
- package/dist/types/skc-runtime/deep-interview-stage.d.ts +37 -0
- package/dist/types/skc-runtime/gc-runtime.d.ts +1 -1
- package/dist/types/skc-runtime/linux-proc.d.ts +22 -14
- package/dist/types/skc-runtime/memory-guard-owner-claims.d.ts +47 -0
- package/dist/types/skc-runtime/ralplan-runtime.d.ts +112 -1
- package/dist/types/skc-runtime/repository-binding.d.ts +63 -0
- package/dist/types/skc-runtime/state-runtime.d.ts +3 -1
- package/dist/types/skc-runtime/state-writer.d.ts +5 -1
- package/dist/types/skc-runtime/team-launch.d.ts +1 -1
- package/dist/types/skc-runtime/team-runtime.d.ts +9 -2
- package/dist/types/skc-runtime/team-store.d.ts +12 -0
- package/dist/types/skc-runtime/team-worker-memory-guard.d.ts +92 -0
- package/dist/types/skc-runtime/tmux-owner-isolation.d.ts +7 -0
- package/dist/types/skc-runtime/ultragoal-guard.d.ts +6 -5
- package/dist/types/skc-runtime/ultragoal-receipt-freshness.d.ts +28 -0
- package/dist/types/skc-runtime/ultragoal-runtime.d.ts +43 -5
- package/dist/types/skill-state/workflow-hud.d.ts +3 -0
- package/dist/types/ssh/utils.d.ts +1 -0
- package/dist/types/task/discovery.d.ts +3 -1
- package/dist/types/task/executor.d.ts +6 -0
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/task/provider-retry-status.d.ts +13 -0
- package/dist/types/task/receipt.d.ts +2 -0
- package/dist/types/task/types.d.ts +133 -0
- package/dist/types/task/ultragoal-redteam-activation.d.ts +33 -0
- package/dist/types/tools/browser/launch.d.ts +7 -0
- package/dist/types/tools/fetch.d.ts +22 -9
- package/dist/types/tools/image-gen.d.ts +63 -1
- package/dist/types/tools/index.d.ts +7 -1
- package/dist/types/tools/output-meta.d.ts +21 -1
- package/dist/types/tools/read-internals.d.ts +12 -0
- package/dist/types/tools/read.d.ts +45 -1
- package/dist/types/tools/resource-gc.d.ts +23 -0
- package/dist/types/tools/skill-discovery.d.ts +7 -0
- package/dist/types/tools/sqlite-reader.d.ts +7 -0
- package/dist/types/tools/tool-result.d.ts +7 -1
- package/dist/types/utils/prompt-suggestion.d.ts +33 -0
- package/dist/types/utils/shell-snapshot.d.ts +12 -0
- package/dist/types/web/insane/bridge.d.ts +1 -0
- package/dist/types/web/insane/url-guard.d.ts +17 -0
- package/package.json +8 -12
- package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
- package/scripts/capture-platform-shortcut-labels-showcase.ts +342 -0
- package/scripts/capture-sticky-viewport-showcase.ts +292 -0
- package/scripts/compile-args.ts +0 -1
- package/scripts/dogfood-repository-binding.ts +209 -0
- package/scripts/generate-docs-index.ts +4 -1
- package/scripts/generate-sdk-operation-inventory.ts +9 -0
- package/scripts/run-test-manifest.ts +6 -4
- package/scripts/verify-skc-sdk-canonicalization.ts +122 -18
- package/scripts/verify-sticky-viewport-showcase.ts +611 -0
- package/src/capability/index.ts +58 -42
- package/src/capability/types.ts +3 -0
- package/src/cli/args.ts +16 -100
- package/src/cli/fast-help.ts +1 -1
- package/src/cli/mcp-cli.ts +4 -21
- package/src/cli/notify-cli.ts +6 -38
- package/src/cli/read-cli.ts +2 -1
- package/src/cli/setup-cli.ts +10 -4
- package/src/cli.ts +133 -11
- package/src/commands/daemon.ts +22 -5
- package/src/commands/deep-interview.ts +26 -1
- package/src/commands/harness.ts +35 -12
- package/src/commands/read.ts +11 -2
- package/src/commands/sdk.ts +134 -17
- package/src/commands/team.ts +1 -1
- package/src/commit/agentic/index.ts +3 -3
- package/src/commit/map-reduce/index.ts +2 -2
- package/src/config/keybindings.ts +158 -25
- package/src/config/model-profile-contract.ts +174 -0
- package/src/config/model-profiles.ts +51 -10
- package/src/config/model-registry.ts +24 -4
- package/src/config/model-resolver.ts +2 -2
- package/src/config/provider-auth-health.ts +42 -0
- package/src/config/provider-ranking.ts +119 -0
- package/src/config/settings-schema.ts +157 -10
- package/src/config/settings.ts +254 -108
- package/src/coordinator-mcp/model-preset.ts +21 -74
- package/src/defaults/skc/skills/deep-interview/SKILL.md +147 -24
- package/src/defaults/skc/skills/ralplan/SKILL.md +91 -34
- package/src/defaults/skc/skills/team/SKILL.md +1 -1
- package/src/defaults/skc/skills/ultragoal/SKILL.md +68 -17
- package/src/discovery/ssh.ts +12 -1
- package/src/edit/index.ts +3 -6
- package/src/edit/modes/patch.ts +38 -1
- package/src/edit/modes/replace.ts +42 -0
- package/src/edit/path-mutation-lock.ts +112 -0
- package/src/eval/js/tool-bridge.ts +1 -1
- package/src/eval/py/executor.ts +37 -13
- package/src/eval/py/kernel.ts +1 -21
- package/src/eval/py/prelude.py +2 -2
- package/src/eval/py/runner-artifact.ts +84 -0
- package/src/eval/py/tool-bridge.ts +34 -18
- package/src/extensibility/extensions/runner.ts +4 -0
- package/src/extensibility/extensions/types.ts +42 -4
- package/src/extensibility/plugins/marketplace/fetcher.ts +191 -7
- package/src/extensibility/shared-events.ts +5 -0
- package/src/extensibility/skc-plugins/runtime-adapters.ts +2 -1
- package/src/hooks/native-skill-hook.ts +17 -4
- package/src/internal-urls/docs-index.generated.ts +17 -16
- package/src/internal-urls/local-protocol.ts +87 -25
- package/src/internal-urls/local-root-gc.ts +127 -0
- package/src/internal-urls/mcp-protocol.ts +73 -11
- package/src/main.ts +120 -42
- package/src/memories/index.ts +10 -0
- package/src/modes/DESIGN.md +52 -0
- package/src/modes/acp/acp-agent.ts +647 -83
- package/src/modes/acp/acp-event-mapper.ts +106 -12
- package/src/modes/acp/acp-mode.ts +39 -3
- package/src/modes/action-registry.ts +1 -1
- package/src/modes/components/assistant-message.ts +123 -22
- package/src/modes/components/btw-panel.ts +82 -16
- package/src/modes/components/irc-sidebar.ts +176 -62
- package/src/modes/components/model-selector.ts +61 -4
- package/src/modes/components/notifications-settings-editor.ts +1 -1
- package/src/modes/components/oauth-selector.ts +42 -12
- package/src/modes/components/plan-preview-overlay.ts +1 -1
- package/src/modes/components/queue-pane.ts +55 -9
- package/src/modes/components/queued-message-selector.ts +53 -10
- package/src/modes/components/read-tool-group.ts +82 -14
- package/src/modes/components/runtime-mcp-add-wizard.ts +5 -0
- package/src/modes/components/sayknow-pet-widget.ts +20 -8
- package/src/modes/components/session-observer-overlay.ts +187 -32
- package/src/modes/components/settings-selector.ts +60 -18
- package/src/modes/components/tool-execution.ts +138 -27
- package/src/modes/components/tool-status-header.ts +26 -8
- package/src/modes/components/welcome.ts +50 -23
- package/src/modes/controllers/btw-controller.ts +119 -36
- package/src/modes/controllers/command-controller.ts +101 -54
- package/src/modes/controllers/event-controller.ts +119 -27
- package/src/modes/controllers/extension-ui-controller.ts +23 -12
- package/src/modes/controllers/input-controller.ts +100 -8
- package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -6
- package/src/modes/controllers/selector-controller.ts +4 -1
- package/src/modes/interactive-mode.ts +201 -60
- package/src/modes/irc-observation-ledger.ts +71 -15
- package/src/modes/prompt-action-autocomplete.ts +32 -13
- package/src/modes/prompt-suggestion-controller.ts +96 -0
- package/src/modes/runtime-init.ts +20 -2
- package/src/modes/shared/agent-wire/command-dispatch.ts +3 -3
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +2 -2
- package/src/modes/types.ts +6 -0
- package/src/modes/utils/hotkeys-markdown.ts +64 -36
- package/src/modes/utils/ui-helpers.ts +99 -4
- package/src/prompts/agent-fragments/restricted-bash.md +1 -1
- package/src/prompts/agents/architect.md +17 -3
- package/src/prompts/agents/critic.md +17 -2
- package/src/prompts/agents/executor.md +1 -1
- package/src/prompts/agents/planner.md +8 -1
- package/src/prompts/system/btw-user.md +3 -8
- package/src/prompts/system/prompt-suggestion-system.md +32 -0
- package/src/prompts/system/system-prompt.md +6 -3
- package/src/prompts/tools/cron.md +3 -1
- package/src/prompts/tools/read.md +4 -2
- package/src/prompts/tools/skill-discovery.md +1 -0
- package/src/runtime/memory-domain.ts +66 -0
- package/src/runtime/memory-guard-contract.ts +73 -0
- package/src/runtime/memory-guard.ts +292 -0
- package/src/runtime/memory-limit.ts +50 -0
- package/src/runtime-mcp/client.ts +41 -55
- package/src/runtime-mcp/content-limits.ts +71 -0
- package/src/runtime-mcp/discoverable-tool-metadata.ts +1 -1
- package/src/runtime-mcp/json-rpc.ts +28 -11
- package/src/runtime-mcp/manager.ts +77 -59
- package/src/runtime-mcp/oauth-flow.ts +0 -72
- package/src/runtime-mcp/plugin-network-boundary.ts +101 -0
- package/src/runtime-mcp/redaction.ts +30 -0
- package/src/runtime-mcp/smithery-auth.ts +17 -2
- package/src/runtime-mcp/smithery-connect.ts +11 -1
- package/src/runtime-mcp/transports/http.ts +63 -22
- package/src/sdk/acp/adapter.ts +8 -1
- package/src/sdk/acp/final-text.ts +40 -0
- package/src/sdk/acp/mcp.ts +26 -0
- package/src/sdk/broker/broker.ts +34 -20
- package/src/sdk/broker/identity.ts +22 -12
- package/src/sdk/broker/lifecycle.ts +293 -43
- package/src/sdk/broker/session-index.ts +11 -1
- package/src/sdk/bus/chat-daemon-cli.ts +2 -2
- package/src/sdk/bus/chat-daemon-control.ts +22 -5
- package/src/sdk/bus/config-commands.ts +2 -2
- package/src/sdk/bus/config.ts +10 -2
- package/src/sdk/bus/control-drain-lease.ts +104 -0
- package/src/sdk/bus/conversation-store.ts +40 -6
- package/src/sdk/bus/daemon-paths.ts +2 -0
- package/src/sdk/bus/index.ts +793 -121
- package/src/sdk/bus/kind-aware-reconciliation.ts +242 -0
- package/src/sdk/bus/lifecycle-commands.ts +63 -10
- package/src/sdk/bus/lifecycle-control-runtime.ts +11 -2
- package/src/sdk/bus/lifecycle-orchestrator.ts +32 -1
- package/src/sdk/bus/notification-orchestration.ts +12 -0
- package/src/sdk/bus/notification-service.ts +87 -25
- package/src/sdk/bus/operator-runtime.ts +31 -5
- package/src/sdk/bus/prompt-reconciliation.ts +240 -0
- package/src/sdk/bus/rate-limit-pool.ts +8 -0
- package/src/sdk/bus/recent-activity.ts +90 -26
- package/src/sdk/bus/reconciliation-store.ts +224 -0
- package/src/sdk/bus/telegram-cli.ts +6 -13
- package/src/sdk/bus/telegram-daemon-cli.ts +8 -3
- package/src/sdk/bus/telegram-daemon-contract.ts +34 -9
- package/src/sdk/bus/telegram-daemon-control.ts +161 -40
- package/src/sdk/bus/telegram-daemon.ts +3649 -593
- package/src/sdk/bus/telegram-reference.ts +20 -2
- package/src/sdk/bus/topic-registry.ts +451 -12
- package/src/sdk/cli/session-cli.ts +15 -2
- package/src/sdk/client/discovery.ts +19 -3
- package/src/sdk/client/liveness.ts +49 -0
- package/src/sdk/host/control/dispatch.ts +8 -2
- package/src/sdk/host/control/operations.ts +3 -2
- package/src/sdk/host/host.ts +27 -9
- package/src/sdk/host/query/handlers.ts +125 -5
- package/src/sdk/index.ts +12 -0
- package/src/sdk/lifecycle-session.ts +19 -3
- package/src/sdk/mcp/server.ts +46 -18
- package/src/sdk/prompt-status.ts +97 -0
- package/src/sdk/protocol/operation-inventory.generated.json +145 -0
- package/src/sdk/protocol/operation-registry.ts +24 -4
- package/src/sdk/session-directory.ts +5 -1
- package/src/sdk/session.ts +69 -8
- package/src/sdk/startup-capability.ts +15 -1
- package/src/sdk/transport/auth-preface.ts +82 -0
- package/src/sdk/transport/index.ts +18 -0
- package/src/sdk/transport/relay.ts +252 -0
- package/src/sdk/transport/serve-cli.ts +105 -0
- package/src/sdk/transport/socket.ts +197 -0
- package/src/sdk/transport/stdio.ts +17 -0
- package/src/session/agent-session.ts +1112 -314
- package/src/session/blob-store.ts +25 -7
- package/src/session/btw-contract.ts +59 -0
- package/src/session/fallback-chain-controller.ts +47 -8
- package/src/session/internal/managed-session-scope.ts +1426 -259
- package/src/session/internal/managed-session-storage.ts +414 -238
- package/src/session/internal/native-publish-outcome.ts +271 -0
- package/src/session/memory-guard-checkpoint-participant.ts +131 -0
- package/src/session/session-manager.ts +2079 -469
- package/src/session/session-storage.ts +151 -11
- package/src/session/streaming-output.ts +262 -43
- package/src/setup/credential-import.ts +28 -3
- package/src/setup/provider-onboarding.ts +49 -5
- package/src/setup/provider-presets.json +2 -1
- package/src/skc-runtime/deep-interview-runtime.ts +303 -36
- package/src/skc-runtime/deep-interview-stage.ts +1016 -0
- package/src/skc-runtime/deep-interview-state.ts +8 -5
- package/src/skc-runtime/gc-render.ts +1 -0
- package/src/skc-runtime/gc-runtime.ts +11 -1
- package/src/skc-runtime/linux-proc.ts +70 -36
- package/src/skc-runtime/managed-owner-supervisor.ts +83 -4
- package/src/skc-runtime/memory-guard-owner-claims.ts +389 -0
- package/src/skc-runtime/ralplan-runtime.ts +1057 -75
- package/src/skc-runtime/repository-binding.ts +267 -0
- package/src/skc-runtime/session-state-sidecar.ts +25 -9
- package/src/skc-runtime/state-runtime.ts +50 -12
- package/src/skc-runtime/state-writer.ts +68 -56
- package/src/skc-runtime/team-launch.ts +34 -5
- package/src/skc-runtime/team-runtime.ts +41 -1
- package/src/skc-runtime/team-store.ts +32 -0
- package/src/skc-runtime/team-worker-memory-guard.ts +363 -0
- package/src/skc-runtime/team-workers.ts +1 -0
- package/src/skc-runtime/tmux-common.ts +13 -2
- package/src/skc-runtime/tmux-owner-isolation.ts +20 -1
- package/src/skc-runtime/tmux-sessions.ts +45 -6
- package/src/skc-runtime/ultragoal-guard.ts +93 -15
- package/src/skc-runtime/ultragoal-receipt-freshness.ts +123 -0
- package/src/skc-runtime/ultragoal-runtime.ts +469 -38
- package/src/skc-runtime/workflow-manifest.generated.json +195 -5
- package/src/skc-runtime/workflow-manifest.ts +67 -3
- package/src/skill-state/workflow-hud.ts +25 -2
- package/src/skill-state/workflow-mutation-guard.ts +104 -12
- package/src/slash-commands/builtin-registry.ts +1 -1
- package/src/ssh/utils.ts +14 -0
- package/src/task/discovery.ts +8 -2
- package/src/task/executor.ts +165 -47
- package/src/task/index.ts +123 -15
- package/src/task/provider-retry-status.ts +88 -0
- package/src/task/receipt.ts +3 -0
- package/src/task/render.ts +45 -26
- package/src/task/skc-command.ts +2 -2
- package/src/task/types.ts +55 -10
- package/src/task/ultragoal-redteam-activation.ts +75 -0
- package/src/tools/ask.ts +1 -1
- package/src/tools/ast-edit.ts +2 -2
- package/src/tools/bash-allowed-prefixes.ts +45 -1
- package/src/tools/bash-pty-selection.ts +2 -2
- package/src/tools/browser/launch.ts +41 -6
- package/src/tools/browser/screenshot-format.ts +6 -1
- package/src/tools/cron.ts +1 -1
- package/src/tools/fetch.ts +127 -154
- package/src/tools/image-gen.ts +476 -23
- package/src/tools/index.ts +7 -1
- package/src/tools/output-meta.ts +176 -9
- package/src/tools/path-utils.ts +5 -1
- package/src/tools/read-internals.ts +44 -0
- package/src/tools/read.ts +1544 -310
- package/src/tools/resource-gc.ts +665 -125
- package/src/tools/skill-discovery.ts +39 -3
- package/src/tools/sqlite-reader.ts +63 -5
- package/src/tools/subagent-render.ts +74 -16
- package/src/tools/subagent.ts +2 -0
- package/src/tools/tool-result.ts +14 -1
- package/src/utils/edit-mode.ts +2 -2
- package/src/utils/pasted-image-path.ts +15 -6
- package/src/utils/prompt-suggestion.ts +265 -0
- package/src/utils/shell-snapshot.ts +173 -63
- package/src/utils/sixel.ts +3 -3
- package/src/web/insane/bridge.ts +5 -1
- package/src/web/insane/url-guard.ts +140 -27
- package/src/web/scrapers/docs-rs.ts +30 -5
- package/src/web/scrapers/types.ts +19 -49
- package/src/web/scrapers/utils.ts +12 -26
- package/src/web/search/providers/codex.ts +1 -1
- package/src/workflow/workflow-intent-diff.ts +4 -1
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { appendJsonl, type StateWriterOptions } from "./state-writer";
|
|
4
|
+
|
|
5
|
+
export type SkcTeamWorkerMemoryGuardState = "idle" | "advisory" | "retrying" | "checkpointed" | "replaced" | "blocked";
|
|
6
|
+
|
|
7
|
+
export type SkcTeamWorkerMemoryGuardCheckpointKind =
|
|
8
|
+
| "clean"
|
|
9
|
+
| "eligible"
|
|
10
|
+
| "protected_only"
|
|
11
|
+
| "conflicted"
|
|
12
|
+
| "git_error";
|
|
13
|
+
|
|
14
|
+
export type SkcTeamWorkerMemoryGuardPidProbe =
|
|
15
|
+
| { kind: "live"; start_time: string }
|
|
16
|
+
| { kind: "absent" }
|
|
17
|
+
| { kind: "unverifiable"; reason: string };
|
|
18
|
+
|
|
19
|
+
export interface SkcTeamWorkerMemoryGuardCheckpoint {
|
|
20
|
+
kind: SkcTeamWorkerMemoryGuardCheckpointKind;
|
|
21
|
+
files: string[];
|
|
22
|
+
head?: string | null;
|
|
23
|
+
commit?: string | null;
|
|
24
|
+
recorded_at: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface SkcTeamWorkerMemoryGuardReplacement {
|
|
28
|
+
old_pane_id?: string;
|
|
29
|
+
new_pane_id?: string;
|
|
30
|
+
recorded_at: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface SkcTeamWorkerMemoryGuardLedger {
|
|
34
|
+
schema_version: 1;
|
|
35
|
+
worker_id: string;
|
|
36
|
+
platform: string;
|
|
37
|
+
state: SkcTeamWorkerMemoryGuardState;
|
|
38
|
+
automatic_action_allowed: boolean;
|
|
39
|
+
retry_count: number;
|
|
40
|
+
retry_limit: number;
|
|
41
|
+
current_task_id?: string;
|
|
42
|
+
last_incident_id?: string;
|
|
43
|
+
last_reason?: string;
|
|
44
|
+
last_pid_probe?: SkcTeamWorkerMemoryGuardPidProbe;
|
|
45
|
+
last_checkpoint?: SkcTeamWorkerMemoryGuardCheckpoint;
|
|
46
|
+
last_replacement?: SkcTeamWorkerMemoryGuardReplacement;
|
|
47
|
+
updated_at: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface SkcTeamWorkerMemoryGuardSelectionCandidate {
|
|
51
|
+
worker_id: string;
|
|
52
|
+
platform: string;
|
|
53
|
+
excess_bytes: number;
|
|
54
|
+
retry_count: number;
|
|
55
|
+
retry_limit: number;
|
|
56
|
+
blocked?: boolean;
|
|
57
|
+
current_task_id?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface SkcTeamWorkerMemoryGuardSelection {
|
|
61
|
+
worker_id: string;
|
|
62
|
+
excess_bytes: number;
|
|
63
|
+
retry_count: number;
|
|
64
|
+
current_task_id?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const ledgerKeys = new Set([
|
|
68
|
+
"schema_version",
|
|
69
|
+
"worker_id",
|
|
70
|
+
"platform",
|
|
71
|
+
"state",
|
|
72
|
+
"automatic_action_allowed",
|
|
73
|
+
"retry_count",
|
|
74
|
+
"retry_limit",
|
|
75
|
+
"current_task_id",
|
|
76
|
+
"last_incident_id",
|
|
77
|
+
"last_reason",
|
|
78
|
+
"last_pid_probe",
|
|
79
|
+
"last_checkpoint",
|
|
80
|
+
"last_replacement",
|
|
81
|
+
"updated_at",
|
|
82
|
+
]);
|
|
83
|
+
const checkpointKeys = new Set(["kind", "files", "head", "commit", "recorded_at"]);
|
|
84
|
+
const replacementKeys = new Set(["old_pane_id", "new_pane_id", "recorded_at"]);
|
|
85
|
+
const absentPidProbeKeys = new Set(["kind"]);
|
|
86
|
+
const livePidProbeKeys = new Set(["kind", "start_time"]);
|
|
87
|
+
const unverifiablePidProbeKeys = new Set(["kind", "reason"]);
|
|
88
|
+
|
|
89
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
90
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function hasExactKeys(value: Record<string, unknown>, keys: Set<string>): boolean {
|
|
94
|
+
return Object.keys(value).every(key => keys.has(key));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function isNonEmptyString(value: unknown): value is string {
|
|
98
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function isTimestamp(value: unknown): value is string {
|
|
102
|
+
return typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function isRetryCount(value: unknown): value is number {
|
|
106
|
+
return Number.isInteger(value) && (value as number) >= 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function isWorkerMemoryGuardState(value: unknown): value is SkcTeamWorkerMemoryGuardState {
|
|
110
|
+
return ["idle", "advisory", "retrying", "checkpointed", "replaced", "blocked"].includes(String(value));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function isCheckpointKind(value: unknown): value is SkcTeamWorkerMemoryGuardCheckpointKind {
|
|
114
|
+
return ["clean", "eligible", "protected_only", "conflicted", "git_error"].includes(String(value));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function workerMemoryGuardLedgerPath(dir: string, workerId: string): string {
|
|
118
|
+
return path.join(dir, "workers", workerId, "memory-guard.json");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function normalizeSkcTeamWorkerMemoryGuardPidProbe(
|
|
122
|
+
value: unknown,
|
|
123
|
+
): SkcTeamWorkerMemoryGuardPidProbe | undefined {
|
|
124
|
+
if (value === undefined) return undefined;
|
|
125
|
+
if (!isRecord(value)) throw new Error("invalid_worker_memory_guard_pid_probe");
|
|
126
|
+
const kind = typeof value.kind === "string" ? value.kind : "";
|
|
127
|
+
if (kind === "absent") {
|
|
128
|
+
if (!hasExactKeys(value, absentPidProbeKeys)) throw new Error("invalid_worker_memory_guard_pid_probe:absent");
|
|
129
|
+
return { kind: "absent" };
|
|
130
|
+
}
|
|
131
|
+
if (kind === "live") {
|
|
132
|
+
if (!hasExactKeys(value, livePidProbeKeys) || !isNonEmptyString(value.start_time))
|
|
133
|
+
throw new Error("invalid_worker_memory_guard_pid_probe:live");
|
|
134
|
+
return { kind: "live", start_time: value.start_time.trim() };
|
|
135
|
+
}
|
|
136
|
+
if (kind === "unverifiable") {
|
|
137
|
+
if (!hasExactKeys(value, unverifiablePidProbeKeys) || !isNonEmptyString(value.reason))
|
|
138
|
+
throw new Error("invalid_worker_memory_guard_pid_probe:unverifiable");
|
|
139
|
+
return { kind: "unverifiable", reason: value.reason.trim() };
|
|
140
|
+
}
|
|
141
|
+
throw new Error("invalid_worker_memory_guard_pid_probe");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function isCanonicalSkcTeamWorkerMemoryGuardCheckpoint(
|
|
145
|
+
value: unknown,
|
|
146
|
+
): value is SkcTeamWorkerMemoryGuardCheckpoint {
|
|
147
|
+
return (
|
|
148
|
+
isRecord(value) &&
|
|
149
|
+
hasExactKeys(value, checkpointKeys) &&
|
|
150
|
+
isCheckpointKind(value.kind) &&
|
|
151
|
+
Array.isArray(value.files) &&
|
|
152
|
+
value.files.every(file => isNonEmptyString(file)) &&
|
|
153
|
+
(value.head === undefined || value.head === null || isNonEmptyString(value.head)) &&
|
|
154
|
+
(value.commit === undefined || value.commit === null || isNonEmptyString(value.commit)) &&
|
|
155
|
+
isTimestamp(value.recorded_at)
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function isCanonicalSkcTeamWorkerMemoryGuardReplacement(
|
|
160
|
+
value: unknown,
|
|
161
|
+
): value is SkcTeamWorkerMemoryGuardReplacement {
|
|
162
|
+
return (
|
|
163
|
+
isRecord(value) &&
|
|
164
|
+
hasExactKeys(value, replacementKeys) &&
|
|
165
|
+
(value.old_pane_id === undefined || isNonEmptyString(value.old_pane_id)) &&
|
|
166
|
+
(value.new_pane_id === undefined || isNonEmptyString(value.new_pane_id)) &&
|
|
167
|
+
isTimestamp(value.recorded_at)
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function isCanonicalSkcTeamWorkerMemoryGuardPidProbe(value: unknown): value is SkcTeamWorkerMemoryGuardPidProbe {
|
|
172
|
+
try {
|
|
173
|
+
return normalizeSkcTeamWorkerMemoryGuardPidProbe(value) !== undefined;
|
|
174
|
+
} catch {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function isCanonicalSkcTeamWorkerMemoryGuardLedger(value: unknown): value is SkcTeamWorkerMemoryGuardLedger {
|
|
180
|
+
return (
|
|
181
|
+
isRecord(value) &&
|
|
182
|
+
hasExactKeys(value, ledgerKeys) &&
|
|
183
|
+
value.schema_version === 1 &&
|
|
184
|
+
isNonEmptyString(value.worker_id) &&
|
|
185
|
+
isNonEmptyString(value.platform) &&
|
|
186
|
+
isWorkerMemoryGuardState(value.state) &&
|
|
187
|
+
typeof value.automatic_action_allowed === "boolean" &&
|
|
188
|
+
isRetryCount(value.retry_count) &&
|
|
189
|
+
isRetryCount(value.retry_limit) &&
|
|
190
|
+
(value.current_task_id === undefined || isNonEmptyString(value.current_task_id)) &&
|
|
191
|
+
(value.last_incident_id === undefined || isNonEmptyString(value.last_incident_id)) &&
|
|
192
|
+
(value.last_reason === undefined || isNonEmptyString(value.last_reason)) &&
|
|
193
|
+
(value.last_pid_probe === undefined || isCanonicalSkcTeamWorkerMemoryGuardPidProbe(value.last_pid_probe)) &&
|
|
194
|
+
(value.last_checkpoint === undefined || isCanonicalSkcTeamWorkerMemoryGuardCheckpoint(value.last_checkpoint)) &&
|
|
195
|
+
(value.last_replacement === undefined ||
|
|
196
|
+
isCanonicalSkcTeamWorkerMemoryGuardReplacement(value.last_replacement)) &&
|
|
197
|
+
isTimestamp(value.updated_at)
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function createInitialSkcTeamWorkerMemoryGuardLedger(input: {
|
|
202
|
+
workerId: string;
|
|
203
|
+
platform: string;
|
|
204
|
+
now: string;
|
|
205
|
+
retryLimit?: number;
|
|
206
|
+
}): SkcTeamWorkerMemoryGuardLedger {
|
|
207
|
+
const retryLimit = Number.isInteger(input.retryLimit) && (input.retryLimit ?? 0) > 0 ? input.retryLimit! : 2;
|
|
208
|
+
return {
|
|
209
|
+
schema_version: 1,
|
|
210
|
+
worker_id: input.workerId,
|
|
211
|
+
platform: input.platform.trim() || "unknown",
|
|
212
|
+
state: "idle",
|
|
213
|
+
automatic_action_allowed: false,
|
|
214
|
+
retry_count: 0,
|
|
215
|
+
retry_limit: retryLimit,
|
|
216
|
+
updated_at: input.now,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function workerIndex(workerId: string): number {
|
|
221
|
+
const match = /(?:^|[^0-9])(\d+)$/.exec(workerId);
|
|
222
|
+
return match ? Number.parseInt(match[1]!, 10) : Number.MAX_SAFE_INTEGER;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function selectSkcTeamWorkerMemoryGuardCandidate(
|
|
226
|
+
candidates: readonly SkcTeamWorkerMemoryGuardSelectionCandidate[],
|
|
227
|
+
): SkcTeamWorkerMemoryGuardSelection | undefined {
|
|
228
|
+
const eligible = candidates
|
|
229
|
+
.filter(candidate => candidate.platform === "linux")
|
|
230
|
+
.filter(candidate => Number.isFinite(candidate.excess_bytes) && candidate.excess_bytes > 0)
|
|
231
|
+
.filter(candidate => !candidate.blocked)
|
|
232
|
+
.filter(candidate => candidate.retry_count < candidate.retry_limit)
|
|
233
|
+
.sort((left, right) => {
|
|
234
|
+
if (right.excess_bytes !== left.excess_bytes) return right.excess_bytes - left.excess_bytes;
|
|
235
|
+
if (left.retry_count !== right.retry_count) return left.retry_count - right.retry_count;
|
|
236
|
+
const leftIndex = workerIndex(left.worker_id);
|
|
237
|
+
const rightIndex = workerIndex(right.worker_id);
|
|
238
|
+
if (leftIndex !== rightIndex) return leftIndex - rightIndex;
|
|
239
|
+
return left.worker_id.localeCompare(right.worker_id);
|
|
240
|
+
});
|
|
241
|
+
const first = eligible[0];
|
|
242
|
+
return first
|
|
243
|
+
? {
|
|
244
|
+
worker_id: first.worker_id,
|
|
245
|
+
excess_bytes: first.excess_bytes,
|
|
246
|
+
retry_count: first.retry_count,
|
|
247
|
+
current_task_id: first.current_task_id,
|
|
248
|
+
}
|
|
249
|
+
: undefined;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export type TeamWorkerMemoryGuardAction = "advisory" | "replace" | "blocked";
|
|
253
|
+
export type TeamWorkerMemoryGuardResult = "noop" | "scheduled" | "succeeded" | "failed" | "blocked";
|
|
254
|
+
|
|
255
|
+
export interface TeamWorkerMemoryGuardLedgerEntry {
|
|
256
|
+
schema_version: 1;
|
|
257
|
+
recorded_at: string;
|
|
258
|
+
incident_id: string;
|
|
259
|
+
team_name: string;
|
|
260
|
+
worker_id: string;
|
|
261
|
+
task_id: string;
|
|
262
|
+
claim_token: string;
|
|
263
|
+
attempt: number;
|
|
264
|
+
platform: NodeJS.Platform;
|
|
265
|
+
action: TeamWorkerMemoryGuardAction;
|
|
266
|
+
result: TeamWorkerMemoryGuardResult;
|
|
267
|
+
reason: string;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const teamWorkerMemoryGuardActions = new Set<TeamWorkerMemoryGuardAction>(["advisory", "replace", "blocked"]);
|
|
271
|
+
const teamWorkerMemoryGuardResults = new Set<TeamWorkerMemoryGuardResult>([
|
|
272
|
+
"noop",
|
|
273
|
+
"scheduled",
|
|
274
|
+
"succeeded",
|
|
275
|
+
"failed",
|
|
276
|
+
"blocked",
|
|
277
|
+
]);
|
|
278
|
+
|
|
279
|
+
export function isCanonicalTeamWorkerMemoryGuardLedgerEntry(value: unknown): value is TeamWorkerMemoryGuardLedgerEntry {
|
|
280
|
+
if (!isRecord(value)) return false;
|
|
281
|
+
const requiredKeys = [
|
|
282
|
+
"schema_version",
|
|
283
|
+
"recorded_at",
|
|
284
|
+
"incident_id",
|
|
285
|
+
"team_name",
|
|
286
|
+
"worker_id",
|
|
287
|
+
"task_id",
|
|
288
|
+
"claim_token",
|
|
289
|
+
"attempt",
|
|
290
|
+
"platform",
|
|
291
|
+
"action",
|
|
292
|
+
"result",
|
|
293
|
+
"reason",
|
|
294
|
+
];
|
|
295
|
+
return (
|
|
296
|
+
Object.keys(value).length === requiredKeys.length &&
|
|
297
|
+
requiredKeys.every(key => Object.hasOwn(value, key)) &&
|
|
298
|
+
value.schema_version === 1 &&
|
|
299
|
+
isTimestamp(value.recorded_at) &&
|
|
300
|
+
isNonEmptyString(value.incident_id) &&
|
|
301
|
+
isNonEmptyString(value.team_name) &&
|
|
302
|
+
isNonEmptyString(value.worker_id) &&
|
|
303
|
+
isNonEmptyString(value.task_id) &&
|
|
304
|
+
isNonEmptyString(value.claim_token) &&
|
|
305
|
+
Number.isInteger(value.attempt) &&
|
|
306
|
+
(value.attempt as number) > 0 &&
|
|
307
|
+
isNonEmptyString(value.platform) &&
|
|
308
|
+
teamWorkerMemoryGuardActions.has(value.action as TeamWorkerMemoryGuardAction) &&
|
|
309
|
+
teamWorkerMemoryGuardResults.has(value.result as TeamWorkerMemoryGuardResult) &&
|
|
310
|
+
isNonEmptyString(value.reason)
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export function teamWorkerMemoryGuardDir(workerDirPath: string): string {
|
|
315
|
+
return path.join(workerDirPath, "memory-guard");
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export function teamWorkerMemoryGuardLedgerPath(workerDirPath: string): string {
|
|
319
|
+
return path.join(teamWorkerMemoryGuardDir(workerDirPath), "ledger.jsonl");
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export function canMutateTeamWorkerMemoryGuard(platform: NodeJS.Platform): boolean {
|
|
323
|
+
return platform === "linux";
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export function advisoryReasonForTeamWorkerMemoryGuard(platform: NodeJS.Platform): string | undefined {
|
|
327
|
+
return canMutateTeamWorkerMemoryGuard(platform) ? undefined : `unsupported_platform:${platform}`;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export async function appendTeamWorkerMemoryGuardLedgerEntry(
|
|
331
|
+
workerDirPath: string,
|
|
332
|
+
entry: TeamWorkerMemoryGuardLedgerEntry,
|
|
333
|
+
options?: StateWriterOptions,
|
|
334
|
+
): Promise<string> {
|
|
335
|
+
await fs.mkdir(teamWorkerMemoryGuardDir(workerDirPath), { recursive: true });
|
|
336
|
+
return appendJsonl(teamWorkerMemoryGuardLedgerPath(workerDirPath), entry, options);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export async function readTeamWorkerMemoryGuardLedger(
|
|
340
|
+
workerDirPath: string,
|
|
341
|
+
): Promise<TeamWorkerMemoryGuardLedgerEntry[]> {
|
|
342
|
+
const ledgerPath = teamWorkerMemoryGuardLedgerPath(workerDirPath);
|
|
343
|
+
if (!(await Bun.file(ledgerPath).exists())) return [];
|
|
344
|
+
const entries: TeamWorkerMemoryGuardLedgerEntry[] = [];
|
|
345
|
+
for (const [index, line] of (await Bun.file(ledgerPath).text()).split(/\r?\n/).filter(Boolean).entries()) {
|
|
346
|
+
const parsed = JSON.parse(line) as unknown;
|
|
347
|
+
if (!isCanonicalTeamWorkerMemoryGuardLedgerEntry(parsed))
|
|
348
|
+
throw new Error(`invalid_team_worker_memory_guard_ledger:${ledgerPath}:${index + 1}`);
|
|
349
|
+
entries.push(parsed);
|
|
350
|
+
}
|
|
351
|
+
return entries;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export function nextTeamWorkerMemoryGuardAttempt(
|
|
355
|
+
entries: readonly TeamWorkerMemoryGuardLedgerEntry[],
|
|
356
|
+
incidentId: string,
|
|
357
|
+
): number {
|
|
358
|
+
let attempt = 0;
|
|
359
|
+
for (const entry of entries) {
|
|
360
|
+
if (entry.incident_id === incidentId && entry.attempt > attempt) attempt = entry.attempt;
|
|
361
|
+
}
|
|
362
|
+
return attempt + 1;
|
|
363
|
+
}
|
|
@@ -352,6 +352,7 @@ export async function writeSkcWorkerStartupAck(
|
|
|
352
352
|
pid: typeof input.pid === "number" ? input.pid : undefined,
|
|
353
353
|
session: typeof input.session === "string" ? input.session : undefined,
|
|
354
354
|
protocol_version: String(input.protocol_version ?? "1"),
|
|
355
|
+
replacement_token: typeof input.replacement_token === "string" ? input.replacement_token : undefined,
|
|
355
356
|
ack_at: runtime.now(),
|
|
356
357
|
};
|
|
357
358
|
await runtime.writeJson(path.join(runtime.workerDir(dir, worker), "startup-ack.json"), ack);
|
|
@@ -246,8 +246,19 @@ export function buildSkcTmuxProfileCommands(
|
|
|
246
246
|
commands.push(
|
|
247
247
|
{ description: "enable tmux clipboard integration", args: ["set-option", "-t", target, "set-clipboard", "on"] },
|
|
248
248
|
{
|
|
249
|
-
//
|
|
250
|
-
//
|
|
249
|
+
// Hand tmux ownership of sixel. tmux 3.4+ parses sixel into its own screen
|
|
250
|
+
// model and re-renders it, so scroll / clear / resize / copy-mode all work on
|
|
251
|
+
// the pet. Without this tmux never records the image, and an erase can only
|
|
252
|
+
// reach its cell buffer while the pixels sit in the outer terminal's image
|
|
253
|
+
// plane — which is what leaves residue behind the pet.
|
|
254
|
+
// `-a` appends so a user's own terminal-features survive; unknown on tmux <
|
|
255
|
+
// 3.2, hence `-q`.
|
|
256
|
+
description: "let tmux own sixel graphics",
|
|
257
|
+
args: ["set-option", "-aq", "-t", target, "terminal-features", ",*:sixel"],
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
// Passthrough remains the fallback for terminals/tmux builds that do not
|
|
261
|
+
// claim sixel. `-pq` scopes it to this session's pane (never the global
|
|
251
262
|
// server state) and stays quiet on tmux < 3.3 where the option is unknown.
|
|
252
263
|
description: "allow DCS passthrough for sixel graphics",
|
|
253
264
|
args: ["set-option", "-pq", "-t", target, "allow-passthrough", "on"],
|
|
@@ -960,6 +960,24 @@ export function lifecyclePaths(stateDir: string, sessionId: string, generation:
|
|
|
960
960
|
};
|
|
961
961
|
}
|
|
962
962
|
|
|
963
|
+
export interface MemoryGuardClaimPaths {
|
|
964
|
+
root: string;
|
|
965
|
+
databaseFile: string;
|
|
966
|
+
walFile: string;
|
|
967
|
+
shmFile: string;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
export function memoryGuardClaimPaths(stateDir: string, sessionId: string): MemoryGuardClaimPaths {
|
|
971
|
+
const root = path.join(stateDir, "memory-guard-claims", sessionId);
|
|
972
|
+
const databaseFile = path.join(root, "claims.sqlite");
|
|
973
|
+
return {
|
|
974
|
+
root,
|
|
975
|
+
databaseFile,
|
|
976
|
+
walFile: `${databaseFile}-wal`,
|
|
977
|
+
shmFile: `${databaseFile}-shm`,
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
|
|
963
981
|
export async function replaceOwnerGeneration(
|
|
964
982
|
stateDir: string,
|
|
965
983
|
sessionId: string,
|
|
@@ -1646,7 +1664,8 @@ export function isValidOwnerIntent(intent: unknown, request?: ObserveTerminalReq
|
|
|
1646
1664
|
intent.generation === request.owner_generation &&
|
|
1647
1665
|
intent.session_id === request.session_id &&
|
|
1648
1666
|
intent.server_key === request.socket_key &&
|
|
1649
|
-
|
|
1667
|
+
request.operator_dispatch_id !== undefined &&
|
|
1668
|
+
intent.dispatch_id === request.operator_dispatch_id &&
|
|
1650
1669
|
request.signal === "SIGTERM"
|
|
1651
1670
|
);
|
|
1652
1671
|
}
|
|
@@ -3,6 +3,7 @@ import * as crypto from "node:crypto";
|
|
|
3
3
|
import * as fsSync from "node:fs";
|
|
4
4
|
import * as fs from "node:fs/promises";
|
|
5
5
|
import * as path from "node:path";
|
|
6
|
+
import { Process } from "@sayknow-cli/natives";
|
|
6
7
|
import { readLinuxProcStartTime, readLinuxProcStartTimeSync } from "./linux-proc";
|
|
7
8
|
import { resolveSkcTmuxBinary } from "./psmux-detect";
|
|
8
9
|
import { tmuxRuntimeSessionPath } from "./session-layout";
|
|
@@ -43,6 +44,7 @@ import {
|
|
|
43
44
|
lifecyclePaths,
|
|
44
45
|
type OwnerIsolationProbeSync,
|
|
45
46
|
type OwnerVerdict,
|
|
47
|
+
observeOwnerTerminal,
|
|
46
48
|
type PlanResponse,
|
|
47
49
|
planTmuxOwnerIsolationSync,
|
|
48
50
|
replaceOwnerGenerationSync,
|
|
@@ -963,6 +965,14 @@ async function readProcessStartTime(pid: number): Promise<string | null> {
|
|
|
963
965
|
return readLinuxProcStartTime(pid);
|
|
964
966
|
}
|
|
965
967
|
|
|
968
|
+
function exactManagedOwnerSupervisor(supervisorPid: number, supervisorStartTime: string): Process {
|
|
969
|
+
const supervisor = Process.fromPid(supervisorPid);
|
|
970
|
+
if (!supervisor) throw new Error("managed_owner_supervisor_unverifiable");
|
|
971
|
+
if (process.platform === "linux" && supervisor.incarnation !== `linux:${supervisorStartTime}`)
|
|
972
|
+
throw new Error("managed_owner_supervisor_incarnation_mismatch");
|
|
973
|
+
return supervisor;
|
|
974
|
+
}
|
|
975
|
+
|
|
966
976
|
async function readCurrentGeneration(stateDir: string, sessionId: string): Promise<string | null> {
|
|
967
977
|
try {
|
|
968
978
|
const value: unknown = JSON.parse(
|
|
@@ -1016,12 +1026,12 @@ async function requireUnchangedOwnerForCompatibilityCleanup(
|
|
|
1016
1026
|
initialServer: { pid: number; startTime: string },
|
|
1017
1027
|
listPanePids: (sessionName: string, env: NodeJS.ProcessEnv) => number[],
|
|
1018
1028
|
readStartTime: (pid: number) => Promise<string | null>,
|
|
1019
|
-
): Promise<
|
|
1029
|
+
): Promise<boolean> {
|
|
1020
1030
|
try {
|
|
1021
1031
|
const currentNativeSessionId = readNativeTmuxSessionId(nativeSessionId, env);
|
|
1022
1032
|
if (!currentNativeSessionId) {
|
|
1023
1033
|
if (readNativeTmuxSessionId(sessionName, env)) throw new Error(`skc_tmux_owner_changed:${sessionName}`);
|
|
1024
|
-
return;
|
|
1034
|
+
return false;
|
|
1025
1035
|
}
|
|
1026
1036
|
const currentServer = requireSafeTmuxServerForMutation(resolveSkcTmuxCommand(env), env);
|
|
1027
1037
|
const panePids = listPanePids(nativeSessionId, env);
|
|
@@ -1054,10 +1064,11 @@ async function requireUnchangedOwnerForCompatibilityCleanup(
|
|
|
1054
1064
|
: null,
|
|
1055
1065
|
].filter((value): value is string => value !== null);
|
|
1056
1066
|
if (mismatches.length > 0) throw new Error(`skc_tmux_owner_changed:${sessionName}:${mismatches.join(",")}`);
|
|
1067
|
+
return true;
|
|
1057
1068
|
} catch (error) {
|
|
1058
1069
|
if (!readNativeTmuxSessionId(nativeSessionId, env)) {
|
|
1059
1070
|
if (readNativeTmuxSessionId(sessionName, env)) throw new Error(`skc_tmux_owner_changed:${sessionName}`);
|
|
1060
|
-
return;
|
|
1071
|
+
return false;
|
|
1061
1072
|
}
|
|
1062
1073
|
if (error instanceof Error && error.message.startsWith(`skc_tmux_owner_changed:${sessionName}`))
|
|
1063
1074
|
throw new Error(`skc_tmux_owner_changed:${sessionName}`);
|
|
@@ -1152,6 +1163,7 @@ export async function forceCloseSkcTmuxSession(
|
|
|
1152
1163
|
const now = deps.now ?? (() => new Date());
|
|
1153
1164
|
const sleep = deps.sleep ?? (ms => Bun.sleep(ms));
|
|
1154
1165
|
const dispatchId = crypto.randomUUID();
|
|
1166
|
+
let operatorVerdict: Promise<OwnerVerdict> | null = null;
|
|
1155
1167
|
await closeExactTmuxOwner(
|
|
1156
1168
|
{
|
|
1157
1169
|
stateDir: identity.stateDir,
|
|
@@ -1169,12 +1181,37 @@ export async function forceCloseSkcTmuxSession(
|
|
|
1169
1181
|
sendSigterm: async pid => {
|
|
1170
1182
|
if ((await (deps.readProcessStartTime ?? readProcessStartTime)(pid)) !== identity.startTime)
|
|
1171
1183
|
throw new Error("owner_pid_identity_mismatch");
|
|
1172
|
-
(deps.signalTerm
|
|
1184
|
+
if (deps.signalTerm) {
|
|
1185
|
+
deps.signalTerm(pid);
|
|
1186
|
+
} else {
|
|
1187
|
+
const supervisor = exactManagedOwnerSupervisor(pid, identity.startTime);
|
|
1188
|
+
if (!supervisor.signalRoot(15)) throw new Error("managed_owner_supervisor_signal_failed");
|
|
1189
|
+
operatorVerdict = supervisor
|
|
1190
|
+
.waitForExit({ timeoutMs: FORCE_CLOSE_VERDICT_TIMEOUT_MS - 500 })
|
|
1191
|
+
.then(async exited => {
|
|
1192
|
+
if (!exited) throw new Error("managed_owner_supervisor_exit_timeout");
|
|
1193
|
+
return await observeOwnerTerminal({
|
|
1194
|
+
schema_version: 1,
|
|
1195
|
+
op: "observe_terminal",
|
|
1196
|
+
session_id: identity.sessionId,
|
|
1197
|
+
owner_generation: identity.generation,
|
|
1198
|
+
state_dir: identity.stateDir,
|
|
1199
|
+
socket_key: identity.socketKey,
|
|
1200
|
+
observer: "raw_monitor",
|
|
1201
|
+
observed_at: now().toISOString(),
|
|
1202
|
+
signal: "SIGTERM",
|
|
1203
|
+
exit_code: null,
|
|
1204
|
+
exit_kind: "exact_owner_exit_observed",
|
|
1205
|
+
reason: "operator_observed_owner_exit",
|
|
1206
|
+
operator_dispatch_id: dispatchId,
|
|
1207
|
+
});
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1173
1210
|
},
|
|
1174
1211
|
|
|
1175
|
-
waitForVerdict: () => waitForExpectedVerdict(identity, sleep, now),
|
|
1212
|
+
waitForVerdict: () => operatorVerdict ?? waitForExpectedVerdict(identity, sleep, now),
|
|
1176
1213
|
cleanupSession: async () => {
|
|
1177
|
-
await requireUnchangedOwnerForCompatibilityCleanup(
|
|
1214
|
+
const cleanupRequired = await requireUnchangedOwnerForCompatibilityCleanup(
|
|
1178
1215
|
session.name,
|
|
1179
1216
|
nativeSessionId,
|
|
1180
1217
|
env,
|
|
@@ -1184,6 +1221,7 @@ export async function forceCloseSkcTmuxSession(
|
|
|
1184
1221
|
deps.listPanePids ?? readExactSessionPanePids,
|
|
1185
1222
|
deps.readProcessStartTime ?? readProcessStartTime,
|
|
1186
1223
|
);
|
|
1224
|
+
if (!cleanupRequired) return;
|
|
1187
1225
|
if (deps.cleanupSession) deps.cleanupSession(nativeSessionId, env);
|
|
1188
1226
|
else
|
|
1189
1227
|
runGuardedTmuxSessionCommand(
|
|
@@ -1192,6 +1230,7 @@ export async function forceCloseSkcTmuxSession(
|
|
|
1192
1230
|
initialServer.pid,
|
|
1193
1231
|
env,
|
|
1194
1232
|
`kill-session -t '${nativeSessionId}'`,
|
|
1233
|
+
identity.generation,
|
|
1195
1234
|
);
|
|
1196
1235
|
},
|
|
1197
1236
|
},
|