@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
@@ -149,6 +149,19 @@ async function assertDirectoryNotSymlink(directoryPath: string): Promise<void> {
149
149
  const LEGACY_MIGRATION_MARKER = ".skc-local-legacy-migrated-v1";
150
150
  const MAX_LEGACY_LOCAL_BYTES = 64 * 1024 * 1024;
151
151
 
152
+ type LegacyMigrationState = "complete" | "cleanup_pending";
153
+
154
+ /**
155
+ * Marker values that mean legacy migration has settled for this root and the
156
+ * synchronous resolver may proceed. `cleanup_pending` counts: the entries are
157
+ * installed and content-verified, and only retirement of the legacy source is
158
+ * outstanding. Must stay in sync with {@link readMigrationMarker}, which the
159
+ * async gate uses to decide the same question.
160
+ */
161
+ function isSettledMigrationMarkerValue(value: string): boolean {
162
+ return value === "verified\n" || value === "absent\n" || value === "cleanup_pending\n";
163
+ }
164
+
152
165
  interface LegacyEntrySnapshot {
153
166
  readonly relativePath: string;
154
167
  readonly dev: bigint;
@@ -173,6 +186,26 @@ async function snapshotDirectory(directoryPath: string, relativePath: string): P
173
186
  return { relativePath, dev: stat.dev, ino: stat.ino, size: stat.size };
174
187
  }
175
188
 
189
+ interface CanonicalLegacyRoot {
190
+ readonly root: string;
191
+ readonly identity: LegacyEntrySnapshot;
192
+ }
193
+
194
+ async function canonicalLegacyRoot(artifactsDir: string): Promise<CanonicalLegacyRoot> {
195
+ const lexicalRoot = path.resolve(artifactsDir, "local");
196
+ const lexicalIdentity = await snapshotDirectory(lexicalRoot, "");
197
+ const [canonicalArtifactsDir, canonicalRoot] = await Promise.all([
198
+ fs.realpath(path.resolve(artifactsDir)),
199
+ fs.realpath(lexicalRoot),
200
+ ]);
201
+ if (canonicalRoot === canonicalArtifactsDir) throw new Error("Unsafe legacy local:// migration source");
202
+ ensureWithinRoot(canonicalRoot, canonicalArtifactsDir);
203
+ const canonicalIdentity = await snapshotDirectory(canonicalRoot, "");
204
+ if (!matchesSnapshot(canonicalIdentity, lexicalIdentity))
205
+ throw new Error("Legacy local:// migration source changed during capture");
206
+ return { root: canonicalRoot, identity: lexicalIdentity };
207
+ }
208
+
176
209
  async function snapshotRegularFile(filePath: string, relativePath: string): Promise<LegacyEntrySnapshot> {
177
210
  const before = await fs.lstat(filePath, { bigint: true });
178
211
  if (!before.isFile() || before.isSymbolicLink()) throw new Error("Unsafe legacy local:// migration source");
@@ -206,11 +239,16 @@ function manifestsMatch(left: readonly LegacyEntrySnapshot[], right: readonly Le
206
239
  );
207
240
  }
208
241
 
209
- async function captureLegacyManifest(root: string): Promise<readonly LegacyEntrySnapshot[]> {
242
+ async function captureLegacyManifest(
243
+ root: string,
244
+ expectedRootIdentity: LegacyEntrySnapshot,
245
+ ): Promise<readonly LegacyEntrySnapshot[]> {
210
246
  const manifest: LegacyEntrySnapshot[] = [];
211
247
  let copiedBytes = 0n;
212
248
  const captureDirectory = async (directoryPath: string, relativePath: string): Promise<void> => {
213
249
  const directory = await snapshotDirectory(directoryPath, relativePath);
250
+ if (relativePath === "" && !matchesSnapshot(directory, expectedRootIdentity))
251
+ throw new Error("Legacy local:// migration source changed during capture");
214
252
  manifest.push(directory);
215
253
  const entries = (await fs.readdir(directoryPath, { withFileTypes: true })).sort((a, b) =>
216
254
  a.name.localeCompare(b.name),
@@ -313,7 +351,7 @@ async function migrateManagedLegacyLocal(
313
351
  }
314
352
  const staging = path.join(scratchParent, `.skc-local-migration-${randomUUID()}`);
315
353
  const installed: Array<{ readonly path: string; readonly dev: bigint; readonly ino: bigint }> = [];
316
- let installedMarker: { readonly dev: bigint; readonly ino: bigint } | null = null;
354
+ let sourceRetired = false;
317
355
  try {
318
356
  await fs.mkdir(staging, { mode: 0o700 });
319
357
  for (const entry of captured.entries) {
@@ -327,7 +365,7 @@ async function migrateManagedLegacyLocal(
327
365
  throw new Error("Legacy local:// migration destination verification failed");
328
366
  }
329
367
  }
330
- for (const entry of await fs.readdir(staging)) {
368
+ for (const entry of (await fs.readdir(staging)).sort()) {
331
369
  const destination = path.join(localRoot, entry);
332
370
  try {
333
371
  await fs.lstat(destination);
@@ -339,18 +377,22 @@ async function migrateManagedLegacyLocal(
339
377
  const identity = await fs.lstat(destination, { bigint: true });
340
378
  installed.push({ path: destination, dev: identity.dev, ino: identity.ino });
341
379
  }
380
+ try {
381
+ source.retire(captured.snapshot);
382
+ sourceRetired = true;
383
+ } catch (error) {
384
+ if (!(error instanceof Error) || error.message !== "cleanup_pending") throw error;
385
+ await fs.writeFile(marker, "cleanup_pending\n", { mode: 0o600, flag: "wx" });
386
+ return;
387
+ }
342
388
  await fs.writeFile(marker, "verified\n", { mode: 0o600, flag: "wx" });
343
- const markerIdentity = await fs.lstat(marker, { bigint: true });
344
- installedMarker = { dev: markerIdentity.dev, ino: markerIdentity.ino };
345
- source.retire(captured.snapshot);
346
389
  } catch (error) {
347
- const currentMarker = await fs.lstat(marker, { bigint: true }).catch(() => null);
348
- if (installedMarker && currentMarker?.dev === installedMarker.dev && currentMarker.ino === installedMarker.ino)
349
- await fs.rm(marker, { force: true });
350
- for (const destination of installed.reverse()) {
351
- const current = await fs.lstat(destination.path, { bigint: true }).catch(() => null);
352
- if (current?.dev === destination.dev && current.ino === destination.ino)
353
- await fs.rm(destination.path, { recursive: true, force: true });
390
+ if (!sourceRetired) {
391
+ for (const destination of installed.reverse()) {
392
+ const current = await fs.lstat(destination.path, { bigint: true }).catch(() => null);
393
+ if (current?.dev === destination.dev && current.ino === destination.ino)
394
+ await fs.rm(destination.path, { recursive: true, force: true });
395
+ }
354
396
  }
355
397
  throw error;
356
398
  } finally {
@@ -358,15 +400,16 @@ async function migrateManagedLegacyLocal(
358
400
  }
359
401
  }
360
402
 
361
- async function readMigrationMarker(marker: string): Promise<boolean> {
403
+ async function readMigrationMarker(marker: string): Promise<LegacyMigrationState | null> {
362
404
  try {
363
405
  const snapshot = await snapshotRegularFile(marker, LEGACY_MIGRATION_MARKER);
364
406
  if (snapshot.size > 32n || snapshot.bytes === undefined) throw new Error("Unsafe local:// migration marker");
365
407
  const value = snapshot.bytes.toString("utf8");
366
- if (value !== "verified\n" && value !== "absent\n") throw new Error("Unsafe local:// migration marker");
367
- return true;
408
+ if (value === "cleanup_pending\n") return "cleanup_pending";
409
+ if (value === "verified\n" || value === "absent\n") return "complete";
410
+ throw new Error("Unsafe local:// migration marker");
368
411
  } catch (error) {
369
- if (isEnoent(error)) return false;
412
+ if (isEnoent(error)) return null;
370
413
  throw error;
371
414
  }
372
415
  }
@@ -388,10 +431,11 @@ async function migrateLegacyLocal(
388
431
  await fs.writeFile(marker, "absent\n", { mode: 0o600, flag: "wx" });
389
432
  return;
390
433
  }
391
- const legacyRoot = path.resolve(artifactsDir, "local");
434
+ let legacySource: CanonicalLegacyRoot;
392
435
  let manifest: readonly LegacyEntrySnapshot[];
393
436
  try {
394
- manifest = await captureLegacyManifest(legacyRoot);
437
+ legacySource = await canonicalLegacyRoot(artifactsDir);
438
+ manifest = await captureLegacyManifest(legacySource.root, legacySource.identity);
395
439
  } catch (error) {
396
440
  if (isEnoent(error)) {
397
441
  await fs.writeFile(marker, "absent\n", { mode: 0o600, flag: "wx" });
@@ -401,8 +445,8 @@ async function migrateLegacyLocal(
401
445
  }
402
446
  const staging = path.join(scratchParent, `.skc-local-migration-${randomUUID()}`);
403
447
  try {
404
- await copyLegacyManifest(legacyRoot, staging, manifest);
405
- const verifiedManifest = await captureLegacyManifest(legacyRoot);
448
+ await copyLegacyManifest(legacySource.root, staging, manifest);
449
+ const verifiedManifest = await captureLegacyManifest(legacySource.root, legacySource.identity);
406
450
  if (!manifestsMatch(verifiedManifest, manifest))
407
451
  throw new Error("Legacy local:// migration source changed during capture");
408
452
  for (const entry of await fs.readdir(staging)) {
@@ -414,7 +458,17 @@ async function migrateLegacyLocal(
414
458
  }
415
459
  await fs.rename(path.join(staging, entry), path.join(localRoot, entry));
416
460
  }
417
- await retireLegacyTree(legacyRoot, manifest);
461
+ try {
462
+ await retireLegacyTree(legacySource.root, manifest);
463
+ } catch (error) {
464
+ if (
465
+ !(error instanceof Error) ||
466
+ error.message !== "Legacy local:// migration retirement failed: cleanup_pending"
467
+ )
468
+ throw error;
469
+ await fs.writeFile(marker, "cleanup_pending\n", { mode: 0o600, flag: "wx" });
470
+ return;
471
+ }
418
472
  await fs.writeFile(marker, "verified\n", { mode: 0o600, flag: "wx" });
419
473
  } finally {
420
474
  await fs.rm(staging, { recursive: true, force: true });
@@ -501,8 +555,13 @@ function initializeLocalRootSyncWhenLegacyAbsent(options: LocalProtocolOptions,
501
555
  if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) throw new Error("Unsafe local:// root");
502
556
  const marker = path.join(localRoot, LEGACY_MIGRATION_MARKER);
503
557
  try {
504
- const value = fsSync.readFileSync(marker, "utf8");
505
- if (value !== "verified\n" && value !== "absent\n") throw new Error("Unsafe local:// migration marker");
558
+ // Accept exactly the marker states the async gate treats as settled. A
559
+ // `cleanup_pending` marker means the entries are fully installed and verified
560
+ // and only retirement of the legacy source is outstanding, so resolution is
561
+ // safe; rejecting it here made the sync resolver fail closed on a root the
562
+ // async gate had already completed.
563
+ if (!isSettledMigrationMarkerValue(fsSync.readFileSync(marker, "utf8")))
564
+ throw new Error("Unsafe local:// migration marker");
506
565
  initializedLocalRoots.add(localRoot);
507
566
  return;
508
567
  } catch (error) {
@@ -519,7 +578,10 @@ function initializeLocalRootSyncWhenLegacyAbsent(options: LocalProtocolOptions,
519
578
  fsSync.writeFileSync(marker, "absent\n", { mode: 0o600, flag: "wx" });
520
579
  } catch (error) {
521
580
  if ((error as NodeJS.ErrnoException).code !== "EEXIST") throw error;
522
- if (fsSync.readFileSync(marker, "utf8") !== "absent\n") throw new Error("Unsafe local:// migration marker");
581
+ // A concurrent initializer won the exclusive create. Any settled marker state
582
+ // it wrote is authoritative; only an unrecognized value is unsafe.
583
+ if (!isSettledMigrationMarkerValue(fsSync.readFileSync(marker, "utf8")))
584
+ throw new Error("Unsafe local:// migration marker");
523
585
  }
524
586
  initializedLocalRoots.add(localRoot);
525
587
  }
@@ -0,0 +1,127 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as os from "node:os";
3
+ import * as path from "node:path";
4
+ import { isEnoent } from "@sayknow-cli/utils";
5
+ import type { GcCollectResult, GcContext, GcError, GcRecord, GcStoreAdapter } from "../skc-runtime/gc-runtime";
6
+
7
+ /**
8
+ * GC for `local://` session roots.
9
+ *
10
+ * `resolveLocalRoot` gives every session its own `<tmp>/skc-local/<session-id>`
11
+ * directory, and the first `local://` resolution seeds it with a migration
12
+ * marker. Nothing ever removes those directories, so a machine accumulates one
13
+ * per session indefinitely — and the overwhelming majority only ever hold the
14
+ * marker, because most sessions never write a `local://` file.
15
+ *
16
+ * Only marker-only directories are eligible, and only after a grace period.
17
+ * That keeps the rule provably safe without needing a session-liveness oracle:
18
+ * a directory holding real content is never touched, and a session that just
19
+ * started is still inside its grace window.
20
+ */
21
+
22
+ const LOCAL_ROOT_PARENT = "skc-local";
23
+ const LEGACY_MIGRATION_MARKER = ".skc-local-legacy-migrated-v1";
24
+
25
+ /** Directories younger than this are left alone so a live session is never raced. */
26
+ const GRACE_MS = 24 * 60 * 60 * 1000;
27
+
28
+ /** Bound the scan so a pathological directory cannot stall `skc gc`. */
29
+ const MAX_ENTRIES = 20_000;
30
+
31
+ function localRootParent(env: NodeJS.ProcessEnv): string {
32
+ return path.join(env.TMPDIR?.trim() || os.tmpdir(), LOCAL_ROOT_PARENT);
33
+ }
34
+
35
+ /** A root is prunable only when the marker is the single thing inside it. */
36
+ async function classify(dir: string, now: number): Promise<{ status: string; stale: boolean; reason: string } | null> {
37
+ let entries: string[];
38
+ try {
39
+ entries = await fs.readdir(dir);
40
+ } catch (error) {
41
+ if (isEnoent(error)) return null;
42
+ throw error;
43
+ }
44
+
45
+ const extra = entries.filter(name => name !== LEGACY_MIGRATION_MARKER);
46
+ if (extra.length > 0)
47
+ return {
48
+ status: "in_use",
49
+ stale: false,
50
+ reason: `Holds ${extra.length} entr${extra.length === 1 ? "y" : "ies"} beyond the marker`,
51
+ };
52
+
53
+ const stat = await fs.stat(dir);
54
+ if (now - stat.mtimeMs < GRACE_MS) return { status: "recent", stale: false, reason: "Inside the grace window" };
55
+ return { status: "marker_only", stale: true, reason: "Only the migration marker, past the grace window" };
56
+ }
57
+
58
+ export const localRootsGcAdapter: GcStoreAdapter = {
59
+ store: "local_roots",
60
+ async collect(ctx: GcContext): Promise<GcCollectResult> {
61
+ const records: GcRecord[] = [];
62
+ const errors: GcError[] = [];
63
+ const parent = localRootParent(ctx.env);
64
+ const now = Date.now();
65
+
66
+ let dirents: string[];
67
+ try {
68
+ dirents = await fs.readdir(parent);
69
+ } catch (error) {
70
+ if (isEnoent(error)) return { records, errors };
71
+ errors.push({ store: "local_roots", scope: parent, message: (error as Error).message });
72
+ return { records, errors };
73
+ }
74
+
75
+ for (const name of dirents.slice(0, MAX_ENTRIES)) {
76
+ const dir = path.join(parent, name);
77
+ try {
78
+ const classified = await classify(dir, now);
79
+ if (!classified) continue;
80
+ records.push({
81
+ store: "local_roots",
82
+ id: name,
83
+ path: dir,
84
+ status: classified.status,
85
+ stale: classified.stale,
86
+ removable: classified.stale,
87
+ action: classified.stale ? "would_remove" : "none",
88
+ reason: classified.reason,
89
+ });
90
+ } catch (error) {
91
+ errors.push({ store: "local_roots", scope: dir, message: (error as Error).message });
92
+ }
93
+ }
94
+
95
+ if (dirents.length > MAX_ENTRIES) {
96
+ errors.push({
97
+ store: "local_roots",
98
+ scope: parent,
99
+ message: `Scan truncated at ${MAX_ENTRIES} entries`,
100
+ });
101
+ }
102
+
103
+ return { records, errors };
104
+ },
105
+ async prune(record: GcRecord) {
106
+ const dir = record.path;
107
+ if (!dir) return { removed: false, error: "Missing local root path" };
108
+
109
+ // Re-validate immediately before removing: the session may have written a
110
+ // file between collect and prune.
111
+ let classified: Awaited<ReturnType<typeof classify>>;
112
+ try {
113
+ classified = await classify(dir, Date.now());
114
+ } catch (error) {
115
+ return { removed: false, error: (error as Error).message };
116
+ }
117
+ if (!classified) return { removed: false, skipped: "Local root disappeared" };
118
+ if (!classified.stale) return { removed: false, skipped: `Local root no longer eligible (${classified.status})` };
119
+
120
+ try {
121
+ await fs.rm(dir, { recursive: true, force: true });
122
+ return { removed: true };
123
+ } catch (error) {
124
+ return { removed: false, error: (error as Error).message };
125
+ }
126
+ },
127
+ };
@@ -2,29 +2,91 @@ import { MCPManager } from "../runtime-mcp/manager";
2
2
  import type { MCPResourceReadResult } from "../runtime-mcp/types";
3
3
  import type { InternalResource, InternalUrl, ProtocolHandler } from "./types";
4
4
 
5
- function escapeRegex(text: string): string {
6
- return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5
+ const MAX_MCP_RESOURCE_URI_CHARS = 16_384;
6
+ const MAX_MCP_URI_TEMPLATE_CHARS = 8_192;
7
+ const MAX_MCP_URI_TEMPLATE_EXPRESSIONS = 32;
8
+
9
+ interface CompiledUriTemplate {
10
+ literalSegments: string[];
11
+ literalChars: number;
12
+ expressionCount: number;
13
+ }
14
+
15
+ function containsExpressionLineTerminator(text: string, start: number, end: number): boolean {
16
+ for (let index = start; index < end; index++) {
17
+ const code = text.charCodeAt(index);
18
+ if (code === 0x0a || code === 0x0d || code === 0x2028 || code === 0x2029) return true;
19
+ }
20
+ return false;
21
+ }
22
+
23
+ function compileUriTemplate(uriTemplate: string): CompiledUriTemplate | undefined {
24
+ if (uriTemplate.length > MAX_MCP_URI_TEMPLATE_CHARS) return undefined;
25
+
26
+ const literalSegments: string[] = [];
27
+ let expressionCount = 0;
28
+ let literalChars = 0;
29
+ let segmentStart = 0;
30
+ let scanPosition = 0;
31
+ while (scanPosition < uriTemplate.length) {
32
+ const expressionStart = uriTemplate.indexOf("{", scanPosition);
33
+ if (expressionStart < 0) break;
34
+ const expressionEnd = uriTemplate.indexOf("}", expressionStart + 1);
35
+ if (expressionEnd < 0) break;
36
+ if (expressionEnd === expressionStart + 1) {
37
+ scanPosition = expressionStart + 1;
38
+ continue;
39
+ }
40
+ expressionCount++;
41
+ if (expressionCount > MAX_MCP_URI_TEMPLATE_EXPRESSIONS) return undefined;
42
+ const segment = uriTemplate.slice(segmentStart, expressionStart);
43
+ literalSegments.push(segment);
44
+ literalChars += segment.length;
45
+ segmentStart = expressionEnd + 1;
46
+ scanPosition = segmentStart;
47
+ }
48
+ const finalSegment = uriTemplate.slice(segmentStart);
49
+ literalSegments.push(finalSegment);
50
+ literalChars += finalSegment.length;
51
+ return { literalSegments, literalChars, expressionCount };
52
+ }
53
+
54
+ function matchesUriTemplate(uri: string, template: CompiledUriTemplate): boolean {
55
+ const { literalSegments, expressionCount } = template;
56
+ if (expressionCount === 0) return uri === literalSegments[0];
57
+ if (!uri.startsWith(literalSegments[0])) return false;
58
+
59
+ let cursor = literalSegments[0].length;
60
+ for (let index = 1; index < literalSegments.length - 1; index++) {
61
+ const segment = literalSegments[index];
62
+ const matchIndex = uri.indexOf(segment, cursor);
63
+ if (matchIndex < 0 || containsExpressionLineTerminator(uri, cursor, matchIndex)) return false;
64
+ cursor = matchIndex + segment.length;
65
+ }
66
+
67
+ const suffix = literalSegments.at(-1) ?? "";
68
+ const suffixStart = uri.length - suffix.length;
69
+ return suffixStart >= cursor && uri.endsWith(suffix) && !containsExpressionLineTerminator(uri, cursor, suffixStart);
7
70
  }
8
71
 
9
72
  function getUriTemplateMatchScore(
10
73
  uri: string,
11
74
  uriTemplate: string,
12
75
  ): { literalChars: number; expressionCount: number } | undefined {
13
- const expressionPattern = /\{[^}]+\}/g;
14
- const literalSegments = uriTemplate.split(expressionPattern);
15
- const expressionCount = (uriTemplate.match(expressionPattern) ?? []).length;
16
- const pattern = literalSegments.map(escapeRegex).join("(.*?)");
17
- const regex = new RegExp(`^${pattern}$`);
18
- if (!regex.test(uri)) return undefined;
19
- const literalChars = literalSegments.reduce((total, segment) => total + segment.length, 0);
20
- return { literalChars, expressionCount };
76
+ const template = compileUriTemplate(uriTemplate);
77
+ if (!template || !matchesUriTemplate(uri, template)) return undefined;
78
+ return { literalChars: template.literalChars, expressionCount: template.expressionCount };
21
79
  }
22
80
 
23
81
  function extractResourceUri(url: InternalUrl): string {
24
82
  const host = url.rawHost || url.hostname;
25
83
  const rawPathname = url.rawPathname ?? url.pathname;
26
84
  const hasPath = rawPathname && rawPathname !== "/";
27
- const uri = `${host}${hasPath ? rawPathname : ""}${url.search}${url.hash}`.trim();
85
+ const rawUri = `${host}${hasPath ? rawPathname : ""}${url.search}${url.hash}`;
86
+ if (rawUri.length > MAX_MCP_RESOURCE_URI_CHARS) {
87
+ throw new Error("MCP resource URI exceeds the 16384-character limit.");
88
+ }
89
+ const uri = rawUri.trim();
28
90
  if (!uri) {
29
91
  throw new Error("mcp:// URL requires a resource URI: mcp://<resource-uri>");
30
92
  }