@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.
Files changed (428) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/dist/types/capability/index.d.ts +10 -20
  3. package/dist/types/capability/types.d.ts +3 -0
  4. package/dist/types/cli/args.d.ts +0 -2
  5. package/dist/types/cli/read-cli.d.ts +1 -0
  6. package/dist/types/cli.d.ts +9 -1
  7. package/dist/types/commands/daemon.d.ts +2 -2
  8. package/dist/types/commands/deep-interview.d.ts +9 -0
  9. package/dist/types/commands/harness.d.ts +22 -0
  10. package/dist/types/commands/read.d.ts +6 -0
  11. package/dist/types/commands/sdk.d.ts +20 -2
  12. package/dist/types/config/keybindings.d.ts +34 -4
  13. package/dist/types/config/model-profile-contract.d.ts +40 -0
  14. package/dist/types/config/model-profiles.d.ts +2 -3
  15. package/dist/types/config/model-registry.d.ts +5 -0
  16. package/dist/types/config/provider-auth-health.d.ts +14 -0
  17. package/dist/types/config/provider-ranking.d.ts +59 -0
  18. package/dist/types/config/settings-schema.d.ts +156 -10
  19. package/dist/types/config/settings.d.ts +3 -0
  20. package/dist/types/edit/modes/patch.d.ts +13 -0
  21. package/dist/types/edit/path-mutation-lock.d.ts +15 -0
  22. package/dist/types/eval/py/executor.d.ts +1 -1
  23. package/dist/types/eval/py/runner-artifact.d.ts +8 -0
  24. package/dist/types/eval/py/tool-bridge.d.ts +1 -2
  25. package/dist/types/extensibility/extensions/types.d.ts +43 -2
  26. package/dist/types/extensibility/shared-events.d.ts +6 -0
  27. package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
  28. package/dist/types/main.d.ts +33 -2
  29. package/dist/types/memories/index.d.ts +2 -0
  30. package/dist/types/modes/acp/acp-agent.d.ts +22 -9
  31. package/dist/types/modes/components/assistant-message.d.ts +3 -1
  32. package/dist/types/modes/components/btw-panel.d.ts +1 -0
  33. package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
  34. package/dist/types/modes/components/queue-pane.d.ts +8 -0
  35. package/dist/types/modes/components/queued-message-selector.d.ts +6 -0
  36. package/dist/types/modes/components/read-tool-group.d.ts +4 -4
  37. package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +2 -1
  38. package/dist/types/modes/components/session-observer-overlay.d.ts +4 -0
  39. package/dist/types/modes/components/settings-selector.d.ts +2 -0
  40. package/dist/types/modes/components/tool-execution.d.ts +8 -0
  41. package/dist/types/modes/components/tool-status-header.d.ts +4 -2
  42. package/dist/types/modes/components/welcome.d.ts +5 -0
  43. package/dist/types/modes/controllers/btw-controller.d.ts +5 -0
  44. package/dist/types/modes/controllers/command-controller.d.ts +2 -0
  45. package/dist/types/modes/controllers/event-controller.d.ts +3 -0
  46. package/dist/types/modes/interactive-mode.d.ts +13 -2
  47. package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
  48. package/dist/types/modes/prompt-action-autocomplete.d.ts +6 -1
  49. package/dist/types/modes/prompt-suggestion-controller.d.ts +35 -0
  50. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +2 -2
  51. package/dist/types/modes/types.d.ts +6 -0
  52. package/dist/types/modes/utils/hotkeys-markdown.d.ts +2 -1
  53. package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
  54. package/dist/types/runtime/memory-domain.d.ts +9 -0
  55. package/dist/types/runtime/memory-guard-contract.d.ts +71 -0
  56. package/dist/types/runtime/memory-guard.d.ts +39 -0
  57. package/dist/types/runtime/memory-limit.d.ts +11 -0
  58. package/dist/types/runtime-mcp/content-limits.d.ts +7 -0
  59. package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +1 -1
  60. package/dist/types/runtime-mcp/manager.d.ts +9 -1
  61. package/dist/types/runtime-mcp/oauth-flow.d.ts +0 -5
  62. package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +14 -0
  63. package/dist/types/runtime-mcp/redaction.d.ts +2 -0
  64. package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
  65. package/dist/types/sdk/acp/final-text.d.ts +19 -0
  66. package/dist/types/sdk/acp/mcp.d.ts +23 -0
  67. package/dist/types/sdk/broker/broker.d.ts +2 -0
  68. package/dist/types/sdk/broker/lifecycle.d.ts +13 -0
  69. package/dist/types/sdk/bus/chat-daemon-control.d.ts +9 -1
  70. package/dist/types/sdk/bus/config-commands.d.ts +2 -2
  71. package/dist/types/sdk/bus/config.d.ts +2 -0
  72. package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
  73. package/dist/types/sdk/bus/conversation-store.d.ts +1 -0
  74. package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
  75. package/dist/types/sdk/bus/index.d.ts +52 -4
  76. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +37 -0
  77. package/dist/types/sdk/bus/lifecycle-commands.d.ts +5 -4
  78. package/dist/types/sdk/bus/notification-orchestration.d.ts +1 -0
  79. package/dist/types/sdk/bus/notification-service.d.ts +34 -0
  80. package/dist/types/sdk/bus/operator-runtime.d.ts +1 -0
  81. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +106 -0
  82. package/dist/types/sdk/bus/rate-limit-pool.d.ts +2 -0
  83. package/dist/types/sdk/bus/reconciliation-store.d.ts +65 -0
  84. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +33 -9
  85. package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -1
  86. package/dist/types/sdk/bus/telegram-daemon.d.ts +286 -12
  87. package/dist/types/sdk/bus/telegram-reference.d.ts +2 -0
  88. package/dist/types/sdk/bus/topic-registry.d.ts +88 -2
  89. package/dist/types/sdk/client/discovery.d.ts +2 -0
  90. package/dist/types/sdk/client/liveness.d.ts +7 -0
  91. package/dist/types/sdk/host/control/operations.d.ts +3 -2
  92. package/dist/types/sdk/host/host.d.ts +3 -1
  93. package/dist/types/sdk/host/query/handlers.d.ts +14 -0
  94. package/dist/types/sdk/index.d.ts +2 -0
  95. package/dist/types/sdk/lifecycle-session.d.ts +10 -1
  96. package/dist/types/sdk/prompt-status.d.ts +88 -0
  97. package/dist/types/sdk/session-directory.d.ts +1 -1
  98. package/dist/types/sdk/session.d.ts +7 -0
  99. package/dist/types/sdk/startup-capability.d.ts +9 -0
  100. package/dist/types/sdk/transport/auth-preface.d.ts +9 -0
  101. package/dist/types/sdk/transport/index.d.ts +12 -0
  102. package/dist/types/sdk/transport/relay.d.ts +43 -0
  103. package/dist/types/sdk/transport/serve-cli.d.ts +4 -0
  104. package/dist/types/sdk/transport/socket.d.ts +7 -0
  105. package/dist/types/sdk/transport/stdio.d.ts +3 -0
  106. package/dist/types/session/agent-session.d.ts +83 -24
  107. package/dist/types/session/btw-contract.d.ts +16 -0
  108. package/dist/types/session/fallback-chain-controller.d.ts +18 -2
  109. package/dist/types/session/internal/managed-session-scope.d.ts +70 -10
  110. package/dist/types/session/internal/managed-session-storage.d.ts +34 -12
  111. package/dist/types/session/internal/native-publish-outcome.d.ts +48 -0
  112. package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
  113. package/dist/types/session/session-manager.d.ts +89 -18
  114. package/dist/types/session/session-storage.d.ts +31 -0
  115. package/dist/types/session/streaming-output.d.ts +60 -5
  116. package/dist/types/setup/credential-import.d.ts +5 -1
  117. package/dist/types/setup/provider-onboarding.d.ts +2 -0
  118. package/dist/types/skc-runtime/deep-interview-runtime.d.ts +1 -1
  119. package/dist/types/skc-runtime/deep-interview-stage.d.ts +37 -0
  120. package/dist/types/skc-runtime/gc-runtime.d.ts +1 -1
  121. package/dist/types/skc-runtime/linux-proc.d.ts +22 -14
  122. package/dist/types/skc-runtime/memory-guard-owner-claims.d.ts +47 -0
  123. package/dist/types/skc-runtime/ralplan-runtime.d.ts +112 -1
  124. package/dist/types/skc-runtime/repository-binding.d.ts +63 -0
  125. package/dist/types/skc-runtime/state-runtime.d.ts +3 -1
  126. package/dist/types/skc-runtime/state-writer.d.ts +5 -1
  127. package/dist/types/skc-runtime/team-launch.d.ts +1 -1
  128. package/dist/types/skc-runtime/team-runtime.d.ts +9 -2
  129. package/dist/types/skc-runtime/team-store.d.ts +12 -0
  130. package/dist/types/skc-runtime/team-worker-memory-guard.d.ts +92 -0
  131. package/dist/types/skc-runtime/tmux-owner-isolation.d.ts +7 -0
  132. package/dist/types/skc-runtime/ultragoal-guard.d.ts +6 -5
  133. package/dist/types/skc-runtime/ultragoal-receipt-freshness.d.ts +28 -0
  134. package/dist/types/skc-runtime/ultragoal-runtime.d.ts +43 -5
  135. package/dist/types/skill-state/workflow-hud.d.ts +3 -0
  136. package/dist/types/ssh/utils.d.ts +1 -0
  137. package/dist/types/task/discovery.d.ts +3 -1
  138. package/dist/types/task/executor.d.ts +6 -0
  139. package/dist/types/task/index.d.ts +3 -1
  140. package/dist/types/task/provider-retry-status.d.ts +13 -0
  141. package/dist/types/task/receipt.d.ts +2 -0
  142. package/dist/types/task/types.d.ts +133 -0
  143. package/dist/types/task/ultragoal-redteam-activation.d.ts +33 -0
  144. package/dist/types/tools/browser/launch.d.ts +7 -0
  145. package/dist/types/tools/fetch.d.ts +22 -9
  146. package/dist/types/tools/image-gen.d.ts +63 -1
  147. package/dist/types/tools/index.d.ts +7 -1
  148. package/dist/types/tools/output-meta.d.ts +21 -1
  149. package/dist/types/tools/read-internals.d.ts +12 -0
  150. package/dist/types/tools/read.d.ts +45 -1
  151. package/dist/types/tools/resource-gc.d.ts +23 -0
  152. package/dist/types/tools/skill-discovery.d.ts +7 -0
  153. package/dist/types/tools/sqlite-reader.d.ts +7 -0
  154. package/dist/types/tools/tool-result.d.ts +7 -1
  155. package/dist/types/utils/prompt-suggestion.d.ts +33 -0
  156. package/dist/types/utils/shell-snapshot.d.ts +12 -0
  157. package/dist/types/web/insane/bridge.d.ts +1 -0
  158. package/dist/types/web/insane/url-guard.d.ts +17 -0
  159. package/package.json +8 -12
  160. package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
  161. package/scripts/capture-platform-shortcut-labels-showcase.ts +342 -0
  162. package/scripts/capture-sticky-viewport-showcase.ts +292 -0
  163. package/scripts/compile-args.ts +0 -1
  164. package/scripts/dogfood-repository-binding.ts +209 -0
  165. package/scripts/generate-docs-index.ts +4 -1
  166. package/scripts/generate-sdk-operation-inventory.ts +9 -0
  167. package/scripts/run-test-manifest.ts +6 -4
  168. package/scripts/verify-skc-sdk-canonicalization.ts +122 -18
  169. package/scripts/verify-sticky-viewport-showcase.ts +611 -0
  170. package/src/capability/index.ts +58 -42
  171. package/src/capability/types.ts +3 -0
  172. package/src/cli/args.ts +16 -100
  173. package/src/cli/fast-help.ts +1 -1
  174. package/src/cli/mcp-cli.ts +4 -21
  175. package/src/cli/notify-cli.ts +6 -38
  176. package/src/cli/read-cli.ts +2 -1
  177. package/src/cli/setup-cli.ts +10 -4
  178. package/src/cli.ts +133 -11
  179. package/src/commands/daemon.ts +22 -5
  180. package/src/commands/deep-interview.ts +26 -1
  181. package/src/commands/harness.ts +35 -12
  182. package/src/commands/read.ts +11 -2
  183. package/src/commands/sdk.ts +134 -17
  184. package/src/commands/team.ts +1 -1
  185. package/src/commit/agentic/index.ts +3 -3
  186. package/src/commit/map-reduce/index.ts +2 -2
  187. package/src/config/keybindings.ts +158 -25
  188. package/src/config/model-profile-contract.ts +174 -0
  189. package/src/config/model-profiles.ts +51 -10
  190. package/src/config/model-registry.ts +24 -4
  191. package/src/config/model-resolver.ts +2 -2
  192. package/src/config/provider-auth-health.ts +42 -0
  193. package/src/config/provider-ranking.ts +119 -0
  194. package/src/config/settings-schema.ts +157 -10
  195. package/src/config/settings.ts +254 -108
  196. package/src/coordinator-mcp/model-preset.ts +21 -74
  197. package/src/defaults/skc/skills/deep-interview/SKILL.md +147 -24
  198. package/src/defaults/skc/skills/ralplan/SKILL.md +91 -34
  199. package/src/defaults/skc/skills/team/SKILL.md +1 -1
  200. package/src/defaults/skc/skills/ultragoal/SKILL.md +68 -17
  201. package/src/discovery/ssh.ts +12 -1
  202. package/src/edit/index.ts +3 -6
  203. package/src/edit/modes/patch.ts +38 -1
  204. package/src/edit/modes/replace.ts +42 -0
  205. package/src/edit/path-mutation-lock.ts +112 -0
  206. package/src/eval/js/tool-bridge.ts +1 -1
  207. package/src/eval/py/executor.ts +37 -13
  208. package/src/eval/py/kernel.ts +1 -21
  209. package/src/eval/py/prelude.py +2 -2
  210. package/src/eval/py/runner-artifact.ts +84 -0
  211. package/src/eval/py/tool-bridge.ts +34 -18
  212. package/src/extensibility/extensions/runner.ts +4 -0
  213. package/src/extensibility/extensions/types.ts +42 -4
  214. package/src/extensibility/plugins/marketplace/fetcher.ts +191 -7
  215. package/src/extensibility/shared-events.ts +5 -0
  216. package/src/extensibility/skc-plugins/runtime-adapters.ts +2 -1
  217. package/src/hooks/native-skill-hook.ts +17 -4
  218. package/src/internal-urls/docs-index.generated.ts +17 -16
  219. package/src/internal-urls/local-protocol.ts +87 -25
  220. package/src/internal-urls/local-root-gc.ts +127 -0
  221. package/src/internal-urls/mcp-protocol.ts +73 -11
  222. package/src/main.ts +120 -42
  223. package/src/memories/index.ts +10 -0
  224. package/src/modes/DESIGN.md +52 -0
  225. package/src/modes/acp/acp-agent.ts +647 -83
  226. package/src/modes/acp/acp-event-mapper.ts +106 -12
  227. package/src/modes/acp/acp-mode.ts +39 -3
  228. package/src/modes/action-registry.ts +1 -1
  229. package/src/modes/components/assistant-message.ts +123 -22
  230. package/src/modes/components/btw-panel.ts +82 -16
  231. package/src/modes/components/irc-sidebar.ts +176 -62
  232. package/src/modes/components/model-selector.ts +61 -4
  233. package/src/modes/components/notifications-settings-editor.ts +1 -1
  234. package/src/modes/components/oauth-selector.ts +42 -12
  235. package/src/modes/components/plan-preview-overlay.ts +1 -1
  236. package/src/modes/components/queue-pane.ts +55 -9
  237. package/src/modes/components/queued-message-selector.ts +53 -10
  238. package/src/modes/components/read-tool-group.ts +82 -14
  239. package/src/modes/components/runtime-mcp-add-wizard.ts +5 -0
  240. package/src/modes/components/sayknow-pet-widget.ts +27 -8
  241. package/src/modes/components/session-observer-overlay.ts +187 -32
  242. package/src/modes/components/settings-selector.ts +60 -18
  243. package/src/modes/components/tool-execution.ts +138 -27
  244. package/src/modes/components/tool-status-header.ts +26 -8
  245. package/src/modes/components/welcome.ts +50 -23
  246. package/src/modes/controllers/btw-controller.ts +119 -36
  247. package/src/modes/controllers/command-controller.ts +101 -54
  248. package/src/modes/controllers/event-controller.ts +119 -27
  249. package/src/modes/controllers/extension-ui-controller.ts +23 -12
  250. package/src/modes/controllers/input-controller.ts +100 -8
  251. package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -6
  252. package/src/modes/controllers/selector-controller.ts +4 -1
  253. package/src/modes/interactive-mode.ts +201 -60
  254. package/src/modes/irc-observation-ledger.ts +71 -15
  255. package/src/modes/prompt-action-autocomplete.ts +32 -13
  256. package/src/modes/prompt-suggestion-controller.ts +96 -0
  257. package/src/modes/runtime-init.ts +20 -2
  258. package/src/modes/shared/agent-wire/command-dispatch.ts +3 -3
  259. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +2 -2
  260. package/src/modes/types.ts +6 -0
  261. package/src/modes/utils/hotkeys-markdown.ts +64 -36
  262. package/src/modes/utils/ui-helpers.ts +99 -4
  263. package/src/prompts/agent-fragments/restricted-bash.md +1 -1
  264. package/src/prompts/agents/architect.md +17 -3
  265. package/src/prompts/agents/critic.md +17 -2
  266. package/src/prompts/agents/executor.md +1 -1
  267. package/src/prompts/agents/planner.md +8 -1
  268. package/src/prompts/system/btw-user.md +3 -8
  269. package/src/prompts/system/prompt-suggestion-system.md +32 -0
  270. package/src/prompts/system/system-prompt.md +6 -3
  271. package/src/prompts/tools/cron.md +3 -1
  272. package/src/prompts/tools/read.md +4 -2
  273. package/src/prompts/tools/skill-discovery.md +1 -0
  274. package/src/runtime/memory-domain.ts +66 -0
  275. package/src/runtime/memory-guard-contract.ts +73 -0
  276. package/src/runtime/memory-guard.ts +292 -0
  277. package/src/runtime/memory-limit.ts +50 -0
  278. package/src/runtime-mcp/client.ts +41 -55
  279. package/src/runtime-mcp/content-limits.ts +71 -0
  280. package/src/runtime-mcp/discoverable-tool-metadata.ts +1 -1
  281. package/src/runtime-mcp/json-rpc.ts +28 -11
  282. package/src/runtime-mcp/manager.ts +77 -59
  283. package/src/runtime-mcp/oauth-flow.ts +0 -72
  284. package/src/runtime-mcp/plugin-network-boundary.ts +101 -0
  285. package/src/runtime-mcp/redaction.ts +30 -0
  286. package/src/runtime-mcp/smithery-auth.ts +17 -2
  287. package/src/runtime-mcp/smithery-connect.ts +11 -1
  288. package/src/runtime-mcp/transports/http.ts +63 -22
  289. package/src/sdk/acp/adapter.ts +8 -1
  290. package/src/sdk/acp/final-text.ts +40 -0
  291. package/src/sdk/acp/mcp.ts +26 -0
  292. package/src/sdk/broker/broker.ts +34 -20
  293. package/src/sdk/broker/identity.ts +22 -12
  294. package/src/sdk/broker/lifecycle.ts +293 -43
  295. package/src/sdk/broker/session-index.ts +11 -1
  296. package/src/sdk/bus/chat-daemon-cli.ts +2 -2
  297. package/src/sdk/bus/chat-daemon-control.ts +22 -5
  298. package/src/sdk/bus/config-commands.ts +2 -2
  299. package/src/sdk/bus/config.ts +10 -2
  300. package/src/sdk/bus/control-drain-lease.ts +104 -0
  301. package/src/sdk/bus/conversation-store.ts +40 -6
  302. package/src/sdk/bus/daemon-paths.ts +2 -0
  303. package/src/sdk/bus/index.ts +793 -121
  304. package/src/sdk/bus/kind-aware-reconciliation.ts +242 -0
  305. package/src/sdk/bus/lifecycle-commands.ts +63 -10
  306. package/src/sdk/bus/lifecycle-control-runtime.ts +11 -2
  307. package/src/sdk/bus/lifecycle-orchestrator.ts +32 -1
  308. package/src/sdk/bus/notification-orchestration.ts +12 -0
  309. package/src/sdk/bus/notification-service.ts +87 -25
  310. package/src/sdk/bus/operator-runtime.ts +31 -5
  311. package/src/sdk/bus/prompt-reconciliation.ts +240 -0
  312. package/src/sdk/bus/rate-limit-pool.ts +8 -0
  313. package/src/sdk/bus/recent-activity.ts +90 -26
  314. package/src/sdk/bus/reconciliation-store.ts +224 -0
  315. package/src/sdk/bus/telegram-cli.ts +6 -13
  316. package/src/sdk/bus/telegram-daemon-cli.ts +8 -3
  317. package/src/sdk/bus/telegram-daemon-contract.ts +34 -9
  318. package/src/sdk/bus/telegram-daemon-control.ts +161 -40
  319. package/src/sdk/bus/telegram-daemon.ts +3649 -593
  320. package/src/sdk/bus/telegram-reference.ts +20 -2
  321. package/src/sdk/bus/topic-registry.ts +451 -12
  322. package/src/sdk/cli/session-cli.ts +15 -2
  323. package/src/sdk/client/discovery.ts +19 -3
  324. package/src/sdk/client/liveness.ts +49 -0
  325. package/src/sdk/host/control/dispatch.ts +8 -2
  326. package/src/sdk/host/control/operations.ts +3 -2
  327. package/src/sdk/host/host.ts +27 -9
  328. package/src/sdk/host/query/handlers.ts +125 -5
  329. package/src/sdk/index.ts +12 -0
  330. package/src/sdk/lifecycle-session.ts +19 -3
  331. package/src/sdk/mcp/server.ts +46 -18
  332. package/src/sdk/prompt-status.ts +97 -0
  333. package/src/sdk/protocol/operation-inventory.generated.json +145 -0
  334. package/src/sdk/protocol/operation-registry.ts +24 -4
  335. package/src/sdk/session-directory.ts +5 -1
  336. package/src/sdk/session.ts +69 -8
  337. package/src/sdk/startup-capability.ts +15 -1
  338. package/src/sdk/transport/auth-preface.ts +82 -0
  339. package/src/sdk/transport/index.ts +18 -0
  340. package/src/sdk/transport/relay.ts +252 -0
  341. package/src/sdk/transport/serve-cli.ts +105 -0
  342. package/src/sdk/transport/socket.ts +197 -0
  343. package/src/sdk/transport/stdio.ts +17 -0
  344. package/src/session/agent-session.ts +1112 -314
  345. package/src/session/blob-store.ts +25 -7
  346. package/src/session/btw-contract.ts +59 -0
  347. package/src/session/fallback-chain-controller.ts +47 -8
  348. package/src/session/internal/managed-session-scope.ts +1426 -259
  349. package/src/session/internal/managed-session-storage.ts +414 -238
  350. package/src/session/internal/native-publish-outcome.ts +271 -0
  351. package/src/session/memory-guard-checkpoint-participant.ts +131 -0
  352. package/src/session/session-manager.ts +2079 -469
  353. package/src/session/session-storage.ts +151 -11
  354. package/src/session/streaming-output.ts +262 -43
  355. package/src/setup/credential-import.ts +28 -3
  356. package/src/setup/provider-onboarding.ts +49 -5
  357. package/src/setup/provider-presets.json +2 -1
  358. package/src/skc-runtime/deep-interview-runtime.ts +303 -36
  359. package/src/skc-runtime/deep-interview-stage.ts +1016 -0
  360. package/src/skc-runtime/deep-interview-state.ts +8 -5
  361. package/src/skc-runtime/gc-render.ts +1 -0
  362. package/src/skc-runtime/gc-runtime.ts +11 -1
  363. package/src/skc-runtime/linux-proc.ts +70 -36
  364. package/src/skc-runtime/managed-owner-supervisor.ts +83 -4
  365. package/src/skc-runtime/memory-guard-owner-claims.ts +389 -0
  366. package/src/skc-runtime/ralplan-runtime.ts +1057 -75
  367. package/src/skc-runtime/repository-binding.ts +267 -0
  368. package/src/skc-runtime/session-state-sidecar.ts +25 -9
  369. package/src/skc-runtime/state-runtime.ts +50 -12
  370. package/src/skc-runtime/state-writer.ts +68 -56
  371. package/src/skc-runtime/team-launch.ts +34 -5
  372. package/src/skc-runtime/team-runtime.ts +41 -1
  373. package/src/skc-runtime/team-store.ts +32 -0
  374. package/src/skc-runtime/team-worker-memory-guard.ts +363 -0
  375. package/src/skc-runtime/team-workers.ts +1 -0
  376. package/src/skc-runtime/tmux-common.ts +13 -2
  377. package/src/skc-runtime/tmux-owner-isolation.ts +20 -1
  378. package/src/skc-runtime/tmux-sessions.ts +45 -6
  379. package/src/skc-runtime/ultragoal-guard.ts +93 -15
  380. package/src/skc-runtime/ultragoal-receipt-freshness.ts +123 -0
  381. package/src/skc-runtime/ultragoal-runtime.ts +469 -38
  382. package/src/skc-runtime/workflow-manifest.generated.json +195 -5
  383. package/src/skc-runtime/workflow-manifest.ts +67 -3
  384. package/src/skill-state/workflow-hud.ts +25 -2
  385. package/src/skill-state/workflow-mutation-guard.ts +104 -12
  386. package/src/slash-commands/builtin-registry.ts +1 -1
  387. package/src/ssh/utils.ts +14 -0
  388. package/src/task/discovery.ts +8 -2
  389. package/src/task/executor.ts +165 -47
  390. package/src/task/index.ts +123 -15
  391. package/src/task/provider-retry-status.ts +88 -0
  392. package/src/task/receipt.ts +3 -0
  393. package/src/task/render.ts +45 -26
  394. package/src/task/skc-command.ts +2 -2
  395. package/src/task/types.ts +55 -10
  396. package/src/task/ultragoal-redteam-activation.ts +75 -0
  397. package/src/tools/ask.ts +1 -1
  398. package/src/tools/ast-edit.ts +2 -2
  399. package/src/tools/bash-allowed-prefixes.ts +45 -1
  400. package/src/tools/bash-pty-selection.ts +2 -2
  401. package/src/tools/browser/launch.ts +41 -6
  402. package/src/tools/browser/screenshot-format.ts +6 -1
  403. package/src/tools/cron.ts +1 -1
  404. package/src/tools/fetch.ts +127 -154
  405. package/src/tools/image-gen.ts +476 -23
  406. package/src/tools/index.ts +7 -1
  407. package/src/tools/output-meta.ts +176 -9
  408. package/src/tools/path-utils.ts +5 -1
  409. package/src/tools/read-internals.ts +44 -0
  410. package/src/tools/read.ts +1544 -310
  411. package/src/tools/resource-gc.ts +665 -125
  412. package/src/tools/skill-discovery.ts +39 -3
  413. package/src/tools/sqlite-reader.ts +63 -5
  414. package/src/tools/subagent-render.ts +74 -16
  415. package/src/tools/subagent.ts +2 -0
  416. package/src/tools/tool-result.ts +14 -1
  417. package/src/utils/edit-mode.ts +2 -2
  418. package/src/utils/pasted-image-path.ts +15 -6
  419. package/src/utils/prompt-suggestion.ts +265 -0
  420. package/src/utils/shell-snapshot.ts +173 -63
  421. package/src/utils/sixel.ts +3 -3
  422. package/src/web/insane/bridge.ts +5 -1
  423. package/src/web/insane/url-guard.ts +140 -27
  424. package/src/web/scrapers/docs-rs.ts +30 -5
  425. package/src/web/scrapers/types.ts +19 -49
  426. package/src/web/scrapers/utils.ts +12 -26
  427. package/src/web/search/providers/codex.ts +1 -1
  428. 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 normalizeIPv4MappedIPv6(address: string): string {
71
- return address.toLowerCase().startsWith("::ffff:") ? address.slice(7) : address;
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 normalized = address.toLowerCase();
76
- const mapped = normalizeIPv4MappedIPv6(normalized);
77
- if (mapped !== normalized && net.isIP(mapped) === 4) return isPrivateIPv4(mapped);
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
- normalized === "::" || // unspecified
80
- normalized === "::1" || // loopback
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 normalized = normalizeIPv4MappedIPv6(address);
96
- const family = net.isIP(normalized);
97
- if (family === 4) return isPrivateIPv4(normalized);
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 literalFamily = net.isIP(url.hostname);
199
+ const hostname = url.hostname.replace(/^\[|\]$/g, "");
200
+ const literalFamily = net.isIP(hostname);
132
201
  if (literalFamily !== 0) {
133
- if (isPrivateOrSpecialAddress(url.hostname)) {
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: [url.hostname] };
205
+ return { ok: true, url, addresses: [hostname] };
137
206
  }
138
207
 
139
208
  let addresses: string[];
140
209
  try {
141
- addresses = await resolver(url.hostname);
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 [jsonStr, stat] = await Promise.all([Bun.file(cachePath).text(), fs.stat(cachePath)]);
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: { "User-Agent": "skc-web-fetch/1.0", Accept: "application/gzip" },
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
- break;
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 { validatePublicHttpUrl } from "../insane/url-guard";
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
- let initialUrl = url;
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 response = await fetch(currentUrl, requestInit);
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: currentUrl,
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
- const redirectUrl = new URL(location, currentUrl).toString();
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 = response.url || currentUrl;
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 { validatePublicHttpUrl } from "../insane/url-guard";
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 response = await fetch(currentUrl, {
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
- const redirectUrl = new URL(location, currentUrl).toString();
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
- /\bultragoal\b/i,
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,