@sayknow-cli/coding-agent 0.4.6 → 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 +112 -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 +27 -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
|
@@ -28,12 +28,36 @@ export type PublicUrlResult = PublicUrlAccepted | PublicUrlRejected;
|
|
|
28
28
|
/** Resolver seam so tests can inject DNS results without real lookups. */
|
|
29
29
|
export type AddressResolver = (hostname: string) => Promise<string[]>;
|
|
30
30
|
|
|
31
|
+
type ProxyEnvironment = Record<string, string | undefined>;
|
|
32
|
+
|
|
33
|
+
export type GuardedPublicFetchResult =
|
|
34
|
+
| { ok: true; response: Response; logicalUrl: URL; wireUrl: URL }
|
|
35
|
+
| { ok: false; reason: string; logicalUrl: string };
|
|
36
|
+
|
|
31
37
|
const defaultResolver: AddressResolver = async hostname => {
|
|
32
38
|
const records = await dns.lookup(hostname, { all: true, verbatim: true });
|
|
33
39
|
return records.map(record => record.address);
|
|
34
40
|
};
|
|
35
41
|
|
|
36
42
|
const BLOCKED_HOSTNAMES = new Set(["localhost", "localhost.localdomain", "0.0.0.0", ""]);
|
|
43
|
+
const PROXY_ENV_KEYS = ["HTTP_PROXY", "http_proxy", "HTTPS_PROXY", "https_proxy", "ALL_PROXY", "all_proxy"] as const;
|
|
44
|
+
|
|
45
|
+
export function hasConfiguredProxy(env: ProxyEnvironment): boolean {
|
|
46
|
+
return PROXY_ENV_KEYS.some(key => Boolean(env[key]));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function resolveWithSignal(resolver: AddressResolver, hostname: string, signal?: AbortSignal): Promise<string[]> {
|
|
50
|
+
if (!signal) return resolver(hostname);
|
|
51
|
+
if (signal.aborted) throw signal.reason;
|
|
52
|
+
const { promise, reject } = Promise.withResolvers<never>();
|
|
53
|
+
const onAbort = () => reject(signal.reason);
|
|
54
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
55
|
+
try {
|
|
56
|
+
return await Promise.race([resolver(hostname), promise]);
|
|
57
|
+
} finally {
|
|
58
|
+
signal.removeEventListener("abort", onAbort);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
37
61
|
|
|
38
62
|
function isBlockedHostname(hostname: string): boolean {
|
|
39
63
|
const normalized = hostname.toLowerCase().replace(/\.$/, "");
|
|
@@ -67,37 +91,81 @@ function isPrivateIPv4(address: string): boolean {
|
|
|
67
91
|
);
|
|
68
92
|
}
|
|
69
93
|
|
|
70
|
-
function
|
|
71
|
-
|
|
94
|
+
function parseIPv6Bytes(address: string): Uint8Array | undefined {
|
|
95
|
+
let normalized = address.toLowerCase();
|
|
96
|
+
const ipv4Tail = normalized.slice(normalized.lastIndexOf(":") + 1);
|
|
97
|
+
if (ipv4Tail.includes(".")) {
|
|
98
|
+
const parts = ipv4Tail.split(".").map(part => Number.parseInt(part, 10));
|
|
99
|
+
if (parts.length !== 4 || parts.some(part => !Number.isInteger(part) || part < 0 || part > 255)) return;
|
|
100
|
+
normalized = `${normalized.slice(0, normalized.lastIndexOf(":") + 1)}${((parts[0] << 8) | parts[1]).toString(16)}:${((parts[2] << 8) | parts[3]).toString(16)}`;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const halves = normalized.split("::");
|
|
104
|
+
if (halves.length > 2) return;
|
|
105
|
+
const left = halves[0] ? halves[0].split(":") : [];
|
|
106
|
+
const right = halves[1] ? halves[1].split(":") : [];
|
|
107
|
+
const omitted = 8 - left.length - right.length;
|
|
108
|
+
if ((halves.length === 1 && omitted !== 0) || (halves.length === 2 && omitted < 1)) return;
|
|
109
|
+
const words = [...left, ...Array.from({ length: omitted }, () => "0"), ...right];
|
|
110
|
+
if (words.length !== 8 || words.some(word => !/^[0-9a-f]{1,4}$/.test(word))) return;
|
|
111
|
+
|
|
112
|
+
const bytes = new Uint8Array(16);
|
|
113
|
+
for (let index = 0; index < words.length; index++) {
|
|
114
|
+
const word = Number.parseInt(words[index], 16);
|
|
115
|
+
bytes[index * 2] = word >> 8;
|
|
116
|
+
bytes[index * 2 + 1] = word & 0xff;
|
|
117
|
+
}
|
|
118
|
+
return bytes;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
interface IPv6Cidr {
|
|
122
|
+
network: Uint8Array;
|
|
123
|
+
prefixLength: number;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function ipv6Cidr(network: string, prefixLength: number): IPv6Cidr {
|
|
127
|
+
const bytes = parseIPv6Bytes(network);
|
|
128
|
+
if (!bytes) throw new Error(`Invalid static IPv6 CIDR: ${network}/${prefixLength}`);
|
|
129
|
+
return { network: bytes, prefixLength };
|
|
72
130
|
}
|
|
73
131
|
|
|
132
|
+
function matchesIPv6Cidr(address: Uint8Array, cidr: IPv6Cidr): boolean {
|
|
133
|
+
const wholeBytes = Math.floor(cidr.prefixLength / 8);
|
|
134
|
+
for (let index = 0; index < wholeBytes; index++) {
|
|
135
|
+
if (address[index] !== cidr.network[index]) return false;
|
|
136
|
+
}
|
|
137
|
+
const remainingBits = cidr.prefixLength % 8;
|
|
138
|
+
if (remainingBits === 0) return true;
|
|
139
|
+
const mask = (0xff << (8 - remainingBits)) & 0xff;
|
|
140
|
+
return (address[wholeBytes] & mask) === (cidr.network[wholeBytes] & mask);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const IPV6_GLOBAL_UNICAST = ipv6Cidr("2000::", 3);
|
|
144
|
+
const BLOCKED_GLOBAL_IPV6_RANGES = [
|
|
145
|
+
ipv6Cidr("2001::", 23), // IETF protocol assignments
|
|
146
|
+
ipv6Cidr("2001:db8::", 32), // documentation
|
|
147
|
+
ipv6Cidr("2002::", 16), // 6to4
|
|
148
|
+
ipv6Cidr("2620:4f:8000::", 48), // AS112 service
|
|
149
|
+
ipv6Cidr("3ffe::", 16), // returned 6bone range
|
|
150
|
+
ipv6Cidr("3fff::", 20), // documentation
|
|
151
|
+
] as const;
|
|
152
|
+
|
|
74
153
|
function isPrivateIPv6(address: string): boolean {
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
154
|
+
const bytes = parseIPv6Bytes(address);
|
|
155
|
+
if (!bytes) return true;
|
|
156
|
+
const isIPv4Mapped = bytes.subarray(0, 10).every(byte => byte === 0) && bytes[10] === 0xff && bytes[11] === 0xff;
|
|
157
|
+
if (isIPv4Mapped) return isPrivateIPv4(`${bytes[12]}.${bytes[13]}.${bytes[14]}.${bytes[15]}`);
|
|
78
158
|
return (
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
normalized.startsWith("fc") || // ULA fc00::/7
|
|
82
|
-
normalized.startsWith("fd") || // ULA
|
|
83
|
-
normalized.startsWith("fe8") || // link-local fe80::/10
|
|
84
|
-
normalized.startsWith("fe9") ||
|
|
85
|
-
normalized.startsWith("fea") ||
|
|
86
|
-
normalized.startsWith("feb") ||
|
|
87
|
-
normalized.startsWith("ff") || // multicast ff00::/8
|
|
88
|
-
normalized.startsWith("2001:db8") || // documentation
|
|
89
|
-
normalized.startsWith("::ffff:") // any remaining IPv4-mapped form we could not classify
|
|
159
|
+
!matchesIPv6Cidr(bytes, IPV6_GLOBAL_UNICAST) ||
|
|
160
|
+
BLOCKED_GLOBAL_IPV6_RANGES.some(cidr => matchesIPv6Cidr(bytes, cidr))
|
|
90
161
|
);
|
|
91
162
|
}
|
|
92
163
|
|
|
93
164
|
/** True for any address that is not a routable public unicast address. */
|
|
94
165
|
export function isPrivateOrSpecialAddress(address: string): boolean {
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
if (family ===
|
|
98
|
-
if (family === 6) return isPrivateIPv6(normalized);
|
|
99
|
-
// Re-check the raw value in case it was an IPv4-mapped IPv6 literal.
|
|
100
|
-
if (net.isIP(address) === 6) return isPrivateIPv6(address);
|
|
166
|
+
const family = net.isIP(address);
|
|
167
|
+
if (family === 4) return isPrivateIPv4(address);
|
|
168
|
+
if (family === 6) return isPrivateIPv6(address);
|
|
101
169
|
return true; // not a recognizable IP -> treat as unsafe
|
|
102
170
|
}
|
|
103
171
|
|
|
@@ -108,7 +176,7 @@ export function isPrivateOrSpecialAddress(address: string): boolean {
|
|
|
108
176
|
*/
|
|
109
177
|
export async function validatePublicHttpUrl(
|
|
110
178
|
rawUrl: string,
|
|
111
|
-
options: { resolver?: AddressResolver } = {},
|
|
179
|
+
options: { resolver?: AddressResolver; signal?: AbortSignal } = {},
|
|
112
180
|
): Promise<PublicUrlResult> {
|
|
113
181
|
const resolver = options.resolver ?? defaultResolver;
|
|
114
182
|
|
|
@@ -128,18 +196,20 @@ export async function validatePublicHttpUrl(
|
|
|
128
196
|
return { ok: false, reason: "localhost or internal host" };
|
|
129
197
|
}
|
|
130
198
|
|
|
131
|
-
const
|
|
199
|
+
const hostname = url.hostname.replace(/^\[|\]$/g, "");
|
|
200
|
+
const literalFamily = net.isIP(hostname);
|
|
132
201
|
if (literalFamily !== 0) {
|
|
133
|
-
if (isPrivateOrSpecialAddress(
|
|
202
|
+
if (isPrivateOrSpecialAddress(hostname)) {
|
|
134
203
|
return { ok: false, reason: "private, loopback, link-local, or reserved IP literal" };
|
|
135
204
|
}
|
|
136
|
-
return { ok: true, url, addresses: [
|
|
205
|
+
return { ok: true, url, addresses: [hostname] };
|
|
137
206
|
}
|
|
138
207
|
|
|
139
208
|
let addresses: string[];
|
|
140
209
|
try {
|
|
141
|
-
addresses = await resolver
|
|
210
|
+
addresses = await resolveWithSignal(resolver, hostname, options.signal);
|
|
142
211
|
} catch {
|
|
212
|
+
if (options.signal?.aborted) return { ok: false, reason: "host resolution aborted" };
|
|
143
213
|
return { ok: false, reason: "host could not be resolved" };
|
|
144
214
|
}
|
|
145
215
|
if (addresses.length === 0) {
|
|
@@ -151,6 +221,49 @@ export async function validatePublicHttpUrl(
|
|
|
151
221
|
return { ok: true, url, addresses };
|
|
152
222
|
}
|
|
153
223
|
|
|
224
|
+
export async function guardedPublicFetch(
|
|
225
|
+
rawUrl: string,
|
|
226
|
+
init: BunFetchRequestInit = {},
|
|
227
|
+
options: { resolver?: AddressResolver } = {},
|
|
228
|
+
): Promise<GuardedPublicFetchResult> {
|
|
229
|
+
if (Object.hasOwn(init, "proxy") || Object.hasOwn(init, "unix") || hasConfiguredProxy(process.env)) {
|
|
230
|
+
return { ok: false, reason: "proxy or Unix-socket routing is not allowed", logicalUrl: rawUrl };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const signal = init.signal ?? undefined;
|
|
234
|
+
const guard = await validatePublicHttpUrl(rawUrl, { resolver: options.resolver, signal });
|
|
235
|
+
if (signal?.aborted) throw signal.reason;
|
|
236
|
+
if (!guard.ok) return { ok: false, reason: guard.reason, logicalUrl: rawUrl };
|
|
237
|
+
|
|
238
|
+
const logicalUrl = guard.url;
|
|
239
|
+
const headers = new Headers(init.headers);
|
|
240
|
+
headers.delete("host");
|
|
241
|
+
headers.set("Host", logicalUrl.host);
|
|
242
|
+
const hostname = logicalUrl.hostname.replace(/^\[|\]$/g, "");
|
|
243
|
+
const tls =
|
|
244
|
+
logicalUrl.protocol === "https:"
|
|
245
|
+
? { rejectUnauthorized: true, ...(net.isIP(hostname) === 0 ? { serverName: hostname } : {}) }
|
|
246
|
+
: undefined;
|
|
247
|
+
const method = (init.method ?? "GET").toUpperCase();
|
|
248
|
+
const addresses = method === "GET" || method === "HEAD" ? guard.addresses : guard.addresses.slice(0, 1);
|
|
249
|
+
let lastError: unknown;
|
|
250
|
+
for (const address of addresses) {
|
|
251
|
+
if (hasConfiguredProxy(process.env)) {
|
|
252
|
+
return { ok: false, reason: "proxy routing appeared during resolution", logicalUrl: rawUrl };
|
|
253
|
+
}
|
|
254
|
+
const wireUrl = new URL(logicalUrl);
|
|
255
|
+
wireUrl.hostname = net.isIP(address) === 6 ? `[${address}]` : address;
|
|
256
|
+
try {
|
|
257
|
+
const response = await fetch(wireUrl, { ...init, headers, redirect: "manual", keepalive: false, tls });
|
|
258
|
+
return { ok: true, response, logicalUrl, wireUrl };
|
|
259
|
+
} catch (error) {
|
|
260
|
+
if (signal?.aborted) throw signal.reason;
|
|
261
|
+
lastError = error;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
throw lastError;
|
|
265
|
+
}
|
|
266
|
+
|
|
154
267
|
export async function validatePublicHttpUrlForInsane(
|
|
155
268
|
rawUrl: string,
|
|
156
269
|
options: { resolver?: AddressResolver } = {},
|
|
@@ -299,7 +299,21 @@ async function readCachedRustdocCrate(
|
|
|
299
299
|
): Promise<{ crate: RustdocCrate; fetchedAt: string } | null> {
|
|
300
300
|
const cachePath = getDocsRsCachePath(target);
|
|
301
301
|
try {
|
|
302
|
-
const
|
|
302
|
+
const stat = await fs.stat(cachePath);
|
|
303
|
+
if (stat.size > MAX_BYTES) {
|
|
304
|
+
await fs.rm(cachePath, { force: true });
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const cacheBytes = await Bun.file(cachePath)
|
|
309
|
+
.slice(0, MAX_BYTES + 1)
|
|
310
|
+
.arrayBuffer();
|
|
311
|
+
if (cacheBytes.byteLength > MAX_BYTES) {
|
|
312
|
+
await fs.rm(cachePath, { force: true });
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const jsonStr = Buffer.from(cacheBytes).toString("utf-8");
|
|
303
317
|
const crate = tryParseJson<RustdocCrate>(jsonStr);
|
|
304
318
|
if (!crate?.index) return null;
|
|
305
319
|
return { crate, fetchedAt: stat.mtime.toISOString() };
|
|
@@ -378,11 +392,22 @@ export const handleDocsRs: SpecialHandler = async (
|
|
|
378
392
|
const requestSignal = ptree.combineSignals(signal, timeout * 1000);
|
|
379
393
|
const response = await fetch(jsonUrl, {
|
|
380
394
|
signal: requestSignal,
|
|
381
|
-
headers: {
|
|
395
|
+
headers: {
|
|
396
|
+
"User-Agent": "skc-web-fetch/1.0",
|
|
397
|
+
Accept: "application/gzip",
|
|
398
|
+
"Accept-Encoding": "identity",
|
|
399
|
+
},
|
|
382
400
|
redirect: "follow",
|
|
401
|
+
decompress: false,
|
|
383
402
|
});
|
|
384
403
|
if (!response.ok) return null;
|
|
385
404
|
|
|
405
|
+
const contentEncoding = response.headers.get("Content-Encoding");
|
|
406
|
+
if (contentEncoding && contentEncoding.trim().toLowerCase() !== "identity") {
|
|
407
|
+
await response.body?.cancel();
|
|
408
|
+
return null;
|
|
409
|
+
}
|
|
410
|
+
|
|
386
411
|
const reader = response.body?.getReader();
|
|
387
412
|
if (!reader) return null;
|
|
388
413
|
|
|
@@ -394,13 +419,13 @@ export const handleDocsRs: SpecialHandler = async (
|
|
|
394
419
|
chunks.push(value);
|
|
395
420
|
totalSize += value.length;
|
|
396
421
|
if (totalSize > MAX_BYTES) {
|
|
397
|
-
reader.cancel();
|
|
398
|
-
|
|
422
|
+
await reader.cancel();
|
|
423
|
+
return null;
|
|
399
424
|
}
|
|
400
425
|
}
|
|
401
426
|
|
|
402
427
|
const compressed = Buffer.concat(chunks);
|
|
403
|
-
const jsonStr = gunzipSync(compressed).toString("utf-8");
|
|
428
|
+
const jsonStr = gunzipSync(compressed, { maxOutputLength: MAX_BYTES }).toString("utf-8");
|
|
404
429
|
crate_ = tryParseJson<RustdocCrate>(jsonStr);
|
|
405
430
|
if (crate_?.index) {
|
|
406
431
|
await writeCachedRustdocCrate(target, jsonStr);
|
|
@@ -5,7 +5,7 @@ import { ptree } from "@sayknow-cli/utils";
|
|
|
5
5
|
import type { AgentStorage } from "../../session/agent-storage";
|
|
6
6
|
import { ToolAbortError } from "../../tools/tool-errors";
|
|
7
7
|
import type { AddressResolver } from "../insane/url-guard";
|
|
8
|
-
import {
|
|
8
|
+
import { guardedPublicFetch } from "../insane/url-guard";
|
|
9
9
|
|
|
10
10
|
export { formatNumber } from "@sayknow-cli/utils";
|
|
11
11
|
|
|
@@ -85,20 +85,6 @@ export interface LoadPageResult {
|
|
|
85
85
|
error?: string;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
async function guardPublicFetchUrl(
|
|
89
|
-
rawUrl: string,
|
|
90
|
-
resolver: AddressResolver | undefined,
|
|
91
|
-
context: string,
|
|
92
|
-
): Promise<{ ok: true; url: string } | { ok: false; error: string; finalUrl: string }> {
|
|
93
|
-
const guard = await validatePublicHttpUrl(rawUrl, { resolver });
|
|
94
|
-
if (guard.ok) return { ok: true, url: guard.url.toString() };
|
|
95
|
-
return {
|
|
96
|
-
ok: false,
|
|
97
|
-
error: `${context}: target URL is not public HTTP(S): ${guard.reason}`,
|
|
98
|
-
finalUrl: rawUrl,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
88
|
function shouldRewriteRedirectMethod(status: number, method: string): boolean {
|
|
103
89
|
const normalized = method.toUpperCase();
|
|
104
90
|
return status === 303 || ((status === 301 || status === 302) && normalized === "POST");
|
|
@@ -120,20 +106,7 @@ export async function loadPage(url: string, options: LoadPageOptions = {}): Prom
|
|
|
120
106
|
maxRedirects = 10,
|
|
121
107
|
} = options;
|
|
122
108
|
|
|
123
|
-
|
|
124
|
-
if (publicUrlGuard) {
|
|
125
|
-
const guarded = await guardPublicFetchUrl(url, resolver, "Blocked URL fetch");
|
|
126
|
-
if (!guarded.ok) {
|
|
127
|
-
return {
|
|
128
|
-
content: "",
|
|
129
|
-
contentType: "",
|
|
130
|
-
finalUrl: guarded.finalUrl,
|
|
131
|
-
ok: false,
|
|
132
|
-
error: guarded.error,
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
initialUrl = guarded.url;
|
|
136
|
-
}
|
|
109
|
+
const initialUrl = url;
|
|
137
110
|
|
|
138
111
|
attempts: for (let attempt = 0; attempt < USER_AGENTS.length; attempt++) {
|
|
139
112
|
if (signal?.aborted) {
|
|
@@ -165,36 +138,33 @@ export async function loadPage(url: string, options: LoadPageOptions = {}): Prom
|
|
|
165
138
|
requestInit.body = currentBody;
|
|
166
139
|
}
|
|
167
140
|
|
|
168
|
-
const
|
|
141
|
+
const dial = publicUrlGuard
|
|
142
|
+
? await guardedPublicFetch(currentUrl, requestInit, { resolver })
|
|
143
|
+
: { ok: true as const, response: await fetch(currentUrl, requestInit), logicalUrl: new URL(currentUrl) };
|
|
144
|
+
if (!dial.ok) {
|
|
145
|
+
return {
|
|
146
|
+
content: "",
|
|
147
|
+
contentType: "",
|
|
148
|
+
finalUrl: dial.logicalUrl,
|
|
149
|
+
ok: false,
|
|
150
|
+
error: `Blocked URL fetch: target URL is not public HTTP(S): ${dial.reason}`,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const { response } = dial;
|
|
154
|
+
const logicalUrl = dial.logicalUrl.toString();
|
|
169
155
|
if (REDIRECT_STATUSES.has(response.status)) {
|
|
170
156
|
const location = response.headers.get("location");
|
|
171
157
|
if (!location) {
|
|
172
158
|
return {
|
|
173
159
|
content: "",
|
|
174
160
|
contentType: "",
|
|
175
|
-
finalUrl:
|
|
161
|
+
finalUrl: logicalUrl,
|
|
176
162
|
ok: false,
|
|
177
163
|
status: response.status,
|
|
178
164
|
error: "Redirect response missing Location header",
|
|
179
165
|
};
|
|
180
166
|
}
|
|
181
|
-
|
|
182
|
-
if (publicUrlGuard) {
|
|
183
|
-
const guarded = await guardPublicFetchUrl(redirectUrl, resolver, "Blocked URL redirect");
|
|
184
|
-
if (!guarded.ok) {
|
|
185
|
-
return {
|
|
186
|
-
content: "",
|
|
187
|
-
contentType: "",
|
|
188
|
-
finalUrl: guarded.finalUrl,
|
|
189
|
-
ok: false,
|
|
190
|
-
status: response.status,
|
|
191
|
-
error: guarded.error,
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
currentUrl = guarded.url;
|
|
195
|
-
} else {
|
|
196
|
-
currentUrl = redirectUrl;
|
|
197
|
-
}
|
|
167
|
+
currentUrl = new URL(location, logicalUrl).toString();
|
|
198
168
|
if (shouldRewriteRedirectMethod(response.status, currentMethod)) {
|
|
199
169
|
currentMethod = "GET";
|
|
200
170
|
currentBody = undefined;
|
|
@@ -203,7 +173,7 @@ export async function loadPage(url: string, options: LoadPageOptions = {}): Prom
|
|
|
203
173
|
}
|
|
204
174
|
|
|
205
175
|
const contentType = response.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
206
|
-
const finalUrl =
|
|
176
|
+
const finalUrl = logicalUrl;
|
|
207
177
|
|
|
208
178
|
const reader = response.body?.getReader();
|
|
209
179
|
if (!reader) {
|
|
@@ -5,7 +5,7 @@ export { isRecord };
|
|
|
5
5
|
import { ToolAbortError } from "../../tools/tool-errors";
|
|
6
6
|
import { convertBufferWithMarkit } from "../../utils/markit";
|
|
7
7
|
import type { AddressResolver } from "../insane/url-guard";
|
|
8
|
-
import {
|
|
8
|
+
import { guardedPublicFetch } from "../insane/url-guard";
|
|
9
9
|
import { MAX_BYTES } from "./types";
|
|
10
10
|
|
|
11
11
|
export function asRecord(value: unknown): Record<string, unknown> | null {
|
|
@@ -70,16 +70,6 @@ async function readResponseWithLimit(response: Response, maxBytes: number, signa
|
|
|
70
70
|
return new Uint8Array(Buffer.concat(chunks, totalBytes));
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
async function guardPublicBinaryUrl(
|
|
74
|
-
rawUrl: string,
|
|
75
|
-
resolver: AddressResolver | undefined,
|
|
76
|
-
context: string,
|
|
77
|
-
): Promise<{ ok: true; url: string } | { ok: false; error: string }> {
|
|
78
|
-
const guard = await validatePublicHttpUrl(rawUrl, { resolver });
|
|
79
|
-
if (guard.ok) return { ok: true, url: guard.url.toString() };
|
|
80
|
-
return { ok: false, error: `${context}: target URL is not public HTTP(S): ${guard.reason}` };
|
|
81
|
-
}
|
|
82
|
-
|
|
83
73
|
/**
|
|
84
74
|
* Fetch binary content from a URL
|
|
85
75
|
*/
|
|
@@ -93,32 +83,28 @@ export async function fetchBinary(
|
|
|
93
83
|
const { publicUrlGuard = true, resolver, maxRedirects = 10 } = options;
|
|
94
84
|
try {
|
|
95
85
|
let currentUrl = url;
|
|
96
|
-
if (publicUrlGuard) {
|
|
97
|
-
const guarded = await guardPublicBinaryUrl(url, resolver, "Blocked binary fetch");
|
|
98
|
-
if (!guarded.ok) return { ok: false, error: guarded.error };
|
|
99
|
-
currentUrl = guarded.url;
|
|
100
|
-
}
|
|
101
86
|
|
|
102
87
|
for (let redirectCount = 0; redirectCount <= maxRedirects; redirectCount++) {
|
|
103
|
-
const
|
|
88
|
+
const requestInit: BunFetchRequestInit = {
|
|
104
89
|
signal: requestSignal,
|
|
105
90
|
headers: {
|
|
106
91
|
"User-Agent": "Mozilla/5.0 (compatible; TextBot/1.0)",
|
|
107
92
|
},
|
|
108
93
|
redirect: "manual",
|
|
109
|
-
}
|
|
94
|
+
};
|
|
95
|
+
const dial = publicUrlGuard
|
|
96
|
+
? await guardedPublicFetch(currentUrl, requestInit, { resolver })
|
|
97
|
+
: { ok: true as const, response: await fetch(currentUrl, requestInit), logicalUrl: new URL(currentUrl) };
|
|
98
|
+
if (!dial.ok) {
|
|
99
|
+
return { ok: false, error: `Blocked binary fetch: target URL is not public HTTP(S): ${dial.reason}` };
|
|
100
|
+
}
|
|
101
|
+
const { response } = dial;
|
|
102
|
+
const logicalUrl = dial.logicalUrl.toString();
|
|
110
103
|
|
|
111
104
|
if (REDIRECT_STATUSES.has(response.status)) {
|
|
112
105
|
const location = response.headers.get("location");
|
|
113
106
|
if (!location) return { ok: false, error: "Redirect response missing Location header" };
|
|
114
|
-
|
|
115
|
-
if (publicUrlGuard) {
|
|
116
|
-
const guarded = await guardPublicBinaryUrl(redirectUrl, resolver, "Blocked binary redirect");
|
|
117
|
-
if (!guarded.ok) return { ok: false, error: guarded.error };
|
|
118
|
-
currentUrl = guarded.url;
|
|
119
|
-
} else {
|
|
120
|
-
currentUrl = redirectUrl;
|
|
121
|
-
}
|
|
107
|
+
currentUrl = new URL(location, logicalUrl).toString();
|
|
122
108
|
continue;
|
|
123
109
|
}
|
|
124
110
|
|
|
@@ -36,7 +36,7 @@ const DEFAULT_INSTRUCTIONS =
|
|
|
36
36
|
"You are a helpful assistant with web search capabilities. Search the web to answer the user's question accurately and cite your sources.";
|
|
37
37
|
|
|
38
38
|
function getConfiguredModel(): string | undefined {
|
|
39
|
-
const configuredModel = $env.PI_CODEX_WEB_SEARCH_MODEL?.trim();
|
|
39
|
+
const configuredModel = ($env.SKC_OPENAI_CODE_WEB_SEARCH_MODEL ?? $env.PI_CODEX_WEB_SEARCH_MODEL)?.trim();
|
|
40
40
|
return configuredModel ? configuredModel : undefined;
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -40,7 +40,10 @@ interface RouteMatch {
|
|
|
40
40
|
const PROMPT_PREVIEW_LIMIT = 240;
|
|
41
41
|
|
|
42
42
|
const DURABLE_TRACKING_PATTERNS = [
|
|
43
|
-
|
|
43
|
+
/^\s*\/skill:ultragoal\b/i,
|
|
44
|
+
/\b(?:use|run|start|create|activate|invoke|execute)\s+(?:the\s+)?ultragoal\b/i,
|
|
45
|
+
/\bultragoal(?:로|으로)[^.!?\n]{0,40}(?:해|진행|실행|관리|처리)/i,
|
|
46
|
+
/\bultragoal(?:을|를)\s+(?:(?:사용|실행|시작|활성화|호출|진행|관리|처리)(?:해줘|해주세요|하세요)|(?:써|쓰)(?:줘|주세요|세요)|해줘|해주세요|하세요)/i,
|
|
44
47
|
/\bdurable (?:goal|tracking|ledger|plan)\b/i,
|
|
45
48
|
/\b(?:goal|tracking|plan) ledger\b/i,
|
|
46
49
|
/\bcheckpoint(?:ed|ing)? (?:goal|plan|workflow|release|work)\b/i,
|