@sayknow-cli/coding-agent 0.4.7 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (428) hide show
  1. package/CHANGELOG.md +122 -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 +20 -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
@@ -6,12 +6,12 @@
6
6
  */
7
7
  import * as path from "node:path";
8
8
  import * as url from "node:url";
9
- import type { TSchema } from "@sayknow-cli/ai";
9
+ import { isCanonicalMCPOAuthBinding, resolveMCPOAuthResourceOrigin, type TSchema } from "@sayknow-cli/ai";
10
10
  import { logger } from "@sayknow-cli/utils";
11
11
  import type { SourceMeta } from "../capability/types";
12
12
  import * as configValue from "../config/resolve-config-value";
13
13
  import type { CustomTool } from "../extensibility/custom-tools/types";
14
- import type { AuthStorage } from "../session/auth-storage";
14
+ import type { AuthStorage, OAuthCredential } from "../session/auth-storage";
15
15
  import {
16
16
  connectToServer,
17
17
  disconnectServer,
@@ -27,7 +27,6 @@ import {
27
27
  unsubscribeFromResources,
28
28
  } from "./client";
29
29
  import { loadAllMCPConfigs, validateServerConfig } from "./config";
30
- import { refreshMCPOAuthToken } from "./oauth-flow";
31
30
  import type { MCPToolDetails } from "./tool-bridge";
32
31
  import { DeferredMCPTool, MCPTool } from "./tool-bridge";
33
32
  import type { MCPToolCache } from "./tool-cache";
@@ -69,17 +68,24 @@ type ConnectionTask = {
69
68
 
70
69
  const STARTUP_TIMEOUT_MS = 250;
71
70
  const STARTUP_TIMEOUT_GRACE_MS = 500;
71
+ /**
72
+ * Default ceiling on how long `discoverAndConnect` waits for a server batch to
73
+ * come up. Deliberately short: a config with a large `timeout` must not be able
74
+ * to hang ordinary startup. ACP lifecycle launches carry their own, larger
75
+ * budget derived from the readiness deadline (see `maxStartupTimeoutMs`).
76
+ */
72
77
  const MAX_STARTUP_TIMEOUT_MS = 1_750;
73
78
 
74
- function resolveStartupTimeoutMs(configs: MCPServerConfig[]): number {
79
+ export function resolveStartupTimeoutMs(configs: MCPServerConfig[], maxStartupTimeoutMs?: number): number {
80
+ const ceiling =
81
+ typeof maxStartupTimeoutMs === "number" && Number.isFinite(maxStartupTimeoutMs) && maxStartupTimeoutMs > 0
82
+ ? Math.max(STARTUP_TIMEOUT_MS, maxStartupTimeoutMs)
83
+ : MAX_STARTUP_TIMEOUT_MS;
75
84
  const configuredTimeouts = configs
76
85
  .map(config => config.timeout)
77
86
  .filter((timeout): timeout is number => typeof timeout === "number" && Number.isFinite(timeout) && timeout > 0);
78
87
  if (configuredTimeouts.length === 0) return STARTUP_TIMEOUT_MS;
79
- return Math.min(
80
- MAX_STARTUP_TIMEOUT_MS,
81
- Math.max(STARTUP_TIMEOUT_MS, Math.max(...configuredTimeouts) + STARTUP_TIMEOUT_GRACE_MS),
82
- );
88
+ return Math.min(ceiling, Math.max(STARTUP_TIMEOUT_MS, Math.max(...configuredTimeouts) + STARTUP_TIMEOUT_GRACE_MS));
83
89
  }
84
90
 
85
91
  function trackPromise<T>(promise: Promise<T>): TrackedPromise<T> {
@@ -186,6 +192,13 @@ export interface MCPDiscoverOptions {
186
192
  export interface MCPManagerOptions {
187
193
  /** Restrict this instance to tools from an explicit MCP config. */
188
194
  toolsOnly?: boolean;
195
+ /**
196
+ * Ceiling for the startup wait, in milliseconds. Only ACP lifecycle launches
197
+ * set this, so a slow ACP MCP handshake gets the readiness budget while every
198
+ * other consumer keeps the short default. Non-positive or non-finite values
199
+ * are ignored and the default applies.
200
+ */
201
+ maxStartupTimeoutMs?: number;
189
202
  }
190
203
 
191
204
  /**
@@ -270,12 +283,15 @@ export class MCPManager {
270
283
  );
271
284
  }
272
285
 
286
+ readonly #maxStartupTimeoutMs: number | undefined;
287
+
273
288
  constructor(
274
289
  private cwd: string,
275
290
  private toolCache: MCPToolCache | null = null,
276
291
  options: MCPManagerOptions = {},
277
292
  ) {
278
293
  this.#toolsOnly = options.toolsOnly === true;
294
+ this.#maxStartupTimeoutMs = options.maxStartupTimeoutMs;
279
295
  }
280
296
 
281
297
  isToolsOnly(): boolean {
@@ -634,7 +650,10 @@ export class MCPManager {
634
650
  }
635
651
 
636
652
  if (connectionTasks.length > 0) {
637
- const startupTimeoutMs = resolveStartupTimeoutMs(connectionTasks.map(task => task.config));
653
+ const startupTimeoutMs = resolveStartupTimeoutMs(
654
+ connectionTasks.map(task => task.config),
655
+ this.#maxStartupTimeoutMs,
656
+ );
638
657
  const firstUnexpectedFailure = Promise.withResolvers<{ reason: unknown }>();
639
658
  if (this.#toolsOnly) {
640
659
  for (const task of connectionTasks) {
@@ -1469,64 +1488,63 @@ export class MCPManager {
1469
1488
  let resolved: MCPServerConfig = { ...config };
1470
1489
 
1471
1490
  const auth = config.auth;
1472
- if (auth?.type === "oauth" && auth.credentialId && this.#authStorage) {
1491
+ if (auth?.type === "oauth") {
1492
+ if (!auth.credentialId || !this.#authStorage || (config.type !== "http" && config.type !== "sse")) {
1493
+ throw new MCPExpectedFailure();
1494
+ }
1473
1495
  const credentialId = auth.credentialId;
1474
1496
  let credential = this.#authStorage.get(credentialId);
1475
- if (credential?.type === "oauth") {
1476
- // Proactive refresh: 5-minute buffer before expiry
1477
- // Force refresh: on 401/403 auth errors (revoked tokens, clock skew, missing expires)
1478
- const REFRESH_BUFFER_MS = 5 * 60_000;
1479
- const shouldRefresh =
1480
- forceRefresh || (credential.expires && Date.now() >= credential.expires - REFRESH_BUFFER_MS);
1481
- let refreshedCredential:
1482
- | {
1483
- type: "oauth";
1484
- access: string;
1485
- refresh: string;
1486
- expires: number;
1487
- }
1488
- | undefined;
1489
- if (shouldRefresh && credential.refresh && auth.tokenUrl) {
1490
- try {
1491
- const refreshed = await refreshMCPOAuthToken(
1492
- auth.tokenUrl,
1493
- credential.refresh,
1494
- auth.clientId,
1495
- auth.clientSecret,
1496
- );
1497
- refreshedCredential = { type: "oauth", ...refreshed };
1498
- } catch (error) {
1499
- if (!(error instanceof MCPExpectedFailure)) throw error;
1500
- if (this.#toolsOnly) {
1501
- logger.debug("MCP OAuth refresh failed");
1502
- } else {
1503
- logger.warn("MCP OAuth refresh failed, using existing token");
1504
- }
1497
+ const binding = credential?.type === "oauth" ? credential.mcpBinding : undefined;
1498
+ const endpointOrigin = resolveMCPOAuthResourceOrigin(config.url);
1499
+ if (
1500
+ credential?.type !== "oauth" ||
1501
+ !binding ||
1502
+ !isCanonicalMCPOAuthBinding(binding) ||
1503
+ binding.resourceOrigin !== endpointOrigin ||
1504
+ (auth.tokenUrl !== undefined && auth.tokenUrl !== binding.tokenEndpoint)
1505
+ ) {
1506
+ throw new MCPExpectedFailure();
1507
+ }
1508
+
1509
+ // Proactive refresh: 5-minute buffer before expiry
1510
+ // Force refresh: on 401/403 auth errors (revoked tokens, clock skew, missing expires)
1511
+ const REFRESH_BUFFER_MS = 5 * 60_000;
1512
+ const shouldRefresh =
1513
+ forceRefresh || (credential.expires && Date.now() >= credential.expires - REFRESH_BUFFER_MS);
1514
+ if (shouldRefresh && credential.refresh) {
1515
+ let refreshedCredential: OAuthCredential | undefined;
1516
+ try {
1517
+ refreshedCredential = await this.#authStorage.forceRefreshOAuthCredential(credentialId, credential, {
1518
+ clientId: auth.clientId,
1519
+ clientSecret: auth.clientSecret,
1520
+ });
1521
+ } catch {
1522
+ if (forceRefresh) throw new MCPExpectedFailure();
1523
+ if (this.#toolsOnly) {
1524
+ logger.debug("MCP OAuth refresh failed");
1525
+ } else {
1526
+ logger.warn("MCP OAuth refresh failed, using existing token");
1505
1527
  }
1506
1528
  }
1507
1529
  if (refreshedCredential) {
1508
- await this.#authStorage.set(credentialId, refreshedCredential);
1530
+ const refreshedBinding = refreshedCredential.mcpBinding;
1531
+ if (
1532
+ !refreshedBinding ||
1533
+ refreshedBinding.resourceOrigin !== binding.resourceOrigin ||
1534
+ refreshedBinding.tokenEndpoint !== binding.tokenEndpoint
1535
+ ) {
1536
+ throw new MCPExpectedFailure();
1537
+ }
1509
1538
  credential = refreshedCredential;
1510
1539
  }
1511
-
1512
- if (resolved.type === "http" || resolved.type === "sse") {
1513
- resolved = {
1514
- ...resolved,
1515
- headers: {
1516
- ...resolved.headers,
1517
- Authorization: `Bearer ${credential.access}`,
1518
- },
1519
- };
1520
- } else {
1521
- resolved = {
1522
- ...resolved,
1523
- env: {
1524
- ...resolved.env,
1525
- OAUTH_ACCESS_TOKEN: credential.access,
1526
- },
1527
- };
1528
- }
1529
1540
  }
1541
+ resolved = {
1542
+ ...config,
1543
+ headers: {
1544
+ ...config.headers,
1545
+ Authorization: `Bearer ${credential.access}`,
1546
+ },
1547
+ };
1530
1548
  }
1531
1549
  if (this.#toolsOnly && resolved.type === "stdio") {
1532
1550
  resolved = { ...resolved, noInheritEnv: true };
@@ -8,29 +8,10 @@
8
8
  import type { OAuthCallbackFlowOptions } from "@sayknow-cli/ai/utils/oauth/callback-server";
9
9
  import { OAuthCallbackFlow } from "@sayknow-cli/ai/utils/oauth/callback-server";
10
10
  import type { OAuthController, OAuthCredentials } from "@sayknow-cli/ai/utils/oauth/types";
11
- import { MCPExpectedFailure } from "./types";
12
11
 
13
12
  const DEFAULT_PORT = 3000;
14
13
  const CALLBACK_PATH = "/callback";
15
14
  const CALLBACK_BIND_HOSTNAME = "127.0.0.1";
16
- type RefreshTokenResponse = {
17
- access_token: string;
18
- refresh_token?: string;
19
- expires_in?: number;
20
- };
21
-
22
- function isRefreshTokenResponse(value: unknown): value is RefreshTokenResponse {
23
- if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
24
- const payload = value as Record<string, unknown>;
25
- return (
26
- typeof payload.access_token === "string" &&
27
- payload.access_token.length > 0 &&
28
- (payload.refresh_token === undefined || typeof payload.refresh_token === "string") &&
29
- (payload.expires_in === undefined ||
30
- (typeof payload.expires_in === "number" && Number.isFinite(payload.expires_in) && payload.expires_in >= 0))
31
- );
32
- }
33
-
34
15
  function isLoopbackHostname(hostname: string): boolean {
35
16
  return hostname === "localhost" || hostname === "127.0.0.1";
36
17
  }
@@ -384,56 +365,3 @@ export class MCPOAuthFlow extends OAuthCallbackFlow {
384
365
  }
385
366
  }
386
367
  }
387
-
388
- /**
389
- * Refresh an MCP OAuth token using the standard refresh_token grant.
390
- * Returns updated credentials; preserves the old refresh token if the server doesn't rotate it.
391
- */
392
- export async function refreshMCPOAuthToken(
393
- tokenUrl: string,
394
- refreshToken: string,
395
- clientId?: string,
396
- clientSecret?: string,
397
- ): Promise<OAuthCredentials> {
398
- const params = new URLSearchParams({
399
- grant_type: "refresh_token",
400
- refresh_token: refreshToken,
401
- });
402
- if (clientId) params.set("client_id", clientId);
403
- if (clientSecret) params.set("client_secret", clientSecret);
404
-
405
- let response: Response;
406
- try {
407
- response = await fetch(tokenUrl, {
408
- method: "POST",
409
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
410
- body: params.toString(),
411
- });
412
- } catch (error) {
413
- throw new MCPExpectedFailure(error);
414
- }
415
-
416
- if (!response.ok) {
417
- let text: string;
418
- try {
419
- text = await response.text();
420
- } catch (error) {
421
- throw new MCPExpectedFailure(error);
422
- }
423
- throw new MCPExpectedFailure(new Error(`MCP OAuth refresh failed: ${response.status} ${text}`));
424
- }
425
-
426
- let data: unknown;
427
- try {
428
- data = await response.json();
429
- } catch {
430
- throw new MCPExpectedFailure();
431
- }
432
- if (!isRefreshTokenResponse(data)) throw new MCPExpectedFailure();
433
- const expiresIn = data.expires_in ?? 3600;
434
- return {
435
- access: data.access_token,
436
- refresh: data.refresh_token ?? refreshToken,
437
- expires: Date.now() + expiresIn * 1000,
438
- };
439
- }
@@ -0,0 +1,101 @@
1
+ import { type AddressResolver, guardedPublicFetch } from "../web/insane/url-guard";
2
+ import { cancelMCPStream } from "./content-limits";
3
+ import type { MCPHttpServerConfig, MCPSseServerConfig } from "./types";
4
+
5
+ const PLUGIN_MCP_PUBLIC_NETWORK_BOUNDARY: unique symbol = Symbol("plugin-mcp-public-network-boundary");
6
+ const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
7
+ const MAX_REDIRECTS = 20;
8
+ const REQUEST_BODY_HEADERS = [
9
+ "content-encoding",
10
+ "content-language",
11
+ "content-length",
12
+ "content-location",
13
+ "content-type",
14
+ ] as const;
15
+
16
+ /** Mark an in-memory plugin-bundle remote MCP config for connection-bound public-network enforcement. */
17
+ export function bindPluginMcpToPublicNetwork<T extends MCPHttpServerConfig | MCPSseServerConfig>(config: T): T {
18
+ return Object.assign(config, { [PLUGIN_MCP_PUBLIC_NETWORK_BOUNDARY]: true });
19
+ }
20
+
21
+ /** The marker is an internal symbol, so persisted user MCP configs cannot opt into or forge this path. */
22
+ export function isPluginMcpPublicNetworkBound(config: MCPHttpServerConfig | MCPSseServerConfig): boolean {
23
+ return (
24
+ (config as MCPHttpServerConfig & { [PLUGIN_MCP_PUBLIC_NETWORK_BOUNDARY]?: boolean })[
25
+ PLUGIN_MCP_PUBLIC_NETWORK_BOUNDARY
26
+ ] === true
27
+ );
28
+ }
29
+
30
+ function blocked(reason: string): Error {
31
+ return new Error(`Plugin MCP network request blocked: ${reason}`);
32
+ }
33
+
34
+ function parseHttpsUrl(rawUrl: string): URL {
35
+ let url: URL;
36
+ try {
37
+ url = new URL(rawUrl);
38
+ } catch {
39
+ throw blocked("invalid URL");
40
+ }
41
+ if (url.protocol !== "https:") throw blocked("HTTPS is required");
42
+ return url;
43
+ }
44
+
45
+ function rewritesToGet(status: number, method: string): boolean {
46
+ return (
47
+ ((status === 301 || status === 302) && method === "POST") ||
48
+ (status === 303 && method !== "GET" && method !== "HEAD")
49
+ );
50
+ }
51
+
52
+ /**
53
+ * Fetch a plugin-bundle MCP request through a DNS-pinned public address. Every
54
+ * redirect is handled manually and revalidated before the next connection.
55
+ */
56
+ export async function fetchPluginMcpRequest(
57
+ rawUrl: string,
58
+ init: BunFetchRequestInit,
59
+ options: { resolver?: AddressResolver; maxRedirects?: number } = {},
60
+ ): Promise<Response> {
61
+ let currentUrl = parseHttpsUrl(rawUrl);
62
+ let currentInit: BunFetchRequestInit = { ...init };
63
+ const maxRedirects = options.maxRedirects ?? MAX_REDIRECTS;
64
+
65
+ for (let redirectCount = 0; ; redirectCount++) {
66
+ const dial = await guardedPublicFetch(currentUrl.toString(), currentInit, { resolver: options.resolver });
67
+ if (!dial.ok) throw blocked(dial.reason);
68
+ const { response, logicalUrl } = dial;
69
+ if (!REDIRECT_STATUSES.has(response.status)) return response;
70
+
71
+ const location = response.headers.get("location");
72
+ if (!location) return response;
73
+ if (redirectCount >= maxRedirects) {
74
+ cancelMCPStream(response.body);
75
+ throw blocked("redirect limit exceeded");
76
+ }
77
+
78
+ let nextUrl: URL;
79
+ try {
80
+ nextUrl = parseHttpsUrl(new URL(location, logicalUrl).toString());
81
+ } catch (error) {
82
+ cancelMCPStream(response.body);
83
+ throw error;
84
+ }
85
+ if (logicalUrl.origin !== nextUrl.origin) {
86
+ cancelMCPStream(response.body);
87
+ throw blocked("cross-origin redirects are not allowed");
88
+ }
89
+
90
+ const headers = new Headers(currentInit.headers);
91
+ const method = (currentInit.method ?? "GET").toUpperCase();
92
+ if (rewritesToGet(response.status, method)) {
93
+ for (const name of REQUEST_BODY_HEADERS) headers.delete(name);
94
+ currentInit = { ...currentInit, method: "GET", headers, body: undefined };
95
+ } else {
96
+ currentInit = { ...currentInit, headers };
97
+ }
98
+ currentUrl = nextUrl;
99
+ cancelMCPStream(response.body);
100
+ }
101
+ }
@@ -0,0 +1,30 @@
1
+ const REDACTED = "<redacted>";
2
+ const SENSITIVE_KEY_PATTERN = /(?:token|secret|key|credential|password|authorization|auth|bearer|cookie|session)/i;
3
+
4
+ export function redactMCPEndpoint(value: string | undefined): string | undefined {
5
+ if (!value) return value;
6
+ try {
7
+ const url = new URL(value);
8
+ if (url.username) url.username = REDACTED;
9
+ if (url.password) url.password = REDACTED;
10
+ if (url.pathname !== "/") url.pathname = `/${REDACTED}`;
11
+ for (const key of Array.from(url.searchParams.keys())) {
12
+ url.searchParams.set(key, REDACTED);
13
+ }
14
+ url.hash = "";
15
+ return url.toString();
16
+ } catch {
17
+ return REDACTED;
18
+ }
19
+ }
20
+
21
+ export function redactMCPDiagnosticValue(value: unknown): unknown {
22
+ if (Array.isArray(value)) return value.map(redactMCPDiagnosticValue);
23
+ if (!value || typeof value !== "object") return value;
24
+ return Object.fromEntries(
25
+ Object.entries(value).map(([key, entry]) => [
26
+ key,
27
+ SENSITIVE_KEY_PATTERN.test(key) ? REDACTED : redactMCPDiagnosticValue(entry),
28
+ ]),
29
+ );
30
+ }
@@ -2,9 +2,18 @@ import * as fs from "node:fs/promises";
2
2
  import * as path from "node:path";
3
3
  import { isEnoent, logger } from "@sayknow-cli/utils";
4
4
  import { getAgentDir } from "@sayknow-cli/utils/dirs";
5
+ import { $credentialEnv } from "@sayknow-cli/utils/env";
5
6
 
6
7
  const SMITHERY_AUTH_FILENAME = "smithery.json";
7
- const SMITHERY_URL = process.env.SMITHERY_URL || "https://smithery.ai";
8
+ /**
9
+ * Smithery web origin, from trusted environment sources only.
10
+ *
11
+ * This origin serves the CLI auth session and the verification URL the user is
12
+ * sent to, so whatever can set it can drive the login flow. `$env` merges the
13
+ * caller's `cwd/.env` into `process.env`, so reading it there would let
14
+ * repository content redirect that flow.
15
+ */
16
+ const SMITHERY_URL = $credentialEnv("SMITHERY_URL") || "https://smithery.ai";
8
17
 
9
18
  type SmitheryCliAuthSession = {
10
19
  sessionId: string;
@@ -31,6 +40,11 @@ function normalizeApiKey(value: string | undefined): string | undefined {
31
40
  return trimmed.length > 0 ? trimmed : undefined;
32
41
  }
33
42
 
43
+ /** Test seam: the Smithery origin and env API key as resolved from trusted env. */
44
+ export function resolveSmitheryEnvForTest(): { url: string; apiKey: string | undefined } {
45
+ return { url: SMITHERY_URL, apiKey: normalizeApiKey($credentialEnv("SMITHERY_API_KEY")) };
46
+ }
47
+
34
48
  export function getSmitheryLoginUrl(): string {
35
49
  return SMITHERY_URL;
36
50
  }
@@ -62,7 +76,8 @@ export async function pollSmitheryCliAuthSession(
62
76
  }
63
77
 
64
78
  export async function getSmitheryApiKey(): Promise<string | undefined> {
65
- const envKey = normalizeApiKey(process.env.SMITHERY_API_KEY);
79
+ // Trusted sources only: this key authenticates every Smithery API call.
80
+ const envKey = normalizeApiKey($credentialEnv("SMITHERY_API_KEY"));
66
81
  if (envKey) return envKey;
67
82
 
68
83
  const authPath = getSmitheryAuthPath();
@@ -1,4 +1,14 @@
1
- const SMITHERY_API_BASE_URL = (process.env.SMITHERY_API_URL || "https://api.smithery.ai").replace(/\/+$/, "");
1
+ import { $credentialEnv } from "@sayknow-cli/utils/env";
2
+
3
+ /**
4
+ * Smithery API base, from trusted environment sources only.
5
+ *
6
+ * Every request to this base carries `Authorization: Bearer <apiKey>` and the
7
+ * `/connect` routes return the connection records the agent consumes, so
8
+ * whatever can set it receives the key and supplies those records. `$env` merges
9
+ * the caller's `cwd/.env` into `process.env`.
10
+ */
11
+ const SMITHERY_API_BASE_URL = ($credentialEnv("SMITHERY_API_URL") || "https://api.smithery.ai").replace(/\/+$/, "");
2
12
 
3
13
  export class SmitheryConnectError extends Error {
4
14
  status: number;