@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
@@ -1,3 +1,6 @@
1
+ import * as http from "node:http";
2
+ import * as https from "node:https";
3
+ import * as net from "node:net";
1
4
  import * as os from "node:os";
2
5
  import * as path from "node:path";
3
6
  import { getAntigravityUserAgent, getEnvApiKey, type Model } from "@sayknow-cli/ai";
@@ -23,22 +26,27 @@ import packageJson from "../../package.json" with { type: "json" };
23
26
  import { isAuthenticated, type ModelRegistry } from "../config/model-registry";
24
27
  import type { CustomTool } from "../extensibility/custom-tools/types";
25
28
  import imageGenDescription from "../prompts/tools/image-gen.md" with { type: "text" };
29
+ import { isPrivateOrSpecialAddress, validatePublicHttpUrl } from "../web/insane/url-guard";
26
30
  import { resolveReadPath } from "./path-utils";
27
31
 
28
32
  const DEFAULT_MODEL = "gemini-3-pro-image-preview";
29
- const DEFAULT_OPENROUTER_MODEL = "google/gemini-3-pro-image-preview";
30
- const DEFAULT_ANTIGRAVITY_MODEL = "gemini-3-pro-image";
31
33
  const IMAGE_TIMEOUT = 3 * 60 * 1000; // 3 minutes
32
34
  const MAX_IMAGE_SIZE = 35 * 1024 * 1024;
35
+ const MAX_IMAGE_REDIRECTS = 5;
36
+ const MAX_IMAGE_HEADER_SIZE = 16 * 1024;
37
+ const MAX_IMAGE_ERROR_PREVIEW_SIZE = 8 * 1024;
38
+ const IMAGE_REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
33
39
  const DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
34
40
  const OPENAI_IMAGE_OUTPUT_FORMAT = "webp";
35
41
  const OPENAI_IMAGE_MIME_TYPE = "image/webp";
36
42
 
37
43
  const ANTIGRAVITY_ENDPOINT = "https://daily-cloudcode-pa.sandbox.googleapis.com";
44
+ const ALIBABA_TOKEN_PLAN_HOST = "https://token-plan.ap-southeast-1.maas.aliyuncs.com";
45
+ const ALIBABA_IMAGE_GENERATION_URL = `${ALIBABA_TOKEN_PLAN_HOST}/api/v1/services/aigc/multimodal-generation/generation`;
38
46
  const IMAGE_SYSTEM_INSTRUCTION =
39
47
  "You are an AI image generator. Generate images based on user descriptions. Focus on creating high-quality, visually appealing images that match the user's request.";
40
48
 
41
- type ImageProvider = "antigravity" | "gemini" | "openai" | "openai-codex" | "openrouter";
49
+ type ImageProvider = "alibaba" | "antigravity" | "gemini" | "openai" | "openai-codex" | "openrouter";
42
50
  interface ImageApiKey {
43
51
  provider: ImageProvider;
44
52
  apiKey: string;
@@ -290,6 +298,81 @@ interface AntigravityResponseChunk {
290
298
  };
291
299
  }
292
300
 
