@sayknow-cli/coding-agent 0.4.7 → 0.5.1
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 +122 -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
|
@@ -74,7 +74,7 @@ export class NotificationOperatorRuntime {
|
|
|
74
74
|
#stopRequested = false;
|
|
75
75
|
#activeAbort: AbortController | undefined;
|
|
76
76
|
#intervals = new Map<string, OperatorIntervalHandle>();
|
|
77
|
-
#exclusive = new
|
|
77
|
+
#exclusive = new Map<string, Promise<void>>();
|
|
78
78
|
|
|
79
79
|
#deps: NotificationOperatorTimerDeps;
|
|
80
80
|
|
|
@@ -130,7 +130,7 @@ export class NotificationOperatorRuntime {
|
|
|
130
130
|
|
|
131
131
|
stopInterval(name: string): void {
|
|
132
132
|
const timer = this.#intervals.get(name);
|
|
133
|
-
if (
|
|
133
|
+
if (timer === undefined) return;
|
|
134
134
|
const clearIntervalImpl = this.#deps.clearIntervalImpl ?? clearInterval;
|
|
135
135
|
clearIntervalImpl(timer);
|
|
136
136
|
this.#intervals.delete(name);
|
|
@@ -142,14 +142,40 @@ export class NotificationOperatorRuntime {
|
|
|
142
142
|
|
|
143
143
|
async runExclusive(name: string, fn: () => Promise<void>): Promise<void> {
|
|
144
144
|
if (this.#exclusive.has(name)) return;
|
|
145
|
-
|
|
145
|
+
const completion = Promise.withResolvers<void>();
|
|
146
|
+
this.#exclusive.set(name, completion.promise);
|
|
146
147
|
try {
|
|
147
|
-
|
|
148
|
+
try {
|
|
149
|
+
void fn().then(completion.resolve, completion.reject);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
completion.reject(error);
|
|
152
|
+
}
|
|
153
|
+
await completion.promise;
|
|
148
154
|
} finally {
|
|
149
|
-
this.#exclusive.delete(name);
|
|
155
|
+
if (this.#exclusive.get(name) === completion.promise) this.#exclusive.delete(name);
|
|
150
156
|
}
|
|
151
157
|
}
|
|
152
158
|
|
|
159
|
+
async joinExclusive(name: string, timeoutMs: number): Promise<boolean> {
|
|
160
|
+
const completion = this.#exclusive.get(name);
|
|
161
|
+
if (!completion) return true;
|
|
162
|
+
const setTimeoutImpl = this.#deps.setTimeoutImpl ?? setTimeout;
|
|
163
|
+
const clearTimeoutImpl = this.#deps.clearTimeoutImpl ?? clearTimeout;
|
|
164
|
+
const { promise, resolve } = Promise.withResolvers<boolean>();
|
|
165
|
+
const timer = setTimeoutImpl(() => resolve(false), timeoutMs);
|
|
166
|
+
void completion.then(
|
|
167
|
+
() => {
|
|
168
|
+
clearTimeoutImpl(timer);
|
|
169
|
+
resolve(true);
|
|
170
|
+
},
|
|
171
|
+
() => {
|
|
172
|
+
clearTimeoutImpl(timer);
|
|
173
|
+
resolve(true);
|
|
174
|
+
},
|
|
175
|
+
);
|
|
176
|
+
return await promise;
|
|
177
|
+
}
|
|
178
|
+
|
|
153
179
|
sleep(ms: number, signal?: AbortSignal): Promise<void> {
|
|
154
180
|
return new Promise<void>(resolve => {
|
|
155
181
|
if (signal?.aborted) return resolve();
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded authoritative reconciliation state for Q26 `turn.prompt_status`.
|
|
3
|
+
*
|
|
4
|
+
* Separate from the lifecycle delivery buffers (promptSubmissions /
|
|
5
|
+
* promptTerminalTombstones), which exist to deliver frames and intentionally
|
|
6
|
+
* forget outcomes. This record preserves accepted/in_flight/terminal_ok/failed
|
|
7
|
+
* plus bounded sanitized failure metadata so a caller can reconcile a prior
|
|
8
|
+
* `turn.prompt` after disconnect/reconnect.
|
|
9
|
+
*
|
|
10
|
+
* Semantics (public contract, mirrored in sdk/prompt-status.ts):
|
|
11
|
+
* - Active records are NEVER converted to terminal by age or capacity.
|
|
12
|
+
* - Terminal records are retained for TERMINAL_TTL_MS and bounded to
|
|
13
|
+
* TERMINAL_CAPACITY, evicted oldest-terminal-first by terminalAt; only then
|
|
14
|
+
* does a lookup honestly report `unknown`.
|
|
15
|
+
* - Process-local durability floor is the live session process: restart means `unknown`.
|
|
16
|
+
* Session-scoped durable retention (kind-aware store) is provided by reconciliation-store.ts (#3032).
|
|
17
|
+
* - The clientRef index is session-runtime scoped; a ref conflicts only while
|
|
18
|
+
* retained and must never be reused as a retry mechanism.
|
|
19
|
+
* - Terminal transitions settle once: the first terminal outcome wins.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
export const PROMPT_RECONCILIATION_ACTIVE_CAPACITY = 128;
|
|
23
|
+
export const PROMPT_RECONCILIATION_TERMINAL_CAPACITY = 256;
|
|
24
|
+
export const PROMPT_RECONCILIATION_TERMINAL_TTL_MS = 15 * 60_000;
|
|
25
|
+
export const PROMPT_FAILURE_CODE_MAX = 64;
|
|
26
|
+
|
|
27
|
+
export type PromptReconciliationStatus = "accepted" | "in_flight" | "terminal_ok" | "failed";
|
|
28
|
+
|
|
29
|
+
export interface PromptCorrelation {
|
|
30
|
+
commandId: string;
|
|
31
|
+
turnId: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface PromptReconciliationRecord extends PromptCorrelation {
|
|
35
|
+
clientRef?: string;
|
|
36
|
+
status: PromptReconciliationStatus;
|
|
37
|
+
error?: { code: string; message: string };
|
|
38
|
+
acceptedAt: number;
|
|
39
|
+
startedAt?: number;
|
|
40
|
+
terminalAt?: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export type TurnPromptReconciliation =
|
|
44
|
+
| {
|
|
45
|
+
status: "accepted";
|
|
46
|
+
commandId: string;
|
|
47
|
+
turnId: string;
|
|
48
|
+
clientRef?: string;
|
|
49
|
+
acceptedAt: number;
|
|
50
|
+
}
|
|
51
|
+
| {
|
|
52
|
+
status: "in_flight";
|
|
53
|
+
commandId: string;
|
|
54
|
+
turnId: string;
|
|
55
|
+
clientRef?: string;
|
|
56
|
+
acceptedAt: number;
|
|
57
|
+
startedAt: number;
|
|
58
|
+
}
|
|
59
|
+
| {
|
|
60
|
+
status: "terminal_ok";
|
|
61
|
+
commandId: string;
|
|
62
|
+
turnId: string;
|
|
63
|
+
clientRef?: string;
|
|
64
|
+
acceptedAt: number;
|
|
65
|
+
startedAt?: number;
|
|
66
|
+
terminalAt: number;
|
|
67
|
+
}
|
|
68
|
+
| {
|
|
69
|
+
status: "failed";
|
|
70
|
+
commandId: string;
|
|
71
|
+
turnId: string;
|
|
72
|
+
clientRef?: string;
|
|
73
|
+
acceptedAt: number;
|
|
74
|
+
startedAt?: number;
|
|
75
|
+
terminalAt: number;
|
|
76
|
+
error: { code: string; message: string };
|
|
77
|
+
}
|
|
78
|
+
| { status: "unknown" };
|
|
79
|
+
|
|
80
|
+
export interface PromptReconciliation {
|
|
81
|
+
/** Fail-closed admission BEFORE any execution; holds an identity-bound reservation. */
|
|
82
|
+
admit(clientRef?: string): void;
|
|
83
|
+
/** Discard one admission reservation without creating a record (rejection/cancellation). */
|
|
84
|
+
releaseAdmission(clientRef?: string): void;
|
|
85
|
+
/** Transition a reservation into the accepted record at preflight acceptance. */
|
|
86
|
+
noteAccepted(correlation: PromptCorrelation, clientRef?: string): void;
|
|
87
|
+
/** Lifecycle transition; terminal outcomes settle exactly once. */
|
|
88
|
+
noteTransition(
|
|
89
|
+
correlation: PromptCorrelation | undefined,
|
|
90
|
+
frame: { type: "agent_start" | "agent_end" } | { type: "agent_failed"; error: unknown },
|
|
91
|
+
): void;
|
|
92
|
+
lookup(selector: { commandId?: string; turnId?: string; clientRef?: string }): TurnPromptReconciliation;
|
|
93
|
+
cleanup(): void;
|
|
94
|
+
activeCount(): number;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Safe-token code capped at 64; arbitrary failure text is never retained. */
|
|
98
|
+
export function sanitizePromptFailure(error: unknown): { code: string; message: string } {
|
|
99
|
+
const candidate = error as { code?: unknown } | undefined;
|
|
100
|
+
const rawCode = typeof candidate?.code === "string" ? candidate.code : "";
|
|
101
|
+
const code = rawCode.length <= PROMPT_FAILURE_CODE_MAX && /^[A-Za-z0-9._-]+$/.test(rawCode) ? rawCode : "internal";
|
|
102
|
+
return { code, message: "Prompt submission failed." };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function createPromptReconciliation(options: { now?: () => number } = {}): PromptReconciliation {
|
|
106
|
+
const now = options.now ?? Date.now;
|
|
107
|
+
const records = new Map<string, PromptReconciliationRecord>();
|
|
108
|
+
const clientRefIndex = new Map<string, string>();
|
|
109
|
+
const reservedClientRefs = new Set<string>();
|
|
110
|
+
// One identity-bound entry per admission. Transitions consume exactly one
|
|
111
|
+
// matching entry and stale/duplicate transitions are no-ops, so reservation
|
|
112
|
+
// accounting is exactly-once even under repeated calls.
|
|
113
|
+
const reservations: Array<string | undefined> = [];
|
|
114
|
+
const keyOf = (correlation: PromptCorrelation) => `${correlation.commandId}:${correlation.turnId}`;
|
|
115
|
+
|
|
116
|
+
const remove = (key: string) => {
|
|
117
|
+
const record = records.get(key);
|
|
118
|
+
if (!record) return;
|
|
119
|
+
records.delete(key);
|
|
120
|
+
if (record.clientRef !== undefined && clientRefIndex.get(record.clientRef) === key)
|
|
121
|
+
clientRefIndex.delete(record.clientRef);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const cleanup = () => {
|
|
125
|
+
const at = now();
|
|
126
|
+
for (const [key, record] of records)
|
|
127
|
+
if (record.terminalAt !== undefined && record.terminalAt + PROMPT_RECONCILIATION_TERMINAL_TTL_MS <= at)
|
|
128
|
+
remove(key);
|
|
129
|
+
const terminalEntries = [...records.entries()].filter(([, record]) => record.terminalAt !== undefined);
|
|
130
|
+
if (terminalEntries.length <= PROMPT_RECONCILIATION_TERMINAL_CAPACITY) return;
|
|
131
|
+
// Evict oldest-terminal-first by terminalAt, not acceptance/insertion
|
|
132
|
+
// order; the stable sort keeps acceptance order for exact ties.
|
|
133
|
+
terminalEntries.sort((a, b) => (a[1].terminalAt as number) - (b[1].terminalAt as number));
|
|
134
|
+
for (const [key] of terminalEntries.slice(0, terminalEntries.length - PROMPT_RECONCILIATION_TERMINAL_CAPACITY))
|
|
135
|
+
remove(key);
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const activeCount = () => {
|
|
139
|
+
let count = 0;
|
|
140
|
+
for (const record of records.values()) if (record.terminalAt === undefined) count++;
|
|
141
|
+
return count;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/** Consume one reservation matching clientRef; no-op when none is outstanding. */
|
|
145
|
+
const consumeReservation = (clientRef?: string) => {
|
|
146
|
+
const index = reservations.indexOf(clientRef);
|
|
147
|
+
if (index === -1) return;
|
|
148
|
+
reservations.splice(index, 1);
|
|
149
|
+
if (clientRef !== undefined && !reservations.includes(clientRef)) reservedClientRefs.delete(clientRef);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const admit = (clientRef?: string) => {
|
|
153
|
+
cleanup();
|
|
154
|
+
if (clientRef !== undefined && (clientRefIndex.has(clientRef) || reservedClientRefs.has(clientRef)))
|
|
155
|
+
throw Object.assign(
|
|
156
|
+
new Error("A prompt with this clientRef is already retained; never reuse a clientRef for retry."),
|
|
157
|
+
{ code: "client_ref_conflict" },
|
|
158
|
+
);
|
|
159
|
+
if (activeCount() + reservations.length >= PROMPT_RECONCILIATION_ACTIVE_CAPACITY)
|
|
160
|
+
throw Object.assign(new Error("Too many active prompt submissions; reconcile or await terminal state."), {
|
|
161
|
+
code: "reconciliation_capacity",
|
|
162
|
+
});
|
|
163
|
+
reservations.push(clientRef);
|
|
164
|
+
if (clientRef !== undefined) reservedClientRefs.add(clientRef);
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const releaseAdmission = (clientRef?: string) => {
|
|
168
|
+
consumeReservation(clientRef);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const noteAccepted = (correlation: PromptCorrelation, clientRef?: string) => {
|
|
172
|
+
cleanup();
|
|
173
|
+
consumeReservation(clientRef);
|
|
174
|
+
const at = now();
|
|
175
|
+
const key = keyOf(correlation);
|
|
176
|
+
records.set(key, {
|
|
177
|
+
commandId: correlation.commandId,
|
|
178
|
+
turnId: correlation.turnId,
|
|
179
|
+
...(clientRef !== undefined ? { clientRef } : {}),
|
|
180
|
+
status: "accepted",
|
|
181
|
+
acceptedAt: at,
|
|
182
|
+
});
|
|
183
|
+
if (clientRef !== undefined) clientRefIndex.set(clientRef, key);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const noteTransition = (
|
|
187
|
+
correlation: PromptCorrelation | undefined,
|
|
188
|
+
frame: { type: "agent_start" | "agent_end" } | { type: "agent_failed"; error: unknown },
|
|
189
|
+
) => {
|
|
190
|
+
if (!correlation) return;
|
|
191
|
+
const record = records.get(keyOf(correlation));
|
|
192
|
+
if (!record || record.terminalAt !== undefined) return;
|
|
193
|
+
if (frame.type === "agent_start") {
|
|
194
|
+
if (record.status === "accepted") {
|
|
195
|
+
record.status = "in_flight";
|
|
196
|
+
record.startedAt = now();
|
|
197
|
+
}
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
record.terminalAt = now();
|
|
201
|
+
if (frame.type === "agent_failed") {
|
|
202
|
+
record.status = "failed";
|
|
203
|
+
record.error = sanitizePromptFailure(frame.error);
|
|
204
|
+
} else {
|
|
205
|
+
record.status = "terminal_ok";
|
|
206
|
+
}
|
|
207
|
+
// Enforce terminal retention immediately at settlement, not lazily.
|
|
208
|
+
cleanup();
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const lookup = (selector: { commandId?: string; turnId?: string; clientRef?: string }): TurnPromptReconciliation => {
|
|
212
|
+
cleanup();
|
|
213
|
+
const key =
|
|
214
|
+
selector.clientRef !== undefined
|
|
215
|
+
? clientRefIndex.get(selector.clientRef)
|
|
216
|
+
: selector.commandId !== undefined && selector.turnId !== undefined
|
|
217
|
+
? keyOf({ commandId: selector.commandId, turnId: selector.turnId })
|
|
218
|
+
: undefined;
|
|
219
|
+
const record = key === undefined ? undefined : records.get(key);
|
|
220
|
+
if (!record) return { status: "unknown" };
|
|
221
|
+
const identity = {
|
|
222
|
+
commandId: record.commandId,
|
|
223
|
+
turnId: record.turnId,
|
|
224
|
+
...(record.clientRef !== undefined ? { clientRef: record.clientRef } : {}),
|
|
225
|
+
acceptedAt: record.acceptedAt,
|
|
226
|
+
};
|
|
227
|
+
if (record.status === "accepted") return { status: "accepted", ...identity };
|
|
228
|
+
if (record.status === "in_flight")
|
|
229
|
+
return { status: "in_flight", ...identity, startedAt: record.startedAt as number };
|
|
230
|
+
const terminal = {
|
|
231
|
+
...identity,
|
|
232
|
+
...(record.startedAt !== undefined ? { startedAt: record.startedAt } : {}),
|
|
233
|
+
terminalAt: record.terminalAt as number,
|
|
234
|
+
};
|
|
235
|
+
if (record.status === "terminal_ok") return { status: "terminal_ok", ...terminal };
|
|
236
|
+
return { status: "failed", ...terminal, error: record.error ?? sanitizePromptFailure(undefined) };
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
return { admit, releaseAdmission, noteAccepted, noteTransition, lookup, cleanup, activeCount };
|
|
240
|
+
}
|
|
@@ -116,6 +116,14 @@ export class RateLimitPool<T = unknown> {
|
|
|
116
116
|
return total;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
/** Whether any queued item currently matches the predicate. */
|
|
120
|
+
someQueued(predicate: (item: RateLimitItem<T>) => boolean): boolean {
|
|
121
|
+
for (const queue of this.lanes.values()) {
|
|
122
|
+
if (queue.some(entry => predicate(entry.item))) return true;
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
119
127
|
/** Current available token count (after refill at `now`). */
|
|
120
128
|
availableTokens(nowMs: number = this.now()): number {
|
|
121
129
|
this.refill(nowMs);
|
|
@@ -11,7 +11,7 @@ import * as fs from "node:fs/promises";
|
|
|
11
11
|
import * as path from "node:path";
|
|
12
12
|
import { verifyOwnerOnlyPathSecurity } from "@sayknow-cli/natives";
|
|
13
13
|
import { getAgentDir, getSessionsDir } from "@sayknow-cli/utils";
|
|
14
|
-
import { FileSessionStorage } from "../../session/session-storage";
|
|
14
|
+
import { FileSessionStorage, type SessionStorageSnapshot } from "../../session/session-storage";
|
|
15
15
|
import {
|
|
16
16
|
type LogicalSessionCandidate,
|
|
17
17
|
listManagedSessionCandidates,
|
|
@@ -58,25 +58,52 @@ export interface RecentActivityDeps {
|
|
|
58
58
|
readInitialLines?: (file: string, maxLines: number) => string[];
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
class ManagedCandidateChangedError extends Error {}
|
|
62
|
+
class ManagedCandidateUnavailableError extends Error {}
|
|
63
|
+
|
|
64
|
+
const CHANGED_CANDIDATE_WARNING = "Ignored managed session candidate that changed during inspection.";
|
|
65
|
+
|
|
66
|
+
function isAppendExtension(bytes: Uint8Array, candidate: LogicalSessionCandidate): boolean {
|
|
67
|
+
return (
|
|
68
|
+
bytes.byteLength >= candidate.identity.size &&
|
|
69
|
+
createHash("sha256").update(bytes.subarray(0, candidate.identity.size)).digest("hex") ===
|
|
70
|
+
candidate.identity.sha256
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
61
74
|
function readCandidateInitialLines(
|
|
62
75
|
candidate: LogicalSessionCandidate,
|
|
63
76
|
readInitialLines: ((file: string, maxLines: number) => string[]) | undefined,
|
|
77
|
+
appendBase?: LogicalSessionCandidate,
|
|
64
78
|
): string[] {
|
|
65
79
|
if (readInitialLines) return readInitialLines(candidate.path, 8);
|
|
66
80
|
if (candidate.provenance !== "legacy") {
|
|
67
81
|
const security = verifyOwnerOnlyPathSecurity(candidate.path, "file");
|
|
68
|
-
if (!security.ok) throw new
|
|
82
|
+
if (!security.ok) throw new ManagedCandidateUnavailableError("Managed session metadata path is unsafe.");
|
|
69
83
|
}
|
|
70
|
-
|
|
84
|
+
let snapshot: SessionStorageSnapshot;
|
|
85
|
+
try {
|
|
86
|
+
snapshot = new FileSessionStorage().readSnapshotSync(candidate.path);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
89
|
+
if (code === "ENOENT" || code === "ELOOP" || code === "ENOTDIR")
|
|
90
|
+
throw new ManagedCandidateUnavailableError("Managed session metadata is unavailable.");
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
const sameFile = snapshot.stat.dev === candidate.identity.dev && snapshot.stat.ino === candidate.identity.ino;
|
|
71
94
|
const digest = createHash("sha256").update(snapshot.bytes).digest("hex");
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
snapshot.stat.
|
|
75
|
-
snapshot.stat.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
95
|
+
const exactIdentity =
|
|
96
|
+
sameFile &&
|
|
97
|
+
snapshot.stat.size === candidate.identity.size &&
|
|
98
|
+
snapshot.stat.mtimeNs === candidate.identity.mtimeNs &&
|
|
99
|
+
digest === candidate.identity.sha256;
|
|
100
|
+
if (appendBase && (!sameFile || !isAppendExtension(snapshot.bytes, appendBase)))
|
|
101
|
+
throw new ManagedCandidateUnavailableError("Managed session no longer extends the verified transcript.");
|
|
102
|
+
if (!exactIdentity) {
|
|
103
|
+
if (sameFile && isAppendExtension(snapshot.bytes, candidate))
|
|
104
|
+
throw new ManagedCandidateChangedError("Managed session was appended after ownership was verified.");
|
|
105
|
+
throw new ManagedCandidateUnavailableError("Managed session changed without an append-only extension.");
|
|
106
|
+
}
|
|
80
107
|
return Buffer.from(snapshot.bytes).toString("utf8").split("\n").slice(0, 8);
|
|
81
108
|
}
|
|
82
109
|
|
|
@@ -227,13 +254,13 @@ export async function listRecentSessions(deps: RecentActivityDeps): Promise<List
|
|
|
227
254
|
const resolved = await resolveRecentScopes(deps);
|
|
228
255
|
if (resolved.kind === "error") return resolved;
|
|
229
256
|
const warnings = [...resolved.warnings];
|
|
230
|
-
const candidates: LogicalSessionCandidate
|
|
257
|
+
const candidates: Array<{ scope: ManagedSessionScope; candidate: LogicalSessionCandidate }> = [];
|
|
231
258
|
for (const scope of resolved.scopes) {
|
|
232
259
|
const listed = await listManagedSessionCandidates({ scope });
|
|
233
260
|
if (listed.kind !== "complete") {
|
|
234
261
|
return { kind: "error", code: "managed_scan_failed", message: listed.message };
|
|
235
262
|
}
|
|
236
|
-
candidates.push(...listed.owned);
|
|
263
|
+
candidates.push(...listed.owned.map(candidate => ({ scope, candidate })));
|
|
237
264
|
warnings.push(
|
|
238
265
|
...listed.invalid
|
|
239
266
|
.filter(
|
|
@@ -245,28 +272,65 @@ export async function listRecentSessions(deps: RecentActivityDeps): Promise<List
|
|
|
245
272
|
}
|
|
246
273
|
|
|
247
274
|
const entries: RecentSessionEntry[] = [];
|
|
248
|
-
for (const candidate of candidates) {
|
|
249
|
-
let
|
|
275
|
+
for (const { scope, candidate } of candidates) {
|
|
276
|
+
let selected = candidate;
|
|
277
|
+
let initialLines: string[] | undefined;
|
|
250
278
|
try {
|
|
251
|
-
initialLines = readCandidateInitialLines(
|
|
279
|
+
initialLines = readCandidateInitialLines(selected, readInitialLines);
|
|
252
280
|
} catch (error) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
281
|
+
if (error instanceof ManagedCandidateChangedError) {
|
|
282
|
+
const refreshed = await listManagedSessionCandidates({ scope });
|
|
283
|
+
if (refreshed.kind !== "complete")
|
|
284
|
+
return { kind: "error", code: "managed_scan_failed", message: refreshed.message };
|
|
285
|
+
const sameFile = refreshed.owned.find(
|
|
286
|
+
current =>
|
|
287
|
+
path.resolve(current.path) === path.resolve(candidate.path) &&
|
|
288
|
+
current.identity.dev === candidate.identity.dev &&
|
|
289
|
+
current.identity.ino === candidate.identity.ino,
|
|
290
|
+
);
|
|
291
|
+
if (sameFile) {
|
|
292
|
+
try {
|
|
293
|
+
initialLines = readCandidateInitialLines(sameFile, readInitialLines, candidate);
|
|
294
|
+
selected = sameFile;
|
|
295
|
+
} catch (retryError) {
|
|
296
|
+
if (
|
|
297
|
+
!(retryError instanceof ManagedCandidateChangedError) &&
|
|
298
|
+
!(retryError instanceof ManagedCandidateUnavailableError)
|
|
299
|
+
)
|
|
300
|
+
return {
|
|
301
|
+
kind: "error",
|
|
302
|
+
code: "managed_scan_failed",
|
|
303
|
+
message: `Could not read managed session metadata: ${
|
|
304
|
+
retryError instanceof Error ? retryError.message : String(retryError)
|
|
305
|
+
}`,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
} else if (!(error instanceof ManagedCandidateUnavailableError)) {
|
|
310
|
+
return {
|
|
311
|
+
kind: "error",
|
|
312
|
+
code: "managed_scan_failed",
|
|
313
|
+
message: `Could not read managed session metadata: ${
|
|
314
|
+
error instanceof Error ? error.message : String(error)
|
|
315
|
+
}`,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
if (!initialLines) {
|
|
319
|
+
warnings.push(CHANGED_CANDIDATE_WARNING);
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
258
322
|
}
|
|
259
323
|
const meta = headerMeta(initialLines[0]);
|
|
260
324
|
const internal = isInternalSession(initialLines);
|
|
261
325
|
if (internal && !includeInternal) continue;
|
|
262
326
|
entries.push({
|
|
263
|
-
sessionId:
|
|
264
|
-
path:
|
|
327
|
+
sessionId: selected.sessionId,
|
|
328
|
+
path: selected.cwd,
|
|
265
329
|
branch: meta.branch,
|
|
266
330
|
title: meta.title,
|
|
267
|
-
sessionStateFile:
|
|
268
|
-
mtimeMs:
|
|
269
|
-
currentTerminal: breadcrumbs.has(path.resolve(
|
|
331
|
+
sessionStateFile: selected.path,
|
|
332
|
+
mtimeMs: selected.identity.mtimeMs,
|
|
333
|
+
currentTerminal: breadcrumbs.has(path.resolve(selected.path)) || undefined,
|
|
270
334
|
internal: internal || undefined,
|
|
271
335
|
});
|
|
272
336
|
}
|