@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
|
@@ -197,21 +197,30 @@ export function mapAgentSessionEventToAcpSessionUpdates(
|
|
|
197
197
|
return [toSessionNotification(sessionId, update)];
|
|
198
198
|
}
|
|
199
199
|
case "tool_execution_end": {
|
|
200
|
-
const
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
200
|
+
const args = getToolExecutionEndArgs(event, options);
|
|
201
|
+
const resultContent = [
|
|
202
|
+
...extractDiffToolCallContent(event.result, options.cwd),
|
|
203
|
+
...extractToolCallContent(event.result),
|
|
204
|
+
];
|
|
205
|
+
const content = mergeToolUpdateContent(buildToolStartContent(event.toolName, args), resultContent);
|
|
205
206
|
const update: SessionUpdate = {
|
|
206
207
|
sessionUpdate: "tool_call_update",
|
|
207
208
|
toolCallId: event.toolCallId,
|
|
208
209
|
status: event.isError ? "failed" : "completed",
|
|
209
210
|
rawOutput: event.result,
|
|
210
211
|
};
|
|
212
|
+
if (event.isError) {
|
|
213
|
+
// Failure is carried by `status`; `kind` stays the tool's real category so
|
|
214
|
+
// clients keep the icon/treatment established by the initial `tool_call`.
|
|
215
|
+
update.title = `Failed: ${buildToolTitle(event.toolName, args, undefined)}`;
|
|
216
|
+
}
|
|
211
217
|
if (content.length > 0) {
|
|
212
218
|
update.content = content;
|
|
213
219
|
}
|
|
214
|
-
const locations =
|
|
220
|
+
const locations = mergeToolLocations(
|
|
221
|
+
extractToolLocations(args, options.cwd),
|
|
222
|
+
extractToolLocationsFromResult(event.result, options.cwd),
|
|
223
|
+
);
|
|
215
224
|
if (locations.length > 0) {
|
|
216
225
|
update.locations = locations;
|
|
217
226
|
}
|
|
@@ -295,14 +304,83 @@ export function mapAgentSessionEventToAcpSessionUpdates(
|
|
|
295
304
|
return [toSessionNotification(sessionId, { sessionUpdate: "session_info_update", _meta: meta })];
|
|
296
305
|
}
|
|
297
306
|
case "auto_retry_start":
|
|
307
|
+
return [
|
|
308
|
+
toSessionNotification(sessionId, {
|
|
309
|
+
sessionUpdate: "session_info_update",
|
|
310
|
+
_meta: {
|
|
311
|
+
skcPhase: "retrying",
|
|
312
|
+
skcRetryState: "waiting",
|
|
313
|
+
skcRetryAttempt: event.attempt,
|
|
314
|
+
skcRetryMaxAttempts: event.maxAttempts,
|
|
315
|
+
skcRetryDelayMs: event.delayMs,
|
|
316
|
+
skcRetryErrorMessage: event.errorMessage,
|
|
317
|
+
skcRetryUnbounded: event.unbounded ?? false,
|
|
318
|
+
running: true,
|
|
319
|
+
skcRunning: true,
|
|
320
|
+
},
|
|
321
|
+
}),
|
|
322
|
+
];
|
|
298
323
|
case "auto_retry_end":
|
|
324
|
+
return [
|
|
325
|
+
toSessionNotification(sessionId, {
|
|
326
|
+
sessionUpdate: "session_info_update",
|
|
327
|
+
_meta: {
|
|
328
|
+
skcPhase: event.success ? "responding" : "retry_failed",
|
|
329
|
+
skcRetryState: event.success ? "succeeded" : "failed",
|
|
330
|
+
skcRetryAttempt: event.attempt,
|
|
331
|
+
...(event.finalError ? { skcRetryFinalError: event.finalError } : {}),
|
|
332
|
+
running: true,
|
|
333
|
+
skcRunning: true,
|
|
334
|
+
},
|
|
335
|
+
}),
|
|
336
|
+
];
|
|
299
337
|
case "ttsr_triggered":
|
|
338
|
+
return [
|
|
339
|
+
toSessionNotification(sessionId, {
|
|
340
|
+
sessionUpdate: "session_info_update",
|
|
341
|
+
_meta: {
|
|
342
|
+
skcTtsrTriggered: true,
|
|
343
|
+
skcTtsrRuleCount: event.rules.length,
|
|
344
|
+
},
|
|
345
|
+
}),
|
|
346
|
+
];
|
|
300
347
|
case "irc_message":
|
|
301
348
|
case "subagent_steer_message":
|
|
349
|
+
return [];
|
|
302
350
|
case "notice":
|
|
351
|
+
return [
|
|
352
|
+
toSessionNotification(sessionId, {
|
|
353
|
+
sessionUpdate: "agent_thought_chunk",
|
|
354
|
+
content: {
|
|
355
|
+
type: "text",
|
|
356
|
+
text: `[${event.level}${event.source ? `:${event.source}` : ""}] ${event.message}\n`,
|
|
357
|
+
},
|
|
358
|
+
}),
|
|
359
|
+
];
|
|
303
360
|
case "thinking_level_changed":
|
|
361
|
+
return [
|
|
362
|
+
toSessionNotification(sessionId, {
|
|
363
|
+
sessionUpdate: "session_info_update",
|
|
364
|
+
_meta: { skcThinkingLevel: event.thinkingLevel ?? "off" },
|
|
365
|
+
}),
|
|
366
|
+
];
|
|
304
367
|
case "goal_updated":
|
|
305
|
-
return [
|
|
368
|
+
return [
|
|
369
|
+
toSessionNotification(sessionId, {
|
|
370
|
+
sessionUpdate: "session_info_update",
|
|
371
|
+
_meta: {
|
|
372
|
+
skcGoalActive: event.goal !== null,
|
|
373
|
+
...(event.goal
|
|
374
|
+
? {
|
|
375
|
+
skcGoalId: event.goal.id,
|
|
376
|
+
skcGoalStatus: event.goal.status,
|
|
377
|
+
skcGoalObjective: event.goal.objective,
|
|
378
|
+
}
|
|
379
|
+
: {}),
|
|
380
|
+
...(event.state ? { skcGoalModeState: event.state } : {}),
|
|
381
|
+
},
|
|
382
|
+
}),
|
|
383
|
+
];
|
|
306
384
|
default:
|
|
307
385
|
return assertNeverAcp(event);
|
|
308
386
|
}
|
|
@@ -547,6 +625,19 @@ function mergeToolUpdateContent(startContent: ToolCallContent[], resultContent:
|
|
|
547
625
|
return merged;
|
|
548
626
|
}
|
|
549
627
|
|
|
628
|
+
function mergeToolLocations(...groups: ToolCallLocation[][]): ToolCallLocation[] {
|
|
629
|
+
const locations: ToolCallLocation[] = [];
|
|
630
|
+
const seen = new Set<string>();
|
|
631
|
+
for (const group of groups) {
|
|
632
|
+
for (const location of group) {
|
|
633
|
+
if (seen.has(location.path)) continue;
|
|
634
|
+
seen.add(location.path);
|
|
635
|
+
locations.push(location);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
return locations;
|
|
639
|
+
}
|
|
640
|
+
|
|
550
641
|
function isCommandToolName(toolName: string): boolean {
|
|
551
642
|
return toolName === "bash" || toolName === "shell" || toolName === "exec";
|
|
552
643
|
}
|
|
@@ -626,7 +717,7 @@ function extractToolLocationsFromResult(result: unknown, cwd?: string): ToolCall
|
|
|
626
717
|
}
|
|
627
718
|
|
|
628
719
|
/** Emit a `diff` ToolCallContent for each per-file edit result that carries oldText/newText. */
|
|
629
|
-
function extractDiffToolCallContent(result: unknown): ToolCallContent[] {
|
|
720
|
+
function extractDiffToolCallContent(result: unknown, cwd?: string): ToolCallContent[] {
|
|
630
721
|
if (typeof result !== "object" || result === null) return [];
|
|
631
722
|
const details = (result as { details?: unknown }).details;
|
|
632
723
|
if (typeof details !== "object" || details === null) return [];
|
|
@@ -634,13 +725,13 @@ function extractDiffToolCallContent(result: unknown): ToolCallContent[] {
|
|
|
634
725
|
const perFile = (details as { perFileResults?: unknown }).perFileResults;
|
|
635
726
|
const entries: unknown[] = Array.isArray(perFile) ? perFile : [details];
|
|
636
727
|
for (const entry of entries) {
|
|
637
|
-
const block = buildDiffContent(entry);
|
|
728
|
+
const block = buildDiffContent(entry, cwd);
|
|
638
729
|
if (block) blocks.push(block);
|
|
639
730
|
}
|
|
640
731
|
return blocks;
|
|
641
732
|
}
|
|
642
733
|
|
|
643
|
-
function buildDiffContent(entry: unknown): ToolCallContent | undefined {
|
|
734
|
+
function buildDiffContent(entry: unknown, cwd?: string): ToolCallContent | undefined {
|
|
644
735
|
if (typeof entry !== "object" || entry === null) return undefined;
|
|
645
736
|
const candidate = entry as { path?: unknown; oldText?: unknown; newText?: unknown; isError?: unknown };
|
|
646
737
|
if (candidate.isError === true) return undefined;
|
|
@@ -651,7 +742,8 @@ function buildDiffContent(entry: unknown): ToolCallContent | undefined {
|
|
|
651
742
|
if (oldText === undefined && newText === undefined) return undefined;
|
|
652
743
|
return {
|
|
653
744
|
type: "diff",
|
|
654
|
-
path,
|
|
745
|
+
// `Diff.path` is specified as an absolute path, same as ToolCallLocation.
|
|
746
|
+
path: toAcpLocationPath(path, cwd),
|
|
655
747
|
oldText: oldText ?? null,
|
|
656
748
|
newText: newText ?? "",
|
|
657
749
|
};
|
|
@@ -772,7 +864,9 @@ function toToolCallContent(value: unknown): ToolCallContent | undefined {
|
|
|
772
864
|
resourceLinkContent.mimeType = mimeType;
|
|
773
865
|
}
|
|
774
866
|
const size = extractNumberProperty<ResourceLinkLikeContent>(value, "size");
|
|
775
|
-
|
|
867
|
+
// `ResourceLink.size` is a byte count typed as int64; drop fractional, negative,
|
|
868
|
+
// or non-representable values rather than emitting a block clients must reject.
|
|
869
|
+
if (size !== undefined && Number.isSafeInteger(size) && size >= 0) {
|
|
776
870
|
resourceLinkContent.size = size;
|
|
777
871
|
}
|
|
778
872
|
return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as stream from "node:stream";
|
|
2
|
-
import { AgentSideConnection, ndJsonStream, type Stream } from "@agentclientprotocol/sdk";
|
|
3
|
-
import { AcpAgent } from "./acp-agent";
|
|
2
|
+
import { type Agent, AgentSideConnection, ndJsonStream, type Stream } from "@agentclientprotocol/sdk";
|
|
3
|
+
import { AcpAgent, acpRequestFailure } from "./acp-agent";
|
|
4
4
|
import type { AcpStartupOptions } from "./startup-options";
|
|
5
5
|
|
|
6
6
|
export interface AcpModeOptions {
|
|
@@ -8,8 +8,44 @@ export interface AcpModeOptions {
|
|
|
8
8
|
startupOptions?: AcpStartupOptions;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Every agent method reports failures to the client, and the SDK only derives a
|
|
13
|
+
* JSON-RPC code from a `RequestError` — anything else collapses to an opaque
|
|
14
|
+
* `-32603 Internal error` with the reason buried in `data`. Translating once at the
|
|
15
|
+
* connection boundary keeps that contract in one place instead of asking each method
|
|
16
|
+
* to remember it.
|
|
17
|
+
*/
|
|
18
|
+
function withAcpRequestFailures(agent: AcpAgent): Agent {
|
|
19
|
+
const wrapped = new Map<string | symbol, (...args: unknown[]) => unknown>();
|
|
20
|
+
return new Proxy(agent, {
|
|
21
|
+
get(target, property) {
|
|
22
|
+
// Read against the target, not the proxy: `signal`/`closed` are getters that
|
|
23
|
+
// touch private fields, and the proxy carries no private-field brand.
|
|
24
|
+
const value = Reflect.get(target, property, target);
|
|
25
|
+
if (typeof value !== "function") return value;
|
|
26
|
+
const cached = wrapped.get(property);
|
|
27
|
+
if (cached) return cached;
|
|
28
|
+
// Cache per property so repeated reads keep a stable method identity.
|
|
29
|
+
const wrapper = (...args: unknown[]) => {
|
|
30
|
+
try {
|
|
31
|
+
const result = (value as (...a: unknown[]) => unknown).apply(target, args);
|
|
32
|
+
return result instanceof Promise
|
|
33
|
+
? result.catch((error: unknown) => {
|
|
34
|
+
throw acpRequestFailure(error);
|
|
35
|
+
})
|
|
36
|
+
: result;
|
|
37
|
+
} catch (error) {
|
|
38
|
+
throw acpRequestFailure(error);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
wrapped.set(property, wrapper);
|
|
42
|
+
return wrapper;
|
|
43
|
+
},
|
|
44
|
+
}) as unknown as Agent;
|
|
45
|
+
}
|
|
46
|
+
|
|
11
47
|
export function createAcpConnection(transport: Stream, options: AcpModeOptions = {}): AgentSideConnection {
|
|
12
|
-
return new AgentSideConnection(conn => new AcpAgent(conn, options), transport);
|
|
48
|
+
return new AgentSideConnection(conn => withAcpRequestFailures(new AcpAgent(conn, options)), transport);
|
|
13
49
|
}
|
|
14
50
|
|
|
15
51
|
export async function runAcpMode(options: AcpModeOptions = {}): Promise<never> {
|
|
@@ -49,7 +49,7 @@ export const APP_ACTION_METADATA: readonly ActionMetadata[] = [
|
|
|
49
49
|
action("app.clipboard.copyPrompt", "Copy prompt", "Clipboard", ["composer"]),
|
|
50
50
|
action("app.session.new", "New session", "Session", ["composer"]),
|
|
51
51
|
action("app.session.tree", "Session tree", "Session", ["composer"]),
|
|
52
|
-
action("app.session.fork", "
|
|
52
|
+
action("app.session.fork", "Branch from message", "Session", ["composer"]),
|
|
53
53
|
action("app.session.resume", "Resume session", "Session", ["composer"]),
|
|
54
54
|
action("app.session.observe", "Observe sessions", "Session", ["composer"]),
|
|
55
55
|
action("app.session.dashboard", "Show sessions dashboard", "Session", ["composer"]),
|
|
@@ -84,8 +84,10 @@ export class AssistantMessageComponent extends Container {
|
|
|
84
84
|
#lastMessage?: AssistantMessage;
|
|
85
85
|
#toolImagesByCallId = new Map<string, ImageContent[]>();
|
|
86
86
|
#usageInfo?: Usage;
|
|
87
|
-
#convertedKittyImages = new Map<string, ImageContent>();
|
|
88
|
-
#kittyConversionsInFlight = new
|
|
87
|
+
#convertedKittyImages = new Map<string, ImageContent & { source: string }>();
|
|
88
|
+
#kittyConversionsInFlight = new Map<string, string>();
|
|
89
|
+
#toolImageGenerations = new Map<string, number>();
|
|
90
|
+
|
|
89
91
|
#responseHeader = new Text(theme.bold(theme.fg("statusLineModel", "sayknow")), 1, 0);
|
|
90
92
|
#contentBlocksCache = new WeakMap<object, { source: string; component: Component }>();
|
|
91
93
|
#lastStreaming = false;
|
|
@@ -94,11 +96,17 @@ export class AssistantMessageComponent extends Container {
|
|
|
94
96
|
#nextContentBlockKey = 0;
|
|
95
97
|
#reusableChildren = new WeakSet<Component>();
|
|
96
98
|
#viewportAnchorId?: string;
|
|
99
|
+
#visibleSignature = "";
|
|
100
|
+
#visibleSignatureInitialized = false;
|
|
101
|
+
#toolImagesRevision = 0;
|
|
102
|
+
#convertedToolImagesRevision = 0;
|
|
103
|
+
#disposed = false;
|
|
97
104
|
constructor(
|
|
98
105
|
message?: AssistantMessage,
|
|
99
106
|
private hideThinkingBlock = false,
|
|
100
107
|
private readonly onImageUpdate?: () => void,
|
|
101
108
|
viewportAnchorId?: string,
|
|
109
|
+
private readonly onVisibleMutation?: () => void,
|
|
102
110
|
) {
|
|
103
111
|
super();
|
|
104
112
|
this.#viewportAnchorId = viewportAnchorId;
|
|
@@ -109,6 +117,56 @@ export class AssistantMessageComponent extends Container {
|
|
|
109
117
|
if (message) {
|
|
110
118
|
this.updateContent(message);
|
|
111
119
|
}
|
|
120
|
+
this.#visibleSignature = this.#visibleContentSignature();
|
|
121
|
+
this.#visibleSignatureInitialized = true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
#visibleContentSignature(): string {
|
|
125
|
+
const message = this.#lastMessage;
|
|
126
|
+
const content: string[] = [];
|
|
127
|
+
let hasMarkdownContent = false;
|
|
128
|
+
for (const block of message?.content ?? []) {
|
|
129
|
+
if (block.type === "text" && block.text.trim()) {
|
|
130
|
+
content.push(`text:${block.text.trim()}`);
|
|
131
|
+
hasMarkdownContent = true;
|
|
132
|
+
} else if (block.type === "thinking" && block.thinking.trim()) {
|
|
133
|
+
content.push(
|
|
134
|
+
this.hideThinkingBlock
|
|
135
|
+
? "thinking"
|
|
136
|
+
: `thinking:${elideRunawayThinkingRepetition(block.thinking.trim())}`,
|
|
137
|
+
);
|
|
138
|
+
if (!this.hideThinkingBlock) hasMarkdownContent = true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (hasMarkdownContent) {
|
|
142
|
+
content.unshift(this.#lastStreaming ? "streaming" : "final");
|
|
143
|
+
}
|
|
144
|
+
const hasToolCalls = message?.content.some(block => block.type === "toolCall") ?? false;
|
|
145
|
+
if (!hasToolCalls && message?.stopReason === "aborted" && !isSilentAbort(message.errorMessage)) {
|
|
146
|
+
content.push(`aborted:${message.errorMessage ?? ""}`);
|
|
147
|
+
} else if (!hasToolCalls && message?.stopReason === "error") {
|
|
148
|
+
content.push(`error:${message.errorMessage ?? ""}`);
|
|
149
|
+
} else if (
|
|
150
|
+
message?.errorMessage &&
|
|
151
|
+
!isSilentAbort(message.errorMessage) &&
|
|
152
|
+
message.stopReason !== "aborted" &&
|
|
153
|
+
message.stopReason !== "error"
|
|
154
|
+
) {
|
|
155
|
+
content.push(`message-error:${message.errorMessage}`);
|
|
156
|
+
}
|
|
157
|
+
if (settings.get("display.showTokenUsage") && this.#usageInfo) {
|
|
158
|
+
const usage = this.#usageInfo;
|
|
159
|
+
content.push(`usage:${usage.input}:${usage.cacheWrite}:${usage.output}:${usage.cacheRead}`);
|
|
160
|
+
}
|
|
161
|
+
content.push(`images:${this.#toolImagesRevision}:${this.#convertedToolImagesRevision}`);
|
|
162
|
+
return content.join("\u0000");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
#notifyVisibleMutation(): void {
|
|
166
|
+
const after = this.#visibleContentSignature();
|
|
167
|
+
if (after === this.#visibleSignature) return;
|
|
168
|
+
this.#visibleSignature = after;
|
|
169
|
+
if (this.#visibleSignatureInitialized) this.onVisibleMutation?.();
|
|
112
170
|
}
|
|
113
171
|
|
|
114
172
|
#contentAnchorSource(
|
|
@@ -126,22 +184,36 @@ export class AssistantMessageComponent extends Container {
|
|
|
126
184
|
}
|
|
127
185
|
|
|
128
186
|
setHideThinkingBlock(hide: boolean): void {
|
|
187
|
+
if (this.hideThinkingBlock === hide) return;
|
|
129
188
|
this.hideThinkingBlock = hide;
|
|
189
|
+
this.#notifyVisibleMutation();
|
|
130
190
|
}
|
|
131
191
|
|
|
132
192
|
setToolResultImages(toolCallId: string, images: ImageContent[]): void {
|
|
133
193
|
if (!toolCallId) return;
|
|
134
194
|
const validImages = images.filter(img => img.type === "image" && img.data && img.mimeType);
|
|
195
|
+
const previousImages = this.#toolImagesByCallId.get(toolCallId);
|
|
196
|
+
if (
|
|
197
|
+
(previousImages?.length ?? 0) === validImages.length &&
|
|
198
|
+
(previousImages?.every(
|
|
199
|
+
(image, index) =>
|
|
200
|
+
image.type === validImages[index]?.type &&
|
|
201
|
+
image.data === validImages[index]?.data &&
|
|
202
|
+
image.mimeType === validImages[index]?.mimeType,
|
|
203
|
+
) ??
|
|
204
|
+
true)
|
|
205
|
+
) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
135
208
|
for (const key of Array.from(this.#convertedKittyImages.keys())) {
|
|
136
|
-
if (key.startsWith(`${toolCallId}:`))
|
|
137
|
-
this.#convertedKittyImages.delete(key);
|
|
138
|
-
}
|
|
209
|
+
if (key.startsWith(`${toolCallId}:`)) this.#convertedKittyImages.delete(key);
|
|
139
210
|
}
|
|
140
|
-
for (const key of Array.from(this.#kittyConversionsInFlight)) {
|
|
141
|
-
if (key.startsWith(`${toolCallId}:`))
|
|
142
|
-
this.#kittyConversionsInFlight.delete(key);
|
|
143
|
-
}
|
|
211
|
+
for (const key of Array.from(this.#kittyConversionsInFlight.keys())) {
|
|
212
|
+
if (key.startsWith(`${toolCallId}:`)) this.#kittyConversionsInFlight.delete(key);
|
|
144
213
|
}
|
|
214
|
+
this.#toolImageGenerations.set(toolCallId, (this.#toolImageGenerations.get(toolCallId) ?? 0) + 1);
|
|
215
|
+
|
|
216
|
+
this.#toolImagesRevision += 1;
|
|
145
217
|
if (validImages.length === 0) {
|
|
146
218
|
this.#toolImagesByCallId.delete(toolCallId);
|
|
147
219
|
} else {
|
|
@@ -153,30 +225,49 @@ export class AssistantMessageComponent extends Container {
|
|
|
153
225
|
}
|
|
154
226
|
}
|
|
155
227
|
|
|
228
|
+
#toolImageSource(image: ImageContent): string {
|
|
229
|
+
return `${image.mimeType}\u0000${image.data}`;
|
|
230
|
+
}
|
|
231
|
+
|
|
156
232
|
#convertToolImagesForKitty(toolCallId: string, images: ImageContent[]): void {
|
|
157
233
|
if (TERMINAL.imageProtocol !== ImageProtocol.Kitty) return;
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (
|
|
234
|
+
const generation = this.#toolImageGenerations.get(toolCallId) ?? 0;
|
|
235
|
+
for (const [index, image] of images.entries()) {
|
|
236
|
+
if (image.mimeType === "image/png") continue;
|
|
161
237
|
const key = `${toolCallId}:${index}`;
|
|
162
|
-
|
|
163
|
-
|
|
238
|
+
const source = this.#toolImageSource(image);
|
|
239
|
+
if (
|
|
240
|
+
this.#convertedKittyImages.get(key)?.source === source ||
|
|
241
|
+
this.#kittyConversionsInFlight.get(key) === source
|
|
242
|
+
)
|
|
243
|
+
continue;
|
|
244
|
+
this.#kittyConversionsInFlight.set(key, source);
|
|
164
245
|
new Bun.Image(Buffer.from(image.data, "base64"))
|
|
165
246
|
.png()
|
|
166
247
|
.toBase64()
|
|
167
248
|
.then(data => {
|
|
249
|
+
const currentImage = this.#toolImagesByCallId.get(toolCallId)?.[index];
|
|
250
|
+
if (
|
|
251
|
+
this.#disposed ||
|
|
252
|
+
this.#toolImageGenerations.get(toolCallId) !== generation ||
|
|
253
|
+
this.#kittyConversionsInFlight.get(key) !== source ||
|
|
254
|
+
!currentImage ||
|
|
255
|
+
this.#toolImageSource(currentImage) !== source
|
|
256
|
+
)
|
|
257
|
+
return;
|
|
168
258
|
this.#kittyConversionsInFlight.delete(key);
|
|
169
|
-
this.#convertedKittyImages.set(key, {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
mimeType: "image/png",
|
|
173
|
-
});
|
|
174
|
-
if (this.#lastMessage) {
|
|
175
|
-
this.updateContent(this.#lastMessage, { streaming: this.#lastStreaming });
|
|
176
|
-
}
|
|
259
|
+
this.#convertedKittyImages.set(key, { type: "image", data, mimeType: "image/png", source });
|
|
260
|
+
this.#convertedToolImagesRevision += 1;
|
|
261
|
+
if (this.#lastMessage) this.updateContent(this.#lastMessage, { streaming: this.#lastStreaming });
|
|
177
262
|
this.onImageUpdate?.();
|
|
178
263
|
})
|
|
179
264
|
.catch(() => {
|
|
265
|
+
if (
|
|
266
|
+
this.#disposed ||
|
|
267
|
+
this.#toolImageGenerations.get(toolCallId) !== generation ||
|
|
268
|
+
this.#kittyConversionsInFlight.get(key) !== source
|
|
269
|
+
)
|
|
270
|
+
return;
|
|
180
271
|
this.#kittyConversionsInFlight.delete(key);
|
|
181
272
|
});
|
|
182
273
|
}
|
|
@@ -487,5 +578,15 @@ export class AssistantMessageComponent extends Container {
|
|
|
487
578
|
}
|
|
488
579
|
|
|
489
580
|
this.#reconcileChildren(descriptors);
|
|
581
|
+
this.#notifyVisibleMutation();
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
override dispose(): void {
|
|
585
|
+
if (this.#disposed) return;
|
|
586
|
+
this.#disposed = true;
|
|
587
|
+
this.#toolImageGenerations.clear();
|
|
588
|
+
this.#kittyConversionsInFlight.clear();
|
|
589
|
+
this.#convertedKittyImages.clear();
|
|
590
|
+
super.dispose();
|
|
490
591
|
}
|
|
491
592
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { type Component, Container, Markdown, Spacer, Text, type TUI } from "@sayknow-cli/tui";
|
|
2
|
+
import {
|
|
3
|
+
BTW_MAX_ANSWER_UTF8_BYTES,
|
|
4
|
+
BTW_MAX_CONTEXT_TURNS,
|
|
5
|
+
sanitizeBtwError,
|
|
6
|
+
truncateUtf8,
|
|
7
|
+
} from "../../session/btw-contract";
|
|
2
8
|
import { replaceTabs } from "../../tools/render-utils";
|
|
3
9
|
import { getMarkdownTheme, theme } from "../theme/theme";
|
|
4
10
|
import { DynamicBorder } from "./dynamic-border";
|
|
@@ -10,12 +16,21 @@ interface BtwPanelComponentOptions {
|
|
|
10
16
|
tui: TUI;
|
|
11
17
|
}
|
|
12
18
|
|
|
19
|
+
interface BtwTurn {
|
|
20
|
+
question: string;
|
|
21
|
+
answer: string;
|
|
22
|
+
state: BtwPanelState;
|
|
23
|
+
errorMessage?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
13
26
|
export class BtwPanelComponent extends Container {
|
|
14
27
|
#question: string;
|
|
15
28
|
#tui: TUI;
|
|
16
29
|
#state: BtwPanelState = "running";
|
|
17
30
|
#answer = "";
|
|
18
31
|
#errorMessage: string | undefined;
|
|
32
|
+
#completedTurns: BtwTurn[] = [];
|
|
33
|
+
#streamingContent = new Container();
|
|
19
34
|
#closed = false;
|
|
20
35
|
|
|
21
36
|
constructor(options: BtwPanelComponentOptions) {
|
|
@@ -25,16 +40,29 @@ export class BtwPanelComponent extends Container {
|
|
|
25
40
|
this.#rebuild();
|
|
26
41
|
}
|
|
27
42
|
|
|
43
|
+
beginTurn(question: string): void {
|
|
44
|
+
if (this.#closed) return;
|
|
45
|
+
if (this.#state === "complete") {
|
|
46
|
+
this.#completedTurns.push(this.#currentTurn());
|
|
47
|
+
if (this.#completedTurns.length > BTW_MAX_CONTEXT_TURNS) this.#completedTurns.shift();
|
|
48
|
+
}
|
|
49
|
+
this.#question = question;
|
|
50
|
+
this.#answer = "";
|
|
51
|
+
this.#errorMessage = undefined;
|
|
52
|
+
this.#state = "running";
|
|
53
|
+
this.#rebuild();
|
|
54
|
+
}
|
|
55
|
+
|
|
28
56
|
appendText(delta: string): void {
|
|
29
57
|
if (!delta || this.#closed) return;
|
|
30
|
-
this.#answer
|
|
31
|
-
this.#
|
|
58
|
+
this.#answer = truncateUtf8(this.#answer + delta, BTW_MAX_ANSWER_UTF8_BYTES);
|
|
59
|
+
this.#updateStreamingContent();
|
|
32
60
|
}
|
|
33
61
|
|
|
34
62
|
setAnswer(text: string): void {
|
|
35
63
|
if (this.#closed) return;
|
|
36
|
-
this.#answer = text;
|
|
37
|
-
this.#
|
|
64
|
+
this.#answer = truncateUtf8(text, BTW_MAX_ANSWER_UTF8_BYTES);
|
|
65
|
+
this.#updateStreamingContent();
|
|
38
66
|
}
|
|
39
67
|
|
|
40
68
|
markComplete(): void {
|
|
@@ -54,21 +82,33 @@ export class BtwPanelComponent extends Container {
|
|
|
54
82
|
markError(message: string): void {
|
|
55
83
|
if (this.#closed) return;
|
|
56
84
|
this.#state = "error";
|
|
57
|
-
this.#
|
|
85
|
+
this.#answer = "";
|
|
86
|
+
this.#errorMessage = sanitizeBtwError(message);
|
|
58
87
|
this.#rebuild();
|
|
59
88
|
}
|
|
60
89
|
|
|
61
90
|
close(): void {
|
|
62
91
|
this.#closed = true;
|
|
92
|
+
this.#question = "";
|
|
93
|
+
this.#completedTurns = [];
|
|
94
|
+
this.#answer = "";
|
|
95
|
+
this.#errorMessage = undefined;
|
|
96
|
+
this.#streamingContent.clear();
|
|
97
|
+
this.clear();
|
|
63
98
|
}
|
|
64
99
|
|
|
65
100
|
#rebuild(): void {
|
|
66
101
|
this.clear();
|
|
67
102
|
this.addChild(new DynamicBorder(str => theme.fg("dim", str)));
|
|
68
103
|
this.addChild(new Spacer(1));
|
|
104
|
+
for (const turn of this.#completedTurns) {
|
|
105
|
+
this.addChild(this.#turnComponent(turn));
|
|
106
|
+
this.addChild(new Spacer(1));
|
|
107
|
+
}
|
|
69
108
|
this.addChild(new Text(theme.fg("accent", replaceTabs(this.#question)), 1, 0));
|
|
70
109
|
this.addChild(new Spacer(1));
|
|
71
|
-
this
|
|
110
|
+
this.#updateStreamingContent(false);
|
|
111
|
+
this.addChild(this.#streamingContent);
|
|
72
112
|
this.addChild(new Spacer(1));
|
|
73
113
|
this.addChild(new Text(this.#footerLine(), 1, 0));
|
|
74
114
|
this.addChild(new Spacer(1));
|
|
@@ -76,29 +116,55 @@ export class BtwPanelComponent extends Container {
|
|
|
76
116
|
this.#tui.requestRender();
|
|
77
117
|
}
|
|
78
118
|
|
|
119
|
+
#updateStreamingContent(requestRender = true): void {
|
|
120
|
+
this.#streamingContent.clear();
|
|
121
|
+
this.#streamingContent.addChild(this.#contentComponent(this.#state, this.#answer, this.#errorMessage));
|
|
122
|
+
if (requestRender) this.#tui.requestRender();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
#currentTurn(): BtwTurn {
|
|
126
|
+
return {
|
|
127
|
+
question: this.#question,
|
|
128
|
+
answer: this.#answer,
|
|
129
|
+
state: this.#state,
|
|
130
|
+
errorMessage: this.#errorMessage,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
#turnComponent(turn: BtwTurn): Component {
|
|
135
|
+
const container = new Container();
|
|
136
|
+
container.addChild(new Text(theme.fg("accent", replaceTabs(turn.question)), 1, 0));
|
|
137
|
+
container.addChild(new Spacer(1));
|
|
138
|
+
container.addChild(this.#contentComponent(turn.state, turn.answer, turn.errorMessage));
|
|
139
|
+
return container;
|
|
140
|
+
}
|
|
141
|
+
|
|
79
142
|
#footerLine(): string {
|
|
80
143
|
switch (this.#state) {
|
|
81
144
|
case "running":
|
|
82
|
-
return theme.fg("muted", "Esc cancel /btw");
|
|
145
|
+
return theme.fg("muted", "Esc cancel /btw and return to main chat");
|
|
83
146
|
case "complete":
|
|
84
|
-
return theme.fg("muted", "Esc
|
|
147
|
+
return theme.fg("muted", "Type a follow-up · Esc return to main chat");
|
|
85
148
|
case "aborted":
|
|
86
|
-
return theme.fg(
|
|
149
|
+
return theme.fg(
|
|
150
|
+
"warning",
|
|
151
|
+
`${theme.status.warning} Cancelled · Type a follow-up · Esc return to main chat`,
|
|
152
|
+
);
|
|
87
153
|
case "error":
|
|
88
|
-
return theme.fg("error", `${theme.status.error} Error · Esc
|
|
154
|
+
return theme.fg("error", `${theme.status.error} Error · Type a follow-up · Esc return to main chat`);
|
|
89
155
|
}
|
|
90
156
|
}
|
|
91
157
|
|
|
92
|
-
#contentComponent(): Component {
|
|
93
|
-
if (
|
|
94
|
-
return new Text(theme.fg("error", replaceTabs(
|
|
158
|
+
#contentComponent(state: BtwPanelState, answer: string, errorMessage: string | undefined): Component {
|
|
159
|
+
if (state === "error") {
|
|
160
|
+
return new Text(theme.fg("error", replaceTabs(errorMessage ?? "Unknown error")), 1, 0);
|
|
95
161
|
}
|
|
96
|
-
const text = replaceTabs(
|
|
162
|
+
const text = replaceTabs(answer).trim();
|
|
97
163
|
if (!text) {
|
|
98
|
-
const waiting =
|
|
99
|
-
this.#state === "running" ? `${theme.status.pending} Waiting for response…` : "No text returned.";
|
|
164
|
+
const waiting = state === "running" ? `${theme.status.pending} Waiting for response…` : "No text returned.";
|
|
100
165
|
return new Text(theme.fg("dim", waiting), 1, 0);
|
|
101
166
|
}
|
|
167
|
+
if (state === "running") return new Text(text, 1, 0);
|
|
102
168
|
return new Markdown(text, 1, 0, getMarkdownTheme());
|
|
103
169
|
}
|
|
104
170
|
}
|