@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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as crypto from "node:crypto";
|
|
1
2
|
import {
|
|
2
3
|
type Component,
|
|
3
4
|
padding,
|
|
@@ -21,6 +22,46 @@ const IRC_SIDEBAR_MAX_RENDER_SOURCE_UTF8_BYTES = 64 * 1_024;
|
|
|
21
22
|
const IRC_SIDEBAR_OLDER_MESSAGES_ELISION = "… older IRC messages elided …";
|
|
22
23
|
const IRC_SIDEBAR_MESSAGE_ELISION = " … message elided …";
|
|
23
24
|
|
|
25
|
+
export const __ircSidebarPerfCounters = {
|
|
26
|
+
enabled: false,
|
|
27
|
+
projectionMemoHits: 0,
|
|
28
|
+
projectionMemoMisses: 0,
|
|
29
|
+
recordsVisited: 0,
|
|
30
|
+
sourceBytes: 0,
|
|
31
|
+
rows: 0,
|
|
32
|
+
styledCacheHits: 0,
|
|
33
|
+
styledCacheMisses: 0,
|
|
34
|
+
wrapCalls: 0,
|
|
35
|
+
snapshot() {
|
|
36
|
+
return {
|
|
37
|
+
projectionMemoHits: this.projectionMemoHits,
|
|
38
|
+
projectionMemoMisses: this.projectionMemoMisses,
|
|
39
|
+
recordsVisited: this.recordsVisited,
|
|
40
|
+
sourceBytes: this.sourceBytes,
|
|
41
|
+
rows: this.rows,
|
|
42
|
+
styledCacheHits: this.styledCacheHits,
|
|
43
|
+
styledCacheMisses: this.styledCacheMisses,
|
|
44
|
+
wrapCalls: this.wrapCalls,
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
enable(): void {
|
|
48
|
+
this.enabled = true;
|
|
49
|
+
},
|
|
50
|
+
disable(): void {
|
|
51
|
+
this.enabled = false;
|
|
52
|
+
},
|
|
53
|
+
reset(): void {
|
|
54
|
+
this.projectionMemoHits = 0;
|
|
55
|
+
this.projectionMemoMisses = 0;
|
|
56
|
+
this.recordsVisited = 0;
|
|
57
|
+
this.sourceBytes = 0;
|
|
58
|
+
this.rows = 0;
|
|
59
|
+
this.styledCacheHits = 0;
|
|
60
|
+
this.styledCacheMisses = 0;
|
|
61
|
+
this.wrapCalls = 0;
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
24
65
|
/** Computes transcript/sidebar widths while preserving at least half the terminal for the transcript. */
|
|
25
66
|
export function computeIrcSplitWidths(width: number): {
|
|
26
67
|
leftWidth: number;
|
|
@@ -34,12 +75,7 @@ export function computeIrcSplitWidths(width: number): {
|
|
|
34
75
|
0,
|
|
35
76
|
Math.min(preferredSidebar, normalizedWidth - IRC_SEPARATOR_WIDTH - transcriptFloor),
|
|
36
77
|
);
|
|
37
|
-
|
|
38
|
-
// The sidebar yields entirely rather than rendering below its readable minimum.
|
|
39
|
-
if (sidebarWidth < IRC_SIDEBAR_MIN_WIDTH) {
|
|
40
|
-
return { leftWidth: normalizedWidth, separatorWidth: 0, rightWidth: 0 };
|
|
41
|
-
}
|
|
42
|
-
|
|
78
|
+
if (sidebarWidth < IRC_SIDEBAR_MIN_WIDTH) return { leftWidth: normalizedWidth, separatorWidth: 0, rightWidth: 0 };
|
|
43
79
|
return {
|
|
44
80
|
leftWidth: normalizedWidth - IRC_SEPARATOR_WIDTH - sidebarWidth,
|
|
45
81
|
separatorWidth: IRC_SEPARATOR_WIDTH,
|
|
@@ -47,52 +83,99 @@ export function computeIrcSplitWidths(width: number): {
|
|
|
47
83
|
};
|
|
48
84
|
}
|
|
49
85
|
|
|
50
|
-
|
|
51
|
-
|
|
86
|
+
type SemanticLine = Readonly<{
|
|
87
|
+
kind: "header" | "body" | "elision" | "blank";
|
|
88
|
+
text: string;
|
|
89
|
+
sender?: string;
|
|
90
|
+
recipient?: string;
|
|
91
|
+
time?: string;
|
|
92
|
+
}>;
|
|
93
|
+
export type IrcSidebarSemanticProjection = Readonly<{ token: string; lines: readonly SemanticLine[] }>;
|
|
94
|
+
const projectionMemo = new WeakMap<
|
|
95
|
+
IrcObservationLedger,
|
|
96
|
+
{ epoch: number; width: number; projection: IrcSidebarSemanticProjection }
|
|
97
|
+
>();
|
|
98
|
+
|
|
99
|
+
function semanticProjectionToken(lines: readonly SemanticLine[]): string {
|
|
100
|
+
const hash = crypto.createHash("sha256");
|
|
101
|
+
const length = Buffer.allocUnsafe(4);
|
|
102
|
+
const writeField = (value: string | undefined): void => {
|
|
103
|
+
length.writeUInt32BE(value === undefined ? 0xffffffff : Buffer.byteLength(value, "utf8"));
|
|
104
|
+
hash.update(length);
|
|
105
|
+
if (value !== undefined) hash.update(value, "utf8");
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
hash.update("skc:irc:sidebar-semantic-projection:v1\0");
|
|
109
|
+
length.writeUInt32BE(lines.length);
|
|
110
|
+
hash.update(length);
|
|
111
|
+
for (const line of lines) {
|
|
112
|
+
writeField(line.kind);
|
|
113
|
+
writeField(line.text);
|
|
114
|
+
writeField(line.sender);
|
|
115
|
+
writeField(line.recipient);
|
|
116
|
+
writeField(line.time);
|
|
117
|
+
}
|
|
118
|
+
return hash.digest("hex");
|
|
52
119
|
}
|
|
53
120
|
|
|
54
|
-
function
|
|
121
|
+
function projectRecord(
|
|
55
122
|
record: IrcObservationRecord,
|
|
56
123
|
width: number,
|
|
57
|
-
componentTheme: IrcSidebarTheme,
|
|
58
124
|
maxRows: number,
|
|
59
125
|
maxSourceUtf8Bytes: number,
|
|
60
|
-
): { lines:
|
|
126
|
+
): { lines: SemanticLine[]; sourceUtf8Bytes: number; truncated: boolean } {
|
|
61
127
|
const bodyWidth = Math.max(1, width - 2);
|
|
62
128
|
const sourceLimit = Math.min(maxSourceUtf8Bytes, Math.max(0, maxRows - 1) * bodyWidth);
|
|
63
129
|
const clipped = projectIrcText(record.text, sourceLimit);
|
|
64
130
|
const block = formatIrcMessageBlock({ ...record, text: clipped.text });
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
131
|
+
const lines: SemanticLine[] = [
|
|
132
|
+
{
|
|
133
|
+
kind: "header",
|
|
134
|
+
text: `${block.sender} → ${block.recipient} · ${block.time}`,
|
|
135
|
+
sender: block.sender,
|
|
136
|
+
recipient: block.recipient,
|
|
137
|
+
time: block.time,
|
|
138
|
+
},
|
|
139
|
+
];
|
|
68
140
|
let truncated = clipped.truncated;
|
|
69
|
-
|
|
70
141
|
body: for (const bodyLine of block.bodyLines) {
|
|
142
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.wrapCalls++;
|
|
71
143
|
for (const wrappedLine of wrapTextWithAnsi(bodyLine, bodyWidth)) {
|
|
72
144
|
if (lines.length >= maxRows) {
|
|
73
145
|
truncated = true;
|
|
74
146
|
break body;
|
|
75
147
|
}
|
|
76
|
-
lines.push(
|
|
148
|
+
lines.push({ kind: "body", text: ` ${wrappedLine}` });
|
|
77
149
|
}
|
|
78
150
|
}
|
|
79
151
|
if (truncated && maxRows > 1) {
|
|
80
|
-
const marker =
|
|
81
|
-
if (lines.length >= maxRows) lines[maxRows - 1] =
|
|
82
|
-
else lines.push(
|
|
152
|
+
const marker: SemanticLine = { kind: "elision", text: IRC_SIDEBAR_MESSAGE_ELISION };
|
|
153
|
+
if (lines.length >= maxRows) lines[maxRows - 1] = marker;
|
|
154
|
+
else lines.push(marker);
|
|
83
155
|
}
|
|
84
156
|
return { lines, sourceUtf8Bytes: clipped.utf8Bytes, truncated };
|
|
85
157
|
}
|
|
86
158
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
159
|
+
/** The authoritative bounded, display-neutral IRC sidebar projection. */
|
|
160
|
+
export function getIrcSidebarSemanticProjection(
|
|
161
|
+
ledger: IrcObservationLedger,
|
|
162
|
+
width: number,
|
|
163
|
+
): IrcSidebarSemanticProjection {
|
|
164
|
+
if (width <= 0) return { token: "", lines: [] };
|
|
165
|
+
const memo = projectionMemo.get(ledger);
|
|
166
|
+
const cachedProjection = memo?.epoch === ledger.mutationEpoch && memo.width === width ? memo.projection : undefined;
|
|
167
|
+
if (cachedProjection) {
|
|
168
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.projectionMemoHits++;
|
|
169
|
+
return cachedProjection;
|
|
170
|
+
}
|
|
171
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.projectionMemoMisses++;
|
|
172
|
+
const newestFirstBlocks: SemanticLine[][] = [];
|
|
92
173
|
let renderedRows = 0;
|
|
93
174
|
let renderedSourceUtf8Bytes = 0;
|
|
94
175
|
let omittedOlderRecords = false;
|
|
176
|
+
const records = ledger.getSidebarRecords();
|
|
95
177
|
for (let index = records.length - 1; index >= 0; index--) {
|
|
178
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.recordsVisited++;
|
|
96
179
|
const separatorRows = newestFirstBlocks.length > 0 ? 1 : 0;
|
|
97
180
|
const availableRows = IRC_SIDEBAR_MAX_RENDER_ROWS - renderedRows - separatorRows - 2;
|
|
98
181
|
const availableSourceUtf8Bytes = IRC_SIDEBAR_MAX_RENDER_SOURCE_UTF8_BYTES - renderedSourceUtf8Bytes;
|
|
@@ -101,32 +184,32 @@ function renderSidebarRecords(ledger: IrcObservationLedger, width: number, compo
|
|
|
101
184
|
omittedOlderRecords = true;
|
|
102
185
|
break;
|
|
103
186
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
availableSourceUtf8Bytes,
|
|
111
|
-
);
|
|
112
|
-
newestFirstBlocks.push(rendered.lines);
|
|
113
|
-
renderedRows += separatorRows + rendered.lines.length;
|
|
114
|
-
renderedSourceUtf8Bytes += rendered.sourceUtf8Bytes;
|
|
115
|
-
if (rendered.truncated) {
|
|
187
|
+
const projected = projectRecord(records[index], width, availableRows, availableSourceUtf8Bytes);
|
|
188
|
+
newestFirstBlocks.push(projected.lines);
|
|
189
|
+
renderedRows += separatorRows + projected.lines.length;
|
|
190
|
+
renderedSourceUtf8Bytes += projected.sourceUtf8Bytes;
|
|
191
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.sourceBytes += projected.sourceUtf8Bytes;
|
|
192
|
+
if (projected.truncated) {
|
|
116
193
|
omittedOlderRecords = index > 0;
|
|
117
194
|
break;
|
|
118
195
|
}
|
|
119
196
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
lines.push(truncateToWidth(componentTheme.fg("dim", IRC_SIDEBAR_OLDER_MESSAGES_ELISION), width));
|
|
124
|
-
}
|
|
197
|
+
const lines: SemanticLine[] = omittedOlderRecords
|
|
198
|
+
? [{ kind: "elision", text: IRC_SIDEBAR_OLDER_MESSAGES_ELISION }]
|
|
199
|
+
: [];
|
|
125
200
|
for (const block of newestFirstBlocks.reverse()) {
|
|
126
|
-
if (lines.length > 0) lines.push("");
|
|
201
|
+
if (lines.length > 0) lines.push({ kind: "blank", text: "" });
|
|
127
202
|
lines.push(...block);
|
|
128
203
|
}
|
|
129
|
-
|
|
204
|
+
const bounded = lines.slice(0, IRC_SIDEBAR_MAX_RENDER_ROWS);
|
|
205
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.rows += bounded.length;
|
|
206
|
+
const projection = { token: semanticProjectionToken(bounded), lines: bounded };
|
|
207
|
+
projectionMemo.set(ledger, { epoch: ledger.mutationEpoch, width, projection });
|
|
208
|
+
return projection;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function getIrcSidebarSemanticToken(ledger: IrcObservationLedger, width: number): string {
|
|
212
|
+
return getIrcSidebarSemanticProjection(ledger, width).token;
|
|
130
213
|
}
|
|
131
214
|
|
|
132
215
|
export interface IrcSidebarTheme {
|
|
@@ -134,64 +217,96 @@ export interface IrcSidebarTheme {
|
|
|
134
217
|
bold(text: string): string;
|
|
135
218
|
readonly boxSharp: { readonly vertical: string };
|
|
136
219
|
}
|
|
137
|
-
|
|
138
220
|
export type IrcSidebarThemeSource = IrcSidebarTheme | (() => IrcSidebarTheme);
|
|
139
221
|
|
|
140
222
|
/** Read-only IRC history alongside the active transcript. */
|
|
141
223
|
export class IrcSplitViewComponent implements ViewportAnchorProvider {
|
|
142
224
|
#visible = false;
|
|
225
|
+
#themeGeneration = 0;
|
|
226
|
+
#styledMemo:
|
|
227
|
+
| { token: string; width: number; themeGeneration: number; theme: IrcSidebarTheme; lines: string[] }
|
|
228
|
+
| undefined;
|
|
143
229
|
|
|
144
230
|
constructor(
|
|
145
231
|
private readonly leftPane: Component,
|
|
146
232
|
private readonly ledger: IrcObservationLedger,
|
|
147
233
|
private readonly componentTheme: IrcSidebarThemeSource,
|
|
148
234
|
) {}
|
|
149
|
-
|
|
150
235
|
get visible(): boolean {
|
|
151
236
|
return this.#visible;
|
|
152
237
|
}
|
|
153
|
-
|
|
154
238
|
effectiveSidebarVisible(width = process.stdout.columns ?? 0): boolean {
|
|
155
239
|
return this.#visible && computeIrcSplitWidths(width).rightWidth > 0;
|
|
156
240
|
}
|
|
157
|
-
|
|
158
241
|
setVisible(visible: boolean): void {
|
|
159
|
-
if (this.#visible
|
|
160
|
-
|
|
161
|
-
|
|
242
|
+
if (this.#visible !== visible) {
|
|
243
|
+
this.#visible = visible;
|
|
244
|
+
this.invalidate();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
invalidateTheme(): void {
|
|
248
|
+
this.#themeGeneration++;
|
|
249
|
+
this.#styledMemo = undefined;
|
|
250
|
+
}
|
|
251
|
+
resetSource(): void {
|
|
252
|
+
projectionMemo.delete(this.ledger);
|
|
253
|
+
this.#styledMemo = undefined;
|
|
162
254
|
}
|
|
163
|
-
|
|
164
255
|
render(width: number): string[] {
|
|
165
256
|
return this.renderWithViewportAnchors(width).lines;
|
|
166
257
|
}
|
|
167
|
-
|
|
258
|
+
#renderSidebar(width: number, componentTheme: IrcSidebarTheme): string[] {
|
|
259
|
+
const projection = getIrcSidebarSemanticProjection(this.ledger, width);
|
|
260
|
+
const cached = this.#styledMemo;
|
|
261
|
+
if (
|
|
262
|
+
cached?.token === projection.token &&
|
|
263
|
+
cached.width === width &&
|
|
264
|
+
cached.themeGeneration === this.#themeGeneration &&
|
|
265
|
+
cached.theme === componentTheme
|
|
266
|
+
) {
|
|
267
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.styledCacheHits++;
|
|
268
|
+
return cached.lines;
|
|
269
|
+
}
|
|
270
|
+
if (__ircSidebarPerfCounters.enabled) __ircSidebarPerfCounters.styledCacheMisses++;
|
|
271
|
+
const lines = projection.lines.map(line => {
|
|
272
|
+
if (line.kind === "header")
|
|
273
|
+
return truncateToWidth(
|
|
274
|
+
`${componentTheme.fg("accent", componentTheme.bold(line.sender!))} → ${line.recipient} · ${componentTheme.fg("dim", line.time!)}`,
|
|
275
|
+
width,
|
|
276
|
+
);
|
|
277
|
+
return truncateToWidth(line.kind === "elision" ? componentTheme.fg("dim", line.text) : line.text, width);
|
|
278
|
+
});
|
|
279
|
+
this.#styledMemo = {
|
|
280
|
+
token: projection.token,
|
|
281
|
+
width,
|
|
282
|
+
themeGeneration: this.#themeGeneration,
|
|
283
|
+
theme: componentTheme,
|
|
284
|
+
lines,
|
|
285
|
+
};
|
|
286
|
+
return lines;
|
|
287
|
+
}
|
|
168
288
|
renderWithViewportAnchors(width: number): ViewportAnchorRender {
|
|
169
289
|
if (!this.#visible) return renderComponentWithViewportAnchors(this.leftPane, width);
|
|
170
|
-
|
|
171
290
|
const componentTheme = typeof this.componentTheme === "function" ? this.componentTheme() : this.componentTheme;
|
|
172
291
|
const { leftWidth, separatorWidth, rightWidth } = computeIrcSplitWidths(width);
|
|
173
292
|
if (rightWidth === 0) return renderComponentWithViewportAnchors(this.leftPane, width);
|
|
174
|
-
|
|
175
|
-
const separatorText = componentTheme.fg("dim", ` ${componentTheme.boxSharp.vertical} `);
|
|
176
|
-
const separator = separatorWidth > 0 ? separatorText : "";
|
|
293
|
+
const separator = separatorWidth > 0 ? componentTheme.fg("dim", ` ${componentTheme.boxSharp.vertical} `) : "";
|
|
177
294
|
const leftRender = withTerminalGraphicsFallback(
|
|
178
295
|
() => renderComponentWithViewportAnchors(this.leftPane, leftWidth),
|
|
179
296
|
{ allowCursorNeutralImages: true },
|
|
180
297
|
);
|
|
181
|
-
const rightLines =
|
|
298
|
+
const rightLines = this.#renderSidebar(rightWidth, componentTheme);
|
|
182
299
|
const lineCount = Math.max(leftRender.lines.length, rightLines.length);
|
|
183
300
|
const lines: string[] = [];
|
|
184
301
|
const anchors: ViewportAnchorRender["anchors"] = [];
|
|
185
|
-
|
|
186
302
|
const leftOffset = lineCount - leftRender.lines.length;
|
|
187
303
|
const rightOffset = lineCount - rightLines.length;
|
|
188
304
|
for (let index = 0; index < lineCount; index++) {
|
|
189
305
|
const leftIndex = index - leftOffset;
|
|
190
306
|
const leftRaw = leftRender.lines[leftIndex] ?? "";
|
|
191
307
|
const right = truncateToWidth(rightLines[index - rightOffset] ?? "", rightWidth);
|
|
192
|
-
if (TERMINAL.isImageLine(leftRaw))
|
|
193
|
-
|
|
194
|
-
} else {
|
|
308
|
+
if (TERMINAL.isImageLine(leftRaw)) lines.push(leftRaw + padding(leftWidth) + separator + right);
|
|
309
|
+
else {
|
|
195
310
|
const left = truncateToWidth(leftRaw, leftWidth);
|
|
196
311
|
lines.push(left + padding(Math.max(0, leftWidth - visibleWidth(left))) + separator + right);
|
|
197
312
|
}
|
|
@@ -199,7 +314,6 @@ export class IrcSplitViewComponent implements ViewportAnchorProvider {
|
|
|
199
314
|
}
|
|
200
315
|
return { lines, anchors };
|
|
201
316
|
}
|
|
202
|
-
|
|
203
317
|
invalidate(): void {
|
|
204
318
|
this.leftPane.invalidate?.();
|
|
205
319
|
}
|
|
@@ -32,6 +32,8 @@ import {
|
|
|
32
32
|
} from "../../config/model-resolver";
|
|
33
33
|
import { type ModelSelectorValue, normalizeModelSelectorValue, selectorHead } from "../../config/model-selector-value";
|
|
34
34
|
import type { ModelProfileConfig } from "../../config/models-config-schema";
|
|
35
|
+
import { getProviderAuthHealth } from "../../config/provider-auth-health";
|
|
36
|
+
import { compareRankedProviders, type ProviderAuthState } from "../../config/provider-ranking";
|
|
35
37
|
import type { Settings } from "../../config/settings";
|
|
36
38
|
import { t } from "../../i18n";
|
|
37
39
|
import { type ThemeColor, theme } from "../../modes/theme/theme";
|
|
@@ -521,10 +523,22 @@ export class ModelSelectorComponent extends Container {
|
|
|
521
523
|
this.#applyTabFilter();
|
|
522
524
|
}
|
|
523
525
|
|
|
526
|
+
#resolveProviderAuthState(providerId: string): ProviderAuthState {
|
|
527
|
+
const health = getProviderAuthHealth(this.#modelRegistry.authStorage, providerId);
|
|
528
|
+
if (health) return health;
|
|
529
|
+
return this.#modelRegistry.hasConfiguredProviderAuth(providerId) ? "configured" : "none";
|
|
530
|
+
}
|
|
531
|
+
|
|
524
532
|
#sortModels(models: ModelItem[]): void {
|
|
525
|
-
// Sort: default-tagged model first, then MRU, then
|
|
533
|
+
// Sort: default-tagged model first, then MRU, then provider ranking
|
|
526
534
|
const mruOrder = this.#settings.getStorage()?.getModelUsageOrder() ?? [];
|
|
527
535
|
const mruIndex = new Map(mruOrder.map((key, i) => [key, i]));
|
|
536
|
+
const providerAuthStateById = new Map<string, ProviderAuthState>();
|
|
537
|
+
for (const item of models) {
|
|
538
|
+
if (!providerAuthStateById.has(item.provider)) {
|
|
539
|
+
providerAuthStateById.set(item.provider, this.#resolveProviderAuthState(item.provider));
|
|
540
|
+
}
|
|
541
|
+
}
|
|
528
542
|
|
|
529
543
|
const modelRank = (item: ModelItem) => computeModelRank(item.model, this.#roles);
|
|
530
544
|
|
|
@@ -545,7 +559,18 @@ export class ModelSelectorComponent extends Container {
|
|
|
545
559
|
if (aMru !== bMru) return aMru - bMru;
|
|
546
560
|
|
|
547
561
|
// By provider, then recency within provider
|
|
548
|
-
const providerCmp =
|
|
562
|
+
const providerCmp = compareRankedProviders(
|
|
563
|
+
{
|
|
564
|
+
id: a.provider,
|
|
565
|
+
label: a.provider,
|
|
566
|
+
authState: providerAuthStateById.get(a.provider) ?? "none",
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
id: b.provider,
|
|
570
|
+
label: b.provider,
|
|
571
|
+
authState: providerAuthStateById.get(b.provider) ?? "none",
|
|
572
|
+
},
|
|
573
|
+
);
|
|
549
574
|
if (providerCmp !== 0) return providerCmp;
|
|
550
575
|
|
|
551
576
|
// Priority field (lower = better, e.g. OpenAI code backend priority values)
|
|
@@ -587,6 +612,12 @@ export class ModelSelectorComponent extends Container {
|
|
|
587
612
|
#sortCanonicalModels(models: CanonicalModelItem[]): void {
|
|
588
613
|
const mruOrder = this.#settings.getStorage()?.getModelUsageOrder() ?? [];
|
|
589
614
|
const mruIndex = new Map(mruOrder.map((key, i) => [key, i]));
|
|
615
|
+
const providerAuthStateById = new Map<string, ProviderAuthState>();
|
|
616
|
+
for (const item of models) {
|
|
617
|
+
if (!providerAuthStateById.has(item.model.provider)) {
|
|
618
|
+
providerAuthStateById.set(item.model.provider, this.#resolveProviderAuthState(item.model.provider));
|
|
619
|
+
}
|
|
620
|
+
}
|
|
590
621
|
|
|
591
622
|
const modelRank = (item: CanonicalModelItem) => computeModelRank(item.model, this.#roles);
|
|
592
623
|
|
|
@@ -599,7 +630,18 @@ export class ModelSelectorComponent extends Container {
|
|
|
599
630
|
const bMru = mruIndex.get(`${b.model.provider}/${b.model.id}`) ?? Number.MAX_SAFE_INTEGER;
|
|
600
631
|
if (aMru !== bMru) return aMru - bMru;
|
|
601
632
|
|
|
602
|
-
const providerCmp =
|
|
633
|
+
const providerCmp = compareRankedProviders(
|
|
634
|
+
{
|
|
635
|
+
id: a.model.provider,
|
|
636
|
+
label: a.model.provider,
|
|
637
|
+
authState: providerAuthStateById.get(a.model.provider) ?? "none",
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
id: b.model.provider,
|
|
641
|
+
label: b.model.provider,
|
|
642
|
+
authState: providerAuthStateById.get(b.model.provider) ?? "none",
|
|
643
|
+
},
|
|
644
|
+
);
|
|
603
645
|
if (providerCmp !== 0) return providerCmp;
|
|
604
646
|
|
|
605
647
|
return a.id.localeCompare(b.id);
|
|
@@ -714,8 +756,23 @@ export class ModelSelectorComponent extends Container {
|
|
|
714
756
|
for (const provider of this.#modelRegistry.getDiscoverableProviders()) {
|
|
715
757
|
providerSet.add(provider);
|
|
716
758
|
}
|
|
759
|
+
const providerAuthStateById = new Map<string, ProviderAuthState>();
|
|
760
|
+
for (const provider of providerSet) {
|
|
761
|
+
providerAuthStateById.set(provider, this.#resolveProviderAuthState(provider));
|
|
762
|
+
}
|
|
717
763
|
const sortedProviderIds = Array.from(providerSet).sort((left, right) =>
|
|
718
|
-
|
|
764
|
+
compareRankedProviders(
|
|
765
|
+
{
|
|
766
|
+
id: left,
|
|
767
|
+
label: formatProviderTabLabel(left),
|
|
768
|
+
authState: providerAuthStateById.get(left) ?? "none",
|
|
769
|
+
},
|
|
770
|
+
{
|
|
771
|
+
id: right,
|
|
772
|
+
label: formatProviderTabLabel(right),
|
|
773
|
+
authState: providerAuthStateById.get(right) ?? "none",
|
|
774
|
+
},
|
|
775
|
+
),
|
|
719
776
|
);
|
|
720
777
|
this.#providers = [...STATIC_PROVIDER_TABS, ...sortedProviderIds.map(createProviderTab)];
|
|
721
778
|
const activeIndex = this.#providers.findIndex(tab => tab.id === activeTabId);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getOAuthProviders } from "@sayknow-cli/ai/utils/oauth";
|
|
2
2
|
import type { OAuthProviderInfo } from "@sayknow-cli/ai/utils/oauth/types";
|
|
3
3
|
import { Container, matchesKey, Spacer, TruncatedText } from "@sayknow-cli/tui";
|
|
4
|
+
import { recordProviderAuthHealth } from "../../config/provider-auth-health";
|
|
5
|
+
import { compareRankedProviders, type ProviderAuthState } from "../../config/provider-ranking";
|
|
4
6
|
import { theme } from "../../modes/theme/theme";
|
|
5
7
|
import { matchesSelectCancel } from "../../modes/utils/keybinding-matchers";
|
|
6
8
|
import type { AuthStorage } from "../../session/auth-storage";
|
|
@@ -14,6 +16,7 @@ const OAUTH_SELECTOR_MAX_VISIBLE = 10;
|
|
|
14
16
|
export class OAuthSelectorComponent extends Container {
|
|
15
17
|
#listContainer: Container;
|
|
16
18
|
#allProviders: OAuthProviderInfo[] = [];
|
|
19
|
+
#sortedProviders: OAuthProviderInfo[] = [];
|
|
17
20
|
#selectedIndex: number = 0;
|
|
18
21
|
#mode: "login" | "logout";
|
|
19
22
|
#authStorage: AuthStorage;
|
|
@@ -91,7 +94,7 @@ export class OAuthSelectorComponent extends Container {
|
|
|
91
94
|
}
|
|
92
95
|
this.#authState.set(provider.id, "checking");
|
|
93
96
|
pending += 1;
|
|
94
|
-
void this.#validateProvider(provider.id, generation);
|
|
97
|
+
void this.#validateProvider(provider.id, generation, this.#authStorage.getGeneration());
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
if (pending > 0) {
|
|
@@ -101,7 +104,7 @@ export class OAuthSelectorComponent extends Container {
|
|
|
101
104
|
}
|
|
102
105
|
}
|
|
103
106
|
|
|
104
|
-
async #validateProvider(providerId: string, generation: number): Promise<void> {
|
|
107
|
+
async #validateProvider(providerId: string, generation: number, authGeneration: number): Promise<void> {
|
|
105
108
|
if (!this.#validateAuthCallback) return;
|
|
106
109
|
let isValid = false;
|
|
107
110
|
try {
|
|
@@ -112,6 +115,11 @@ export class OAuthSelectorComponent extends Container {
|
|
|
112
115
|
|
|
113
116
|
if (generation !== this.#validationGeneration) return;
|
|
114
117
|
this.#authState.set(providerId, isValid ? "valid" : "invalid");
|
|
118
|
+
// Only record the ordering hint when the credentials validated are still the
|
|
119
|
+
// current ones; a result from a superseded generation must not describe them.
|
|
120
|
+
if (authGeneration === this.#authStorage.getGeneration()) {
|
|
121
|
+
recordProviderAuthHealth(this.#authStorage, providerId, isValid ? "valid" : "invalid");
|
|
122
|
+
}
|
|
115
123
|
if (![...this.#authState.values()].includes("checking")) {
|
|
116
124
|
this.#stopSpinner();
|
|
117
125
|
}
|
|
@@ -138,6 +146,10 @@ export class OAuthSelectorComponent extends Container {
|
|
|
138
146
|
}
|
|
139
147
|
}
|
|
140
148
|
|
|
149
|
+
#getProviderAuthState(providerId: string): ProviderAuthState {
|
|
150
|
+
return this.#authState.get(providerId) ?? "none";
|
|
151
|
+
}
|
|
152
|
+
|
|
141
153
|
#getStatusIndicator(providerId: string): string {
|
|
142
154
|
const state = this.#authState.get(providerId);
|
|
143
155
|
if (state === "checking") {
|
|
@@ -154,9 +166,25 @@ export class OAuthSelectorComponent extends Container {
|
|
|
154
166
|
return this.#authStorage.hasAuth(providerId) ? theme.fg("success", ` ${theme.status.success} logged in`) : "";
|
|
155
167
|
}
|
|
156
168
|
#updateList(): void {
|
|
169
|
+
const selectedProviderId = this.#sortedProviders[this.#selectedIndex]?.id;
|
|
170
|
+
const rankedProviders = this.#allProviders.map(provider => ({
|
|
171
|
+
provider,
|
|
172
|
+
id: provider.id,
|
|
173
|
+
label: provider.name,
|
|
174
|
+
authState: this.#getProviderAuthState(provider.id),
|
|
175
|
+
}));
|
|
176
|
+
rankedProviders.sort(compareRankedProviders);
|
|
177
|
+
this.#sortedProviders = rankedProviders.map(({ provider }) => provider);
|
|
178
|
+
if (selectedProviderId !== undefined) {
|
|
179
|
+
const selectedIndex = this.#sortedProviders.findIndex(provider => provider.id === selectedProviderId);
|
|
180
|
+
if (selectedIndex >= 0) this.#selectedIndex = selectedIndex;
|
|
181
|
+
}
|
|
182
|
+
if (this.#selectedIndex >= this.#sortedProviders.length) {
|
|
183
|
+
this.#selectedIndex = Math.max(0, this.#sortedProviders.length - 1);
|
|
184
|
+
}
|
|
157
185
|
this.#listContainer.clear();
|
|
158
186
|
|
|
159
|
-
const total = this.#
|
|
187
|
+
const total = this.#sortedProviders.length;
|
|
160
188
|
const maxVisible = OAUTH_SELECTOR_MAX_VISIBLE;
|
|
161
189
|
const startIndex =
|
|
162
190
|
total <= maxVisible
|
|
@@ -165,7 +193,7 @@ export class OAuthSelectorComponent extends Container {
|
|
|
165
193
|
const endIndex = Math.min(startIndex + maxVisible, total);
|
|
166
194
|
|
|
167
195
|
for (let i = startIndex; i < endIndex; i++) {
|
|
168
|
-
const provider = this.#
|
|
196
|
+
const provider = this.#sortedProviders[i];
|
|
169
197
|
if (!provider) continue;
|
|
170
198
|
const isSelected = i === this.#selectedIndex;
|
|
171
199
|
const isAvailable = provider.available;
|
|
@@ -218,23 +246,25 @@ export class OAuthSelectorComponent extends Container {
|
|
|
218
246
|
handleInput(keyData: string): void {
|
|
219
247
|
// Up arrow
|
|
220
248
|
if (matchesKey(keyData, "up")) {
|
|
221
|
-
if (this.#
|
|
222
|
-
this.#selectedIndex =
|
|
249
|
+
if (this.#sortedProviders.length > 0) {
|
|
250
|
+
this.#selectedIndex =
|
|
251
|
+
this.#selectedIndex === 0 ? this.#sortedProviders.length - 1 : this.#selectedIndex - 1;
|
|
223
252
|
}
|
|
224
253
|
this.#statusMessage = undefined;
|
|
225
254
|
this.#updateList();
|
|
226
255
|
}
|
|
227
256
|
// Down arrow
|
|
228
257
|
else if (matchesKey(keyData, "down")) {
|
|
229
|
-
if (this.#
|
|
230
|
-
this.#selectedIndex =
|
|
258
|
+
if (this.#sortedProviders.length > 0) {
|
|
259
|
+
this.#selectedIndex =
|
|
260
|
+
this.#selectedIndex === this.#sortedProviders.length - 1 ? 0 : this.#selectedIndex + 1;
|
|
231
261
|
}
|
|
232
262
|
this.#statusMessage = undefined;
|
|
233
263
|
this.#updateList();
|
|
234
264
|
}
|
|
235
265
|
// Page up - jump up by one visible page
|
|
236
266
|
else if (matchesKey(keyData, "pageUp")) {
|
|
237
|
-
if (this.#
|
|
267
|
+
if (this.#sortedProviders.length > 0) {
|
|
238
268
|
this.#selectedIndex = Math.max(0, this.#selectedIndex - OAUTH_SELECTOR_MAX_VISIBLE);
|
|
239
269
|
}
|
|
240
270
|
this.#statusMessage = undefined;
|
|
@@ -242,9 +272,9 @@ export class OAuthSelectorComponent extends Container {
|
|
|
242
272
|
}
|
|
243
273
|
// Page down - jump down by one visible page
|
|
244
274
|
else if (matchesKey(keyData, "pageDown")) {
|
|
245
|
-
if (this.#
|
|
275
|
+
if (this.#sortedProviders.length > 0) {
|
|
246
276
|
this.#selectedIndex = Math.min(
|
|
247
|
-
this.#
|
|
277
|
+
this.#sortedProviders.length - 1,
|
|
248
278
|
this.#selectedIndex + OAUTH_SELECTOR_MAX_VISIBLE,
|
|
249
279
|
);
|
|
250
280
|
}
|
|
@@ -253,7 +283,7 @@ export class OAuthSelectorComponent extends Container {
|
|
|
253
283
|
}
|
|
254
284
|
// Enter
|
|
255
285
|
else if (matchesKey(keyData, "enter") || matchesKey(keyData, "return") || keyData === "\n") {
|
|
256
|
-
const selectedProvider = this.#
|
|
286
|
+
const selectedProvider = this.#sortedProviders[this.#selectedIndex];
|
|
257
287
|
if (selectedProvider?.available) {
|
|
258
288
|
this.#statusMessage = undefined;
|
|
259
289
|
this.stopValidation();
|
|
@@ -122,7 +122,7 @@ export class PlanPreviewOverlay extends Container {
|
|
|
122
122
|
? `${this.#inputKind === "notes" ? "Notes" : `Comment for source line ${this.#sourceLine}`} (Enter save, Esc cancel): ${this.#input.getValue()}`
|
|
123
123
|
: this.#focus === "sourceSelect"
|
|
124
124
|
? `Source line ${this.#sourceLine}/${this.lines.length || 1} j/k:select c:comment Esc:done`
|
|
125
|
-
: `${this.#scroll + 1}-${Math.min(this.#scroll + height, body.length)}/${body.length || 1} s:source line n:notes ${this.options.externalEditorKey ? `${this.options.externalEditorKey
|
|
125
|
+
: `${this.#scroll + 1}-${Math.min(this.#scroll + height, body.length)}/${body.length || 1} s:source line n:notes ${this.options.externalEditorKey ? `${this.options.externalEditorKey}:edit ` : ""}Tab:actions PgUp/PgDn:page`;
|
|
126
126
|
|
|
127
127
|
const rendered = [
|
|
128
128
|
new DynamicBorder().render(width)[0] ?? "",
|