301
+ interface AlibabaImageContentPart {
302
+ type?: string;
303
+ text?: string;
304
+ image?: string;
305
+ }
306
+
307
+ interface AlibabaImageResponse {
308
+ code?: string;
309
+ message?: string;
310
+ output?: {
311
+ choices?: Array<{ message?: { content?: AlibabaImageContentPart[] } }>;
312
+ };
313
+ }
314
+
315
+ /** Map the tool's image_size values onto wan2.7's 1K/2K size classes. */
316
+ export function resolveAlibabaImageSize(imageSize: string | undefined): string | undefined {
317
+ switch (imageSize) {
318
+ case "1024x1024":
319
+ return "1K";
320
+ case "1536x1024":
321
+ case "1024x1536":
322
+ return "2K";
323
+ default:
324
+ return undefined;
325
+ }
326
+ }
327
+
328
+ /**
329
+ * Build the Bailian multimodal-generation request body for wan2.7 image
330
+ * generation/editing. Input images ride along as data URLs; generation-only
331
+ * calls send just the prompt text. The sync endpoint returns OSS URLs inline.
332
+ */
333
+ export function buildAlibabaImageRequest(
334
+ model: string,
335
+ promptText: string,
336
+ inputImages: InlineImageData[],
337
+ imageSize: string | undefined,
338
+ ): {
339
+ model: string;
340
+ input: { messages: Array<{ role: "user"; content: Array<{ text: string } | { image: string }> }> };
341
+ parameters: { n: number; watermark: boolean; size?: string };
342
+ } {
343
+ const content: Array<{ text: string } | { image: string }> = [];
344
+ for (const image of inputImages) {
345
+ content.push({ image: toDataUrl(image) });
346
+ }
347
+ content.push({ text: promptText });
348
+ const size = resolveAlibabaImageSize(imageSize);
349
+ return {
350
+ model,
351
+ input: { messages: [{ role: "user", content }] },
352
+ parameters: { n: 1, watermark: false, ...(size ? { size } : {}) },
353
+ };
354
+ }
355
+
356
+ /** Collect OSS image URLs and any text parts from a Bailian image response. */
357
+ export function collectAlibabaImageResult(response: AlibabaImageResponse): {
358
+ imageUrls: string[];
359
+ responseText?: string;
360
+ } {
361
+ const imageUrls: string[] = [];
362
+ const textParts: string[] = [];
363
+ for (const choice of response.output?.choices ?? []) {
364
+ for (const part of choice.message?.content ?? []) {
365
+ if (part.image) {
366
+ imageUrls.push(part.image);
367
+ } else if (part.text) {
368
+ textParts.push(part.text);
369
+ }
370
+ }
371
+ }
372
+ const responseText = textParts.join("\n").trim();
373
+ return { imageUrls, responseText: responseText.length > 0 ? responseText : undefined };
374
+ }
375
+
293
376
  interface ImageGenToolDetails {
294
377
  provider: ImageProvider;
295
378
  model: string;
@@ -327,6 +410,160 @@ function toDataUrl(image: InlineImageData): string {
327
410
  return `data:${image.mimeType};base64,${image.data}`;
328
411
  }
329
412
 
413
+ function withAbortSignal<T>(operation: Promise<T>, signal: AbortSignal | undefined): Promise<T> {
414
+ if (!signal) return operation;
415
+ if (signal.aborted) return Promise.reject(signal.reason);
416
+ const deferred = Promise.withResolvers<T>();
417
+ const abort = () => deferred.reject(signal.reason);
418
+ signal.addEventListener("abort", abort, { once: true });
419
+ operation.then(deferred.resolve, deferred.reject).finally(() => signal.removeEventListener("abort", abort));
420
+ return deferred.promise;
421
+ }
422
+
423
+ function normalizePeerAddress(address: string): string {
424
+ const normalized = address.toLowerCase();
425
+ return normalized.startsWith("::ffff:") ? normalized.slice(7) : normalized;
426
+ }
427
+
428
+ function normalizeUrlHostname(hostname: string): string {
429
+ return hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
430
+ }
431
+
432
+ function responseHeaderByteLength(response: http.IncomingMessage): number {
433
+ let bytes = Buffer.byteLength(
434
+ `HTTP/${response.httpVersion} ${response.statusCode ?? ""}${response.statusMessage ? ` ${response.statusMessage}` : ""}\r\n`,
435
+ );
436
+ for (let index = 0; index < response.rawHeaders.length; index += 2) {
437
+ bytes += Buffer.byteLength(`${response.rawHeaders[index] ?? ""}: ${response.rawHeaders[index + 1] ?? ""}\r\n`);
438
+ }
439
+ return bytes + Buffer.byteLength("\r\n");
440
+ }
441
+
442
+ async function validateImageUrl(rawUrl: string, signal: AbortSignal | undefined) {
443
+ return withAbortSignal(validatePublicHttpUrl(rawUrl), signal);
444
+ }
445
+
446
+ function openImageResponse(
447
+ url: URL,
448
+ addresses: string[],
449
+ signal: AbortSignal | undefined,
450
+ ): Promise<http.IncomingMessage> {
451
+ const hostname = normalizeUrlHostname(url.hostname);
452
+ const approved = addresses.map(address => ({ address, family: net.isIP(address) }));
453
+ const approvedPeers = new Set(approved.map(record => normalizePeerAddress(record.address)));
454
+ const lookup: net.LookupFunction = (requestedHostname, options, callback) => {
455
+ const requestedFamily = options.family === "IPv4" ? 4 : options.family === "IPv6" ? 6 : (options.family ?? 0);
456
+ const matching = approved.filter(record => requestedFamily === 0 || record.family === requestedFamily);
457
+ if (normalizeUrlHostname(requestedHostname) !== hostname || matching.length === 0) {
458
+ const error = Object.assign(new Error("No approved address for image host"), { code: "ENOTFOUND" });
459
+ callback(error, options.all ? [] : "", 0);
460
+ return;
461
+ }
462
+ if (options.all) callback(null, matching);
463
+ else callback(null, matching[0].address, matching[0].family);
464
+ };
465
+ const deferred = Promise.withResolvers<http.IncomingMessage>();
466
+ const options: https.RequestOptions = {
467
+ protocol: url.protocol,
468
+ hostname,
469
+ port: url.port || undefined,
470
+ path: `${url.pathname}${url.search}`,
471
+ method: "GET",
472
+ headers: { Accept: "image/*", "Accept-Encoding": "identity", Connection: "close", Host: url.host },
473
+ agent: false,
474
+ insecureHTTPParser: false,
475
+ lookup,
476
+ maxHeaderSize: MAX_IMAGE_HEADER_SIZE,
477
+ signal,
478
+ ...(url.protocol === "https:"
479
+ ? { rejectUnauthorized: true, servername: net.isIP(hostname) === 0 ? hostname : undefined }
480
+ : {}),
481
+ };
482
+ const requestFn = url.protocol === "https:" ? https.request : http.request;
483
+ const request = requestFn(options, response => {
484
+ if (responseHeaderByteLength(response) > MAX_IMAGE_HEADER_SIZE) {
485
+ response.destroy();
486
+ deferred.reject(new Error("Image response headers exceed the maximum size of 16 KiB"));
487
+ return;
488
+ }
489
+ const peer = response.socket.remoteAddress;
490
+ if (peer && (isPrivateOrSpecialAddress(peer) || !approvedPeers.has(normalizePeerAddress(peer)))) {
491
+ response.destroy();
492
+ deferred.reject(new Error("Refusing image response from an unapproved connected peer"));
493
+ return;
494
+ }
495
+ deferred.resolve(response);
496
+ });
497
+ request.once("error", deferred.reject);
498
+ const abort = () => {
499
+ request.destroy(signal?.reason);
500
+ deferred.reject(signal?.reason);
501
+ };
502
+ if (signal?.aborted) abort();
503
+ else signal?.addEventListener("abort", abort, { once: true });
504
+ request.once("close", () => signal?.removeEventListener("abort", abort));
505
+ request.end();
506
+ return deferred.promise;
507
+ }
508
+
509
+ function validateImageResponseFraming(response: http.IncomingMessage): void {
510
+ const rawContentLengths: string[] = [];
511
+ let hasTransferEncoding = false;
512
+ for (let index = 0; index < response.rawHeaders.length; index += 2) {
513
+ const name = response.rawHeaders[index]?.toLowerCase();
514
+ if (name === "content-length") rawContentLengths.push(response.rawHeaders[index + 1] ?? "");
515
+ if (name === "transfer-encoding") hasTransferEncoding = true;
516
+ }
517
+ if (rawContentLengths.length > 1 || (rawContentLengths.length > 0 && hasTransferEncoding)) {
518
+ response.destroy();
519
+ throw new Error("Image response has ambiguous framing");
520
+ }
521
+ const contentLength = response.headers["content-length"];
522
+ if (contentLength === undefined) return;
523
+ const declaredBytes = typeof contentLength === "string" && /^\d+$/.test(contentLength) ? Number(contentLength) : NaN;
524
+ if (!Number.isSafeInteger(declaredBytes)) {
525
+ response.destroy();
526
+ throw new Error("Image response has an invalid Content-Length");
527
+ }
528
+ if (declaredBytes > MAX_IMAGE_SIZE) {
529
+ response.destroy();
530
+ throw new Error("Image response exceeds the maximum size of 35 MiB");
531
+ }
532
+ }
533
+
534
+ async function readImageResponse(
535
+ response: http.IncomingMessage,
536
+ maxBytes: number,
537
+ signal: AbortSignal | undefined,
538
+ ): Promise<Buffer> {
539
+ const abort = () => response.destroy(signal?.reason);
540
+ if (signal?.aborted) {
541
+ abort();
542
+ throw signal.reason;
543
+ }
544
+ signal?.addEventListener("abort", abort, { once: true });
545
+ const chunks: Buffer[] = [];
546
+ let receivedBytes = 0;
547
+ try {
548
+ for await (const chunk of response) {
549
+ const bytes = Buffer.from(chunk);
550
+ receivedBytes += bytes.byteLength;
551
+ if (receivedBytes > maxBytes) {
552
+ response.destroy();
553
+ throw new Error(
554
+ maxBytes === MAX_IMAGE_SIZE
555
+ ? "Image response exceeds the maximum size of 35 MiB"
556
+ : "Image download error response exceeded the preview limit",
557
+ );
558
+ }
559
+ chunks.push(bytes);
560
+ }
561
+ return Buffer.concat(chunks, receivedBytes);
562
+ } finally {
563
+ signal?.removeEventListener("abort", abort);
564
+ }
565
+ }
566
+
330
567
  async function loadImageFromUrl(imageUrl: string, signal?: AbortSignal): Promise<InlineImageData> {
331
568
  if (imageUrl.startsWith("data:")) {
332
569
  const normalized = normalizeDataUrl(imageUrl.trim());
@@ -339,17 +576,40 @@ async function loadImageFromUrl(imageUrl: string, signal?: AbortSignal): Promise
339
576
  return { data: normalized.data, mimeType: normalized.mimeType };
340
577
  }
341
578
 
342
- const response = await fetch(imageUrl, { signal });
343
- if (!response.ok) {
344
- const rawText = await response.text();
345
- throw new Error(`Image download failed (${response.status}): ${rawText}`);
346
- }
347
- const contentType = response.headers.get("content-type")?.split(";")[0];
348
- if (!contentType?.startsWith("image/")) {
349
- throw new Error(`Unsupported image type from URL: ${imageUrl}`);
579
+ let currentUrl = imageUrl;
580
+ for (let redirectCount = 0; ; redirectCount++) {
581
+ const guard = await validateImageUrl(currentUrl, signal);
582
+ if (!guard.ok) {
583
+ throw new Error(`Refusing image URL: target URL is not public HTTP(S): ${guard.reason}`);
584
+ }
585
+ const response = await openImageResponse(guard.url, guard.addresses, signal);
586
+ const status = response.statusCode ?? 0;
587
+ if (IMAGE_REDIRECT_STATUSES.has(status)) {
588
+ if (redirectCount >= MAX_IMAGE_REDIRECTS) {
589
+ response.destroy();
590
+ throw new Error("Too many redirects downloading image");
591
+ }
592
+ const location = response.headers.location;
593
+ response.destroy();
594
+ if (!location) throw new Error("Image redirect is missing a Location header");
595
+ currentUrl = new URL(location, guard.url).toString();
596
+ continue;
597
+ }
598
+ validateImageResponseFraming(response);
599
+ if (status < 200 || status >= 300) {
600
+ const preview = (await readImageResponse(response, MAX_IMAGE_ERROR_PREVIEW_SIZE, signal)).toString("utf8");
601
+ throw new Error(`Image download failed (${status}): ${preview}`);
602
+ }
603
+ const rawContentType = response.headers["content-type"];
604
+ const contentType =
605
+ typeof rawContentType === "string" ? rawContentType.split(";", 1)[0]?.trim().toLowerCase() : undefined;
606
+ if (!contentType?.startsWith("image/")) {
607
+ response.destroy();
608
+ throw new Error("Image response is missing a supported image Content-Type");
609
+ }
610
+ const buffer = await readImageResponse(response, MAX_IMAGE_SIZE, signal);
611
+ return { data: buffer.toBase64(), mimeType: contentType };
350
612
  }
351
- const buffer = await response.bytes();
352
- return { data: buffer.toBase64(), mimeType: contentType };
353
613
  }
354
614
 
355
615
  function collectOpenRouterResponseText(message: OpenRouterMessage | undefined): string | undefined {
@@ -399,6 +659,50 @@ export function setPreferredImageProvider(provider: ImageProvider | "auto"): voi
399
659
  preferredImageProvider = provider;
400
660
  }
401
661
 
662
+ /** Provider → default image model mapping for auto-binding */
663
+ export const IMAGE_PROVIDER_DEFAULTS: Record<string, string> = {
664
+ openai: "gpt-image-2",
665
+ alibaba: "wan2.7-image",
666
+ "openai-codex": "gpt-image-2",
667
+ antigravity: "gemini-3-pro-image",
668
+ gemini: "gemini-3-pro-image-preview",
669
+ openrouter: "google/gemini-3-pro-image-preview",
670
+ };
671
+
672
+ /** Resolved image generation configuration from settings */
673
+ export interface ImageProviderConfig {
674
+ provider: ImageProvider | "auto" | "custom";
675
+ model: string | null;
676
+ customUrl?: string;
677
+ customKey?: string;
678
+ customKeyEnv?: string;
679
+ }
680
+
681
+ /** Module-level configured image model state (set from settings at session init) */
682
+ let configuredImageConfig: ImageProviderConfig | null = null;
683
+
684
+ /** Set the configured image provider + model from settings */
685
+ export function setConfiguredImageModel(config: ImageProviderConfig | null): void {
686
+ configuredImageConfig = config;
687
+ // Keep preferredImageProvider in sync for backward compat
688
+ if (config && config.provider !== "auto" && config.provider !== "custom") {
689
+ preferredImageProvider = config.provider;
690
+ } else if (!config || config.provider === "auto") {
691
+ preferredImageProvider = "auto";
692
+ }
693
+ }
694
+
695
+ /** Get the current configured image model (for UI display) */
696
+ export function getConfiguredImageModel(): ImageProviderConfig | null {
697
+ return configuredImageConfig;
698
+ }
699
+
700
+ /** Resolve the effective image model for a configured provider */
701
+ export function resolveImageModel(provider: string, modelOverride: string | null): string {
702
+ if (modelOverride) return modelOverride;
703
+ return IMAGE_PROVIDER_DEFAULTS[provider] ?? DEFAULT_MODEL;
704
+ }
705
+
402
706
  interface ParsedAntigravityCredentials {
403
707
  accessToken: string;
404
708
  projectId?: string;
@@ -420,6 +724,22 @@ function parseAntigravityCredentials(raw: string): ParsedAntigravityCredentials
420
724
  return rawToken.length > 0 ? { accessToken: rawToken } : null;
421
725
  }
422
726
 
727
+ function createCustomImageModel(baseUrl: string, id: string): Model<"openai-responses"> {
728
+ return {
729
+ id,
730
+ name: id,
731
+ api: "openai-responses",
732
+ provider: "openai",
733
+ baseUrl: baseUrl.replace(/\/+$/, ""),
734
+ reasoning: false,
735
+ input: ["text"],
736
+ output: ["text", "image"],
737
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
738
+ contextWindow: 128_000,
739
+ maxTokens: 16_384,
740
+ };
741
+ }
742
+
423
743
  async function findAntigravityCredentials(
424
744
  modelRegistry: ModelRegistry,
425
745
  sessionId?: string,
@@ -462,12 +782,64 @@ async function findOpenAIHostedImageCredentials(
462
782
  };
463
783
  }
464
784
 
785
+ async function findAlibabaImageCredentials(
786
+ modelRegistry: ModelRegistry | undefined,
787
+ sessionId?: string,
788
+ ): Promise<ImageApiKey | null> {
789
+ const envKey = getEnvApiKey("alibaba-token-plan");
790
+ if (envKey) return { provider: "alibaba", apiKey: envKey };
791
+ if (!modelRegistry) return null;
792
+ const apiKey = await modelRegistry.getApiKeyForProvider("alibaba-token-plan", sessionId);
793
+ if (!isAuthenticated(apiKey)) return null;
794
+ return { provider: "alibaba", apiKey };
795
+ }
796
+
465
797
  async function findImageApiKey(
466
798
  modelRegistry?: ModelRegistry,
467
799
  activeModel?: Model,
468
800
  sessionId?: string,
469
801
  ): Promise<ImageApiKey | null> {
470
- // If a specific provider is preferred, try it first.
802
+ // Config-driven routing: if an explicit provider+model is configured, use it.
803
+ if (configuredImageConfig && configuredImageConfig.provider !== "auto") {
804
+ const config = configuredImageConfig;
805
+ if (config.provider === "custom") {
806
+ const baseUrl = config.customUrl?.trim();
807
+ const apiKey = config.customKey ?? (config.customKeyEnv ? Bun.env[config.customKeyEnv] : undefined);
808
+ if (baseUrl && apiKey) {
809
+ return {
810
+ provider: "openai",
811
+ apiKey,
812
+ model: createCustomImageModel(baseUrl, config.model ?? IMAGE_PROVIDER_DEFAULTS.openai),
813
+ };
814
+ }
815
+ return null;
816
+ }
817
+ // For configured providers, resolve credentials through the existing paths.
818
+ if (config.provider === "openai" || config.provider === "openai-codex") {
819
+ const openAI = await findOpenAIHostedImageCredentials(modelRegistry, activeModel, sessionId);
820
+ if (openAI) return openAI;
821
+ return null;
822
+ }
823
+ if (config.provider === "antigravity") {
824
+ if (!modelRegistry) return null;
825
+ return await findAntigravityCredentials(modelRegistry, sessionId);
826
+ }
827
+ if (config.provider === "gemini") {
828
+ const geminiKey = getEnvApiKey("google");
829
+ if (geminiKey) return { provider: "gemini", apiKey: geminiKey };
830
+ const googleKey = $env.GOOGLE_API_KEY;
831
+ return googleKey ? { provider: "gemini", apiKey: googleKey } : null;
832
+ }
833
+ if (config.provider === "openrouter") {
834
+ const openRouterKey = getEnvApiKey("openrouter");
835
+ return openRouterKey ? { provider: "openrouter", apiKey: openRouterKey } : null;
836
+ }
837
+ if (config.provider === "alibaba") {
838
+ return await findAlibabaImageCredentials(modelRegistry, sessionId);
839
+ }
840
+ }
841
+
842
+ // If a specific provider is preferred (legacy path), try it first.
471
843
  if (preferredImageProvider === "openai") {
472
844
  const openAI = await findOpenAIHostedImageCredentials(modelRegistry, activeModel, sessionId);
473
845
  if (openAI) return openAI;
@@ -483,9 +855,11 @@ async function findImageApiKey(
483
855
  } else if (preferredImageProvider === "openrouter") {
484
856
  const openRouterKey = getEnvApiKey("openrouter");
485
857
  return openRouterKey ? { provider: "openrouter", apiKey: openRouterKey } : null;
858
+ } else if (preferredImageProvider === "alibaba") {
859
+ return await findAlibabaImageCredentials(modelRegistry, sessionId);
486
860
  }
487
861
 
488
- // Auto-detect: GPT hosted image generation, then Antigravity, OpenRouter, Gemini.
862
+ // Auto-detect: GPT hosted image generation, then Antigravity, OpenRouter, Gemini, Alibaba.
489
863
  const openAI = await findOpenAIHostedImageCredentials(modelRegistry, activeModel, sessionId);
490
864
  if (openAI) return openAI;
491
865
 
@@ -503,6 +877,9 @@ async function findImageApiKey(
503
877
  const googleKey = $env.GOOGLE_API_KEY;
504
878
  if (googleKey) return { provider: "gemini", apiKey: googleKey };
505
879
 
880
+ const alibaba = await findAlibabaImageCredentials(modelRegistry, sessionId);
881
+ if (alibaba) return alibaba;
882
+
506
883
  return null;
507
884
  }
508
885
 
@@ -939,19 +1316,23 @@ export const imageGenTool: CustomTool<typeof imageGenSchema, ImageGenToolDetails
939
1316
  const apiKey = await findImageApiKey(ctx.modelRegistry, ctx.model, sessionId);
940
1317
  if (!apiKey) {
941
1318
  throw new Error(
942
- "No image API credentials found. Use a GPT Responses/Codex model with OpenAI credentials, login with google-antigravity, or set OPENROUTER_API_KEY, GEMINI_API_KEY, or GOOGLE_API_KEY.",
1319
+ "No image API credentials found. Use a GPT Responses/Codex model with OpenAI credentials, login with google-antigravity, or set OPENROUTER_API_KEY, GEMINI_API_KEY, GOOGLE_API_KEY, or ALIBABA_TOKEN_PLAN_API_KEY.",
943
1320
  );
944
1321
  }
945
1322
 
946
1323
  const provider = apiKey.provider;
947
1324
  const model =
948
- provider === "openai" || provider === "openai-codex"
949
- ? (apiKey.model?.id ?? "gpt")
950
- : provider === "antigravity"
951
- ? DEFAULT_ANTIGRAVITY_MODEL
952
- : provider === "openrouter"
953
- ? DEFAULT_OPENROUTER_MODEL
954
- : DEFAULT_MODEL;
1325
+ configuredImageConfig && configuredImageConfig.provider !== "auto" && configuredImageConfig.model
1326
+ ? configuredImageConfig.model
1327
+ : provider === "openai" || provider === "openai-codex"
1328
+ ? (apiKey.model?.id ?? resolveImageModel(provider, null))
1329
+ : provider === "antigravity"
1330
+ ? resolveImageModel("antigravity", null)
1331
+ : provider === "alibaba"
1332
+ ? resolveImageModel("alibaba", null)
1333
+ : provider === "openrouter"
1334
+ ? resolveImageModel("openrouter", null)
1335
+ : resolveImageModel("gemini", null);
955
1336
  const resolvedModel = provider === "openrouter" ? resolveOpenRouterModel(model) : model;
956
1337
  const cwd = ctx.sessionManager.getCwd();
957
1338
 
@@ -1169,6 +1550,78 @@ export const imageGenTool: CustomTool<typeof imageGenSchema, ImageGenToolDetails
1169
1550
  };
1170
1551
  }
1171
1552
 
1553
+ if (provider === "alibaba") {
1554
+ const requestBody = buildAlibabaImageRequest(
1555
+ model,
1556
+ assemblePrompt(params),
1557
+ resolvedImages,
1558
+ params.image_size,
1559
+ );
1560
+
1561
+ const response = await fetch(ALIBABA_IMAGE_GENERATION_URL, {
1562
+ method: "POST",
1563
+ headers: {
1564
+ "Content-Type": "application/json",
1565
+ Authorization: `Bearer ${apiKey.apiKey}`,
1566
+ },
1567
+ body: JSON.stringify(requestBody),
1568
+ signal: requestSignal,
1569
+ });
1570
+
1571
+ const rawText = await response.text();
1572
+ if (!response.ok) {
1573
+ let message = rawText;
1574
+ try {
1575
+ const parsed = JSON.parse(rawText) as { message?: string; error?: { message?: string } };
1576
+ message = parsed.error?.message ?? parsed.message ?? message;
1577
+ } catch {
1578
+ // Keep raw text.
1579
+ }
1580
+ throw new Error(`Alibaba image request failed (${response.status}): ${message}`);
1581
+ }
1582
+
1583
+ const data = JSON.parse(rawText) as AlibabaImageResponse;
1584
+ if (data.code) {
1585
+ throw new Error(`Alibaba image request failed: ${data.code}: ${data.message ?? ""}`.trim());
1586
+ }
1587
+
1588
+ const { imageUrls, responseText } = collectAlibabaImageResult(data);
1589
+ // Result URLs are short-lived OSS-signed URLs (24h); download immediately.
1590
+ const inlineImages: InlineImageData[] = [];
1591
+ for (const imageUrl of imageUrls) {
1592
+ inlineImages.push(await loadImageFromUrl(imageUrl, requestSignal));
1593
+ }
1594
+
1595
+ if (inlineImages.length === 0) {
1596
+ const messageText = responseText ? `\n\n${responseText}` : "";
1597
+ return {
1598
+ content: [{ type: "text", text: `No image data returned.${messageText}` }],
1599
+ details: {
1600
+ provider,
1601
+ model,
1602
+ imageCount: 0,
1603
+ imagePaths: [],
1604
+ images: [],
1605
+ responseText,
1606
+ },
1607
+ };
1608
+ }
1609
+
1610
+ const imagePaths = await saveImagesToTemp(inlineImages);
1611
+
1612
+ return {
1613
+ content: [{ type: "text", text: buildResponseSummary(provider, model, imagePaths, responseText) }],
1614
+ details: {
1615
+ provider,
1616
+ model,
1617
+ imageCount: inlineImages.length,
1618
+ imagePaths,
1619
+ images: inlineImages,
1620
+ responseText,
1621
+ },
1622
+ };
1623
+ }
1624
+
1172
1625
  const parts = [] as Array<{ text?: string; inlineData?: InlineImageData }>;
1173
1626
  for (const image of resolvedImages) {
1174
1627
  parts.push({ inlineData: image });
@@ -137,6 +137,8 @@ export interface AskAnswerRequest {
137
137
  options: string[];
138
138
  interaction: "selector" | "custom_editor" | "clarification_editor";
139
139
  controls: readonly AskRemoteControl[];
140
+ /** Optional zero-based recommendation into the authoritative raw options. */
141
+ recommendedIndex?: number;
140
142
  }
141
143
 
142
144
  export type AskRemoteInteraction =
@@ -232,6 +234,8 @@ export interface ToolSession {
232
234
  * its terminal-phase chain guard. Returns the raw phase string or undefined
233
235
  * when no active skill (or accessor) is available. */
234
236
  getActiveSkillPhase?: () => string | undefined;
237
+ /** Restrict provider-facing deep-interview ask metadata to the active workflow stage. */
238
+ getDeepInterviewAskStage?: () => "topology" | "post-topology" | undefined;
235
239
  /** Pre-loaded prompt templates */
236
240
  promptTemplates?: PromptTemplate[];
237
241
  /** Whether LSP integrations are enabled */
@@ -271,9 +275,11 @@ export interface ToolSession {
271
275
  /** Agent identity used for IRC routing. Returns the registry id (e.g. "0-Main", "0-AuthLoader"). */
272
276
  getAgentId?: () => string | null;
273
277
  /** Look up a registered tool by name (used by the eval js backend's tool bridge). */
278
+ getToolByName?: (name: string) => AgentTool | undefined;
279
+ /** Look up a registered tool with the session's execution guards applied. */
280
+ getToolForExecution?: (name: string) => AgentTool | undefined;
274
281
  /** Purge undelivered queued custom messages matching the predicate. Returns counts. */
275
282
  purgeQueuedCustomMessages?: (predicate: (message: CustomMessage) => boolean) => PurgeQueuedCustomMessagesResult;
276
- getToolByName?: (name: string) => AgentTool | undefined;
277
283
  /** Agent registry for IRC routing across live sessions. */
278
284
  agentRegistry?: AgentRegistry;
279
285
  /** Optional restricted bash command prefixes for read-only role agents and constrained modes. */