terminal-pilot 0.0.30 → 0.0.31

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 (328) hide show
  1. package/dist/cli.js +1375 -435
  2. package/dist/cli.js.map +4 -4
  3. package/dist/commands/close-session.js +485 -6
  4. package/dist/commands/close-session.js.map +4 -4
  5. package/dist/commands/create-session.js +485 -6
  6. package/dist/commands/create-session.js.map +4 -4
  7. package/dist/commands/fill.js +485 -6
  8. package/dist/commands/fill.js.map +4 -4
  9. package/dist/commands/get-session.js +485 -6
  10. package/dist/commands/get-session.js.map +4 -4
  11. package/dist/commands/index.js +626 -44
  12. package/dist/commands/index.js.map +4 -4
  13. package/dist/commands/install.js +622 -40
  14. package/dist/commands/install.js.map +4 -4
  15. package/dist/commands/installer.js +68 -17
  16. package/dist/commands/installer.js.map +4 -4
  17. package/dist/commands/list-sessions.js +485 -6
  18. package/dist/commands/list-sessions.js.map +4 -4
  19. package/dist/commands/press-key.js +485 -6
  20. package/dist/commands/press-key.js.map +4 -4
  21. package/dist/commands/read-history.js +485 -6
  22. package/dist/commands/read-history.js.map +4 -4
  23. package/dist/commands/read-screen.js +485 -6
  24. package/dist/commands/read-screen.js.map +4 -4
  25. package/dist/commands/resize.js +485 -6
  26. package/dist/commands/resize.js.map +4 -4
  27. package/dist/commands/screenshot.js +485 -6
  28. package/dist/commands/screenshot.js.map +4 -4
  29. package/dist/commands/send-signal.js +485 -6
  30. package/dist/commands/send-signal.js.map +4 -4
  31. package/dist/commands/type.js +485 -6
  32. package/dist/commands/type.js.map +4 -4
  33. package/dist/commands/uninstall.js +550 -20
  34. package/dist/commands/uninstall.js.map +4 -4
  35. package/dist/commands/wait-for-exit.js +485 -6
  36. package/dist/commands/wait-for-exit.js.map +4 -4
  37. package/dist/commands/wait-for.js +485 -6
  38. package/dist/commands/wait-for.js.map +4 -4
  39. package/dist/testing/cli-repl.js +1375 -435
  40. package/dist/testing/cli-repl.js.map +4 -4
  41. package/dist/testing/qa-cli.js +1385 -445
  42. package/dist/testing/qa-cli.js.map +4 -4
  43. package/node_modules/@poe-code/agent-defs/README.md +35 -0
  44. package/node_modules/@poe-code/agent-defs/dist/agents/claude-code.d.ts +2 -0
  45. package/node_modules/@poe-code/agent-defs/dist/agents/claude-code.js +21 -0
  46. package/node_modules/@poe-code/agent-defs/dist/agents/claude-desktop.d.ts +2 -0
  47. package/node_modules/@poe-code/agent-defs/dist/agents/claude-desktop.js +18 -0
  48. package/node_modules/@poe-code/agent-defs/dist/agents/codex.d.ts +2 -0
  49. package/node_modules/@poe-code/agent-defs/dist/agents/codex.js +25 -0
  50. package/node_modules/@poe-code/agent-defs/dist/agents/cursor.d.ts +2 -0
  51. package/node_modules/@poe-code/agent-defs/dist/agents/cursor.js +15 -0
  52. package/node_modules/@poe-code/agent-defs/dist/agents/gemini-cli.d.ts +2 -0
  53. package/node_modules/@poe-code/agent-defs/dist/agents/gemini-cli.js +16 -0
  54. package/node_modules/@poe-code/agent-defs/dist/agents/goose.d.ts +2 -0
  55. package/node_modules/@poe-code/agent-defs/dist/agents/goose.js +16 -0
  56. package/node_modules/@poe-code/agent-defs/dist/agents/index.d.ts +9 -0
  57. package/node_modules/@poe-code/agent-defs/dist/agents/index.js +9 -0
  58. package/node_modules/@poe-code/agent-defs/dist/agents/kimi.d.ts +2 -0
  59. package/node_modules/@poe-code/agent-defs/dist/agents/kimi.js +16 -0
  60. package/node_modules/@poe-code/agent-defs/dist/agents/opencode.d.ts +2 -0
  61. package/node_modules/@poe-code/agent-defs/dist/agents/opencode.js +20 -0
  62. package/node_modules/@poe-code/agent-defs/dist/agents/poe-agent.d.ts +2 -0
  63. package/node_modules/@poe-code/agent-defs/dist/agents/poe-agent.js +14 -0
  64. package/node_modules/@poe-code/agent-defs/dist/index.d.ts +5 -0
  65. package/node_modules/@poe-code/agent-defs/dist/index.js +3 -0
  66. package/node_modules/@poe-code/agent-defs/dist/registry.d.ts +3 -0
  67. package/node_modules/@poe-code/agent-defs/dist/registry.js +45 -0
  68. package/node_modules/@poe-code/agent-defs/dist/specifier.d.ts +7 -0
  69. package/node_modules/@poe-code/agent-defs/dist/specifier.js +40 -0
  70. package/node_modules/@poe-code/agent-defs/dist/types.d.ts +28 -0
  71. package/node_modules/@poe-code/agent-defs/dist/types.js +1 -0
  72. package/node_modules/@poe-code/agent-defs/package.json +20 -0
  73. package/node_modules/@poe-code/agent-skill-config/dist/apply.js +2 -1
  74. package/node_modules/@poe-code/agent-skill-config/dist/bridge-active-skills.d.ts +1 -0
  75. package/node_modules/@poe-code/agent-skill-config/dist/bridge-active-skills.js +37 -18
  76. package/node_modules/@poe-code/agent-skill-config/dist/resolve-skill-reference.js +8 -4
  77. package/node_modules/@poe-code/agent-skill-config/package.json +1 -5
  78. package/node_modules/@poe-code/config-mutations/README.md +55 -0
  79. package/node_modules/@poe-code/config-mutations/dist/error-codes.d.ts +1 -0
  80. package/node_modules/@poe-code/config-mutations/dist/error-codes.js +6 -0
  81. package/node_modules/@poe-code/config-mutations/dist/execution/apply-mutation.d.ts +6 -0
  82. package/node_modules/@poe-code/config-mutations/dist/execution/apply-mutation.js +829 -0
  83. package/node_modules/@poe-code/config-mutations/dist/execution/path-utils.d.ts +17 -0
  84. package/node_modules/@poe-code/config-mutations/dist/execution/path-utils.js +64 -0
  85. package/node_modules/@poe-code/config-mutations/dist/execution/run-mutations.d.ts +7 -0
  86. package/node_modules/@poe-code/config-mutations/dist/execution/run-mutations.js +39 -0
  87. package/node_modules/@poe-code/config-mutations/dist/formats/index.d.ts +13 -0
  88. package/node_modules/@poe-code/config-mutations/dist/formats/index.js +49 -0
  89. package/node_modules/@poe-code/config-mutations/dist/formats/json.d.ts +32 -0
  90. package/node_modules/@poe-code/config-mutations/dist/formats/json.js +171 -0
  91. package/node_modules/@poe-code/config-mutations/dist/formats/object.d.ts +4 -0
  92. package/node_modules/@poe-code/config-mutations/dist/formats/object.js +27 -0
  93. package/node_modules/@poe-code/config-mutations/dist/formats/toml.d.ts +2 -0
  94. package/node_modules/@poe-code/config-mutations/dist/formats/toml.js +75 -0
  95. package/node_modules/@poe-code/config-mutations/dist/formats/yaml.d.ts +2 -0
  96. package/node_modules/@poe-code/config-mutations/dist/formats/yaml.js +76 -0
  97. package/node_modules/@poe-code/config-mutations/dist/fs-utils.d.ts +18 -0
  98. package/node_modules/@poe-code/config-mutations/dist/fs-utils.js +43 -0
  99. package/node_modules/@poe-code/config-mutations/dist/index.d.ts +8 -0
  100. package/node_modules/@poe-code/config-mutations/dist/index.js +8 -0
  101. package/node_modules/@poe-code/config-mutations/dist/mutations/config-mutation.d.ts +47 -0
  102. package/node_modules/@poe-code/config-mutations/dist/mutations/config-mutation.js +34 -0
  103. package/node_modules/@poe-code/config-mutations/dist/mutations/file-mutation.d.ts +62 -0
  104. package/node_modules/@poe-code/config-mutations/dist/mutations/file-mutation.js +55 -0
  105. package/node_modules/@poe-code/config-mutations/dist/mutations/template-mutation.d.ts +40 -0
  106. package/node_modules/@poe-code/config-mutations/dist/mutations/template-mutation.js +32 -0
  107. package/node_modules/@poe-code/config-mutations/dist/template/render.d.ts +6 -0
  108. package/node_modules/@poe-code/config-mutations/dist/template/render.js +8 -0
  109. package/node_modules/@poe-code/config-mutations/dist/testing/format-utils.d.ts +7 -0
  110. package/node_modules/@poe-code/config-mutations/dist/testing/format-utils.js +21 -0
  111. package/node_modules/@poe-code/config-mutations/dist/testing/index.d.ts +3 -0
  112. package/node_modules/@poe-code/config-mutations/dist/testing/index.js +2 -0
  113. package/node_modules/@poe-code/config-mutations/dist/testing/mock-fs.d.ts +25 -0
  114. package/node_modules/@poe-code/config-mutations/dist/testing/mock-fs.js +194 -0
  115. package/node_modules/@poe-code/config-mutations/dist/types.d.ts +168 -0
  116. package/node_modules/@poe-code/config-mutations/dist/types.js +6 -0
  117. package/node_modules/@poe-code/config-mutations/package.json +29 -0
  118. package/node_modules/@poe-code/frontmatter/README.md +35 -0
  119. package/node_modules/@poe-code/frontmatter/dist/fences.d.ts +25 -0
  120. package/node_modules/@poe-code/frontmatter/dist/fences.js +100 -0
  121. package/node_modules/@poe-code/frontmatter/dist/index.d.ts +3 -0
  122. package/node_modules/@poe-code/frontmatter/dist/index.js +3 -0
  123. package/node_modules/@poe-code/frontmatter/dist/parse.d.ts +20 -0
  124. package/node_modules/@poe-code/frontmatter/dist/parse.js +209 -0
  125. package/node_modules/@poe-code/frontmatter/dist/stringify.d.ts +1 -0
  126. package/node_modules/@poe-code/frontmatter/dist/stringify.js +48 -0
  127. package/node_modules/@poe-code/frontmatter/package.json +25 -0
  128. package/node_modules/toolcraft-design/README.md +160 -0
  129. package/node_modules/toolcraft-design/dist/acp/components.d.ts +12 -0
  130. package/node_modules/toolcraft-design/dist/acp/components.js +137 -0
  131. package/node_modules/toolcraft-design/dist/acp/index.d.ts +3 -0
  132. package/node_modules/toolcraft-design/dist/acp/index.js +2 -0
  133. package/node_modules/toolcraft-design/dist/acp/writer.d.ts +13 -0
  134. package/node_modules/toolcraft-design/dist/acp/writer.js +21 -0
  135. package/node_modules/toolcraft-design/dist/components/browser.d.ts +15 -0
  136. package/node_modules/toolcraft-design/dist/components/browser.js +31 -0
  137. package/node_modules/toolcraft-design/dist/components/catalog.d.ts +26 -0
  138. package/node_modules/toolcraft-design/dist/components/catalog.js +95 -0
  139. package/node_modules/toolcraft-design/dist/components/color.d.ts +31 -0
  140. package/node_modules/toolcraft-design/dist/components/color.js +102 -0
  141. package/node_modules/toolcraft-design/dist/components/command-errors.d.ts +16 -0
  142. package/node_modules/toolcraft-design/dist/components/command-errors.js +23 -0
  143. package/node_modules/toolcraft-design/dist/components/detail-card.d.ts +22 -0
  144. package/node_modules/toolcraft-design/dist/components/detail-card.js +45 -0
  145. package/node_modules/toolcraft-design/dist/components/help-formatter-plain.d.ts +5 -0
  146. package/node_modules/toolcraft-design/dist/components/help-formatter-plain.js +132 -0
  147. package/node_modules/toolcraft-design/dist/components/help-formatter.d.ts +33 -0
  148. package/node_modules/toolcraft-design/dist/components/help-formatter.js +213 -0
  149. package/node_modules/toolcraft-design/dist/components/index.d.ts +16 -0
  150. package/node_modules/toolcraft-design/dist/components/index.js +10 -0
  151. package/node_modules/toolcraft-design/dist/components/logger.d.ts +11 -0
  152. package/node_modules/toolcraft-design/dist/components/logger.js +60 -0
  153. package/node_modules/toolcraft-design/dist/components/symbols.d.ts +12 -0
  154. package/node_modules/toolcraft-design/dist/components/symbols.js +71 -0
  155. package/node_modules/toolcraft-design/dist/components/table.d.ts +15 -0
  156. package/node_modules/toolcraft-design/dist/components/table.js +302 -0
  157. package/node_modules/toolcraft-design/dist/components/template.d.ts +10 -0
  158. package/node_modules/toolcraft-design/dist/components/template.js +437 -0
  159. package/node_modules/toolcraft-design/dist/components/text.d.ts +16 -0
  160. package/node_modules/toolcraft-design/dist/components/text.js +145 -0
  161. package/node_modules/toolcraft-design/dist/dashboard/ansi.d.ts +18 -0
  162. package/node_modules/toolcraft-design/dist/dashboard/ansi.js +343 -0
  163. package/node_modules/toolcraft-design/dist/dashboard/buffer.d.ts +25 -0
  164. package/node_modules/toolcraft-design/dist/dashboard/buffer.js +219 -0
  165. package/node_modules/toolcraft-design/dist/dashboard/components/border.d.ts +9 -0
  166. package/node_modules/toolcraft-design/dist/dashboard/components/border.js +123 -0
  167. package/node_modules/toolcraft-design/dist/dashboard/components/footer.d.ts +8 -0
  168. package/node_modules/toolcraft-design/dist/dashboard/components/footer.js +56 -0
  169. package/node_modules/toolcraft-design/dist/dashboard/components/output-pane.d.ts +12 -0
  170. package/node_modules/toolcraft-design/dist/dashboard/components/output-pane.js +268 -0
  171. package/node_modules/toolcraft-design/dist/dashboard/components/stats-pane.d.ts +7 -0
  172. package/node_modules/toolcraft-design/dist/dashboard/components/stats-pane.js +107 -0
  173. package/node_modules/toolcraft-design/dist/dashboard/dashboard.d.ts +20 -0
  174. package/node_modules/toolcraft-design/dist/dashboard/dashboard.js +167 -0
  175. package/node_modules/toolcraft-design/dist/dashboard/demo.d.ts +13 -0
  176. package/node_modules/toolcraft-design/dist/dashboard/demo.js +145 -0
  177. package/node_modules/toolcraft-design/dist/dashboard/index.d.ts +8 -0
  178. package/node_modules/toolcraft-design/dist/dashboard/index.js +4 -0
  179. package/node_modules/toolcraft-design/dist/dashboard/keymap.d.ts +8 -0
  180. package/node_modules/toolcraft-design/dist/dashboard/keymap.js +233 -0
  181. package/node_modules/toolcraft-design/dist/dashboard/layout.d.ts +25 -0
  182. package/node_modules/toolcraft-design/dist/dashboard/layout.js +79 -0
  183. package/node_modules/toolcraft-design/dist/dashboard/should-use-dashboard.d.ts +10 -0
  184. package/node_modules/toolcraft-design/dist/dashboard/should-use-dashboard.js +7 -0
  185. package/node_modules/toolcraft-design/dist/dashboard/snapshot.d.ts +10 -0
  186. package/node_modules/toolcraft-design/dist/dashboard/snapshot.js +68 -0
  187. package/node_modules/toolcraft-design/dist/dashboard/store.d.ts +8 -0
  188. package/node_modules/toolcraft-design/dist/dashboard/store.js +51 -0
  189. package/node_modules/toolcraft-design/dist/dashboard/terminal-width.d.ts +4 -0
  190. package/node_modules/toolcraft-design/dist/dashboard/terminal-width.js +71 -0
  191. package/node_modules/toolcraft-design/dist/dashboard/terminal.d.ts +37 -0
  192. package/node_modules/toolcraft-design/dist/dashboard/terminal.js +264 -0
  193. package/node_modules/toolcraft-design/dist/dashboard/types.d.ts +38 -0
  194. package/node_modules/toolcraft-design/dist/dashboard/types.js +1 -0
  195. package/node_modules/toolcraft-design/dist/explorer/actions.d.ts +16 -0
  196. package/node_modules/toolcraft-design/dist/explorer/actions.js +39 -0
  197. package/node_modules/toolcraft-design/dist/explorer/demo.d.ts +13 -0
  198. package/node_modules/toolcraft-design/dist/explorer/demo.js +297 -0
  199. package/node_modules/toolcraft-design/dist/explorer/events.d.ts +67 -0
  200. package/node_modules/toolcraft-design/dist/explorer/events.js +1 -0
  201. package/node_modules/toolcraft-design/dist/explorer/filter.d.ts +10 -0
  202. package/node_modules/toolcraft-design/dist/explorer/filter.js +95 -0
  203. package/node_modules/toolcraft-design/dist/explorer/index.d.ts +8 -0
  204. package/node_modules/toolcraft-design/dist/explorer/index.js +8 -0
  205. package/node_modules/toolcraft-design/dist/explorer/jobs.d.ts +7 -0
  206. package/node_modules/toolcraft-design/dist/explorer/jobs.js +59 -0
  207. package/node_modules/toolcraft-design/dist/explorer/keymap.d.ts +21 -0
  208. package/node_modules/toolcraft-design/dist/explorer/keymap.js +376 -0
  209. package/node_modules/toolcraft-design/dist/explorer/layout.d.ts +20 -0
  210. package/node_modules/toolcraft-design/dist/explorer/layout.js +73 -0
  211. package/node_modules/toolcraft-design/dist/explorer/reducer.d.ts +9 -0
  212. package/node_modules/toolcraft-design/dist/explorer/reducer.js +782 -0
  213. package/node_modules/toolcraft-design/dist/explorer/render/detail.d.ts +4 -0
  214. package/node_modules/toolcraft-design/dist/explorer/render/detail.js +97 -0
  215. package/node_modules/toolcraft-design/dist/explorer/render/footer.d.ts +4 -0
  216. package/node_modules/toolcraft-design/dist/explorer/render/footer.js +73 -0
  217. package/node_modules/toolcraft-design/dist/explorer/render/header.d.ts +4 -0
  218. package/node_modules/toolcraft-design/dist/explorer/render/header.js +49 -0
  219. package/node_modules/toolcraft-design/dist/explorer/render/index.d.ts +8 -0
  220. package/node_modules/toolcraft-design/dist/explorer/render/index.js +53 -0
  221. package/node_modules/toolcraft-design/dist/explorer/render/list.d.ts +4 -0
  222. package/node_modules/toolcraft-design/dist/explorer/render/list.js +116 -0
  223. package/node_modules/toolcraft-design/dist/explorer/render/modal.d.ts +3 -0
  224. package/node_modules/toolcraft-design/dist/explorer/render/modal.js +87 -0
  225. package/node_modules/toolcraft-design/dist/explorer/render/test-fixtures.d.ts +8 -0
  226. package/node_modules/toolcraft-design/dist/explorer/render/test-fixtures.js +156 -0
  227. package/node_modules/toolcraft-design/dist/explorer/render/text.d.ts +12 -0
  228. package/node_modules/toolcraft-design/dist/explorer/render/text.js +81 -0
  229. package/node_modules/toolcraft-design/dist/explorer/runtime.d.ts +2 -0
  230. package/node_modules/toolcraft-design/dist/explorer/runtime.js +340 -0
  231. package/node_modules/toolcraft-design/dist/explorer/runtime.test-helpers.d.ts +50 -0
  232. package/node_modules/toolcraft-design/dist/explorer/runtime.test-helpers.js +101 -0
  233. package/node_modules/toolcraft-design/dist/explorer/state.d.ts +137 -0
  234. package/node_modules/toolcraft-design/dist/explorer/state.js +86 -0
  235. package/node_modules/toolcraft-design/dist/explorer/theme.d.ts +27 -0
  236. package/node_modules/toolcraft-design/dist/explorer/theme.js +29 -0
  237. package/node_modules/toolcraft-design/dist/index.d.ts +50 -0
  238. package/node_modules/toolcraft-design/dist/index.js +43 -0
  239. package/node_modules/toolcraft-design/dist/internal/color-support.d.ts +9 -0
  240. package/node_modules/toolcraft-design/dist/internal/color-support.js +12 -0
  241. package/node_modules/toolcraft-design/dist/internal/output-format.d.ts +6 -0
  242. package/node_modules/toolcraft-design/dist/internal/output-format.js +22 -0
  243. package/node_modules/toolcraft-design/dist/internal/strip-ansi.d.ts +1 -0
  244. package/node_modules/toolcraft-design/dist/internal/strip-ansi.js +50 -0
  245. package/node_modules/toolcraft-design/dist/internal/theme-detect.d.ts +12 -0
  246. package/node_modules/toolcraft-design/dist/internal/theme-detect.js +71 -0
  247. package/node_modules/toolcraft-design/dist/internal/theme-state.d.ts +12 -0
  248. package/node_modules/toolcraft-design/dist/internal/theme-state.js +35 -0
  249. package/node_modules/toolcraft-design/dist/prompts/index.d.ts +91 -0
  250. package/node_modules/toolcraft-design/dist/prompts/index.js +137 -0
  251. package/node_modules/toolcraft-design/dist/prompts/interactive/cancel-symbol.d.ts +2 -0
  252. package/node_modules/toolcraft-design/dist/prompts/interactive/cancel-symbol.js +4 -0
  253. package/node_modules/toolcraft-design/dist/prompts/interactive/confirm.d.ts +9 -0
  254. package/node_modules/toolcraft-design/dist/prompts/interactive/confirm.js +47 -0
  255. package/node_modules/toolcraft-design/dist/prompts/interactive/core.d.ts +55 -0
  256. package/node_modules/toolcraft-design/dist/prompts/interactive/core.js +274 -0
  257. package/node_modules/toolcraft-design/dist/prompts/interactive/glyphs.d.ts +20 -0
  258. package/node_modules/toolcraft-design/dist/prompts/interactive/glyphs.js +53 -0
  259. package/node_modules/toolcraft-design/dist/prompts/interactive/index.d.ts +6 -0
  260. package/node_modules/toolcraft-design/dist/prompts/interactive/index.js +6 -0
  261. package/node_modules/toolcraft-design/dist/prompts/interactive/keys.d.ts +2 -0
  262. package/node_modules/toolcraft-design/dist/prompts/interactive/keys.js +28 -0
  263. package/node_modules/toolcraft-design/dist/prompts/interactive/multiselect.d.ts +13 -0
  264. package/node_modules/toolcraft-design/dist/prompts/interactive/multiselect.js +131 -0
  265. package/node_modules/toolcraft-design/dist/prompts/interactive/pagination.d.ts +10 -0
  266. package/node_modules/toolcraft-design/dist/prompts/interactive/pagination.js +52 -0
  267. package/node_modules/toolcraft-design/dist/prompts/interactive/password.d.ts +10 -0
  268. package/node_modules/toolcraft-design/dist/prompts/interactive/password.js +55 -0
  269. package/node_modules/toolcraft-design/dist/prompts/interactive/select.d.ts +18 -0
  270. package/node_modules/toolcraft-design/dist/prompts/interactive/select.js +89 -0
  271. package/node_modules/toolcraft-design/dist/prompts/interactive/test-helpers.d.ts +21 -0
  272. package/node_modules/toolcraft-design/dist/prompts/interactive/test-helpers.js +32 -0
  273. package/node_modules/toolcraft-design/dist/prompts/interactive/text.d.ts +12 -0
  274. package/node_modules/toolcraft-design/dist/prompts/interactive/text.js +60 -0
  275. package/node_modules/toolcraft-design/dist/prompts/interactive/wrap.d.ts +4 -0
  276. package/node_modules/toolcraft-design/dist/prompts/interactive/wrap.js +18 -0
  277. package/node_modules/toolcraft-design/dist/prompts/primitives/cancel.d.ts +2 -0
  278. package/node_modules/toolcraft-design/dist/prompts/primitives/cancel.js +9 -0
  279. package/node_modules/toolcraft-design/dist/prompts/primitives/intro.d.ts +1 -0
  280. package/node_modules/toolcraft-design/dist/prompts/primitives/intro.js +16 -0
  281. package/node_modules/toolcraft-design/dist/prompts/primitives/log.d.ts +18 -0
  282. package/node_modules/toolcraft-design/dist/prompts/primitives/log.js +104 -0
  283. package/node_modules/toolcraft-design/dist/prompts/primitives/note.d.ts +1 -0
  284. package/node_modules/toolcraft-design/dist/prompts/primitives/note.js +39 -0
  285. package/node_modules/toolcraft-design/dist/prompts/primitives/outro.d.ts +1 -0
  286. package/node_modules/toolcraft-design/dist/prompts/primitives/outro.js +16 -0
  287. package/node_modules/toolcraft-design/dist/prompts/primitives/spinner.d.ts +6 -0
  288. package/node_modules/toolcraft-design/dist/prompts/primitives/spinner.js +74 -0
  289. package/node_modules/toolcraft-design/dist/prompts/theme.d.ts +11 -0
  290. package/node_modules/toolcraft-design/dist/prompts/theme.js +15 -0
  291. package/node_modules/toolcraft-design/dist/static/index.d.ts +4 -0
  292. package/node_modules/toolcraft-design/dist/static/index.js +2 -0
  293. package/node_modules/toolcraft-design/dist/static/menu.d.ts +11 -0
  294. package/node_modules/toolcraft-design/dist/static/menu.js +42 -0
  295. package/node_modules/toolcraft-design/dist/static/spinner.d.ts +14 -0
  296. package/node_modules/toolcraft-design/dist/static/spinner.js +52 -0
  297. package/node_modules/toolcraft-design/dist/terminal-markdown/ast.d.ts +92 -0
  298. package/node_modules/toolcraft-design/dist/terminal-markdown/ast.js +1 -0
  299. package/node_modules/toolcraft-design/dist/terminal-markdown/demo-content.d.ts +2 -0
  300. package/node_modules/toolcraft-design/dist/terminal-markdown/demo-content.js +139 -0
  301. package/node_modules/toolcraft-design/dist/terminal-markdown/index.d.ts +6 -0
  302. package/node_modules/toolcraft-design/dist/terminal-markdown/index.js +8 -0
  303. package/node_modules/toolcraft-design/dist/terminal-markdown/parser/block.d.ts +7 -0
  304. package/node_modules/toolcraft-design/dist/terminal-markdown/parser/block.js +1495 -0
  305. package/node_modules/toolcraft-design/dist/terminal-markdown/parser/frontmatter.d.ts +8 -0
  306. package/node_modules/toolcraft-design/dist/terminal-markdown/parser/frontmatter.js +36 -0
  307. package/node_modules/toolcraft-design/dist/terminal-markdown/parser/inline.d.ts +10 -0
  308. package/node_modules/toolcraft-design/dist/terminal-markdown/parser/inline.js +1190 -0
  309. package/node_modules/toolcraft-design/dist/terminal-markdown/parser.d.ts +5 -0
  310. package/node_modules/toolcraft-design/dist/terminal-markdown/parser.js +42 -0
  311. package/node_modules/toolcraft-design/dist/terminal-markdown/renderer.d.ts +6 -0
  312. package/node_modules/toolcraft-design/dist/terminal-markdown/renderer.js +615 -0
  313. package/node_modules/toolcraft-design/dist/terminal-markdown/testing/theme-render-fixture.d.ts +1 -0
  314. package/node_modules/toolcraft-design/dist/terminal-markdown/testing/theme-render-fixture.js +27 -0
  315. package/node_modules/toolcraft-design/dist/tokens/brand.d.ts +5 -0
  316. package/node_modules/toolcraft-design/dist/tokens/brand.js +5 -0
  317. package/node_modules/toolcraft-design/dist/tokens/colors.d.ts +37 -0
  318. package/node_modules/toolcraft-design/dist/tokens/colors.js +85 -0
  319. package/node_modules/toolcraft-design/dist/tokens/index.d.ts +6 -0
  320. package/node_modules/toolcraft-design/dist/tokens/index.js +5 -0
  321. package/node_modules/toolcraft-design/dist/tokens/spacing.d.ts +6 -0
  322. package/node_modules/toolcraft-design/dist/tokens/spacing.js +6 -0
  323. package/node_modules/toolcraft-design/dist/tokens/typography.d.ts +7 -0
  324. package/node_modules/toolcraft-design/dist/tokens/typography.js +8 -0
  325. package/node_modules/toolcraft-design/dist/tokens/widths.d.ts +5 -0
  326. package/node_modules/toolcraft-design/dist/tokens/widths.js +5 -0
  327. package/node_modules/toolcraft-design/package.json +44 -0
  328. package/package.json +15 -5
package/dist/cli.js CHANGED
@@ -7,12 +7,12 @@ var __export = (target, all) => {
7
7
 
8
8
  // src/cli.ts
9
9
  import { realpath as realpath3 } from "node:fs/promises";
10
- import path23 from "node:path";
10
+ import path24 from "node:path";
11
11
  import { fileURLToPath as fileURLToPath5 } from "node:url";
12
12
 
13
13
  // ../toolcraft/src/cli.ts
14
- import { access as access2, lstat as lstat3, readFile as readFile4, rename as rename3, unlink as unlink3, writeFile as writeFile5 } from "node:fs/promises";
15
- import path14 from "node:path";
14
+ import { access as access2, lstat as lstat3, readFile as readFile5, rename as rename3, unlink as unlink3, writeFile as writeFile5 } from "node:fs/promises";
15
+ import path15 from "node:path";
16
16
  import {
17
17
  Command as CommanderCommand,
18
18
  CommanderError as CommanderError2,
@@ -378,7 +378,8 @@ function renderMarkdownCode(content) {
378
378
  currentRun = 0;
379
379
  }
380
380
  const delimiter = "`".repeat(longestRun + 1);
381
- return `${delimiter}${value}${delimiter}`;
381
+ const paddedValue = value.startsWith("`") || value.endsWith("`") ? ` ${value} ` : value;
382
+ return `${delimiter}${paddedValue}${delimiter}`;
382
383
  }
383
384
  function renderMarkdownLink(content) {
384
385
  const value = renderMarkdownInline(content);
@@ -533,7 +534,54 @@ var symbols = {
533
534
 
534
535
  // ../toolcraft-design/src/internal/strip-ansi.ts
535
536
  function stripAnsi(value) {
536
- return value.replace(/\u001b\[[0-9;]*m/g, "");
537
+ let output = "";
538
+ let index = 0;
539
+ while (index < value.length) {
540
+ const char = value[index];
541
+ if (char === "\x1B") {
542
+ index = skipEscapeSequence(value, index);
543
+ continue;
544
+ }
545
+ if (char === "\x9B") {
546
+ index = skipCsiSequence(value, index + 1);
547
+ continue;
548
+ }
549
+ output += char;
550
+ index += char.length;
551
+ }
552
+ return output;
553
+ }
554
+ function skipEscapeSequence(value, index) {
555
+ const next = value[index + 1];
556
+ if (next === "[") {
557
+ return skipCsiSequence(value, index + 2);
558
+ }
559
+ if (next === "]") {
560
+ return skipOscSequence(value, index + 2);
561
+ }
562
+ return Math.min(value.length, index + 2);
563
+ }
564
+ function skipCsiSequence(value, index) {
565
+ while (index < value.length) {
566
+ const codePoint = value.charCodeAt(index);
567
+ index += 1;
568
+ if (codePoint >= 64 && codePoint <= 126) {
569
+ break;
570
+ }
571
+ }
572
+ return index;
573
+ }
574
+ function skipOscSequence(value, index) {
575
+ while (index < value.length) {
576
+ if (value[index] === "\x07") {
577
+ return index + 1;
578
+ }
579
+ if (value[index] === "\x1B" && value[index + 1] === "\\") {
580
+ return index + 2;
581
+ }
582
+ index += 1;
583
+ }
584
+ return index;
537
585
  }
538
586
 
539
587
  // ../toolcraft-design/src/prompts/primitives/log.ts
@@ -1322,38 +1370,14 @@ function renderTable(options) {
1322
1370
  }
1323
1371
 
1324
1372
  // ../toolcraft-design/src/components/detail-card.ts
1373
+ import stringWidth from "fast-string-width";
1374
+ import { wrapAnsi } from "fast-wrap-ansi";
1325
1375
  function wrap(value, width) {
1326
- const lines = [];
1327
- for (const paragraph of value.split("\n")) {
1328
- let line = "";
1329
- for (const rawWord of paragraph.split(" ")) {
1330
- const words = [];
1331
- let word = rawWord;
1332
- while (word.length > width) {
1333
- words.push(word.slice(0, width));
1334
- word = word.slice(width);
1335
- }
1336
- words.push(word);
1337
- for (const word2 of words) {
1338
- if (line.length === 0) {
1339
- line = word2;
1340
- continue;
1341
- }
1342
- if (`${line} ${word2}`.length <= width) {
1343
- line = `${line} ${word2}`;
1344
- continue;
1345
- }
1346
- lines.push(line);
1347
- line = word2;
1348
- }
1349
- }
1350
- lines.push(line);
1351
- }
1352
- return lines;
1376
+ return wrapAnsi(value, Math.max(1, width), { hard: true, trim: true }).split("\n");
1353
1377
  }
1354
1378
  function renderRows(rows, theme, width) {
1355
1379
  if (rows.length === 0) return [];
1356
- const labelWidth = Math.max(...rows.map((row) => row.label.length));
1380
+ const labelWidth = Math.max(...rows.map((row) => stringWidth(row.label)));
1357
1381
  const valueWidth = Math.max(20, width - labelWidth - 2);
1358
1382
  const continuation = " ".repeat(labelWidth + 2);
1359
1383
  return rows.flatMap((row) => {
@@ -1374,12 +1398,16 @@ function renderDetailCard(options) {
1374
1398
  ${options.theme.muted(options.badges.map((badge) => badge[0] + badge.slice(1).toLowerCase()).join(" \xB7 "))}` : identity;
1375
1399
  const blocks = [hero];
1376
1400
  for (const prose of options.prose ?? []) {
1377
- blocks.push(prose.title ? [options.theme.header(prose.title), wrap(prose.value, width).join("\n")].join("\n") : wrap(prose.value, width).join("\n"));
1401
+ blocks.push(
1402
+ prose.title ? [options.theme.header(prose.title), wrap(prose.value, width).join("\n")].join("\n") : wrap(prose.value, width).join("\n")
1403
+ );
1378
1404
  }
1379
1405
  for (const section of options.sections ?? []) {
1380
1406
  if (section.rows.length === 0) continue;
1381
1407
  const rows = renderRows(section.rows, options.theme, width);
1382
- blocks.push(section.title ? [options.theme.header(section.title), ...rows].join("\n") : rows.join("\n"));
1408
+ blocks.push(
1409
+ section.title ? [options.theme.header(section.title), ...rows].join("\n") : rows.join("\n")
1410
+ );
1383
1411
  }
1384
1412
  return blocks.join("\n\n");
1385
1413
  }
@@ -1806,13 +1834,13 @@ import { LineCounter, parse, parseDocument } from "yaml";
1806
1834
  // ../frontmatter/src/stringify.ts
1807
1835
  import { stringify } from "yaml";
1808
1836
 
1837
+ // ../toolcraft-design/src/dashboard/terminal-width.ts
1838
+ var graphemeSegmenter3 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
1839
+
1809
1840
  // ../toolcraft-design/src/acp/writer.ts
1810
1841
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
1811
1842
  var storage = new AsyncLocalStorage2();
1812
1843
 
1813
- // ../toolcraft-design/src/dashboard/terminal-width.ts
1814
- var graphemeSegmenter3 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
1815
-
1816
1844
  // ../toolcraft-design/src/dashboard/terminal.ts
1817
1845
  import readline from "node:readline";
1818
1846
  import { PassThrough } from "node:stream";
@@ -1909,8 +1937,8 @@ function mapKey(name, char) {
1909
1937
  }
1910
1938
 
1911
1939
  // ../toolcraft-design/src/prompts/interactive/wrap.ts
1912
- import { wrapAnsi } from "fast-wrap-ansi";
1913
- import stringWidth from "fast-string-width";
1940
+ import { wrapAnsi as wrapAnsi2 } from "fast-wrap-ansi";
1941
+ import stringWidth2 from "fast-string-width";
1914
1942
  function getColumns(output) {
1915
1943
  return Math.max(1, output.columns ?? 80);
1916
1944
  }
@@ -1918,7 +1946,7 @@ function getRows(output) {
1918
1946
  return Math.max(1, output.rows ?? 20);
1919
1947
  }
1920
1948
  function wrapFrame(output, frame) {
1921
- return wrapAnsi(frame, getColumns(output), { hard: true, trim: false });
1949
+ return wrapAnsi2(frame, getColumns(output), { hard: true, trim: false });
1922
1950
  }
1923
1951
 
1924
1952
  // ../toolcraft-design/src/prompts/interactive/core.ts
@@ -2239,7 +2267,7 @@ function confirmPrompt(opts) {
2239
2267
  }
2240
2268
 
2241
2269
  // ../toolcraft-design/src/prompts/interactive/pagination.ts
2242
- import { wrapAnsi as wrapAnsi2 } from "fast-wrap-ansi";
2270
+ import { wrapAnsi as wrapAnsi3 } from "fast-wrap-ansi";
2243
2271
  function countLines(values) {
2244
2272
  return values.reduce((sum, value) => sum + value.split("\n").length, 0);
2245
2273
  }
@@ -2282,7 +2310,7 @@ function limitOptions(opts) {
2282
2310
  }
2283
2311
  const hasTopMarker = cappedVisibleCount < options.length && start > 0;
2284
2312
  const hasBottomMarker = cappedVisibleCount < options.length && start + cappedVisibleCount < options.length;
2285
- const visible = options.slice(start, start + cappedVisibleCount).map((option, index) => wrapAnsi2(style(option, start + index === cursor2), columns, { hard: true, trim: false }));
2313
+ const visible = options.slice(start, start + cappedVisibleCount).map((option, index) => wrapAnsi3(style(option, start + index === cursor2), columns, { hard: true, trim: false }));
2286
2314
  const trimmed = trimToRows(
2287
2315
  visible,
2288
2316
  Math.max(cursor2 - start, 0),
@@ -2665,6 +2693,9 @@ function isOptionalSchema(schema) {
2665
2693
  function getRequiredKeys(schema) {
2666
2694
  return Object.keys(schema.shape).filter((key2) => !isOptionalSchema(schema.shape[key2])).sort();
2667
2695
  }
2696
+ function getRequiredKeyFingerprint(schema) {
2697
+ return getRequiredKeys(schema).join("+");
2698
+ }
2668
2699
  function assertUniqueRequiredKeyFingerprints(branches) {
2669
2700
  const fingerprints = /* @__PURE__ */ new Map();
2670
2701
  branches.forEach((branch, index) => {
@@ -2702,6 +2733,451 @@ function Union(branches) {
2702
2733
  };
2703
2734
  }
2704
2735
 
2736
+ // ../toolcraft-schema/src/validate.ts
2737
+ var missingValue = /* @__PURE__ */ Symbol("missingValue");
2738
+ function validate(schema, value) {
2739
+ const state = { issues: [] };
2740
+ const result = walkSchema(schema, value, [], state);
2741
+ if (state.issues.length > 0) {
2742
+ return { ok: false, issues: state.issues };
2743
+ }
2744
+ return { ok: true, value: result.present ? result.value : void 0 };
2745
+ }
2746
+ function walkSchema(schema, value, path25, state) {
2747
+ if (schema.kind === "optional") {
2748
+ return walkOptional(schema, value, path25, state);
2749
+ }
2750
+ if (value === missingValue) {
2751
+ addIssue(
2752
+ state,
2753
+ path25,
2754
+ expectedFor(schema),
2755
+ "missing",
2756
+ `Expected ${expectedFor(schema)} at ${formatPath(path25)}`
2757
+ );
2758
+ return { present: false };
2759
+ }
2760
+ if (value === null && schema.nullable === true) {
2761
+ return { present: true, value };
2762
+ }
2763
+ switch (schema.kind) {
2764
+ case "string":
2765
+ return walkString(schema, value, path25, state);
2766
+ case "number":
2767
+ return walkNumber(schema, value, path25, state);
2768
+ case "boolean":
2769
+ return walkBoolean(value, path25, state);
2770
+ case "enum":
2771
+ return walkEnum(schema, value, path25, state);
2772
+ case "array":
2773
+ return walkArray(schema, value, path25, state);
2774
+ case "object":
2775
+ return walkObject(schema, value, path25, state);
2776
+ case "oneOf":
2777
+ return walkOneOf(schema, value, path25, state);
2778
+ case "union":
2779
+ return walkUnion(schema, value, path25, state);
2780
+ case "record":
2781
+ return walkRecord(schema, value, path25, state);
2782
+ case "json":
2783
+ return walkJson(value, path25, state);
2784
+ }
2785
+ }
2786
+ function walkOptional(schema, value, path25, state) {
2787
+ if (value === missingValue || value === void 0) {
2788
+ const defaultValue = getDefault(schema.inner);
2789
+ if (defaultValue.present) {
2790
+ return walkSchema(schema.inner, cloneDefault(defaultValue.value), path25, state);
2791
+ }
2792
+ return { present: false };
2793
+ }
2794
+ return walkSchema(schema.inner, value, path25, state);
2795
+ }
2796
+ function walkString(schema, value, path25, state) {
2797
+ if (typeof value !== "string") {
2798
+ addExpectedIssue(state, path25, "string", value);
2799
+ return { present: true, value };
2800
+ }
2801
+ if (schema.minLength !== void 0 && value.length < schema.minLength) {
2802
+ const expected = `string with length at least ${schema.minLength}`;
2803
+ addIssue(
2804
+ state,
2805
+ path25,
2806
+ expected,
2807
+ `string with length ${value.length}`,
2808
+ `Expected ${expected} at ${formatPath(path25)}`
2809
+ );
2810
+ }
2811
+ if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
2812
+ const expected = `string with length at most ${schema.maxLength}`;
2813
+ addIssue(
2814
+ state,
2815
+ path25,
2816
+ expected,
2817
+ `string with length ${value.length}`,
2818
+ `Expected ${expected} at ${formatPath(path25)}`
2819
+ );
2820
+ }
2821
+ if (schema.pattern !== void 0) {
2822
+ const pattern = compilePattern(schema.pattern);
2823
+ if (pattern === void 0 || !pattern.test(value)) {
2824
+ const expected = `string matching pattern ${schema.pattern}`;
2825
+ addIssue(state, path25, expected, value, `Expected ${expected} at ${formatPath(path25)}`);
2826
+ }
2827
+ }
2828
+ return { present: true, value };
2829
+ }
2830
+ function walkNumber(schema, value, path25, state) {
2831
+ if (typeof value !== "number" || !Number.isFinite(value)) {
2832
+ addExpectedIssue(state, path25, schema.jsonType === "integer" ? "integer" : "number", value);
2833
+ return { present: true, value };
2834
+ }
2835
+ if (schema.jsonType === "integer" && !Number.isInteger(value)) {
2836
+ addExpectedIssue(state, path25, "integer", value);
2837
+ }
2838
+ if (schema.minimum !== void 0 && value < schema.minimum) {
2839
+ const expected = `number greater than or equal to ${schema.minimum}`;
2840
+ addIssue(state, path25, expected, String(value), `Expected ${expected} at ${formatPath(path25)}`);
2841
+ }
2842
+ if (schema.maximum !== void 0 && value > schema.maximum) {
2843
+ const expected = `number less than or equal to ${schema.maximum}`;
2844
+ addIssue(state, path25, expected, String(value), `Expected ${expected} at ${formatPath(path25)}`);
2845
+ }
2846
+ return { present: true, value };
2847
+ }
2848
+ function walkBoolean(value, path25, state) {
2849
+ if (typeof value !== "boolean") {
2850
+ addExpectedIssue(state, path25, "boolean", value);
2851
+ }
2852
+ return { present: true, value };
2853
+ }
2854
+ function walkEnum(schema, value, path25, state) {
2855
+ if (!schema.values.includes(value)) {
2856
+ const expected = `one of ${schema.values.join(", ")}`;
2857
+ addIssue(
2858
+ state,
2859
+ path25,
2860
+ expected,
2861
+ receivedValue(value),
2862
+ `Expected ${expected} at ${formatPath(path25)}`
2863
+ );
2864
+ }
2865
+ return { present: true, value };
2866
+ }
2867
+ function walkArray(schema, value, path25, state) {
2868
+ if (!Array.isArray(value)) {
2869
+ addExpectedIssue(state, path25, "array", value);
2870
+ return { present: true, value };
2871
+ }
2872
+ if (schema.minItems !== void 0 && value.length < schema.minItems) {
2873
+ const expected = `array with at least ${schema.minItems} items`;
2874
+ addIssue(
2875
+ state,
2876
+ path25,
2877
+ expected,
2878
+ `array with ${value.length} items`,
2879
+ `Expected ${expected} at ${formatPath(path25)}`
2880
+ );
2881
+ }
2882
+ if (schema.maxItems !== void 0 && value.length > schema.maxItems) {
2883
+ const expected = `array with at most ${schema.maxItems} items`;
2884
+ addIssue(
2885
+ state,
2886
+ path25,
2887
+ expected,
2888
+ `array with ${value.length} items`,
2889
+ `Expected ${expected} at ${formatPath(path25)}`
2890
+ );
2891
+ }
2892
+ const nextValue = value.map((item, index) => {
2893
+ const result = walkSchema(schema.item, item, [...path25, String(index)], state);
2894
+ return result.present ? result.value : item;
2895
+ });
2896
+ return { present: true, value: nextValue };
2897
+ }
2898
+ function walkObject(schema, value, path25, state, injectedProperties = {}) {
2899
+ if (!isPlainRecord(value)) {
2900
+ addExpectedIssue(state, path25, "object", value);
2901
+ return { present: true, value };
2902
+ }
2903
+ const nextValue = {};
2904
+ const allowedKeys = /* @__PURE__ */ new Set([...Object.keys(schema.shape), ...Object.keys(injectedProperties)]);
2905
+ for (const [key2, propertySchema] of Object.entries(schema.shape)) {
2906
+ const propertyValue = Object.hasOwn(value, key2) ? value[key2] : missingValue;
2907
+ const result = walkSchema(propertySchema, propertyValue, [...path25, key2], state);
2908
+ if (result.present) {
2909
+ setOwnValue(nextValue, key2, result.value);
2910
+ }
2911
+ }
2912
+ for (const [key2, injectedValue] of Object.entries(injectedProperties)) {
2913
+ if (Object.hasOwn(value, key2)) {
2914
+ setOwnValue(nextValue, key2, value[key2]);
2915
+ } else {
2916
+ setOwnValue(nextValue, key2, injectedValue);
2917
+ }
2918
+ }
2919
+ for (const [key2, propertyValue] of Object.entries(value)) {
2920
+ if (allowedKeys.has(key2)) {
2921
+ continue;
2922
+ }
2923
+ if (schema.additionalProperties === true) {
2924
+ setOwnValue(nextValue, key2, propertyValue);
2925
+ } else {
2926
+ addUnexpectedPropertyIssue(state, [...path25, key2]);
2927
+ }
2928
+ }
2929
+ return { present: true, value: nextValue };
2930
+ }
2931
+ function walkOneOf(schema, value, path25, state) {
2932
+ if (!isPlainRecord(value)) {
2933
+ addExpectedIssue(state, path25, "object", value);
2934
+ return { present: true, value };
2935
+ }
2936
+ const discriminatorValue = value[schema.discriminator];
2937
+ const discriminatorPath = [...path25, schema.discriminator];
2938
+ const branchValues = Object.keys(schema.branches);
2939
+ const expected = `one of ${branchValues.join(", ")}`;
2940
+ if (!Object.hasOwn(value, schema.discriminator)) {
2941
+ addIssueWithMessage(
2942
+ state,
2943
+ discriminatorPath,
2944
+ expected,
2945
+ "missing",
2946
+ `Missing discriminator "${schema.discriminator}" at ${formatPath(path25)}. Expected one of: ${branchValues.join(", ")}.`
2947
+ );
2948
+ return { present: true, value };
2949
+ }
2950
+ if (typeof discriminatorValue !== "string" || !Object.hasOwn(schema.branches, discriminatorValue)) {
2951
+ addIssueWithMessage(
2952
+ state,
2953
+ discriminatorPath,
2954
+ expected,
2955
+ receivedValue(discriminatorValue),
2956
+ `Expected ${expected} at ${formatPath(discriminatorPath)}, got ${formatReceivedDiscriminator(discriminatorValue)}`
2957
+ );
2958
+ return { present: true, value };
2959
+ }
2960
+ return walkObject(schema.branches[discriminatorValue], value, path25, state, {
2961
+ [schema.discriminator]: discriminatorValue
2962
+ });
2963
+ }
2964
+ function walkUnion(schema, value, path25, state) {
2965
+ if (isPlainRecord(value)) {
2966
+ const candidateBranches = schema.branches.filter((branch) => hasRequiredKeys(branch, value));
2967
+ if (candidateBranches.length === 1) {
2968
+ return walkObject(candidateBranches[0], value, path25, state);
2969
+ }
2970
+ }
2971
+ const matches = [];
2972
+ for (const branch of schema.branches) {
2973
+ const branchState = { issues: [] };
2974
+ const result = walkObject(branch, value, path25, branchState);
2975
+ if (branchState.issues.length === 0 && result.present) {
2976
+ matches.push({ fingerprint: getRequiredKeyFingerprint(branch), value: result.value });
2977
+ }
2978
+ }
2979
+ if (matches.length === 1) {
2980
+ return { present: true, value: matches[0].value };
2981
+ }
2982
+ if (matches.length === 0) {
2983
+ const branchDescriptions = schema.branches.map((branch) => getRequiredKeyFingerprint(branch));
2984
+ addIssueWithMessage(
2985
+ state,
2986
+ path25,
2987
+ "exactly one union branch",
2988
+ "0 matching branches",
2989
+ `No union branch matched at ${formatPath(path25)}. Tried ${schema.branches.length} branches. Expected one of: ${branchDescriptions.join(" | ")}.`
2990
+ );
2991
+ return { present: true, value };
2992
+ }
2993
+ addIssueWithMessage(
2994
+ state,
2995
+ path25,
2996
+ "exactly one union branch",
2997
+ `${matches.length} matching branches`,
2998
+ `Expected exactly one union branch at ${formatPath(path25)}, but matched more than one branch: ${matches.map((match) => match.fingerprint).join(" | ")}`
2999
+ );
3000
+ return { present: true, value };
3001
+ }
3002
+ function hasRequiredKeys(schema, value) {
3003
+ for (const [key2, propertySchema] of Object.entries(schema.shape)) {
3004
+ if (propertySchema.kind !== "optional" && !Object.hasOwn(value, key2)) {
3005
+ return false;
3006
+ }
3007
+ }
3008
+ return true;
3009
+ }
3010
+ function walkRecord(schema, value, path25, state) {
3011
+ if (!isPlainRecord(value)) {
3012
+ addExpectedIssue(state, path25, "object", value);
3013
+ return { present: true, value };
3014
+ }
3015
+ const nextValue = {};
3016
+ for (const [key2, propertyValue] of Object.entries(value)) {
3017
+ const result = walkSchema(schema.value, propertyValue, [...path25, key2], state);
3018
+ if (result.present) {
3019
+ setOwnValue(nextValue, key2, result.value);
3020
+ }
3021
+ }
3022
+ return { present: true, value: nextValue };
3023
+ }
3024
+ function walkJson(value, path25, state) {
3025
+ if (isJsonValue(value)) {
3026
+ return { present: true, value };
3027
+ }
3028
+ addExpectedIssue(state, path25, "JSON value", value);
3029
+ return { present: true, value };
3030
+ }
3031
+ function getDefault(schema) {
3032
+ if (schema.default !== void 0) {
3033
+ return { present: true, value: schema.default };
3034
+ }
3035
+ if (schema.kind === "optional") {
3036
+ return getDefault(schema.inner);
3037
+ }
3038
+ return { present: false };
3039
+ }
3040
+ function isPlainRecord(value) {
3041
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
3042
+ return false;
3043
+ }
3044
+ const prototype = Object.getPrototypeOf(value);
3045
+ return prototype === Object.prototype || prototype === null;
3046
+ }
3047
+ function isJsonValue(value, ancestors = /* @__PURE__ */ new Set()) {
3048
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
3049
+ return typeof value !== "number" || Number.isFinite(value);
3050
+ }
3051
+ if (Array.isArray(value)) {
3052
+ if (ancestors.has(value)) {
3053
+ return false;
3054
+ }
3055
+ ancestors.add(value);
3056
+ const result = value.every((item) => isJsonValue(item, ancestors));
3057
+ ancestors.delete(value);
3058
+ return result;
3059
+ }
3060
+ if (isPlainRecord(value)) {
3061
+ if (ancestors.has(value)) {
3062
+ return false;
3063
+ }
3064
+ ancestors.add(value);
3065
+ const result = Object.values(value).every((item) => isJsonValue(item, ancestors));
3066
+ ancestors.delete(value);
3067
+ return result;
3068
+ }
3069
+ return false;
3070
+ }
3071
+ function cloneDefault(value) {
3072
+ return structuredClone(value);
3073
+ }
3074
+ function setOwnValue(target, key2, value) {
3075
+ Object.defineProperty(target, key2, {
3076
+ configurable: true,
3077
+ enumerable: true,
3078
+ writable: true,
3079
+ value
3080
+ });
3081
+ }
3082
+ function expectedFor(schema) {
3083
+ switch (schema.kind) {
3084
+ case "string":
3085
+ return "string";
3086
+ case "number":
3087
+ return schema.jsonType === "integer" ? "integer" : "number";
3088
+ case "boolean":
3089
+ return "boolean";
3090
+ case "enum":
3091
+ return `one of ${schema.values.join(", ")}`;
3092
+ case "array":
3093
+ return "array";
3094
+ case "object":
3095
+ case "oneOf":
3096
+ case "record":
3097
+ return "object";
3098
+ case "union":
3099
+ return "exactly one union branch";
3100
+ case "json":
3101
+ return "JSON value";
3102
+ case "optional":
3103
+ return expectedFor(schema.inner);
3104
+ }
3105
+ }
3106
+ function addExpectedIssue(state, path25, expected, value) {
3107
+ addIssue(
3108
+ state,
3109
+ path25,
3110
+ expected,
3111
+ receivedType(value),
3112
+ `Expected ${expected} at ${formatPath(path25)}`
3113
+ );
3114
+ }
3115
+ function addUnexpectedPropertyIssue(state, path25) {
3116
+ addIssue(
3117
+ state,
3118
+ path25,
3119
+ "no additional properties",
3120
+ "unknown property",
3121
+ `Unexpected property ${formatPath(path25)}`
3122
+ );
3123
+ }
3124
+ function addIssue(state, path25, expected, received, _message) {
3125
+ state.issues.push({
3126
+ path: path25,
3127
+ expected,
3128
+ received,
3129
+ message: formatIssueMessage(expected, path25, received)
3130
+ });
3131
+ }
3132
+ function addIssueWithMessage(state, path25, expected, received, message2) {
3133
+ state.issues.push({
3134
+ path: path25,
3135
+ expected,
3136
+ received,
3137
+ message: message2
3138
+ });
3139
+ }
3140
+ function formatIssueMessage(expected, path25, received) {
3141
+ return `Expected ${expected} at ${formatPath(path25)}, got ${received}`;
3142
+ }
3143
+ function formatPath(path25) {
3144
+ return path25.length === 0 ? "value" : path25.join(".");
3145
+ }
3146
+ function compilePattern(pattern) {
3147
+ try {
3148
+ return new RegExp(pattern);
3149
+ } catch {
3150
+ return void 0;
3151
+ }
3152
+ }
3153
+ function receivedType(value) {
3154
+ if (value === null) {
3155
+ return "null";
3156
+ }
3157
+ if (Array.isArray(value)) {
3158
+ return "array";
3159
+ }
3160
+ if (typeof value === "number" && Number.isInteger(value)) {
3161
+ return "integer";
3162
+ }
3163
+ return typeof value;
3164
+ }
3165
+ function receivedValue(value) {
3166
+ if (typeof value === "string") {
3167
+ return value;
3168
+ }
3169
+ if (value === void 0) {
3170
+ return "undefined";
3171
+ }
3172
+ return String(value);
3173
+ }
3174
+ function formatReceivedDiscriminator(value) {
3175
+ if (typeof value === "string") {
3176
+ return JSON.stringify(value);
3177
+ }
3178
+ return receivedValue(value);
3179
+ }
3180
+
2705
3181
  // ../toolcraft-schema/src/index.ts
2706
3182
  function assertValidEnumValues(values) {
2707
3183
  if (values.length === 0) {
@@ -2725,6 +3201,22 @@ function assertFiniteNumber(value, name) {
2725
3201
  throw new Error(`${name} must be finite`);
2726
3202
  }
2727
3203
  }
3204
+ function assertMinMaxOrder(minimum, maximum, minimumName, maximumName) {
3205
+ if (minimum !== void 0 && maximum !== void 0 && minimum > maximum) {
3206
+ throw new Error(`${minimumName} must be less than or equal to ${maximumName}`);
3207
+ }
3208
+ }
3209
+ function assertValidDefault(schema) {
3210
+ if (schema.default === void 0) {
3211
+ return;
3212
+ }
3213
+ const result = validate(schema, schema.default);
3214
+ if (!result.ok) {
3215
+ throw new Error(
3216
+ `default must satisfy schema: ${result.issues[0]?.message ?? "invalid default"}`
3217
+ );
3218
+ }
3219
+ }
2728
3220
  function assertPattern(pattern) {
2729
3221
  if (pattern === void 0) {
2730
3222
  return;
@@ -2739,56 +3231,71 @@ var S = {
2739
3231
  String(options = {}) {
2740
3232
  assertNonNegativeInteger(options.minLength, "minLength");
2741
3233
  assertNonNegativeInteger(options.maxLength, "maxLength");
3234
+ assertMinMaxOrder(options.minLength, options.maxLength, "minLength", "maxLength");
2742
3235
  assertPattern(options.pattern);
2743
- return {
3236
+ const schema = {
2744
3237
  kind: "string",
2745
3238
  ...options
2746
3239
  };
3240
+ assertValidDefault(schema);
3241
+ return schema;
2747
3242
  },
2748
3243
  Number(options = {}) {
2749
3244
  assertFiniteNumber(options.minimum, "minimum");
2750
3245
  assertFiniteNumber(options.maximum, "maximum");
3246
+ assertMinMaxOrder(options.minimum, options.maximum, "minimum", "maximum");
2751
3247
  assertFiniteNumber(options.default, "default");
2752
3248
  if (options.jsonType === "integer" && options.default !== void 0 && !Number.isInteger(options.default)) {
2753
3249
  throw new Error("default must be an integer");
2754
3250
  }
2755
- return {
3251
+ const schema = {
2756
3252
  kind: "number",
2757
3253
  ...options
2758
3254
  };
3255
+ assertValidDefault(schema);
3256
+ return schema;
2759
3257
  },
2760
3258
  Boolean(options = {}) {
2761
- return {
3259
+ const schema = {
2762
3260
  kind: "boolean",
2763
3261
  ...options
2764
3262
  };
3263
+ assertValidDefault(schema);
3264
+ return schema;
2765
3265
  },
2766
3266
  Enum(values, options = {}) {
2767
3267
  assertValidEnumValues(values);
2768
3268
  if (options.jsonType === "integer" && values.some((value) => typeof value !== "number" || !Number.isInteger(value))) {
2769
3269
  throw new Error("Integer enum values must be integers");
2770
3270
  }
2771
- return {
3271
+ const schema = {
2772
3272
  kind: "enum",
2773
3273
  values,
2774
3274
  ...options
2775
3275
  };
3276
+ assertValidDefault(schema);
3277
+ return schema;
2776
3278
  },
2777
3279
  Array(item, options = {}) {
2778
3280
  assertNonNegativeInteger(options.minItems, "minItems");
2779
3281
  assertNonNegativeInteger(options.maxItems, "maxItems");
2780
- return {
3282
+ assertMinMaxOrder(options.minItems, options.maxItems, "minItems", "maxItems");
3283
+ const schema = {
2781
3284
  kind: "array",
2782
3285
  item,
2783
3286
  ...options
2784
3287
  };
3288
+ assertValidDefault(schema);
3289
+ return schema;
2785
3290
  },
2786
3291
  Object(shape, options = {}) {
2787
- return {
3292
+ const schema = {
2788
3293
  kind: "object",
2789
3294
  shape,
2790
3295
  ...options
2791
3296
  };
3297
+ assertValidDefault(schema);
3298
+ return schema;
2792
3299
  },
2793
3300
  Optional(inner) {
2794
3301
  return {
@@ -3360,6 +3867,9 @@ function isRecord(value) {
3360
3867
  function isStateList(value) {
3361
3868
  return Array.isArray(value) && value.every((entry) => typeof entry === "string");
3362
3869
  }
3870
+ function hasVisibleName(value) {
3871
+ return value.trim().length > 0;
3872
+ }
3363
3873
  function canFireFromState(event, fromState) {
3364
3874
  if (event.from === "*") {
3365
3875
  return event.to !== fromState;
@@ -3374,6 +3884,9 @@ function validateMachine(machine) {
3374
3884
  throw new TypeError("State machine states must be a string array.");
3375
3885
  }
3376
3886
  const states = new Set(machine.states);
3887
+ if (machine.states.some((state) => !hasVisibleName(state))) {
3888
+ throw new Error("State names must not be empty.");
3889
+ }
3377
3890
  if (!hasOwnRecordField(machine, "initial") || typeof machine.initial !== "string") {
3378
3891
  throw new TypeError("State machine initial must be a string.");
3379
3892
  }
@@ -3384,6 +3897,9 @@ function validateMachine(machine) {
3384
3897
  throw new TypeError("State machine events must be an object.");
3385
3898
  }
3386
3899
  for (const [eventName, event] of Object.entries(machine.events)) {
3900
+ if (!hasVisibleName(eventName)) {
3901
+ throw new Error("Event names must not be empty.");
3902
+ }
3387
3903
  if (!isRecord(event)) {
3388
3904
  throw new TypeError(`Event "${eventName}" must be an object.`);
3389
3905
  }
@@ -3493,6 +4009,13 @@ import { text as text3 } from "node:stream/consumers";
3493
4009
  // ../process-runner/src/docker/context.ts
3494
4010
  import { execSync } from "node:child_process";
3495
4011
 
4012
+ // ../process-runner/src/docker/build-context.ts
4013
+ import { readdir, readFile } from "node:fs/promises";
4014
+ import { createRequire } from "node:module";
4015
+ import path2 from "node:path";
4016
+ var require2 = createRequire(import.meta.url);
4017
+ var createIgnore = require2("ignore");
4018
+
3496
4019
  // ../process-runner/src/docker/engine.ts
3497
4020
  import { execSync as execSync2 } from "node:child_process";
3498
4021
 
@@ -3501,19 +4024,19 @@ import * as childProcess from "node:child_process";
3501
4024
  import { randomBytes } from "node:crypto";
3502
4025
 
3503
4026
  // ../process-runner/src/docker/args.ts
3504
- import path2 from "node:path";
4027
+ import path3 from "node:path";
3505
4028
 
3506
4029
  // ../process-runner/src/docker/env-file.ts
3507
4030
  import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3508
4031
  import { tmpdir } from "node:os";
3509
- import path3 from "node:path";
4032
+ import path4 from "node:path";
3510
4033
 
3511
4034
  // ../process-runner/src/docker/docker-execution-env.ts
3512
4035
  import { createHash as createHash2, randomBytes as randomBytes2 } from "node:crypto";
3513
4036
  import { mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "node:fs";
3514
- import { readdir, readFile, realpath, writeFile } from "node:fs/promises";
4037
+ import { readFile as readFile2, realpath, writeFile } from "node:fs/promises";
3515
4038
  import { tmpdir as tmpdir2 } from "node:os";
3516
- import path5 from "node:path";
4039
+ import path6 from "node:path";
3517
4040
 
3518
4041
  // ../process-runner/src/host/host-runner.ts
3519
4042
  import { spawn as spawnChildProcess } from "node:child_process";
@@ -3646,7 +4169,7 @@ function bindAbortSignal(signal, onAbort) {
3646
4169
  // ../process-runner/src/workspace-transfer.ts
3647
4170
  import { createHash, randomUUID } from "node:crypto";
3648
4171
  import { promises as nodeFs } from "node:fs";
3649
- import path4 from "node:path";
4172
+ import path5 from "node:path";
3650
4173
 
3651
4174
  // ../process-runner/src/testing/mock-runner.ts
3652
4175
  import { Readable, Writable } from "node:stream";
@@ -3718,7 +4241,7 @@ function resolveEndpoint(options = {}) {
3718
4241
 
3719
4242
  // ../task-list/src/backends/utils.ts
3720
4243
  import { randomUUID as randomUUID2 } from "node:crypto";
3721
- import path6 from "node:path";
4244
+ import path7 from "node:path";
3722
4245
  function compareCreated(left, right) {
3723
4246
  const leftCreated = typeof left.raw.created === "string" ? left.raw.created : "";
3724
4247
  const rightCreated = typeof right.raw.created === "string" ? right.raw.created : "";
@@ -3750,15 +4273,33 @@ function sortStrings(values) {
3750
4273
  function sortTasks(tasks) {
3751
4274
  return [...tasks].sort((left, right) => left.qualifiedId.localeCompare(right.qualifiedId));
3752
4275
  }
4276
+ function isTrimmedPrintableIdentifier(value) {
4277
+ if (value.length === 0 || value !== value.trim()) {
4278
+ return false;
4279
+ }
4280
+ for (let index = 0; index < value.length; index += 1) {
4281
+ const code = value.charCodeAt(index);
4282
+ if (code < 32 || code === 127) {
4283
+ return false;
4284
+ }
4285
+ }
4286
+ return true;
4287
+ }
3753
4288
  function validateTaskId(id) {
3754
- if (id.length === 0 || id.startsWith(".") || id.includes("/") || id.includes("\\") || id.includes("..")) {
4289
+ if (!isTrimmedPrintableIdentifier(id) || id.startsWith(".") || id.includes("/") || id.includes("\\") || id.includes("..")) {
3755
4290
  throw new Error(`Invalid task id "${id}".`);
3756
4291
  }
3757
4292
  return id;
3758
4293
  }
3759
- async function statIfExists(fs4, filePath) {
4294
+ function validateTaskName(name) {
4295
+ if (name.trim().length === 0) {
4296
+ throw new Error("Task name must not be empty.");
4297
+ }
4298
+ return name;
4299
+ }
4300
+ async function statIfExists(fs5, filePath) {
3760
4301
  try {
3761
- return await fs4.stat(filePath);
4302
+ return await fs5.stat(filePath);
3762
4303
  } catch (error3) {
3763
4304
  if (hasErrorCode(error3, "ENOENT")) {
3764
4305
  return void 0;
@@ -3766,15 +4307,18 @@ async function statIfExists(fs4, filePath) {
3766
4307
  throw error3;
3767
4308
  }
3768
4309
  }
3769
- async function rejectSymbolicLinkComponents(fs4, filePath) {
3770
- const resolvedPath = path6.resolve(filePath);
3771
- const rootPath = path6.parse(resolvedPath).root;
3772
- const components = resolvedPath.slice(rootPath.length).split(path6.sep).filter(Boolean);
4310
+ async function rejectSymbolicLinkComponents(fs5, filePath) {
4311
+ const resolvedPath = path7.resolve(filePath);
4312
+ const rootPath = path7.parse(resolvedPath).root;
4313
+ const components = resolvedPath.slice(rootPath.length).split(path7.sep).filter(Boolean);
3773
4314
  let currentPath = rootPath;
3774
4315
  for (const component of components) {
3775
- currentPath = path6.join(currentPath, component);
4316
+ currentPath = path7.join(currentPath, component);
3776
4317
  try {
3777
- if ((await fs4.lstat(currentPath)).isSymbolicLink()) {
4318
+ if ((await fs5.lstat(currentPath)).isSymbolicLink()) {
4319
+ if (currentPath === "/tmp") {
4320
+ continue;
4321
+ }
3778
4322
  throw new Error(`Path "${filePath}" contains a symbolic link.`);
3779
4323
  }
3780
4324
  } catch (error3) {
@@ -3785,19 +4329,19 @@ async function rejectSymbolicLinkComponents(fs4, filePath) {
3785
4329
  }
3786
4330
  }
3787
4331
  }
3788
- async function writeAtomically(fs4, filePath, content) {
4332
+ async function writeAtomically(fs5, filePath, content) {
3789
4333
  const tempPath = `${filePath}.${process.pid}.${randomUUID2()}.tmp`;
3790
4334
  let tempCreated = false;
3791
- await fs4.mkdir(path6.dirname(filePath), { recursive: true });
4335
+ await fs5.mkdir(path7.dirname(filePath), { recursive: true });
3792
4336
  try {
3793
- await fs4.writeFile(tempPath, content, { encoding: "utf8", flag: "wx" });
4337
+ await fs5.writeFile(tempPath, content, { encoding: "utf8", flag: "wx" });
3794
4338
  tempCreated = true;
3795
- await fs4.rename(tempPath, filePath);
4339
+ await fs5.rename(tempPath, filePath);
3796
4340
  tempCreated = false;
3797
4341
  } catch (error3) {
3798
4342
  if (tempCreated || !hasErrorCode(error3, "EEXIST")) {
3799
4343
  try {
3800
- await fs4.unlink(tempPath);
4344
+ await fs5.unlink(tempPath);
3801
4345
  } catch (unlinkError) {
3802
4346
  if (!hasErrorCode(unlinkError, "ENOENT")) {
3803
4347
  throw unlinkError;
@@ -3807,18 +4351,18 @@ async function writeAtomically(fs4, filePath, content) {
3807
4351
  throw error3;
3808
4352
  }
3809
4353
  }
3810
- async function withFileLock(fs4, lockPath, operation) {
3811
- await fs4.mkdir(path6.dirname(lockPath), { recursive: true });
4354
+ async function withFileLock(fs5, lockPath, operation) {
4355
+ await fs5.mkdir(path7.dirname(lockPath), { recursive: true });
3812
4356
  for (; ; ) {
3813
4357
  try {
3814
- await fs4.writeFile(lockPath, String(process.pid), { encoding: "utf8", flag: "wx" });
4358
+ await fs5.writeFile(lockPath, String(process.pid), { encoding: "utf8", flag: "wx" });
3815
4359
  break;
3816
4360
  } catch (error3) {
3817
4361
  if (!hasErrorCode(error3, "EEXIST")) {
3818
- await fs4.unlink(lockPath).catch(() => void 0);
4362
+ await fs5.unlink(lockPath).catch(() => void 0);
3819
4363
  throw error3;
3820
4364
  }
3821
- if (await removeAbandonedLock(fs4, lockPath)) {
4365
+ if (await removeAbandonedLock(fs5, lockPath)) {
3822
4366
  continue;
3823
4367
  }
3824
4368
  await Promise.resolve();
@@ -3827,13 +4371,13 @@ async function withFileLock(fs4, lockPath, operation) {
3827
4371
  try {
3828
4372
  return await operation();
3829
4373
  } finally {
3830
- await fs4.unlink(lockPath);
4374
+ await fs5.unlink(lockPath);
3831
4375
  }
3832
4376
  }
3833
- async function removeAbandonedLock(fs4, lockPath) {
4377
+ async function removeAbandonedLock(fs5, lockPath) {
3834
4378
  let content;
3835
4379
  try {
3836
- content = await fs4.readFile(lockPath, "utf8");
4380
+ content = await fs5.readFile(lockPath, "utf8");
3837
4381
  } catch (error3) {
3838
4382
  if (hasErrorCode(error3, "ENOENT")) {
3839
4383
  return true;
@@ -3841,11 +4385,11 @@ async function removeAbandonedLock(fs4, lockPath) {
3841
4385
  throw error3;
3842
4386
  }
3843
4387
  const owner = Number(content);
3844
- if (!Number.isInteger(owner) || owner <= 0 || isProcessRunning(owner)) {
4388
+ if (Number.isInteger(owner) && owner > 0 && isProcessRunning(owner)) {
3845
4389
  return false;
3846
4390
  }
3847
4391
  try {
3848
- await fs4.unlink(lockPath);
4392
+ await fs5.unlink(lockPath);
3849
4393
  return true;
3850
4394
  } catch (error3) {
3851
4395
  if (hasErrorCode(error3, "ENOENT")) {
@@ -4113,6 +4657,9 @@ async function ghIssuesBackend(deps) {
4113
4657
  if (deps.state?.labelPrefix === "") {
4114
4658
  throw new Error("gh-issues state.labelPrefix must be a non-empty string when configured.");
4115
4659
  }
4660
+ if (deps.stateMachine !== void 0) {
4661
+ validateMachine(deps.stateMachine);
4662
+ }
4116
4663
  const client = createGhClient({
4117
4664
  token: deps.token,
4118
4665
  endpoint: deps.endpoint,
@@ -4272,7 +4819,9 @@ function createTasksView(name, session, context) {
4272
4819
  );
4273
4820
  projectItemId = added.addProjectV2ItemById?.item?.id ?? void 0;
4274
4821
  if (projectItemId === void 0) {
4275
- throw new Error("GitHub addProjectV2ItemById response did not include project item id.");
4822
+ throw new Error(
4823
+ "GitHub addProjectV2ItemById response did not include project item id."
4824
+ );
4276
4825
  }
4277
4826
  }
4278
4827
  if (session.labelPrefix === void 0) {
@@ -4501,12 +5050,15 @@ async function resolveProjectItemId(id, listName, session, context) {
4501
5050
  const issueNumber = parseIssueNumber(id, listName);
4502
5051
  let after;
4503
5052
  while (true) {
4504
- const result = await context.client.graphql(ISSUE_STATE_LABELS_QUERY, {
4505
- owner: context.repoOwner,
4506
- repo: context.repoName,
4507
- number: issueNumber,
4508
- after
4509
- });
5053
+ const result = await context.client.graphql(
5054
+ ISSUE_STATE_LABELS_QUERY,
5055
+ {
5056
+ owner: context.repoOwner,
5057
+ repo: context.repoName,
5058
+ number: issueNumber,
5059
+ after
5060
+ }
5061
+ );
4510
5062
  const issue = result.repository?.issue ?? null;
4511
5063
  if (issue === null) {
4512
5064
  throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
@@ -4783,12 +5335,27 @@ async function fetchIssueTask(id, listName, session, context) {
4783
5335
  });
4784
5336
  }
4785
5337
  function parseIssueNumber(id, listName) {
5338
+ if (!isCanonicalDecimalIssueId(id)) {
5339
+ throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
5340
+ }
4786
5341
  const issueNumber = Number(id);
4787
- if (!Number.isInteger(issueNumber) || issueNumber < 1) {
5342
+ if (!Number.isSafeInteger(issueNumber) || issueNumber < 1) {
4788
5343
  throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
4789
5344
  }
4790
5345
  return issueNumber;
4791
5346
  }
5347
+ function isCanonicalDecimalIssueId(id) {
5348
+ if (id.length === 0 || id[0] === "0") {
5349
+ return false;
5350
+ }
5351
+ for (let index = 0; index < id.length; index += 1) {
5352
+ const charCode = id.charCodeAt(index);
5353
+ if (charCode < 48 || charCode > 57) {
5354
+ return false;
5355
+ }
5356
+ }
5357
+ return true;
5358
+ }
4792
5359
  function mapProjectItemToTask(item, listName, session) {
4793
5360
  const content = item.content;
4794
5361
  if (!isIssueNode(content)) {
@@ -4896,7 +5463,7 @@ function parseQualifiedId(qualifiedId, listName) {
4896
5463
  }
4897
5464
 
4898
5465
  // ../task-list/src/backends/markdown-dir.ts
4899
- import path7 from "node:path";
5466
+ import path8 from "node:path";
4900
5467
  import { parseDocument as parseDocument2, stringify as stringify2 } from "yaml";
4901
5468
 
4902
5469
  // ../task-list/src/schema/task.schema.json
@@ -4999,7 +5566,7 @@ function resolveListLayout(deps) {
4999
5566
  return deps.singleList ? { kind: "single", name: deps.singleList } : { kind: "multi" };
5000
5567
  }
5001
5568
  function validateListName(name) {
5002
- if (name.length === 0 || name === ARCHIVE_DIRECTORY_NAME || name.startsWith(".") || name.includes("/") || name.includes("\\") || name.includes("..")) {
5569
+ if (!isTrimmedPrintableIdentifier(name) || name === ARCHIVE_DIRECTORY_NAME || name.startsWith(".") || name.includes("/") || name.includes("\\") || name.includes("..")) {
5003
5570
  throw new Error(`Invalid task list name "${name}".`);
5004
5571
  }
5005
5572
  return name;
@@ -5015,16 +5582,16 @@ function parseQualifiedId2(qualifiedId) {
5015
5582
  };
5016
5583
  }
5017
5584
  function listPath(rootPath, layout, list) {
5018
- return layout.kind === "single" ? rootPath : path7.join(rootPath, list);
5585
+ return layout.kind === "single" ? rootPath : path8.join(rootPath, list);
5019
5586
  }
5020
5587
  function archiveDirectoryPath(rootPath, layout, list) {
5021
- return layout.kind === "single" ? path7.join(rootPath, ARCHIVE_DIRECTORY_NAME) : path7.join(rootPath, list, ARCHIVE_DIRECTORY_NAME);
5588
+ return layout.kind === "single" ? path8.join(rootPath, ARCHIVE_DIRECTORY_NAME) : path8.join(rootPath, list, ARCHIVE_DIRECTORY_NAME);
5022
5589
  }
5023
5590
  function activeTaskFilename(id, order, width) {
5024
5591
  return `${String(order).padStart(width, "0")}-${id}${MARKDOWN_EXTENSION}`;
5025
5592
  }
5026
5593
  function archivedTaskPath(rootPath, layout, list, id) {
5027
- return path7.join(archiveDirectoryPath(rootPath, layout, list), `${id}${MARKDOWN_EXTENSION}`);
5594
+ return path8.join(archiveDirectoryPath(rootPath, layout, list), `${id}${MARKDOWN_EXTENSION}`);
5028
5595
  }
5029
5596
  function isMarkdownFile(entryName) {
5030
5597
  return entryName.endsWith(MARKDOWN_EXTENSION);
@@ -5126,7 +5693,7 @@ function hasOwnTaskField(frontmatter, key2) {
5126
5693
  function reservedFrontmatterKeys(mode) {
5127
5694
  return mode === "passthrough" ? PASSTHROUGH_RESERVED_FRONTMATTER_KEYS : RESERVED_FRONTMATTER_KEYS;
5128
5695
  }
5129
- function setOwnValue(record, key2, value) {
5696
+ function setOwnValue2(record, key2, value) {
5130
5697
  Object.defineProperty(record, key2, {
5131
5698
  value,
5132
5699
  enumerable: true,
@@ -5139,7 +5706,7 @@ function metadataFromFrontmatter(frontmatter, mode) {
5139
5706
  const reservedKeys = reservedFrontmatterKeys(mode);
5140
5707
  for (const [key2, value] of Object.entries(frontmatter)) {
5141
5708
  if (!reservedKeys.has(key2)) {
5142
- setOwnValue(metadata, key2, value);
5709
+ setOwnValue2(metadata, key2, value);
5143
5710
  }
5144
5711
  }
5145
5712
  return metadata;
@@ -5153,7 +5720,7 @@ function createTask(list, id, frontmatter, body, mode, sourcePath) {
5153
5720
  state: frontmatter.state,
5154
5721
  description: body,
5155
5722
  metadata: metadataFromFrontmatter(frontmatter, mode),
5156
- ...sourcePath !== void 0 && { sourcePath: path7.resolve(sourcePath) }
5723
+ ...sourcePath !== void 0 && { sourcePath: path8.resolve(sourcePath) }
5157
5724
  };
5158
5725
  }
5159
5726
  function serializeTaskDocument(frontmatter, description) {
@@ -5162,9 +5729,9 @@ ${stringify2(frontmatter)}---
5162
5729
 
5163
5730
  ${description}`;
5164
5731
  }
5165
- async function readDirectoryNames(fs4, directoryPath) {
5732
+ async function readDirectoryNames(fs5, directoryPath) {
5166
5733
  try {
5167
- return sortStrings(await fs4.readdir(directoryPath));
5734
+ return sortStrings(await fs5.readdir(directoryPath));
5168
5735
  } catch (error3) {
5169
5736
  if (hasErrorCode(error3, "ENOENT")) {
5170
5737
  return [];
@@ -5180,9 +5747,9 @@ async function ensureRootPath(deps) {
5180
5747
  }
5181
5748
  await deps.fs.stat(deps.path);
5182
5749
  }
5183
- async function readTaskFile(fs4, list, id, filePath, validStates, initialState, mode) {
5184
- await rejectSymbolicLinkComponents(fs4, filePath);
5185
- const content = await fs4.readFile(filePath, "utf8");
5750
+ async function readTaskFile(fs5, list, id, filePath, validStates, initialState, mode) {
5751
+ await rejectSymbolicLinkComponents(fs5, filePath);
5752
+ const content = await fs5.readFile(filePath, "utf8");
5186
5753
  const document = splitTaskDocument(content, filePath, mode);
5187
5754
  const frontmatter = mode === "passthrough" && document.frontmatter.trim().length === 0 ? {} : readFrontmatter(document.frontmatter, filePath);
5188
5755
  if (mode !== "passthrough") {
@@ -5193,57 +5760,106 @@ async function readTaskFile(fs4, list, id, filePath, validStates, initialState,
5193
5760
  task: createTask(list, id, frontmatter, document.body, mode, filePath)
5194
5761
  };
5195
5762
  }
5196
- const parsedFilename = parseActiveFilename(path7.basename(filePath));
5197
- const defaultName = parsedFilename?.id ?? id;
5198
5763
  const effectiveFrontmatter = {
5199
5764
  ...frontmatter,
5200
- name: typeof frontmatter.name === "string" ? frontmatter.name : defaultName,
5765
+ name: typeof frontmatter.name === "string" ? frontmatter.name : id,
5201
5766
  state: typeof frontmatter.state === "string" && validStates.has(frontmatter.state) ? frontmatter.state : initialState
5202
5767
  };
5203
5768
  return {
5204
- path: filePath,
5205
- frontmatter,
5206
- task: createTask(list, id, effectiveFrontmatter, document.body, mode, filePath)
5769
+ path: filePath,
5770
+ frontmatter,
5771
+ task: createTask(list, id, effectiveFrontmatter, document.body, mode, filePath)
5772
+ };
5773
+ }
5774
+ async function readPassthroughFrontmatter(fs5, filePath, mode) {
5775
+ if (mode !== "passthrough") {
5776
+ return {};
5777
+ }
5778
+ const content = await fs5.readFile(filePath, "utf8");
5779
+ const document = splitTaskDocument(content, filePath, mode);
5780
+ if (document.frontmatter.trim().length === 0) {
5781
+ return {};
5782
+ }
5783
+ return readFrontmatter(document.frontmatter, filePath);
5784
+ }
5785
+ async function resolveActiveFilenameEntry(fs5, entryName, entryPath, parsed, mode) {
5786
+ if (mode !== "passthrough" || parsed.order === null) {
5787
+ return parsed;
5788
+ }
5789
+ const frontmatter = await readPassthroughFrontmatter(fs5, entryPath, mode);
5790
+ if (Object.keys(frontmatter).length === 0 && orderedFilenamePrefixLength(entryName) <= MIN_PREFIX_WIDTH) {
5791
+ return parsed;
5792
+ }
5793
+ if (typeof frontmatter.state === "string" || hasOwnTaskField(frontmatter, "$schema") || hasOwnTaskField(frontmatter, "kind") || hasOwnTaskField(frontmatter, "version")) {
5794
+ return parsed;
5795
+ }
5796
+ return {
5797
+ id: entryName.slice(0, -MARKDOWN_EXTENSION.length),
5798
+ order: null,
5799
+ filename: parsed.filename
5207
5800
  };
5208
5801
  }
5209
- async function findActiveTaskFilename(fs4, listDirectoryPath, id) {
5210
- const entries = await readDirectoryNames(fs4, listDirectoryPath);
5802
+ function orderedFilenamePrefixLength(entryName) {
5803
+ const stem = entryName.slice(0, -MARKDOWN_EXTENSION.length);
5804
+ const separatorIndex = stem.indexOf("-");
5805
+ if (separatorIndex <= 0) {
5806
+ return Number.POSITIVE_INFINITY;
5807
+ }
5808
+ for (let index = 0; index < separatorIndex; index += 1) {
5809
+ const code = stem.charCodeAt(index);
5810
+ if (code < 48 || code > 57) {
5811
+ return Number.POSITIVE_INFINITY;
5812
+ }
5813
+ }
5814
+ return separatorIndex;
5815
+ }
5816
+ async function findActiveTaskFilename(fs5, listDirectoryPath, id, mode) {
5817
+ const entries = await readDirectoryNames(fs5, listDirectoryPath);
5211
5818
  for (const entryName of entries) {
5212
5819
  if (isHiddenEntry(entryName)) continue;
5213
5820
  const parsed = parseActiveFilename(entryName);
5214
- if (parsed?.id === id) {
5821
+ if (!parsed) continue;
5822
+ const entryPath = path8.join(listDirectoryPath, entryName);
5823
+ const resolved = await resolveActiveFilenameEntry(
5824
+ fs5,
5825
+ entryName,
5826
+ entryPath,
5827
+ { id: parsed.id, order: parsed.order, filename: entryName },
5828
+ mode
5829
+ );
5830
+ if (resolved.id === id) {
5215
5831
  return entryName;
5216
5832
  }
5217
5833
  }
5218
5834
  return void 0;
5219
5835
  }
5220
- async function findTaskLocation(fs4, rootPath, layout, list, id) {
5836
+ async function findTaskLocation(fs5, rootPath, layout, list, id, mode) {
5221
5837
  const listDirectoryPath = listPath(rootPath, layout, list);
5222
- await rejectSymbolicLinkComponents(fs4, listDirectoryPath);
5223
- const activeName = await findActiveTaskFilename(fs4, listDirectoryPath, id);
5838
+ await rejectSymbolicLinkComponents(fs5, listDirectoryPath);
5839
+ const activeName = await findActiveTaskFilename(fs5, listDirectoryPath, id, mode);
5224
5840
  if (activeName) {
5225
- const activePath = path7.join(listDirectoryPath, activeName);
5226
- await rejectSymbolicLinkComponents(fs4, activePath);
5227
- const activeStat = await statIfExists(fs4, activePath);
5841
+ const activePath = path8.join(listDirectoryPath, activeName);
5842
+ await rejectSymbolicLinkComponents(fs5, activePath);
5843
+ const activeStat = await statIfExists(fs5, activePath);
5228
5844
  if (activeStat?.isFile()) {
5229
5845
  return { archived: false, path: activePath };
5230
5846
  }
5231
5847
  }
5232
5848
  const archivedPath = archivedTaskPath(rootPath, layout, list, id);
5233
- await rejectSymbolicLinkComponents(fs4, archiveDirectoryPath(rootPath, layout, list));
5234
- await rejectSymbolicLinkComponents(fs4, archivedPath);
5235
- const archivedStat = await statIfExists(fs4, archivedPath);
5849
+ await rejectSymbolicLinkComponents(fs5, archiveDirectoryPath(rootPath, layout, list));
5850
+ await rejectSymbolicLinkComponents(fs5, archivedPath);
5851
+ const archivedStat = await statIfExists(fs5, archivedPath);
5236
5852
  if (archivedStat?.isFile()) {
5237
5853
  return { archived: true, path: archivedPath };
5238
5854
  }
5239
5855
  return void 0;
5240
5856
  }
5241
- async function readTaskAtLocation(fs4, rootPath, layout, list, id, validStates, initialState, mode) {
5242
- const location = await findTaskLocation(fs4, rootPath, layout, list, id);
5857
+ async function readTaskAtLocation(fs5, rootPath, layout, list, id, validStates, initialState, mode) {
5858
+ const location = await findTaskLocation(fs5, rootPath, layout, list, id, mode);
5243
5859
  if (!location) {
5244
5860
  throw new TaskNotFoundError(`Task "${list}/${id}" not found.`);
5245
5861
  }
5246
- return readTaskFile(fs4, list, id, location.path, validStates, initialState, mode);
5862
+ return readTaskFile(fs5, list, id, location.path, validStates, initialState, mode);
5247
5863
  }
5248
5864
  function createdFrontmatter(defaults2, input, initialState, mode) {
5249
5865
  const frontmatter = mode !== "passthrough" ? {
@@ -5259,12 +5875,12 @@ function createdFrontmatter(defaults2, input, initialState, mode) {
5259
5875
  const reservedKeys = reservedFrontmatterKeys(mode);
5260
5876
  for (const [key2, value] of Object.entries(defaults2.metadata)) {
5261
5877
  if (!reservedKeys.has(key2)) {
5262
- setOwnValue(frontmatter, key2, value);
5878
+ setOwnValue2(frontmatter, key2, value);
5263
5879
  }
5264
5880
  }
5265
5881
  for (const [key2, value] of Object.entries(input.metadata ?? {})) {
5266
5882
  if (!reservedKeys.has(key2)) {
5267
- setOwnValue(frontmatter, key2, value);
5883
+ setOwnValue2(frontmatter, key2, value);
5268
5884
  }
5269
5885
  }
5270
5886
  frontmatter.created = (/* @__PURE__ */ new Date()).toISOString();
@@ -5286,7 +5902,7 @@ function updatedFrontmatter(existingFrontmatter, task, patch, mode) {
5286
5902
  const reservedKeys = reservedFrontmatterKeys(mode);
5287
5903
  for (const [key2, value] of Object.entries(patch.metadata ?? {})) {
5288
5904
  if (!reservedKeys.has(key2)) {
5289
- setOwnValue(nextFrontmatter, key2, value);
5905
+ setOwnValue2(nextFrontmatter, key2, value);
5290
5906
  }
5291
5907
  }
5292
5908
  return nextFrontmatter;
@@ -5310,7 +5926,7 @@ function firedFrontmatter(existingFrontmatter, task, to, mode, metadataPatch) {
5310
5926
  const reservedKeys = reservedFrontmatterKeys(mode);
5311
5927
  for (const [key2, value] of Object.entries(metadataPatch ?? {})) {
5312
5928
  if (!reservedKeys.has(key2)) {
5313
- setOwnValue(nextFrontmatter, key2, value);
5929
+ setOwnValue2(nextFrontmatter, key2, value);
5314
5930
  }
5315
5931
  }
5316
5932
  return nextFrontmatter;
@@ -5344,11 +5960,19 @@ function createTasksView2(deps, layout, list) {
5344
5960
  if (isHiddenEntry(entryName)) continue;
5345
5961
  const parsed = parseActiveFilename(entryName);
5346
5962
  if (!parsed) continue;
5347
- const entryPath = path7.join(listDirectoryPath, entryName);
5963
+ const entryPath = path8.join(listDirectoryPath, entryName);
5348
5964
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
5349
5965
  const entryStat = await statIfExists(deps.fs, entryPath);
5350
5966
  if (!entryStat?.isFile()) continue;
5351
- result.push({ id: parsed.id, order: parsed.order, filename: entryName });
5967
+ result.push(
5968
+ await resolveActiveFilenameEntry(
5969
+ deps.fs,
5970
+ entryName,
5971
+ entryPath,
5972
+ { id: parsed.id, order: parsed.order, filename: entryName },
5973
+ deps.frontmatterMode
5974
+ )
5975
+ );
5352
5976
  }
5353
5977
  result.sort((left, right) => {
5354
5978
  const leftOrder = left.order ?? Number.POSITIVE_INFINITY;
@@ -5362,7 +5986,7 @@ function createTasksView2(deps, layout, list) {
5362
5986
  const entries = await readActiveEntries();
5363
5987
  const tasks = /* @__PURE__ */ new Map();
5364
5988
  for (const entry of entries) {
5365
- const filePath = path7.join(listDirectoryPath, entry.filename);
5989
+ const filePath = path8.join(listDirectoryPath, entry.filename);
5366
5990
  const file = await readTaskFile(
5367
5991
  deps.fs,
5368
5992
  list,
@@ -5383,7 +6007,7 @@ function createTasksView2(deps, layout, list) {
5383
6007
  const result = [];
5384
6008
  for (const entryName of entries) {
5385
6009
  if (isHiddenEntry(entryName) || !isMarkdownFile(entryName)) continue;
5386
- const entryPath = path7.join(archivePath, entryName);
6010
+ const entryPath = path8.join(archivePath, entryName);
5387
6011
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
5388
6012
  const entryStat = await statIfExists(deps.fs, entryPath);
5389
6013
  if (!entryStat?.isFile()) continue;
@@ -5413,15 +6037,20 @@ function createTasksView2(deps, layout, list) {
5413
6037
  if (desiredOrder === void 0) continue;
5414
6038
  const desiredFilename = activeTaskFilename(entry.id, desiredOrder, width);
5415
6039
  if (entry.filename !== desiredFilename) {
5416
- const fromPath = path7.join(listDirectoryPath, entry.filename);
5417
- const stagingPath = path7.join(
6040
+ const fromPath = path8.join(listDirectoryPath, entry.filename);
6041
+ const stagingPath = path8.join(
5418
6042
  listDirectoryPath,
5419
6043
  `${desiredFilename}.staging-${process.pid}-${index}`
5420
6044
  );
5421
- const targetPath = path7.join(listDirectoryPath, desiredFilename);
6045
+ const targetPath = path8.join(listDirectoryPath, desiredFilename);
5422
6046
  try {
5423
6047
  await deps.fs.rename(fromPath, stagingPath);
5424
- staged.push({ original: fromPath, staging: stagingPath, target: targetPath, finalized: false });
6048
+ staged.push({
6049
+ original: fromPath,
6050
+ staging: stagingPath,
6051
+ target: targetPath,
6052
+ finalized: false
6053
+ });
5425
6054
  } catch (error3) {
5426
6055
  for (const stagedEntry of staged.reverse()) {
5427
6056
  await deps.fs.rename(stagedEntry.staging, stagedEntry.original);
@@ -5556,8 +6185,7 @@ function createTasksView2(deps, layout, list) {
5556
6185
  if (filter?.state && entry.task.state !== filter.state) return false;
5557
6186
  return true;
5558
6187
  });
5559
- const orderedActiveTasks = applyOrder(orderedActive, filter?.order);
5560
- return [...orderedActiveTasks, ...filteredArchived.map((entry) => entry.task)];
6188
+ return applyOrder([...orderedActive, ...filteredArchived], filter?.order);
5561
6189
  },
5562
6190
  async get(id) {
5563
6191
  return (await getTaskFile(id)).task;
@@ -5566,9 +6194,17 @@ function createTasksView2(deps, layout, list) {
5566
6194
  assertCreateDoesNotSetState(input);
5567
6195
  assertCreateHasId(input);
5568
6196
  validateTaskId(input.id);
6197
+ validateTaskName(input.name);
5569
6198
  await rejectSymbolicLinkComponents(deps.fs, listDirectoryPath);
5570
- return withFileLock(deps.fs, path7.join(listDirectoryPath, ".transition.lock"), async () => {
5571
- const existing = await findTaskLocation(deps.fs, deps.path, layout, list, input.id);
6199
+ return withFileLock(deps.fs, path8.join(listDirectoryPath, ".transition.lock"), async () => {
6200
+ const existing = await findTaskLocation(
6201
+ deps.fs,
6202
+ deps.path,
6203
+ layout,
6204
+ list,
6205
+ input.id,
6206
+ deps.frontmatterMode
6207
+ );
5572
6208
  if (existing) {
5573
6209
  throw new TaskAlreadyExistsError(`Task "${list}/${input.id}" already exists.`);
5574
6210
  }
@@ -5580,7 +6216,7 @@ function createTasksView2(deps, layout, list) {
5580
6216
  const nextOrder = maxOrder + 1;
5581
6217
  const width = padWidthForCount(activeEntries.length + 1);
5582
6218
  const filename = activeTaskFilename(input.id, nextOrder, width);
5583
- const targetPath = path7.join(listDirectoryPath, filename);
6219
+ const targetPath = path8.join(listDirectoryPath, filename);
5584
6220
  const frontmatter = createdFrontmatter(
5585
6221
  deps.defaults,
5586
6222
  input,
@@ -5589,12 +6225,22 @@ function createTasksView2(deps, layout, list) {
5589
6225
  );
5590
6226
  const description = input.description ?? "";
5591
6227
  await writeAtomically(deps.fs, targetPath, serializeTaskDocument(frontmatter, description));
5592
- return createTask(list, input.id, frontmatter, description, deps.frontmatterMode, targetPath);
6228
+ return createTask(
6229
+ list,
6230
+ input.id,
6231
+ frontmatter,
6232
+ description,
6233
+ deps.frontmatterMode,
6234
+ targetPath
6235
+ );
5593
6236
  });
5594
6237
  },
5595
6238
  async update(id, patch) {
5596
6239
  assertUpdateDoesNotSetState(patch);
5597
6240
  validateTaskId(id);
6241
+ if (patch.name !== void 0) {
6242
+ validateTaskName(patch.name);
6243
+ }
5598
6244
  const existing = await getTaskFile(id);
5599
6245
  const nextFrontmatter = updatedFrontmatter(
5600
6246
  existing.frontmatter,
@@ -5680,7 +6326,14 @@ function createTasksView2(deps, layout, list) {
5680
6326
  };
5681
6327
  if (stateMachine.events[eventName]?.to === "archived") {
5682
6328
  validateTaskId(id);
5683
- const location = await findTaskLocation(deps.fs, deps.path, layout, list, id);
6329
+ const location = await findTaskLocation(
6330
+ deps.fs,
6331
+ deps.path,
6332
+ layout,
6333
+ list,
6334
+ id,
6335
+ deps.frontmatterMode
6336
+ );
5684
6337
  if (!location) {
5685
6338
  throw new TaskNotFoundError(`Task "${list}/${id}" not found.`);
5686
6339
  }
@@ -5688,7 +6341,7 @@ function createTasksView2(deps, layout, list) {
5688
6341
  validateTaskId(id);
5689
6342
  const { event, nextTask } = await withFileLock(
5690
6343
  deps.fs,
5691
- path7.join(listDirectoryPath, ".transition.lock"),
6344
+ path8.join(listDirectoryPath, ".transition.lock"),
5692
6345
  fireTask
5693
6346
  );
5694
6347
  await event.onEnter?.(nextTask);
@@ -5708,7 +6361,14 @@ function createTasksView2(deps, layout, list) {
5708
6361
  },
5709
6362
  async delete(id) {
5710
6363
  validateTaskId(id);
5711
- const location = await findTaskLocation(deps.fs, deps.path, layout, list, id);
6364
+ const location = await findTaskLocation(
6365
+ deps.fs,
6366
+ deps.path,
6367
+ layout,
6368
+ list,
6369
+ id,
6370
+ deps.frontmatterMode
6371
+ );
5712
6372
  if (!location) {
5713
6373
  throw new TaskNotFoundError(`Task "${list}/${id}" not found.`);
5714
6374
  }
@@ -5781,7 +6441,7 @@ async function markdownDirBackend(deps) {
5781
6441
  if (entryName === ARCHIVE_DIRECTORY_NAME || isHiddenEntry(entryName)) {
5782
6442
  continue;
5783
6443
  }
5784
- const entryPath = path7.join(deps.path, entryName);
6444
+ const entryPath = path8.join(deps.path, entryName);
5785
6445
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
5786
6446
  const entryStat = await statIfExists(deps.fs, entryPath);
5787
6447
  if (entryStat?.isDirectory()) {
@@ -5823,12 +6483,26 @@ async function markdownDirBackend(deps) {
5823
6483
  }
5824
6484
  const targetListDir = listPath(deps.path, layout, targetListName);
5825
6485
  await rejectSymbolicLinkComponents(deps.fs, targetListDir);
5826
- return withFileLock(deps.fs, path7.join(targetListDir, ".transition.lock"), async () => {
5827
- const targetExisting = await findTaskLocation(deps.fs, deps.path, layout, targetListName, id);
6486
+ return withFileLock(deps.fs, path8.join(targetListDir, ".transition.lock"), async () => {
6487
+ const targetExisting = await findTaskLocation(
6488
+ deps.fs,
6489
+ deps.path,
6490
+ layout,
6491
+ targetListName,
6492
+ id,
6493
+ deps.frontmatterMode
6494
+ );
5828
6495
  if (targetExisting) {
5829
6496
  throw new TaskAlreadyExistsError(`Task "${targetListName}/${id}" already exists.`);
5830
6497
  }
5831
- const sourceLocation = await findTaskLocation(deps.fs, deps.path, layout, sourceListName, id);
6498
+ const sourceLocation = await findTaskLocation(
6499
+ deps.fs,
6500
+ deps.path,
6501
+ layout,
6502
+ sourceListName,
6503
+ id,
6504
+ deps.frontmatterMode
6505
+ );
5832
6506
  if (!sourceLocation) {
5833
6507
  throw new TaskNotFoundError(`Task "${sourceListName}/${id}" not found.`);
5834
6508
  }
@@ -5873,7 +6547,7 @@ async function markdownDirBackend(deps) {
5873
6547
  );
5874
6548
  const width = padWidthForCount(targetEntries.length + 1);
5875
6549
  const targetFilename = activeTaskFilename(id, maxOrder + 1, width);
5876
- const targetPath = path7.join(targetListDir, targetFilename);
6550
+ const targetPath = path8.join(targetListDir, targetFilename);
5877
6551
  await deps.fs.rename(sourceLocation.path, targetPath);
5878
6552
  return createTask(
5879
6553
  targetListName,
@@ -5895,7 +6569,7 @@ async function markdownDirBackend(deps) {
5895
6569
  }
5896
6570
 
5897
6571
  // ../task-list/src/backends/yaml-file.ts
5898
- import path8 from "node:path";
6572
+ import path9 from "node:path";
5899
6573
  import { isMap, parseDocument as parseDocument3 } from "yaml";
5900
6574
 
5901
6575
  // ../task-list/src/schema/store.schema.json
@@ -5955,7 +6629,7 @@ function malformedTask2(list, id, field) {
5955
6629
  return new MalformedTaskError(`Malformed task "${list}/${id}": invalid "${field}".`);
5956
6630
  }
5957
6631
  function validateListName2(name) {
5958
- if (name.length === 0 || name.startsWith(".") || name.includes("/") || name.includes("\\") || name.includes("..")) {
6632
+ if (!isTrimmedPrintableIdentifier(name) || name.startsWith(".") || name.includes("/") || name.includes("\\") || name.includes("..")) {
5959
6633
  throw new Error(`Invalid task list name "${name}".`);
5960
6634
  }
5961
6635
  return name;
@@ -5992,7 +6666,7 @@ function createTask2(list, id, taskRecord, sourcePath) {
5992
6666
  state: getOwnEntry(taskRecord, "state"),
5993
6667
  description: descriptionFromTaskRecord(taskRecord),
5994
6668
  metadata: metadataFromTaskRecord(taskRecord),
5995
- ...sourcePath !== void 0 && { sourcePath: path8.resolve(sourcePath) }
6669
+ ...sourcePath !== void 0 && { sourcePath: path9.resolve(sourcePath) }
5996
6670
  };
5997
6671
  }
5998
6672
  function matchesFilter(task, filter) {
@@ -6163,8 +6837,8 @@ function serializeDocument(document) {
6163
6837
  return serialized.endsWith("\n") ? serialized : `${serialized}
6164
6838
  `;
6165
6839
  }
6166
- async function readStore(fs4, filePath, validStates) {
6167
- const content = await fs4.readFile(filePath, "utf8");
6840
+ async function readStore(fs5, filePath, validStates) {
6841
+ const content = await fs5.readFile(filePath, "utf8");
6168
6842
  const document = parseStoreDocument(filePath, content);
6169
6843
  const store = document.toJS();
6170
6844
  assertValidStoreRecord(store, filePath);
@@ -6304,6 +6978,7 @@ function createTasksView3(deps, list) {
6304
6978
  assertCreateDoesNotSetState2(input);
6305
6979
  assertCreateHasId2(input);
6306
6980
  validateTaskId(input.id);
6981
+ validateTaskName(input.name);
6307
6982
  const { document, store } = await readStore(deps.fs, deps.path, validStates);
6308
6983
  if (getTaskRecord(store, list, input.id)) {
6309
6984
  throw new TaskAlreadyExistsError(`Task "${list}/${input.id}" already exists.`);
@@ -6316,6 +6991,9 @@ function createTasksView3(deps, list) {
6316
6991
  async update(id, patch) {
6317
6992
  assertUpdateDoesNotSetState2(patch);
6318
6993
  validateTaskId(id);
6994
+ if (patch.name !== void 0) {
6995
+ validateTaskName(patch.name);
6996
+ }
6319
6997
  const { document, store } = await readStore(deps.fs, deps.path, validStates);
6320
6998
  const existing = getTaskOrThrow(store, list, id);
6321
6999
  const nextTaskRecord = buildUpdatedTaskRecord(existing, patch);
@@ -6407,6 +7085,11 @@ function createTasksView3(deps, list) {
6407
7085
  insertIndex = anchor.position === "top" ? 0 : listNode.items.length;
6408
7086
  } else {
6409
7087
  const anchorId = "before" in anchor ? anchor.before : anchor.after;
7088
+ const activeIds = new Set(activeItemIds(listNode, validStates));
7089
+ if (!activeIds.has(anchorId)) {
7090
+ listNode.items.splice(fromIndex, 0, movedPair);
7091
+ throw new AnchorNotFoundError(anchorId);
7092
+ }
6410
7093
  const anchorIndex = findItemIndex(listNode, anchorId);
6411
7094
  if (anchorIndex < 0) {
6412
7095
  listNode.items.splice(fromIndex, 0, movedPair);
@@ -6591,7 +7274,7 @@ function isRecord4(value) {
6591
7274
 
6592
7275
  // ../task-list/src/move.ts
6593
7276
  import * as fsPromises2 from "node:fs/promises";
6594
- import path9 from "node:path";
7277
+ import path10 from "node:path";
6595
7278
 
6596
7279
  // ../toolcraft/src/human-in-loop/approval-tasks.ts
6597
7280
  import { randomBytes as randomBytes3 } from "node:crypto";
@@ -6778,7 +7461,7 @@ function areEqualStrings(left, right) {
6778
7461
  }
6779
7462
 
6780
7463
  // ../toolcraft/src/human-in-loop/runner.ts
6781
- import { access, lstat, readFile as readFile2, rename, unlink, writeFile as writeFile2 } from "node:fs/promises";
7464
+ import { access, lstat, readFile as readFile3, rename, unlink, writeFile as writeFile2 } from "node:fs/promises";
6782
7465
 
6783
7466
  // ../toolcraft/src/human-in-loop/default-provider.ts
6784
7467
  import process3 from "node:process";
@@ -6810,7 +7493,7 @@ on error number -128
6810
7493
  end try`;
6811
7494
  }
6812
7495
  function parseStdout(out) {
6813
- const value = out.endsWith("\r\n") ? out.slice(0, -2) : out.endsWith("\n") ? out.slice(0, -1) : out;
7496
+ const value = out.endsWith("\r\n") ? out.slice(0, -2) : out.endsWith("\n") ? out.slice(0, -1) : out.endsWith("\r") ? out.slice(0, -1) : out;
6814
7497
  switch (value) {
6815
7498
  case "Approve":
6816
7499
  case "APPROVED":
@@ -7090,13 +7773,13 @@ function formatAvailableApprovalCommandPaths(root) {
7090
7773
  }
7091
7774
  function enumerateApprovalCommandPaths(root) {
7092
7775
  const paths = [];
7093
- const visit = (node, path24) => {
7776
+ const visit = (node, path25) => {
7094
7777
  if (node.kind === "command") {
7095
- paths.push(path24.join("."));
7778
+ paths.push(path25.join("."));
7096
7779
  return;
7097
7780
  }
7098
7781
  for (const child of getVisibleCliChildren(node)) {
7099
- visit(child, [...path24, child.name]);
7782
+ visit(child, [...path25, child.name]);
7100
7783
  }
7101
7784
  };
7102
7785
  if (root.kind === "command") {
@@ -7131,21 +7814,21 @@ function createHandlerContext(command, params17) {
7131
7814
  }
7132
7815
  function createFs() {
7133
7816
  return {
7134
- readFile: async (path24, encoding = "utf8") => readFile2(path24, { encoding }),
7135
- writeFile: async (path24, contents, options) => {
7136
- await writeFile2(path24, contents, options);
7817
+ readFile: async (path25, encoding = "utf8") => readFile3(path25, { encoding }),
7818
+ writeFile: async (path25, contents, options) => {
7819
+ await writeFile2(path25, contents, options);
7137
7820
  },
7138
- exists: async (path24) => {
7821
+ exists: async (path25) => {
7139
7822
  try {
7140
- await access(path24);
7823
+ await access(path25);
7141
7824
  return true;
7142
7825
  } catch {
7143
7826
  return false;
7144
7827
  }
7145
7828
  },
7146
- lstat: async (path24) => lstat(path24),
7829
+ lstat: async (path25) => lstat(path25),
7147
7830
  rename: async (fromPath, toPath) => rename(fromPath, toPath),
7148
- unlink: async (path24) => unlink(path24)
7831
+ unlink: async (path25) => unlink(path25)
7149
7832
  };
7150
7833
  }
7151
7834
  function createEnv(values = process.env) {
@@ -7424,13 +8107,13 @@ function isMissingStateError(error3) {
7424
8107
  import { mkdir as mkdir2, realpath as realpath2, writeFile as writeFile4 } from "node:fs/promises";
7425
8108
  import { randomUUID as randomUUID5 } from "node:crypto";
7426
8109
  import os from "node:os";
7427
- import path13 from "node:path";
8110
+ import path14 from "node:path";
7428
8111
  import { CommanderError } from "commander";
7429
8112
 
7430
8113
  // ../toolcraft/src/mcp-proxy.ts
7431
8114
  import { existsSync as existsSync2 } from "node:fs";
7432
- import { lstat as lstat2, mkdir, readFile as readFile3, rename as rename2, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
7433
- import path12 from "node:path";
8115
+ import { lstat as lstat2, mkdir, readFile as readFile4, rename as rename2, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
8116
+ import path13 from "node:path";
7434
8117
  import { createHash as createHash3, randomUUID as randomUUID4 } from "node:crypto";
7435
8118
 
7436
8119
  // ../tiny-mcp-client/src/internal.ts
@@ -7439,13 +8122,13 @@ import { PassThrough as PassThrough2 } from "node:stream";
7439
8122
 
7440
8123
  // ../mcp-oauth/src/client/auth-store-session-store.ts
7441
8124
  import crypto from "node:crypto";
7442
- import path11 from "node:path";
8125
+ import path12 from "node:path";
7443
8126
 
7444
8127
  // ../auth-store/src/encrypted-file-store.ts
7445
8128
  import { createCipheriv, createDecipheriv, randomBytes as randomBytes4, randomUUID as randomUUID3, scrypt } from "node:crypto";
7446
8129
  import { promises as fs } from "node:fs";
7447
8130
  import { homedir, hostname, userInfo } from "node:os";
7448
- import path10 from "node:path";
8131
+ import path11 from "node:path";
7449
8132
 
7450
8133
  // ../auth-store/src/error-codes.ts
7451
8134
  function hasOwnErrorCode3(error3, code) {
@@ -7474,10 +8157,13 @@ var EncryptedFileStore = class {
7474
8157
  if (input.filePath === void 0) {
7475
8158
  const homeDirectory = (input.getHomeDirectory ?? homedir)();
7476
8159
  const defaultDirectory = input.defaultDirectory ?? ".auth-store";
7477
- this.filePath = path10.join(
8160
+ const defaultFileName = input.defaultFileName ?? "credentials.enc";
8161
+ assertSafeDefaultDirectory(defaultDirectory);
8162
+ assertSafeDefaultFileName(defaultFileName);
8163
+ this.filePath = path11.join(
7478
8164
  homeDirectory,
7479
8165
  defaultDirectory,
7480
- input.defaultFileName ?? "credentials.enc"
8166
+ defaultFileName
7481
8167
  );
7482
8168
  this.symbolicLinkCheckStartPath = resolveDefaultDirectoryCheckStart(
7483
8169
  homeDirectory,
@@ -7537,7 +8223,7 @@ var EncryptedFileStore = class {
7537
8223
  authTag: authTag.toString("base64"),
7538
8224
  ciphertext: ciphertext.toString("base64")
7539
8225
  };
7540
- await this.fs.mkdir(path10.dirname(this.filePath), { recursive: true });
8226
+ await this.fs.mkdir(path11.dirname(this.filePath), { recursive: true });
7541
8227
  await this.assertCredentialPathHasNoSymbolicLinks(this.filePath);
7542
8228
  const temporaryPath = `${this.filePath}.${process.pid}.${randomUUID3()}.tmp`;
7543
8229
  let temporaryCreated = false;
@@ -7569,7 +8255,7 @@ var EncryptedFileStore = class {
7569
8255
  }
7570
8256
  }
7571
8257
  async assertCredentialPathHasNoSymbolicLinks(targetPath) {
7572
- const resolvedPath = path10.resolve(targetPath);
8258
+ const resolvedPath = path11.resolve(targetPath);
7573
8259
  const protectedPaths = getProtectedCredentialPaths(
7574
8260
  resolvedPath,
7575
8261
  this.symbolicLinkCheckStartPath
@@ -7603,27 +8289,62 @@ var EncryptedFileStore = class {
7603
8289
  };
7604
8290
  function resolveDefaultDirectoryCheckStart(homeDirectory, defaultDirectory) {
7605
8291
  const [firstSegment] = defaultDirectory.split(/[\\/]+/).filter(Boolean);
7606
- return path10.resolve(homeDirectory, firstSegment ?? ".");
8292
+ return path11.resolve(homeDirectory, firstSegment ?? ".");
7607
8293
  }
7608
8294
  function getProtectedCredentialPaths(resolvedPath, symbolicLinkCheckStartPath) {
7609
8295
  if (symbolicLinkCheckStartPath === null) {
7610
- return [path10.dirname(resolvedPath), resolvedPath];
8296
+ return getExplicitProtectedCredentialPaths(resolvedPath);
7611
8297
  }
7612
- const resolvedStartPath = path10.resolve(symbolicLinkCheckStartPath);
8298
+ const resolvedStartPath = path11.resolve(symbolicLinkCheckStartPath);
7613
8299
  if (!isPathInsideOrEqual(resolvedPath, resolvedStartPath)) {
7614
- return [path10.dirname(resolvedPath), resolvedPath];
8300
+ return [path11.dirname(resolvedPath), resolvedPath];
7615
8301
  }
7616
8302
  const protectedPaths = [resolvedStartPath];
7617
8303
  let currentPath = resolvedStartPath;
7618
- for (const segment of path10.relative(resolvedStartPath, resolvedPath).split(path10.sep).filter(Boolean)) {
7619
- currentPath = path10.join(currentPath, segment);
8304
+ for (const segment of path11.relative(resolvedStartPath, resolvedPath).split(path11.sep).filter(Boolean)) {
8305
+ currentPath = path11.join(currentPath, segment);
8306
+ protectedPaths.push(currentPath);
8307
+ }
8308
+ return protectedPaths;
8309
+ }
8310
+ function assertSafeDefaultDirectory(defaultDirectory) {
8311
+ if (path11.isAbsolute(defaultDirectory) || path11.win32.isAbsolute(defaultDirectory)) {
8312
+ throw new Error("defaultDirectory must be a relative path inside the home directory");
8313
+ }
8314
+ for (const segment of splitPathSegments(defaultDirectory)) {
8315
+ if (segment === "..") {
8316
+ throw new Error("defaultDirectory must be a relative path inside the home directory");
8317
+ }
8318
+ }
8319
+ }
8320
+ function assertSafeDefaultFileName(defaultFileName) {
8321
+ if (defaultFileName.trim().length === 0 || defaultFileName === "." || defaultFileName === ".." || splitPathSegments(defaultFileName).length !== 1) {
8322
+ throw new Error("defaultFileName must be a file name without path separators");
8323
+ }
8324
+ }
8325
+ function splitPathSegments(value) {
8326
+ return value.split("/").flatMap((segment) => segment.split("\\")).filter((segment) => segment.length > 0);
8327
+ }
8328
+ function getExplicitProtectedCredentialPaths(resolvedPath) {
8329
+ const parsed = path11.parse(resolvedPath);
8330
+ const segments = resolvedPath.slice(parsed.root.length).split(path11.sep).filter((segment) => segment.length > 0);
8331
+ if (segments.length <= 1) {
8332
+ return [resolvedPath];
8333
+ }
8334
+ const protectedPaths = [];
8335
+ let currentPath = parsed.root;
8336
+ for (const [index, segment] of segments.entries()) {
8337
+ currentPath = path11.join(currentPath, segment);
8338
+ if (index === 0) {
8339
+ continue;
8340
+ }
7620
8341
  protectedPaths.push(currentPath);
7621
8342
  }
7622
8343
  return protectedPaths;
7623
8344
  }
7624
8345
  function isPathInsideOrEqual(childPath, parentPath) {
7625
- const relativePath = path10.relative(parentPath, childPath);
7626
- return relativePath === "" || !relativePath.startsWith("..") && !path10.isAbsolute(relativePath);
8346
+ const relativePath = path11.relative(parentPath, childPath);
8347
+ return relativePath === "" || !relativePath.startsWith("..") && !path11.isAbsolute(relativePath);
7627
8348
  }
7628
8349
  async function removeIfPresent(fileSystem, filePath) {
7629
8350
  try {
@@ -7714,8 +8435,14 @@ var KeychainStore = class {
7714
8435
  account;
7715
8436
  constructor(input) {
7716
8437
  this.runCommand = input.runCommand ?? runSecurityCommand;
7717
- this.service = input.service;
7718
- this.account = input.account;
8438
+ this.service = input.service.trim();
8439
+ this.account = input.account.trim();
8440
+ if (this.service.length === 0) {
8441
+ throw new Error("Keychain service must not be empty");
8442
+ }
8443
+ if (this.account.length === 0) {
8444
+ throw new Error("Keychain account must not be empty");
8445
+ }
7719
8446
  }
7720
8447
  async get() {
7721
8448
  const result = await this.executeSecurityCommand(
@@ -7742,10 +8469,10 @@ var KeychainStore = class {
7742
8469
  "-a",
7743
8470
  this.account,
7744
8471
  "-U",
7745
- "-w"
8472
+ "-w",
8473
+ value
7746
8474
  ],
7747
- "store secret in macOS Keychain",
7748
- { stdin: value }
8475
+ "store secret in macOS Keychain"
7749
8476
  );
7750
8477
  if (getCommandExitCode(result) !== 0) {
7751
8478
  throw createSecurityCliFailure("store secret in macOS Keychain", result);
@@ -7890,13 +8617,14 @@ function createSecretStore(input) {
7890
8617
  function resolveBackend(input) {
7891
8618
  const envVar = input.backendEnvVar ?? DEFAULT_BACKEND_ENV_VAR;
7892
8619
  const configuredBackend = input.backend ?? getOwnEnvValue(input.env, envVar) ?? getOwnEnvValue(process.env, envVar);
7893
- if (configuredBackend === "keychain") {
8620
+ const backend = configuredBackend?.trim();
8621
+ if (backend === "keychain") {
7894
8622
  return "keychain";
7895
8623
  }
7896
- if (configuredBackend === void 0 || configuredBackend === "file") {
8624
+ if (backend === void 0 || backend === "file") {
7897
8625
  return "file";
7898
8626
  }
7899
- throw new Error(`Unsupported auth store backend: ${configuredBackend}`);
8627
+ throw new Error(`Unsupported auth store backend: ${backend}`);
7900
8628
  }
7901
8629
  function getOwnEnvValue(env, key2) {
7902
8630
  return env !== void 0 && Object.prototype.hasOwnProperty.call(env, key2) ? env[key2] : void 0;
@@ -7921,6 +8649,7 @@ var DEFAULT_KEYCHAIN_SERVICE = "poe-code-mcp-oauth";
7921
8649
  var DEFAULT_CLIENT_FILE_SALT = "poe-code:mcp-oauth:clients:v1";
7922
8650
  var DEFAULT_CLIENT_FILE_DIRECTORY = ".poe-code/mcp-oauth/clients";
7923
8651
  var DEFAULT_CLIENT_KEYCHAIN_SERVICE = "poe-code-mcp-oauth-clients";
8652
+ var MAX_JS_DATE_MS = 864e13;
7924
8653
  function createAuthStoreSessionStore(options = {}) {
7925
8654
  return {
7926
8655
  async load(resource) {
@@ -7930,10 +8659,10 @@ function createAuthStoreSessionStore(options = {}) {
7930
8659
  return null;
7931
8660
  }
7932
8661
  const parsed = JSON.parse(value);
7933
- if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
8662
+ if (isStoredOAuthSession(parsed)) {
7934
8663
  return parsed;
7935
8664
  }
7936
- throw new Error("Stored OAuth session must be a JSON object");
8665
+ throw new Error("Stored OAuth session must match the expected shape");
7937
8666
  },
7938
8667
  async save(resource, session) {
7939
8668
  const store = createResourceSecretStore(resource, options);
@@ -7977,10 +8706,10 @@ function createAuthStoreClientStore(options) {
7977
8706
  function createNamedSecretStore(key2, options, defaults2) {
7978
8707
  const hash = crypto.createHash("sha256").update(key2).digest("hex");
7979
8708
  const configuredFilePath = options.fileStore?.filePath;
7980
- const parsedFilePath = configuredFilePath === void 0 ? null : path11.parse(configuredFilePath);
8709
+ const parsedFilePath = configuredFilePath === void 0 ? null : path12.parse(configuredFilePath);
7981
8710
  const fileStore = {
7982
8711
  ...options.fileStore,
7983
- filePath: parsedFilePath === null ? void 0 : path11.join(
8712
+ filePath: parsedFilePath === null ? void 0 : path12.join(
7984
8713
  parsedFilePath.dir,
7985
8714
  `${parsedFilePath.name}-${hash}${parsedFilePath.ext || ".enc"}`
7986
8715
  ),
@@ -7996,28 +8725,20 @@ function createNamedSecretStore(key2, options, defaults2) {
7996
8725
  return createSecretStore({ ...options, fileStore, keychainStore }).store;
7997
8726
  }
7998
8727
  function createResourceSecretStore(resource, options) {
7999
- return createNamedSecretStore(
8000
- canonicalizeResourceIndicator(resource),
8001
- options,
8002
- {
8003
- salt: DEFAULT_FILE_SALT,
8004
- directory: DEFAULT_FILE_DIRECTORY,
8005
- service: DEFAULT_KEYCHAIN_SERVICE,
8006
- accountPrefix: "provider"
8007
- }
8008
- );
8728
+ return createNamedSecretStore(canonicalizeResourceIndicator(resource), options, {
8729
+ salt: DEFAULT_FILE_SALT,
8730
+ directory: DEFAULT_FILE_DIRECTORY,
8731
+ service: DEFAULT_KEYCHAIN_SERVICE,
8732
+ accountPrefix: "provider"
8733
+ });
8009
8734
  }
8010
8735
  function createIssuerSecretStore(issuer, options) {
8011
- return createNamedSecretStore(
8012
- issuer,
8013
- options,
8014
- {
8015
- salt: DEFAULT_CLIENT_FILE_SALT,
8016
- directory: DEFAULT_CLIENT_FILE_DIRECTORY,
8017
- service: DEFAULT_CLIENT_KEYCHAIN_SERVICE,
8018
- accountPrefix: "issuer"
8019
- }
8020
- );
8736
+ return createNamedSecretStore(issuer, options, {
8737
+ salt: DEFAULT_CLIENT_FILE_SALT,
8738
+ directory: DEFAULT_CLIENT_FILE_DIRECTORY,
8739
+ service: DEFAULT_CLIENT_KEYCHAIN_SERVICE,
8740
+ accountPrefix: "issuer"
8741
+ });
8021
8742
  }
8022
8743
  function isObjectRecord(value) {
8023
8744
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -8029,6 +8750,50 @@ function getOwnString(record, key2) {
8029
8750
  const value = getOwnEntry4(record, key2);
8030
8751
  return typeof value === "string" ? value : void 0;
8031
8752
  }
8753
+ function isStoredOAuthSession(value) {
8754
+ if (!isObjectRecord(value)) {
8755
+ return false;
8756
+ }
8757
+ return isNonBlankOwnString(value, "resource") && isNonBlankOwnString(value, "authorizationServer") && isStoredOAuthClient(getOwnEntry4(value, "client")) && isStoredOAuthDiscovery(getOwnEntry4(value, "discovery")) && isStoredOAuthTokensOrMissing(getOwnEntry4(value, "tokens"));
8758
+ }
8759
+ function isStoredOAuthClient(value) {
8760
+ if (!isObjectRecord(value) || !isNonBlankOwnString(value, "clientId")) {
8761
+ return false;
8762
+ }
8763
+ const clientSecret = getOwnEntry4(value, "clientSecret");
8764
+ return clientSecret === void 0 || typeof clientSecret === "string" && clientSecret.trim().length > 0;
8765
+ }
8766
+ function isStoredOAuthDiscovery(value) {
8767
+ if (!isObjectRecord(value)) {
8768
+ return false;
8769
+ }
8770
+ return isNonBlankOwnString(value, "resourceMetadataUrl") && isObjectRecord(getOwnEntry4(value, "resourceMetadata")) && isObjectRecord(getOwnEntry4(value, "authorizationServerMetadata"));
8771
+ }
8772
+ function isStoredOAuthTokensOrMissing(value) {
8773
+ if (value === void 0) {
8774
+ return true;
8775
+ }
8776
+ if (!isObjectRecord(value)) {
8777
+ return false;
8778
+ }
8779
+ if (!isNonBlankOwnString(value, "accessToken") || getOwnString(value, "tokenType") !== "Bearer") {
8780
+ return false;
8781
+ }
8782
+ const expiresAt = getOwnEntry4(value, "expiresAt");
8783
+ if (expiresAt !== null && (typeof expiresAt !== "number" || !Number.isSafeInteger(expiresAt) || expiresAt > MAX_JS_DATE_MS || !Number.isFinite(new Date(expiresAt).getTime()))) {
8784
+ return false;
8785
+ }
8786
+ const refreshToken = getOwnEntry4(value, "refreshToken");
8787
+ if (refreshToken !== void 0 && (typeof refreshToken !== "string" || refreshToken.trim().length === 0)) {
8788
+ return false;
8789
+ }
8790
+ const scope = getOwnEntry4(value, "scope");
8791
+ return scope === void 0 || typeof scope === "string" && scope.trim().length > 0;
8792
+ }
8793
+ function isNonBlankOwnString(record, key2) {
8794
+ const value = getOwnString(record, key2);
8795
+ return value !== void 0 && value.trim().length > 0;
8796
+ }
8032
8797
 
8033
8798
  // ../mcp-oauth/src/client/default-oauth-client-provider.ts
8034
8799
  import { URL as URL2 } from "node:url";
@@ -8139,9 +8904,7 @@ function waitForAuthorizationCode(server, authorizationUrl, options, callbackPat
8139
8904
  } catch (error3) {
8140
8905
  res.writeHead(400);
8141
8906
  res.end(error3 instanceof Error ? error3.message : "Invalid OAuth callback");
8142
- if (callbackParameters.error === null) {
8143
- settle(() => reject(error3 instanceof Error ? error3 : new Error(String(error3))));
8144
- }
8907
+ settle(() => reject(error3 instanceof Error ? error3 : new Error(String(error3))));
8145
8908
  return;
8146
8909
  }
8147
8910
  const authorizationError = callbackParameters.error;
@@ -8153,7 +8916,10 @@ function waitForAuthorizationCode(server, authorizationUrl, options, callbackPat
8153
8916
  return;
8154
8917
  }
8155
8918
  try {
8156
- const code = validateAuthorizationCallbackParameters(callbackParameters, expectedAuthorization);
8919
+ const code = validateAuthorizationCallbackParameters(
8920
+ callbackParameters,
8921
+ expectedAuthorization
8922
+ );
8157
8923
  res.writeHead(200, { "Content-Type": "text/html" });
8158
8924
  res.end(buildSuccessPage(options.landingPage));
8159
8925
  settle(() => resolve(code));
@@ -8176,7 +8942,10 @@ function waitForAuthorizationCode(server, authorizationUrl, options, callbackPat
8176
8942
  const description = callbackParameters.errorDescription ?? callbackParameters.error;
8177
8943
  throw createAuthorizationError(callbackParameters.error, description);
8178
8944
  }
8179
- const code = validateAuthorizationCallbackParameters(callbackParameters, expectedAuthorization);
8945
+ const code = validateAuthorizationCallbackParameters(
8946
+ callbackParameters,
8947
+ expectedAuthorization
8948
+ );
8180
8949
  settle(() => resolve(code));
8181
8950
  } catch (error3) {
8182
8951
  settle(() => reject(error3 instanceof Error ? error3 : new Error(String(error3))));
@@ -8281,6 +9050,7 @@ function generateCodeChallenge(verifier) {
8281
9050
  }
8282
9051
 
8283
9052
  // ../mcp-oauth/src/client/token-endpoint.ts
9053
+ var MAX_JS_DATE_MS2 = 864e13;
8284
9054
  var OAuthError = class extends Error {
8285
9055
  error;
8286
9056
  errorDescription;
@@ -8358,22 +9128,32 @@ async function requestTokens(input) {
8358
9128
  if (typeof accessToken !== "string" || accessToken.trim().length === 0) {
8359
9129
  throw new Error("OAuth token response missing access_token");
8360
9130
  }
9131
+ const normalizedAccessToken = accessToken.trim();
8361
9132
  const tokenType = normalizeBearerTokenType(getOwnEntry6(payload, "token_type"));
8362
9133
  if (tokenType === null) {
8363
9134
  throw new Error("OAuth token response missing token_type=Bearer");
8364
9135
  }
8365
9136
  const expiresIn = getOwnEntry6(payload, "expires_in");
8366
- if (typeof expiresIn === "number" && Number.isFinite(expiresIn) && expiresIn < 0) {
8367
- throw new Error("OAuth token response has invalid expires_in");
9137
+ let expiresAt = null;
9138
+ if (expiresIn !== void 0) {
9139
+ if (typeof expiresIn !== "number" || !Number.isFinite(expiresIn) || !Number.isInteger(expiresIn) || expiresIn < 0) {
9140
+ throw new Error("OAuth token response has invalid expires_in");
9141
+ }
9142
+ expiresAt = input.now() + expiresIn * 1e3;
9143
+ if (!Number.isSafeInteger(expiresAt) || expiresAt > MAX_JS_DATE_MS2 || !Number.isFinite(new Date(expiresAt).getTime())) {
9144
+ throw new Error("OAuth token response has invalid expires_in");
9145
+ }
8368
9146
  }
8369
9147
  const refreshToken = getOwnEntry6(payload, "refresh_token");
8370
9148
  const scope = getOwnEntry6(payload, "scope");
9149
+ const normalizedRefreshToken = typeof refreshToken === "string" && refreshToken.trim().length > 0 ? refreshToken.trim() : void 0;
9150
+ const normalizedScope = typeof scope === "string" && scope.trim().length > 0 ? scope.trim() : void 0;
8371
9151
  return {
8372
- accessToken,
8373
- refreshToken: typeof refreshToken === "string" && refreshToken.length > 0 ? refreshToken : void 0,
9152
+ accessToken: normalizedAccessToken,
9153
+ refreshToken: normalizedRefreshToken === void 0 ? void 0 : normalizedRefreshToken,
8374
9154
  tokenType,
8375
- expiresAt: typeof expiresIn === "number" && Number.isFinite(expiresIn) ? input.now() + expiresIn * 1e3 : null,
8376
- scope: typeof scope === "string" && scope.length > 0 ? scope : void 0
9155
+ expiresAt,
9156
+ scope: normalizedScope === void 0 ? void 0 : normalizedScope
8377
9157
  };
8378
9158
  }
8379
9159
  async function readOAuthJsonObjectResponse(response) {
@@ -8424,6 +9204,7 @@ function normalizeBearerTokenType(value) {
8424
9204
  }
8425
9205
 
8426
9206
  // ../mcp-oauth/src/client/default-oauth-client-provider.ts
9207
+ var MAX_JS_DATE_MS3 = 864e13;
8427
9208
  function createOAuthClientProvider(options) {
8428
9209
  if (isProviderOptions(options)) {
8429
9210
  return options.provider;
@@ -8588,7 +9369,12 @@ function createDefaultOAuthClientProvider(options) {
8588
9369
  });
8589
9370
  let resolvedClient = null;
8590
9371
  try {
8591
- resolvedClient = await resolveClient(currentSession, discovery, loopback.redirectUri, fetch2);
9372
+ resolvedClient = await resolveClient(
9373
+ currentSession,
9374
+ discovery,
9375
+ loopback.redirectUri,
9376
+ fetch2
9377
+ );
8592
9378
  const sessionWithoutTokens = {
8593
9379
  resource,
8594
9380
  authorizationServer: discovery.authorizationServer,
@@ -8655,28 +9441,26 @@ function createDefaultOAuthClientProvider(options) {
8655
9441
  return finalPromise;
8656
9442
  }
8657
9443
  async function resolveClient(existingSession, discovery, redirectUri, fetch2) {
9444
+ const configuredClient = normalizeConfiguredClient(options.client);
8658
9445
  if (options.client.mode === "static") {
9446
+ if (configuredClient === null) {
9447
+ throw new Error("OAuth client_id must not be blank");
9448
+ }
8659
9449
  return {
8660
9450
  kind: "static",
8661
9451
  fromStoredRegistration: false,
8662
- client: {
8663
- clientId: options.client.clientId,
8664
- clientSecret: options.client.clientSecret
8665
- }
9452
+ client: configuredClient
8666
9453
  };
8667
9454
  }
8668
9455
  const registrationEndpoint = getOwnString2(
8669
9456
  discovery.authorizationServerMetadata,
8670
9457
  "registration_endpoint"
8671
9458
  );
8672
- if (registrationEndpoint === void 0 && options.client.clientId !== void 0) {
9459
+ if (registrationEndpoint === void 0 && configuredClient !== null) {
8673
9460
  return {
8674
9461
  kind: "static",
8675
9462
  fromStoredRegistration: false,
8676
- client: {
8677
- clientId: options.client.clientId,
8678
- clientSecret: options.client.clientSecret
8679
- }
9463
+ client: configuredClient
8680
9464
  };
8681
9465
  }
8682
9466
  const storedClient = await loadRegisteredClient(discovery.authorizationServer);
@@ -8698,7 +9482,7 @@ function createDefaultOAuthClientProvider(options) {
8698
9482
  throw new Error("Authorization server metadata is missing registration_endpoint");
8699
9483
  }
8700
9484
  if (existingSession !== null && existingSession.client.clientId.length > 0) {
8701
- const isConfiguredStaticFallback = options.client.clientId !== void 0 && existingSession.client.clientId === options.client.clientId && existingSession.client.clientSecret === options.client.clientSecret;
9485
+ const isConfiguredStaticFallback = configuredClient !== null && existingSession.client.clientId === configuredClient.clientId && existingSession.client.clientSecret === configuredClient.clientSecret;
8702
9486
  if (!isConfiguredStaticFallback) {
8703
9487
  await saveRegisteredClient(discovery.authorizationServer, existingSession.client);
8704
9488
  return {
@@ -8726,8 +9510,8 @@ function createDefaultOAuthClientProvider(options) {
8726
9510
  }
8727
9511
  const clientSecret = getOwnString2(payload, "client_secret");
8728
9512
  const registeredClient = {
8729
- clientId,
8730
- clientSecret: clientSecret !== void 0 && clientSecret.length > 0 ? clientSecret : void 0
9513
+ clientId: clientId.trim(),
9514
+ clientSecret: clientSecret !== void 0 && clientSecret.trim().length > 0 ? clientSecret.trim() : void 0
8731
9515
  };
8732
9516
  await saveRegisteredClient(discovery.authorizationServer, registeredClient);
8733
9517
  return {
@@ -8840,14 +9624,16 @@ function normalizeStoredClient(value) {
8840
9624
  if (clientId === void 0 || clientId.trim().length === 0) {
8841
9625
  return null;
8842
9626
  }
9627
+ const normalizedClientId = clientId.trim();
8843
9628
  const clientSecret = getOwnEntry7(value, "clientSecret");
8844
9629
  if (clientSecret === void 0) {
8845
- return { clientId };
9630
+ return { clientId: normalizedClientId };
8846
9631
  }
8847
9632
  if (typeof clientSecret !== "string" || clientSecret.trim().length === 0) {
8848
9633
  return null;
8849
9634
  }
8850
- return { clientId, clientSecret };
9635
+ const normalizedClientSecret = clientSecret.trim();
9636
+ return { clientId: normalizedClientId, clientSecret: normalizedClientSecret };
8851
9637
  }
8852
9638
  function normalizeStoredTokens(value) {
8853
9639
  if (value === void 0 || !isObjectRecord3(value)) {
@@ -8858,20 +9644,45 @@ function normalizeStoredTokens(value) {
8858
9644
  const expiresAt = getOwnEntry7(value, "expiresAt");
8859
9645
  const refreshToken = getOwnEntry7(value, "refreshToken");
8860
9646
  const scope = getOwnString2(value, "scope");
8861
- const normalizedRefreshToken = typeof refreshToken === "string" ? refreshToken : void 0;
8862
- if (accessToken === void 0 || accessToken.trim().length === 0 || tokenType !== "Bearer" || !(expiresAt === null || typeof expiresAt === "number" && Number.isFinite(expiresAt)) || refreshToken !== void 0 && (typeof refreshToken !== "string" || refreshToken.trim().length === 0)) {
9647
+ const normalizedAccessToken = accessToken?.trim();
9648
+ const normalizedRefreshToken = typeof refreshToken === "string" ? refreshToken.trim() : void 0;
9649
+ const normalizedScope = scope?.trim();
9650
+ if (accessToken === void 0 || normalizedAccessToken === void 0 || normalizedAccessToken.length === 0 || tokenType !== "Bearer" || !(expiresAt === null || typeof expiresAt === "number" && Number.isSafeInteger(expiresAt) && expiresAt <= MAX_JS_DATE_MS3 && Number.isFinite(new Date(expiresAt).getTime())) || refreshToken !== void 0 && (typeof refreshToken !== "string" || normalizedRefreshToken === void 0 || normalizedRefreshToken.length === 0)) {
8863
9651
  return void 0;
8864
9652
  }
8865
9653
  return {
8866
- accessToken,
9654
+ accessToken: normalizedAccessToken,
8867
9655
  tokenType,
8868
9656
  expiresAt,
8869
9657
  ...normalizedRefreshToken === void 0 ? {} : { refreshToken: normalizedRefreshToken },
8870
- ...scope === void 0 || scope.length === 0 ? {} : { scope }
9658
+ ...normalizedScope === void 0 || normalizedScope.length === 0 ? {} : { scope: normalizedScope }
8871
9659
  };
8872
9660
  }
8873
9661
  function getClientMetadata(client) {
8874
- return client.metadata;
9662
+ if (client.metadata === void 0) {
9663
+ return void 0;
9664
+ }
9665
+ return {
9666
+ clientName: normalizeOptionalOAuthString(client.metadata.clientName),
9667
+ scope: normalizeOptionalOAuthString(client.metadata.scope),
9668
+ softwareId: normalizeOptionalOAuthString(client.metadata.softwareId),
9669
+ softwareVersion: normalizeOptionalOAuthString(client.metadata.softwareVersion)
9670
+ };
9671
+ }
9672
+ function normalizeConfiguredClient(client) {
9673
+ const clientId = normalizeOptionalOAuthString(client.clientId);
9674
+ if (clientId === void 0) {
9675
+ return null;
9676
+ }
9677
+ const clientSecret = normalizeOptionalOAuthString(client.clientSecret);
9678
+ return clientSecret === void 0 ? { clientId } : { clientId, clientSecret };
9679
+ }
9680
+ function normalizeOptionalOAuthString(value) {
9681
+ if (value === void 0) {
9682
+ return void 0;
9683
+ }
9684
+ const trimmed = value.trim();
9685
+ return trimmed.length === 0 ? void 0 : trimmed;
8875
9686
  }
8876
9687
  function getOwnEntry7(record, key2) {
8877
9688
  return Object.prototype.hasOwnProperty.call(record, key2) ? record[key2] : void 0;
@@ -8900,11 +9711,7 @@ function buildAuthorizationUrl(input) {
8900
9711
  "authorization_endpoint",
8901
9712
  "Authorization server metadata"
8902
9713
  );
8903
- const issuer = requireOwnString(
8904
- input.metadata,
8905
- "issuer",
8906
- "Authorization server metadata"
8907
- );
9714
+ const issuer = requireOwnString(input.metadata, "issuer", "Authorization server metadata");
8908
9715
  const url = new URL2(authorizationEndpoint);
8909
9716
  const resource = canonicalizeResourceIndicator(input.resource);
8910
9717
  const state = createAuthorizationState({
@@ -9512,7 +10319,7 @@ var McpClient = class {
9512
10319
  await onToolsChanged();
9513
10320
  });
9514
10321
  messageLayer.onNotification("notifications/resources/list_changed", async () => {
9515
- if (onResourcesChanged === void 0) {
10322
+ if (onResourcesChanged === void 0 || this.currentServerCapabilities?.resources?.listChanged !== true) {
9516
10323
  return;
9517
10324
  }
9518
10325
  await onResourcesChanged();
@@ -9531,7 +10338,7 @@ var McpClient = class {
9531
10338
  await onResourceUpdated(uri);
9532
10339
  });
9533
10340
  messageLayer.onNotification("notifications/prompts/list_changed", async () => {
9534
- if (onPromptsChanged === void 0) {
10341
+ if (onPromptsChanged === void 0 || this.currentServerCapabilities?.prompts?.listChanged !== true) {
9535
10342
  return;
9536
10343
  }
9537
10344
  await onPromptsChanged();
@@ -9762,7 +10569,11 @@ var McpClient = class {
9762
10569
  throw new Error("Server does not support resources");
9763
10570
  }
9764
10571
  const requestParams = params17.cursor === void 0 ? void 0 : { cursor: params17.cursor };
9765
- return await messageLayer.sendRequest("resources/list", requestParams);
10572
+ const result = await messageLayer.sendRequest("resources/list", requestParams);
10573
+ if (!isResourcesListResult(result)) {
10574
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid resources/list result");
10575
+ }
10576
+ return result;
9766
10577
  }
9767
10578
  async listResourceTemplates(params17 = {}) {
9768
10579
  const messageLayer = this.getMessageLayerOrThrow();
@@ -9771,7 +10582,11 @@ var McpClient = class {
9771
10582
  throw new Error("Server does not support resources");
9772
10583
  }
9773
10584
  const requestParams = params17.cursor === void 0 ? void 0 : { cursor: params17.cursor };
9774
- return await messageLayer.sendRequest("resources/templates/list", requestParams);
10585
+ const result = await messageLayer.sendRequest("resources/templates/list", requestParams);
10586
+ if (!isResourceTemplatesListResult(result)) {
10587
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid resources/templates/list result");
10588
+ }
10589
+ return result;
9775
10590
  }
9776
10591
  async readResource(params17) {
9777
10592
  const messageLayer = this.getMessageLayerOrThrow();
@@ -9779,7 +10594,11 @@ var McpClient = class {
9779
10594
  if (serverCapabilities.resources === void 0) {
9780
10595
  throw new Error("Server does not support resources");
9781
10596
  }
9782
- return await messageLayer.sendRequest("resources/read", params17);
10597
+ const result = await messageLayer.sendRequest("resources/read", params17);
10598
+ if (!isReadResourceResult(result)) {
10599
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid resources/read result");
10600
+ }
10601
+ return result;
9783
10602
  }
9784
10603
  async subscribe(uri) {
9785
10604
  const messageLayer = this.getMessageLayerOrThrow();
@@ -9814,7 +10633,11 @@ var McpClient = class {
9814
10633
  if (serverCapabilities.prompts === void 0) {
9815
10634
  throw new Error("Server does not support prompts");
9816
10635
  }
9817
- return await messageLayer.sendRequest("prompts/get", params17);
10636
+ const result = await messageLayer.sendRequest("prompts/get", params17);
10637
+ if (!isGetPromptResult(result)) {
10638
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid prompts/get result");
10639
+ }
10640
+ return result;
9818
10641
  }
9819
10642
  async complete(params17) {
9820
10643
  const messageLayer = this.getMessageLayerOrThrow();
@@ -9822,7 +10645,11 @@ var McpClient = class {
9822
10645
  if (serverCapabilities.completions === void 0) {
9823
10646
  throw new Error("Server does not support completions");
9824
10647
  }
9825
- return await messageLayer.sendRequest("completion/complete", params17);
10648
+ const result = await messageLayer.sendRequest("completion/complete", params17);
10649
+ if (!isCompleteResult(result)) {
10650
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid completion/complete result");
10651
+ }
10652
+ return result;
9826
10653
  }
9827
10654
  async setLogLevel(level) {
9828
10655
  const messageLayer = this.getMessageLayerOrThrow();
@@ -10813,6 +11640,44 @@ function isCallToolResult(value) {
10813
11640
  function isToolsListResult(value) {
10814
11641
  return isObjectRecord5(value) && Array.isArray(value.tools) && (value.nextCursor === void 0 || typeof value.nextCursor === "string");
10815
11642
  }
11643
+ function isResourcesListResult(value) {
11644
+ return isObjectRecord5(value) && Array.isArray(value.resources) && value.resources.every(isResource) && (value.nextCursor === void 0 || typeof value.nextCursor === "string");
11645
+ }
11646
+ function isResourceTemplatesListResult(value) {
11647
+ return isObjectRecord5(value) && Array.isArray(value.resourceTemplates) && value.resourceTemplates.every(isResourceTemplate) && (value.nextCursor === void 0 || typeof value.nextCursor === "string");
11648
+ }
11649
+ function isReadResourceResult(value) {
11650
+ return isObjectRecord5(value) && Array.isArray(value.contents) && value.contents.every(isResourceContents);
11651
+ }
11652
+ function isGetPromptResult(value) {
11653
+ return isObjectRecord5(value) && (value.description === void 0 || typeof value.description === "string") && Array.isArray(value.messages) && value.messages.every(isPromptMessage);
11654
+ }
11655
+ function isCompleteResult(value) {
11656
+ return isObjectRecord5(value) && isObjectRecord5(value.completion) && Array.isArray(value.completion.values) && value.completion.values.every((candidate) => typeof candidate === "string") && (value.completion.hasMore === void 0 || typeof value.completion.hasMore === "boolean") && (value.completion.total === void 0 || typeof value.completion.total === "number");
11657
+ }
11658
+ function isResource(value) {
11659
+ return isObjectRecord5(value) && typeof value.uri === "string" && typeof value.name === "string" && (value.description === void 0 || typeof value.description === "string") && (value.mimeType === void 0 || typeof value.mimeType === "string") && (value.size === void 0 || typeof value.size === "number");
11660
+ }
11661
+ function isResourceTemplate(value) {
11662
+ return isObjectRecord5(value) && typeof value.uriTemplate === "string" && typeof value.name === "string" && (value.description === void 0 || typeof value.description === "string") && (value.mimeType === void 0 || typeof value.mimeType === "string");
11663
+ }
11664
+ function isResourceContents(value) {
11665
+ if (!isObjectRecord5(value) || typeof value.uri !== "string") {
11666
+ return false;
11667
+ }
11668
+ if (value.mimeType !== void 0 && typeof value.mimeType !== "string") {
11669
+ return false;
11670
+ }
11671
+ const hasText = value.text !== void 0;
11672
+ const hasBlob = value.blob !== void 0;
11673
+ if (!hasText && !hasBlob) {
11674
+ return false;
11675
+ }
11676
+ return (!hasText || typeof value.text === "string") && (!hasBlob || typeof value.blob === "string");
11677
+ }
11678
+ function isPromptMessage(value) {
11679
+ return isObjectRecord5(value) && (value.role === "user" || value.role === "assistant") && isContentItem(value.content);
11680
+ }
10816
11681
  function isContentItem(value) {
10817
11682
  if (!isObjectRecord5(value)) {
10818
11683
  return false;
@@ -10826,7 +11691,7 @@ function isContentItem(value) {
10826
11691
  if (value.type !== "resource" || !isObjectRecord5(value.resource)) {
10827
11692
  return false;
10828
11693
  }
10829
- return typeof value.resource.uri === "string" && (value.resource.mimeType === void 0 || typeof value.resource.mimeType === "string") && (typeof value.resource.text === "string" || typeof value.resource.blob === "string");
11694
+ return isResourceContents(value.resource);
10830
11695
  }
10831
11696
  function hasOwn(value, property) {
10832
11697
  return Object.prototype.hasOwnProperty.call(value, property);
@@ -10966,13 +11831,13 @@ function convertJsonSchema(schema) {
10966
11831
  }
10967
11832
  return convertSchema(schema, schema, []);
10968
11833
  }
10969
- function convertSchema(schema, root, path24) {
10970
- const resolvedSchema = resolveReferencedSchema(schema, root, path24);
11834
+ function convertSchema(schema, root, path25) {
11835
+ const resolvedSchema = resolveReferencedSchema(schema, root, path25);
10971
11836
  const normalizedSchema = normalizeNullability(resolvedSchema);
10972
11837
  const composition = getComposition(normalizedSchema.schema);
10973
11838
  if (Array.isArray(normalizedSchema.schema.type)) {
10974
11839
  throw new Error(
10975
- `JSON Schema "${formatJsonSchemaPath(path24)}" has an unsupported type "${formatJsonSchemaType(
11840
+ `JSON Schema "${formatJsonSchemaPath(path25)}" has an unsupported type "${formatJsonSchemaType(
10976
11841
  normalizedSchema.schema.type
10977
11842
  )}". Supported: string, number, integer, boolean, array, object.`
10978
11843
  );
@@ -10984,13 +11849,13 @@ function convertSchema(schema, root, path24) {
10984
11849
  return convertEnumSchema(resolvedSchema, normalizedSchema.nullable);
10985
11850
  }
10986
11851
  if (composition !== void 0) {
10987
- return convertCompositionSchema(normalizedSchema.schema, root, normalizedSchema.nullable, path24);
11852
+ return convertCompositionSchema(normalizedSchema.schema, root, normalizedSchema.nullable, path25);
10988
11853
  }
10989
11854
  if (isRecordSchema(normalizedSchema.schema)) {
10990
11855
  return applyMetadata(
10991
11856
  S.Record(
10992
11857
  convertSchema(normalizedSchema.schema.additionalProperties, root, [
10993
- ...path24,
11858
+ ...path25,
10994
11859
  "additionalProperties"
10995
11860
  ])
10996
11861
  ),
@@ -11039,12 +11904,12 @@ function convertSchema(schema, root, path24) {
11039
11904
  if (normalizedSchema.schema.items === void 0) {
11040
11905
  throw new Error(
11041
11906
  `JSON Schema "${formatJsonSchemaPath(
11042
- path24
11907
+ path25
11043
11908
  )}" is an array but is missing the "items" field. Add "items": { ... } to declare the element type.`
11044
11909
  );
11045
11910
  }
11046
11911
  return S.Array(
11047
- convertSchema(normalizedSchema.schema.items, root, [...path24, "items"]),
11912
+ convertSchema(normalizedSchema.schema.items, root, [...path25, "items"]),
11048
11913
  createCommonOptions(
11049
11914
  normalizedSchema.schema,
11050
11915
  normalizedSchema.nullable,
@@ -11054,7 +11919,7 @@ function convertSchema(schema, root, path24) {
11054
11919
  case "object":
11055
11920
  return convertObjectSchema(normalizedSchema.schema, root, {
11056
11921
  nullable: normalizedSchema.nullable,
11057
- path: path24
11922
+ path: path25
11058
11923
  });
11059
11924
  case "null":
11060
11925
  return applyMetadata(S.Json(), normalizedSchema.schema, {
@@ -11069,12 +11934,12 @@ function convertSchema(schema, root, path24) {
11069
11934
  }
11070
11935
  throw new Error(
11071
11936
  `JSON Schema "${formatJsonSchemaPath(
11072
- path24
11937
+ path25
11073
11938
  )}" must declare one of: "type", "enum", "const", "oneOf", "anyOf", or "allOf".`
11074
11939
  );
11075
11940
  }
11076
11941
  throw new Error(
11077
- `JSON Schema "${formatJsonSchemaPath(path24)}" has an unsupported type "${formatJsonSchemaType(
11942
+ `JSON Schema "${formatJsonSchemaPath(path25)}" has an unsupported type "${formatJsonSchemaType(
11078
11943
  normalizedSchema.schema.type
11079
11944
  )}". Supported: string, number, integer, boolean, array, object.`
11080
11945
  );
@@ -11118,21 +11983,21 @@ function convertEnumSchema(schema, nullable) {
11118
11983
  )
11119
11984
  });
11120
11985
  }
11121
- function convertCompositionSchema(schema, root, nullable, path24) {
11986
+ function convertCompositionSchema(schema, root, nullable, path25) {
11122
11987
  const composition = getComposition(schema);
11123
11988
  const branchSchemas = composition?.branches ?? [];
11124
11989
  const keyword = composition?.keyword ?? "oneOf";
11125
11990
  const branches = branchSchemas.map(
11126
- (branch, index) => resolveReferencedSchema(branch, root, [...path24, keyword, String(index)])
11991
+ (branch, index) => resolveReferencedSchema(branch, root, [...path25, keyword, String(index)])
11127
11992
  );
11128
- const discriminator = findDiscriminator(branches, root, path24);
11993
+ const discriminator = findDiscriminator(branches, root, path25);
11129
11994
  if (discriminator !== void 0) {
11130
11995
  const convertedBranches = Object.fromEntries(
11131
11996
  branches.map((branch, index) => [
11132
11997
  getDiscriminatorLiteral(branch, discriminator, root),
11133
11998
  convertObjectSchema(branch, root, {
11134
11999
  omitProperty: discriminator,
11135
- path: [...path24, keyword, String(index)]
12000
+ path: [...path25, keyword, String(index)]
11136
12001
  })
11137
12002
  ])
11138
12003
  );
@@ -11151,7 +12016,7 @@ function convertCompositionSchema(schema, root, nullable, path24) {
11151
12016
  S.Union(
11152
12017
  branches.map(
11153
12018
  (branch, index) => convertObjectSchema(branch, root, {
11154
- path: [...path24, keyword, String(index)]
12019
+ path: [...path25, keyword, String(index)]
11155
12020
  })
11156
12021
  )
11157
12022
  ),
@@ -11265,11 +12130,11 @@ function getComposition(schema) {
11265
12130
  }
11266
12131
  return void 0;
11267
12132
  }
11268
- function formatJsonSchemaPath(path24) {
11269
- if (path24.length === 0) {
12133
+ function formatJsonSchemaPath(path25) {
12134
+ if (path25.length === 0) {
11270
12135
  return "#";
11271
12136
  }
11272
- return `#/${path24.map(escapeJsonPointerSegment).join("/")}`;
12137
+ return `#/${path25.map(escapeJsonPointerSegment).join("/")}`;
11273
12138
  }
11274
12139
  function formatJsonSchemaType(type2) {
11275
12140
  return Array.isArray(type2) ? JSON.stringify(type2) : String(type2);
@@ -11285,11 +12150,11 @@ function isRecordSchema(schema) {
11285
12150
  const propertyKeys = Object.keys(schema.properties ?? {});
11286
12151
  return schema.type === "object" && propertyKeys.length === 0 && typeof schema.additionalProperties === "object" && schema.additionalProperties !== null;
11287
12152
  }
11288
- function findDiscriminator(branches, root, path24) {
12153
+ function findDiscriminator(branches, root, path25) {
11289
12154
  const [firstBranch] = branches;
11290
12155
  if (firstBranch === void 0) {
11291
12156
  throw new Error(
11292
- `JSON Schema "${formatJsonSchemaPath(path24)}" uses oneOf/anyOf/allOf but has no branches.`
12157
+ `JSON Schema "${formatJsonSchemaPath(path25)}" uses oneOf/anyOf/allOf but has no branches.`
11293
12158
  );
11294
12159
  }
11295
12160
  const candidateKeys = Object.keys(firstBranch.properties ?? {});
@@ -11329,19 +12194,19 @@ function getDiscriminatorLiteral(branch, key2, root) {
11329
12194
  }
11330
12195
  return void 0;
11331
12196
  }
11332
- function resolveReferencedSchema(schema, root, path24) {
12197
+ function resolveReferencedSchema(schema, root, path25) {
11333
12198
  if (schema.$ref === void 0) {
11334
12199
  return schema;
11335
12200
  }
11336
12201
  const resolvedTarget = resolveLocalRef(root, schema.$ref);
11337
12202
  if (resolvedTarget === void 0) {
11338
12203
  throw new Error(
11339
- `JSON Schema "${formatJsonSchemaPath(path24)}" uses "$ref": ${schema.$ref}. toolcraft only supports internal refs like "#/components/schemas/Foo".`
12204
+ `JSON Schema "${formatJsonSchemaPath(path25)}" uses "$ref": ${schema.$ref}. toolcraft only supports internal refs like "#/components/schemas/Foo".`
11340
12205
  );
11341
12206
  }
11342
12207
  const { $ref: ignoredRef, ...siblingKeywords } = schema;
11343
12208
  void ignoredRef;
11344
- const resolvedSchema = resolveReferencedSchema(resolvedTarget, root, path24);
12209
+ const resolvedSchema = resolveReferencedSchema(resolvedTarget, root, path25);
11345
12210
  if (Object.keys(siblingKeywords).length === 0) {
11346
12211
  return resolvedSchema;
11347
12212
  }
@@ -11365,9 +12230,9 @@ function mergeJsonSchemas(base, overlay) {
11365
12230
  ...mergedRequired === void 0 ? {} : { required: mergedRequired }
11366
12231
  };
11367
12232
  }
11368
- function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__PURE__ */ new Set()) {
12233
+ function hasSelfReferencingRef(schema, root, path25 = "#", activePaths = /* @__PURE__ */ new Set()) {
11369
12234
  const nextActivePaths = new Set(activePaths);
11370
- nextActivePaths.add(path24);
12235
+ nextActivePaths.add(path25);
11371
12236
  const localRefPath = getLocalRefPath(schema.$ref);
11372
12237
  if (localRefPath !== void 0) {
11373
12238
  if (nextActivePaths.has(localRefPath)) {
@@ -11378,13 +12243,13 @@ function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__P
11378
12243
  return true;
11379
12244
  }
11380
12245
  }
11381
- if (schema.items !== void 0 && hasSelfReferencingRef(schema.items, root, `${path24}/items`, nextActivePaths)) {
12246
+ if (schema.items !== void 0 && hasSelfReferencingRef(schema.items, root, `${path25}/items`, nextActivePaths)) {
11382
12247
  return true;
11383
12248
  }
11384
12249
  if (typeof schema.additionalProperties === "object" && schema.additionalProperties !== null && hasSelfReferencingRef(
11385
12250
  schema.additionalProperties,
11386
12251
  root,
11387
- `${path24}/additionalProperties`,
12252
+ `${path25}/additionalProperties`,
11388
12253
  nextActivePaths
11389
12254
  )) {
11390
12255
  return true;
@@ -11393,7 +12258,7 @@ function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__P
11393
12258
  if (hasSelfReferencingRef(
11394
12259
  childSchema,
11395
12260
  root,
11396
- `${path24}/properties/${escapeJsonPointerSegment(key2)}`,
12261
+ `${path25}/properties/${escapeJsonPointerSegment(key2)}`,
11397
12262
  nextActivePaths
11398
12263
  )) {
11399
12264
  return true;
@@ -11403,24 +12268,24 @@ function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__P
11403
12268
  if (hasSelfReferencingRef(
11404
12269
  childSchema,
11405
12270
  root,
11406
- `${path24}/$defs/${escapeJsonPointerSegment(key2)}`,
12271
+ `${path25}/$defs/${escapeJsonPointerSegment(key2)}`,
11407
12272
  nextActivePaths
11408
12273
  )) {
11409
12274
  return true;
11410
12275
  }
11411
12276
  }
11412
12277
  for (const [index, childSchema] of (schema.oneOf ?? []).entries()) {
11413
- if (hasSelfReferencingRef(childSchema, root, `${path24}/oneOf/${index}`, nextActivePaths)) {
12278
+ if (hasSelfReferencingRef(childSchema, root, `${path25}/oneOf/${index}`, nextActivePaths)) {
11414
12279
  return true;
11415
12280
  }
11416
12281
  }
11417
12282
  for (const [index, childSchema] of (schema.anyOf ?? []).entries()) {
11418
- if (hasSelfReferencingRef(childSchema, root, `${path24}/anyOf/${index}`, nextActivePaths)) {
12283
+ if (hasSelfReferencingRef(childSchema, root, `${path25}/anyOf/${index}`, nextActivePaths)) {
11419
12284
  return true;
11420
12285
  }
11421
12286
  }
11422
12287
  for (const [index, childSchema] of (schema.allOf ?? []).entries()) {
11423
- if (hasSelfReferencingRef(childSchema, root, `${path24}/allOf/${index}`, nextActivePaths)) {
12288
+ if (hasSelfReferencingRef(childSchema, root, `${path25}/allOf/${index}`, nextActivePaths)) {
11424
12289
  return true;
11425
12290
  }
11426
12291
  }
@@ -11436,14 +12301,14 @@ function getLocalRefPath(ref) {
11436
12301
  return ref.startsWith("#/") ? ref : void 0;
11437
12302
  }
11438
12303
  function resolveLocalRef(root, ref) {
11439
- const path24 = getLocalRefPath(ref);
11440
- if (path24 === void 0) {
12304
+ const path25 = getLocalRefPath(ref);
12305
+ if (path25 === void 0) {
11441
12306
  return void 0;
11442
12307
  }
11443
- if (path24 === "#") {
12308
+ if (path25 === "#") {
11444
12309
  return root;
11445
12310
  }
11446
- const segments = path24.slice(2).split("/").map(unescapeJsonPointerSegment);
12311
+ const segments = path25.slice(2).split("/").map(unescapeJsonPointerSegment);
11447
12312
  let current = root;
11448
12313
  for (const segment of segments) {
11449
12314
  if (Array.isArray(current)) {
@@ -11489,15 +12354,15 @@ function getBooleanDefault(value) {
11489
12354
  return typeof value === "boolean" ? value : void 0;
11490
12355
  }
11491
12356
  function getArrayDefault(value) {
11492
- return Array.isArray(value) && value.every((item) => isJsonValue(item)) ? value : void 0;
12357
+ return Array.isArray(value) && value.every((item) => isJsonValue2(item)) ? value : void 0;
11493
12358
  }
11494
12359
  function getPrimitiveEnumDefault(value, candidates) {
11495
12360
  return isPrimitiveEnumValue(value) && candidates.includes(value) ? value : void 0;
11496
12361
  }
11497
12362
  function getJsonDefault(value) {
11498
- return isJsonValue(value) ? value : void 0;
12363
+ return isJsonValue2(value) ? value : void 0;
11499
12364
  }
11500
- function isJsonValue(value) {
12365
+ function isJsonValue2(value) {
11501
12366
  if (value === null) {
11502
12367
  return true;
11503
12368
  }
@@ -11505,12 +12370,12 @@ function isJsonValue(value) {
11505
12370
  return true;
11506
12371
  }
11507
12372
  if (Array.isArray(value)) {
11508
- return value.every((item) => isJsonValue(item));
12373
+ return value.every((item) => isJsonValue2(item));
11509
12374
  }
11510
12375
  if (!isPlainObject(value)) {
11511
12376
  return false;
11512
12377
  }
11513
- return Object.values(value).every((item) => isJsonValue(item));
12378
+ return Object.values(value).every((item) => isJsonValue2(item));
11514
12379
  }
11515
12380
  function isPlainObject(value) {
11516
12381
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -11700,7 +12565,7 @@ async function ensureConnected(connection) {
11700
12565
  async function readCache(cachePath) {
11701
12566
  try {
11702
12567
  await assertCachePathHasNoSymlinks(cachePath);
11703
- const raw = await readFile3(cachePath, "utf8");
12568
+ const raw = await readFile4(cachePath, "utf8");
11704
12569
  const parsed = JSON.parse(raw);
11705
12570
  if (parsed === null || typeof parsed !== "object" || !Array.isArray(parsed.tools) || parsed.upstream === void 0 || typeof parsed.upstream.name !== "string" || typeof parsed.upstream.version !== "string") {
11706
12571
  return void 0;
@@ -11721,7 +12586,7 @@ async function readCache(cachePath) {
11721
12586
  }
11722
12587
  }
11723
12588
  async function writeCache(cachePath, cache) {
11724
- const directory = path12.dirname(cachePath);
12589
+ const directory = path13.dirname(cachePath);
11725
12590
  const tempPath = `${cachePath}.tmp-${randomUUID4()}`;
11726
12591
  let tempCreated = false;
11727
12592
  await assertCachePathHasNoSymlinks(cachePath);
@@ -11918,13 +12783,13 @@ function collectProxyGroups(root) {
11918
12783
  function findProjectRoot(from = process.cwd()) {
11919
12784
  let current = process.cwd();
11920
12785
  if (from !== current) {
11921
- current = path12.resolve(from);
12786
+ current = path13.resolve(from);
11922
12787
  }
11923
12788
  while (true) {
11924
- if (existsSync2(path12.join(current, "package.json"))) {
12789
+ if (existsSync2(path13.join(current, "package.json"))) {
11925
12790
  return current;
11926
12791
  }
11927
- const parent = path12.dirname(current);
12792
+ const parent = path13.dirname(current);
11928
12793
  if (parent === current) {
11929
12794
  return void 0;
11930
12795
  }
@@ -11941,7 +12806,7 @@ function resolveCachePath(name, projectRoot) {
11941
12806
  if (name.length === 0 || name === "." || name === ".." || name.includes("/") || name.includes("\\")) {
11942
12807
  throw new Error(`MCP proxy group name must be a file-safe name: "${name}".`);
11943
12808
  }
11944
- return path12.join(resolvedProjectRoot, ".toolcraft", "mcp", `${name}.json`);
12809
+ return path13.join(resolvedProjectRoot, ".toolcraft", "mcp", `${name}.json`);
11945
12810
  }
11946
12811
  async function assertCachePathHasNoSymlinks(filePath) {
11947
12812
  let currentPath = filePath;
@@ -11955,10 +12820,10 @@ async function assertCachePathHasNoSymlinks(filePath) {
11955
12820
  throw error3;
11956
12821
  }
11957
12822
  }
11958
- if (path12.basename(currentPath) === ".toolcraft") {
12823
+ if (path13.basename(currentPath) === ".toolcraft") {
11959
12824
  return;
11960
12825
  }
11961
- const parentPath = path12.dirname(currentPath);
12826
+ const parentPath = path13.dirname(currentPath);
11962
12827
  if (parentPath === currentPath) {
11963
12828
  return;
11964
12829
  }
@@ -12104,20 +12969,20 @@ function reportsEnabled(option, env) {
12104
12969
  function resolveReportDir(option, projectRoot) {
12105
12970
  const configuredDir = typeof option === "object" ? option.dir : void 0;
12106
12971
  if (configuredDir === void 0 || configuredDir.length === 0) {
12107
- return path13.join(projectRoot, ".toolcraft", "errors");
12972
+ return path14.join(projectRoot, ".toolcraft", "errors");
12108
12973
  }
12109
- return path13.isAbsolute(configuredDir) ? configuredDir : path13.join(projectRoot, configuredDir);
12974
+ return path14.isAbsolute(configuredDir) ? configuredDir : path14.join(projectRoot, configuredDir);
12110
12975
  }
12111
12976
  function reportDirMustStayWithinProject(option) {
12112
12977
  const configuredDir = typeof option === "object" ? option.dir : void 0;
12113
- return configuredDir === void 0 || configuredDir.length === 0 || !path13.isAbsolute(configuredDir);
12978
+ return configuredDir === void 0 || configuredDir.length === 0 || !path14.isAbsolute(configuredDir);
12114
12979
  }
12115
12980
  function isWithinDirectory(parent, child) {
12116
- const relative = path13.relative(parent, child);
12117
- return relative === "" || !path13.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path13.sep}`);
12981
+ const relative = path14.relative(parent, child);
12982
+ return relative === "" || !path14.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path14.sep}`);
12118
12983
  }
12119
12984
  async function assertReportDirWithinProject(projectRoot, reportDir) {
12120
- if (!isWithinDirectory(path13.resolve(projectRoot), path13.resolve(reportDir))) {
12985
+ if (!isWithinDirectory(path14.resolve(projectRoot), path14.resolve(reportDir))) {
12121
12986
  throw new Error("Error report directory resolves outside project root.");
12122
12987
  }
12123
12988
  const [canonicalProjectRoot, canonicalReportDir] = await Promise.all([
@@ -12168,7 +13033,7 @@ function slugifyCommandPath(commandPath) {
12168
13033
  return output.length === 0 ? "root" : output;
12169
13034
  }
12170
13035
  function relativeDisplayPath(projectRoot, absolutePath) {
12171
- const relative = path13.relative(projectRoot, absolutePath);
13036
+ const relative = path14.relative(projectRoot, absolutePath);
12172
13037
  return relative.length === 0 || relative.startsWith("..") ? absolutePath : relative;
12173
13038
  }
12174
13039
  function redactValue(value) {
@@ -12488,7 +13353,7 @@ async function writeErrorReport(context) {
12488
13353
  const projectRoot = resolveProjectRoot(context.projectRoot);
12489
13354
  const reportDir = resolveReportDir(context.errorReports, projectRoot);
12490
13355
  const fileName = `${formatTimestamp(/* @__PURE__ */ new Date())}-${slugifyCommandPath(context.commandPath)}-${randomUUID5()}.log`;
12491
- const absolutePath = path13.join(reportDir, fileName);
13356
+ const absolutePath = path14.join(reportDir, fileName);
12492
13357
  await mkdir2(reportDir, { recursive: true });
12493
13358
  if (reportDirMustStayWithinProject(context.errorReports)) {
12494
13359
  await assertReportDirWithinProject(projectRoot, reportDir);
@@ -12958,7 +13823,7 @@ function inferProgramName(argv) {
12958
13823
  if (typeof entrypoint !== "string" || entrypoint.length === 0) {
12959
13824
  return "toolcraft";
12960
13825
  }
12961
- const parsed = path14.parse(entrypoint);
13826
+ const parsed = path15.parse(entrypoint);
12962
13827
  return parsed.name.length > 0 ? parsed.name : "toolcraft";
12963
13828
  }
12964
13829
  function normalizeRoots(roots, argv) {
@@ -13016,11 +13881,11 @@ function formatSegment(segment, casing) {
13016
13881
  const separator = casing === "snake" ? "_" : "-";
13017
13882
  return splitWords3(segment).join(separator);
13018
13883
  }
13019
- function toOptionFlag(path24, casing) {
13020
- return `--${path24.map((segment) => formatSegment(segment, casing)).join(".")}`;
13884
+ function toOptionFlag(path25, casing) {
13885
+ return `--${path25.map((segment) => formatSegment(segment, casing)).join(".")}`;
13021
13886
  }
13022
- function toOptionAttribute(path24, casing) {
13023
- return path24.map((segment) => {
13887
+ function toOptionAttribute(path25, casing) {
13888
+ return path25.map((segment) => {
13024
13889
  const formatted = formatSegment(segment, casing);
13025
13890
  if (casing === "snake") {
13026
13891
  return formatted;
@@ -13031,23 +13896,23 @@ function toOptionAttribute(path24, casing) {
13031
13896
  ).join("");
13032
13897
  }).join(".");
13033
13898
  }
13034
- function toDisplayPath(path24) {
13035
- return path24.join(".");
13899
+ function toDisplayPath(path25) {
13900
+ return path25.join(".");
13036
13901
  }
13037
- function toUnionKindControlPath(path24) {
13038
- if (path24.length === 0) {
13902
+ function toUnionKindControlPath(path25) {
13903
+ if (path25.length === 0) {
13039
13904
  return ["kind"];
13040
13905
  }
13041
- const head = path24.slice(0, -1);
13042
- const tail = path24[path24.length - 1] ?? "";
13906
+ const head = path25.slice(0, -1);
13907
+ const tail = path25[path25.length - 1] ?? "";
13043
13908
  return [...head, `${tail}Kind`];
13044
13909
  }
13045
- function toUnionKindDisplayPath(path24) {
13046
- if (path24.length === 0) {
13910
+ function toUnionKindDisplayPath(path25) {
13911
+ if (path25.length === 0) {
13047
13912
  return "kind";
13048
13913
  }
13049
- const head = path24.slice(0, -1);
13050
- const tail = path24[path24.length - 1] ?? "";
13914
+ const head = path25.slice(0, -1);
13915
+ const tail = path25[path25.length - 1] ?? "";
13051
13916
  return [...head, `${tail}-kind`].join(".");
13052
13917
  }
13053
13918
  function createSyntheticEnumSchema(values) {
@@ -13063,14 +13928,14 @@ function getRequiredBranchFingerprint(branch, casing) {
13063
13928
  const requiredKeys = Object.entries(branch.shape).filter(([, schema]) => schema.kind !== "optional").map(([key2]) => formatSegment(key2, casing)).sort();
13064
13929
  return requiredKeys.join("+");
13065
13930
  }
13066
- function collectFields(schema, casing, globalLongOptionFlags, path24 = [], inheritedOptional = false, variantContext) {
13931
+ function collectFields(schema, casing, globalLongOptionFlags, path25 = [], inheritedOptional = false, variantContext) {
13067
13932
  const collected = {
13068
13933
  dynamicFields: [],
13069
13934
  fields: [],
13070
13935
  variants: []
13071
13936
  };
13072
13937
  for (const [key2, rawChildSchema] of Object.entries(schema.shape)) {
13073
- const nextPath = [...path24, key2];
13938
+ const nextPath = [...path25, key2];
13074
13939
  const runtimeOptional = inheritedOptional || rawChildSchema.kind === "optional";
13075
13940
  const childSchema = unwrapOptional2(rawChildSchema);
13076
13941
  const requiredWhenActive = rawChildSchema.kind !== "optional" && childSchema.default === void 0;
@@ -13256,9 +14121,9 @@ function collectFields(schema, casing, globalLongOptionFlags, path24 = [], inher
13256
14121
  }
13257
14122
  return collected;
13258
14123
  }
13259
- function toCommanderOptionAttribute(path24, casing, globalLongOptionFlags) {
13260
- const optionAttribute = toOptionAttribute(path24, casing);
13261
- const optionFlag = toOptionFlag(path24, casing);
14124
+ function toCommanderOptionAttribute(path25, casing, globalLongOptionFlags) {
14125
+ const optionAttribute = toOptionAttribute(path25, casing);
14126
+ const optionFlag = toOptionFlag(path25, casing);
13262
14127
  if (!globalLongOptionFlags.has(optionFlag)) {
13263
14128
  return optionAttribute;
13264
14129
  }
@@ -13531,6 +14396,20 @@ function parseArrayValue(value, schema, label) {
13531
14396
  (item) => parseScalarValue(item, itemSchema, label)
13532
14397
  );
13533
14398
  }
14399
+ function isNegativeNumericArrayToken(token, schema) {
14400
+ if (!token.startsWith("-") || token.startsWith("--")) {
14401
+ return false;
14402
+ }
14403
+ const itemSchema = unwrapOptional2(schema.item);
14404
+ if (itemSchema.kind !== "number") {
14405
+ return false;
14406
+ }
14407
+ const items = splitArrayInput(token);
14408
+ return items.length > 0 && items.every((item) => isValidNumberSchemaValue(Number(item), itemSchema));
14409
+ }
14410
+ function isNextArrayOptionToken(token, schema) {
14411
+ return token.startsWith("-") && !isNegativeNumericArrayToken(token, schema);
14412
+ }
13534
14413
  function validateArrayBounds(value, schema, label) {
13535
14414
  if (schema.minItems !== void 0 && value.length < schema.minItems) {
13536
14415
  throw new UserError(
@@ -14338,10 +15217,10 @@ function parseDebugStackMode(value) {
14338
15217
  formatInvalidEnumMessage("--debug", String(value), ["raw"], { candidates: ["raw"] })
14339
15218
  );
14340
15219
  }
14341
- function setNestedValue(target, path24, value) {
15220
+ function setNestedValue(target, path25, value) {
14342
15221
  let cursor2 = target;
14343
- for (let index = 0; index < path24.length - 1; index += 1) {
14344
- const segment = path24[index] ?? "";
15222
+ for (let index = 0; index < path25.length - 1; index += 1) {
15223
+ const segment = path25[index] ?? "";
14345
15224
  const existing = Object.prototype.hasOwnProperty.call(cursor2, segment) ? cursor2[segment] : void 0;
14346
15225
  if (typeof existing === "object" && existing !== null) {
14347
15226
  cursor2 = existing;
@@ -14356,7 +15235,7 @@ function setNestedValue(target, path24, value) {
14356
15235
  });
14357
15236
  cursor2 = next;
14358
15237
  }
14359
- const leaf = path24[path24.length - 1];
15238
+ const leaf = path25[path25.length - 1];
14360
15239
  if (leaf !== void 0) {
14361
15240
  Object.defineProperty(cursor2, leaf, {
14362
15241
  value,
@@ -14473,21 +15352,21 @@ async function withOutputFormat2(output, fn) {
14473
15352
  }
14474
15353
  function createFs2() {
14475
15354
  return {
14476
- readFile: async (path24, encoding = "utf8") => readFile4(path24, { encoding }),
14477
- writeFile: async (path24, contents, options) => {
14478
- await writeFile5(path24, contents, options);
15355
+ readFile: async (path25, encoding = "utf8") => readFile5(path25, { encoding }),
15356
+ writeFile: async (path25, contents, options) => {
15357
+ await writeFile5(path25, contents, options);
14479
15358
  },
14480
- exists: async (path24) => {
15359
+ exists: async (path25) => {
14481
15360
  try {
14482
- await access2(path24);
15361
+ await access2(path25);
14483
15362
  return true;
14484
15363
  } catch {
14485
15364
  return false;
14486
15365
  }
14487
15366
  },
14488
- lstat: async (path24) => lstat3(path24),
15367
+ lstat: async (path25) => lstat3(path25),
14489
15368
  rename: async (fromPath, toPath) => rename3(fromPath, toPath),
14490
- unlink: async (path24) => unlink3(path24)
15369
+ unlink: async (path25) => unlink3(path25)
14491
15370
  };
14492
15371
  }
14493
15372
  function createEnv2(values = process.env) {
@@ -14503,9 +15382,9 @@ function isPlainObject4(value) {
14503
15382
  function hasFieldValue(value) {
14504
15383
  return value !== void 0;
14505
15384
  }
14506
- function hasNestedField(fields, path24) {
15385
+ function hasNestedField(fields, path25) {
14507
15386
  return fields.some(
14508
- (field) => path24.length < field.path.length && path24.every((segment, index) => field.path[index] === segment)
15387
+ (field) => path25.length < field.path.length && path25.every((segment, index) => field.path[index] === segment)
14509
15388
  );
14510
15389
  }
14511
15390
  function describeExpectedPresetValue(schema) {
@@ -14608,7 +15487,7 @@ function validatePresetFieldValue(value, field, presetPath) {
14608
15487
  async function loadPresetValues(fields, presetPath) {
14609
15488
  let rawPreset;
14610
15489
  try {
14611
- rawPreset = await readFile4(presetPath, {
15490
+ rawPreset = await readFile5(presetPath, {
14612
15491
  encoding: "utf8"
14613
15492
  });
14614
15493
  } catch (error3) {
@@ -14634,9 +15513,9 @@ async function loadPresetValues(fields, presetPath) {
14634
15513
  }
14635
15514
  const fieldByPath = new Map(fields.map((field) => [field.displayPath, field]));
14636
15515
  const presetValues = {};
14637
- function visitObject(current, path24) {
15516
+ function visitObject(current, path25) {
14638
15517
  for (const [key2, value] of Object.entries(current)) {
14639
- const nextPath = [...path24, key2];
15518
+ const nextPath = [...path25, key2];
14640
15519
  const displayPath = toDisplayPath(nextPath);
14641
15520
  const field = fieldByPath.get(displayPath);
14642
15521
  if (field !== void 0) {
@@ -14843,8 +15722,8 @@ function createFixtureService(definition) {
14843
15722
  );
14844
15723
  }
14845
15724
  function resolveFixturePath(commandPath) {
14846
- const parsed = path14.parse(commandPath);
14847
- return path14.join(parsed.dir, `${parsed.name}.fixture.json`);
15725
+ const parsed = path15.parse(commandPath);
15726
+ return path15.join(parsed.dir, `${parsed.name}.fixture.json`);
14848
15727
  }
14849
15728
  function selectFixtureScenario(scenarios, selector, fixturePath) {
14850
15729
  if (isNumericFixtureSelector(selector)) {
@@ -14875,7 +15754,7 @@ async function loadFixtureScenario(command, selector) {
14875
15754
  const fixturePath = resolveFixturePath(commandPath);
14876
15755
  let rawFixture;
14877
15756
  try {
14878
- rawFixture = await readFile4(fixturePath, {
15757
+ rawFixture = await readFile5(fixturePath, {
14879
15758
  encoding: "utf8"
14880
15759
  });
14881
15760
  } catch {
@@ -14978,8 +15857,8 @@ function validateServices(services) {
14978
15857
  }
14979
15858
  }
14980
15859
  }
14981
- function getNestedValue(target, path24) {
14982
- return path24.reduce(
15860
+ function getNestedValue(target, path25) {
15861
+ return path25.reduce(
14983
15862
  (current, segment) => current !== null && typeof current === "object" ? current[segment] : void 0,
14984
15863
  target
14985
15864
  );
@@ -15064,7 +15943,7 @@ function consumeFieldValue(args, index, schema, label, inlineValue) {
15064
15943
  let cursor2 = index + 1;
15065
15944
  while (cursor2 < args.length) {
15066
15945
  const token = args[cursor2] ?? "";
15067
- if (token.startsWith("-")) {
15946
+ if (isNextArrayOptionToken(token, schema)) {
15068
15947
  break;
15069
15948
  }
15070
15949
  const parsed = parseArrayValue(token, schema, label);
@@ -15940,6 +16819,12 @@ This is a bug in toolcraft or in the command definition; it cannot be worked aro
15940
16819
  );
15941
16820
  return;
15942
16821
  }
16822
+ logger2.error(
16823
+ appendUsagePointer(formatCommanderErrorMessage(error3), {
16824
+ rootUsageName: options.rootUsageName,
16825
+ commandPath: options.commandPath.length > 0 ? options.commandPath : findCurrentCommanderCommandPath(options.program, options.argv ?? process.argv)
16826
+ })
16827
+ );
15943
16828
  return;
15944
16829
  }
15945
16830
  if (isHttpErrorLike(error3)) {
@@ -15957,6 +16842,9 @@ This is a bug in toolcraft or in the command definition; it cannot be worked aro
15957
16842
  }
15958
16843
  process.exitCode = 1;
15959
16844
  }
16845
+ function formatCommanderErrorMessage(error3) {
16846
+ return error3.message.startsWith("error:") ? error3.message : `error: ${error3.message}`;
16847
+ }
15960
16848
  function formatInvalidEnumMessage(label, value, values, opts = {}) {
15961
16849
  const suggestions = suggest(
15962
16850
  value,
@@ -16281,7 +17169,7 @@ import { randomUUID as randomUUID6 } from "node:crypto";
16281
17169
  // src/terminal-session.ts
16282
17170
  import { EventEmitter as EventEmitter2 } from "node:events";
16283
17171
  import { accessSync, chmodSync, constants } from "node:fs";
16284
- import { createRequire } from "node:module";
17172
+ import { createRequire as createRequire2 } from "node:module";
16285
17173
  import { dirname, join } from "node:path";
16286
17174
  import * as nodePty from "node-pty";
16287
17175
 
@@ -17493,8 +18381,8 @@ var spawnHelperChecked = false;
17493
18381
  function ensureSpawnHelperExecutable() {
17494
18382
  if (spawnHelperChecked) return;
17495
18383
  spawnHelperChecked = true;
17496
- const require3 = createRequire(import.meta.url);
17497
- const nodePtyDir = dirname(require3.resolve("node-pty"));
18384
+ const require4 = createRequire2(import.meta.url);
18385
+ const nodePtyDir = dirname(require4.resolve("node-pty"));
17498
18386
  const helper = join(nodePtyDir, "..", "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper");
17499
18387
  try {
17500
18388
  accessSync(helper, constants.X_OK);
@@ -17907,7 +18795,7 @@ var getSession = defineCommand({
17907
18795
 
17908
18796
  // ../agent-skill-config/src/configs.ts
17909
18797
  import os2 from "node:os";
17910
- import path15 from "node:path";
18798
+ import path16 from "node:path";
17911
18799
 
17912
18800
  // ../agent-defs/src/agents/claude-code.ts
17913
18801
  var claudeCodeAgent = {
@@ -18271,7 +19159,7 @@ var templateMutation = {
18271
19159
 
18272
19160
  // ../config-mutations/src/execution/apply-mutation.ts
18273
19161
  import { randomUUID as randomUUID7 } from "node:crypto";
18274
- import path17 from "node:path";
19162
+ import path18 from "node:path";
18275
19163
 
18276
19164
  // ../config-mutations/src/formats/json.ts
18277
19165
  import * as jsonc from "jsonc-parser";
@@ -18394,22 +19282,22 @@ function prune(obj, shape) {
18394
19282
  }
18395
19283
  return { changed, result };
18396
19284
  }
18397
- function modifyAtPath(content, path24, value) {
19285
+ function modifyAtPath(content, path25, value) {
18398
19286
  const indent = detectIndent(content);
18399
19287
  const formattingOptions = {
18400
19288
  tabSize: indent === " " ? 1 : indent.length,
18401
19289
  insertSpaces: indent !== " ",
18402
19290
  eol: "\n"
18403
19291
  };
18404
- const edits = jsonc.modify(content, path24, value, { formattingOptions });
19292
+ const edits = jsonc.modify(content, path25, value, { formattingOptions });
18405
19293
  let result = jsonc.applyEdits(content, edits);
18406
19294
  if (!result.endsWith("\n")) {
18407
19295
  result += "\n";
18408
19296
  }
18409
19297
  return result;
18410
19298
  }
18411
- function removeAtPath(content, path24) {
18412
- return modifyAtPath(content, path24, void 0);
19299
+ function removeAtPath(content, path25) {
19300
+ return modifyAtPath(content, path25, void 0);
18413
19301
  }
18414
19302
  function serializeUpdate(content, current, next) {
18415
19303
  let result = content || "{}";
@@ -18419,15 +19307,15 @@ function serializeUpdate(content, current, next) {
18419
19307
  }
18420
19308
  return result;
18421
19309
  }
18422
- function applyObjectUpdate(content, path24, current, next) {
19310
+ function applyObjectUpdate(content, path25, current, next) {
18423
19311
  let result = content;
18424
19312
  for (const key2 of Object.keys(current)) {
18425
19313
  if (!hasConfigEntry(next, key2)) {
18426
- result = removeAtPath(result, [...path24, key2]);
19314
+ result = removeAtPath(result, [...path25, key2]);
18427
19315
  }
18428
19316
  }
18429
19317
  for (const [key2, nextValue] of Object.entries(next)) {
18430
- const nextPath = [...path24, key2];
19318
+ const nextPath = [...path25, key2];
18431
19319
  const hasCurrent = hasConfigEntry(current, key2);
18432
19320
  const currentValue = hasCurrent ? current[key2] : void 0;
18433
19321
  if (hasCurrent && isConfigObject(currentValue) && isConfigObject(nextValue)) {
@@ -18627,20 +19515,20 @@ function getConfigFormat(pathOrFormat) {
18627
19515
  }
18628
19516
  return formatRegistry[formatName];
18629
19517
  }
18630
- function detectFormat(path24) {
18631
- const ext = getExtension(path24);
19518
+ function detectFormat(path25) {
19519
+ const ext = getExtension(path25);
18632
19520
  return extensionMap[ext];
18633
19521
  }
18634
- function getExtension(path24) {
18635
- const lastDot = path24.lastIndexOf(".");
19522
+ function getExtension(path25) {
19523
+ const lastDot = path25.lastIndexOf(".");
18636
19524
  if (lastDot === -1) {
18637
19525
  return "";
18638
19526
  }
18639
- return path24.slice(lastDot).toLowerCase();
19527
+ return path25.slice(lastDot).toLowerCase();
18640
19528
  }
18641
19529
 
18642
19530
  // ../config-mutations/src/execution/path-utils.ts
18643
- import path16 from "node:path";
19531
+ import path17 from "node:path";
18644
19532
  function expandHome(targetPath, homeDir) {
18645
19533
  if (!targetPath?.startsWith("~")) {
18646
19534
  return targetPath;
@@ -18657,7 +19545,7 @@ function expandHome(targetPath, homeDir) {
18657
19545
  remainder = remainder.slice(1);
18658
19546
  }
18659
19547
  }
18660
- return remainder.length === 0 ? homeDir : path16.join(homeDir, remainder);
19548
+ return remainder.length === 0 ? homeDir : path17.join(homeDir, remainder);
18661
19549
  }
18662
19550
  function validateHomePath(targetPath) {
18663
19551
  if (typeof targetPath !== "string" || targetPath.length === 0) {
@@ -18672,21 +19560,21 @@ function validateHomePath(targetPath) {
18672
19560
  function resolvePath(rawPath, homeDir, pathMapper) {
18673
19561
  validateHomePath(rawPath);
18674
19562
  const expanded = expandHome(rawPath, homeDir);
18675
- const canonicalHome = path16.resolve(homeDir);
18676
- const canonicalExpanded = path16.resolve(expanded);
18677
- const relative = path16.relative(canonicalHome, canonicalExpanded);
18678
- if (relative === ".." || relative.startsWith(`..${path16.sep}`) || path16.isAbsolute(relative)) {
19563
+ const canonicalHome = path17.resolve(homeDir);
19564
+ const canonicalExpanded = path17.resolve(expanded);
19565
+ const relative = path17.relative(canonicalHome, canonicalExpanded);
19566
+ if (relative === ".." || relative.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative)) {
18679
19567
  throw new Error(`Target path resolves outside home directory: "${rawPath}"`);
18680
19568
  }
18681
19569
  if (!pathMapper) {
18682
19570
  return canonicalExpanded;
18683
19571
  }
18684
- const rawDirectory = path16.dirname(expanded);
19572
+ const rawDirectory = path17.dirname(expanded);
18685
19573
  const mappedDirectory = pathMapper.mapTargetDirectory({
18686
19574
  targetDirectory: rawDirectory
18687
19575
  });
18688
- const filename = path16.basename(expanded);
18689
- return filename.length === 0 ? mappedDirectory : path16.join(mappedDirectory, filename);
19576
+ const filename = path17.basename(expanded);
19577
+ return filename.length === 0 ? mappedDirectory : path17.join(mappedDirectory, filename);
18690
19578
  }
18691
19579
 
18692
19580
  // ../config-mutations/src/error-codes.ts
@@ -18698,9 +19586,9 @@ function hasOwnErrorCode5(error3, code) {
18698
19586
  function isNotFound(error3) {
18699
19587
  return hasOwnErrorCode5(error3, "ENOENT");
18700
19588
  }
18701
- async function readFileIfExists(fs4, target) {
19589
+ async function readFileIfExists(fs5, target) {
18702
19590
  try {
18703
- return await fs4.readFile(target, "utf8");
19591
+ return await fs5.readFile(target, "utf8");
18704
19592
  } catch (error3) {
18705
19593
  if (isNotFound(error3)) {
18706
19594
  return null;
@@ -18708,9 +19596,9 @@ async function readFileIfExists(fs4, target) {
18708
19596
  throw error3;
18709
19597
  }
18710
19598
  }
18711
- async function pathExists(fs4, target) {
19599
+ async function pathExists(fs5, target) {
18712
19600
  try {
18713
- await fs4.stat(target);
19601
+ await fs5.stat(target);
18714
19602
  return true;
18715
19603
  } catch (error3) {
18716
19604
  if (isNotFound(error3)) {
@@ -18756,8 +19644,8 @@ function isAlreadyExists(error3) {
18756
19644
  return hasOwnErrorCode5(error3, "EEXIST");
18757
19645
  }
18758
19646
  async function assertRegularWriteTarget(context, targetPath) {
18759
- const boundary = path17.dirname(path17.resolve(context.homeDir));
18760
- let currentPath = path17.resolve(targetPath);
19647
+ const boundary = path18.dirname(path18.resolve(context.homeDir));
19648
+ let currentPath = path18.resolve(targetPath);
18761
19649
  while (currentPath !== boundary) {
18762
19650
  try {
18763
19651
  if ((await context.fs.lstat(currentPath)).isSymbolicLink()) {
@@ -18768,7 +19656,7 @@ async function assertRegularWriteTarget(context, targetPath) {
18768
19656
  throw error3;
18769
19657
  }
18770
19658
  }
18771
- const parentPath = path17.dirname(currentPath);
19659
+ const parentPath = path18.dirname(currentPath);
18772
19660
  if (parentPath === currentPath) {
18773
19661
  return;
18774
19662
  }
@@ -18833,6 +19721,56 @@ function describeMutation(kind, targetPath) {
18833
19721
  return "Operation";
18834
19722
  }
18835
19723
  }
19724
+ function mutationTargetPath(mutation, options) {
19725
+ switch (mutation.kind) {
19726
+ case "ensureDirectory":
19727
+ case "removeDirectory":
19728
+ return resolveValue(mutation.path, options);
19729
+ case "removeFile":
19730
+ case "chmod":
19731
+ case "backup":
19732
+ case "restoreBackup":
19733
+ case "configMerge":
19734
+ case "configPrune":
19735
+ case "configTransform":
19736
+ case "templateWrite":
19737
+ case "templateMergeToml":
19738
+ case "templateMergeJson":
19739
+ return resolveValue(mutation.target, options);
19740
+ default:
19741
+ return void 0;
19742
+ }
19743
+ }
19744
+ function resolveMutationDetails(mutation, context, options) {
19745
+ try {
19746
+ const rawTarget = mutationTargetPath(mutation, options);
19747
+ if (rawTarget === void 0) {
19748
+ return {
19749
+ kind: mutation.kind,
19750
+ label: mutation.label ?? mutation.kind
19751
+ };
19752
+ }
19753
+ try {
19754
+ const targetPath = resolvePath(rawTarget, context.homeDir, context.pathMapper);
19755
+ return {
19756
+ kind: mutation.kind,
19757
+ label: mutation.label ?? describeMutation(mutation.kind, targetPath),
19758
+ targetPath
19759
+ };
19760
+ } catch {
19761
+ return {
19762
+ kind: mutation.kind,
19763
+ label: mutation.label ?? describeMutation(mutation.kind, rawTarget),
19764
+ targetPath: void 0
19765
+ };
19766
+ }
19767
+ } catch {
19768
+ return {
19769
+ kind: mutation.kind,
19770
+ label: mutation.label ?? mutation.kind
19771
+ };
19772
+ }
19773
+ }
18836
19774
  function pruneKeysByPrefix(table, prefix) {
18837
19775
  const result = {};
18838
19776
  for (const [key2, value] of Object.entries(table)) {
@@ -18923,6 +19861,7 @@ async function applyEnsureDirectory(mutation, context, options) {
18923
19861
  label: mutation.label ?? describeMutation(mutation.kind, targetPath),
18924
19862
  targetPath
18925
19863
  };
19864
+ await assertRegularWriteTarget(context, targetPath);
18926
19865
  const existed = await pathExists(context.fs, targetPath);
18927
19866
  if (!context.dryRun) {
18928
19867
  await context.fs.mkdir(targetPath, { recursive: true });
@@ -19039,6 +19978,7 @@ async function applyChmod(mutation, context, options) {
19039
19978
  };
19040
19979
  }
19041
19980
  try {
19981
+ await assertRegularWriteTarget(context, targetPath);
19042
19982
  const stat2 = await context.fs.stat(targetPath);
19043
19983
  const currentMode = typeof stat2.mode === "number" ? stat2.mode & 511 : null;
19044
19984
  if (currentMode === mutation.mode) {
@@ -19072,6 +20012,7 @@ async function applyBackup(mutation, context, options) {
19072
20012
  label: mutation.label ?? describeMutation(mutation.kind, targetPath),
19073
20013
  targetPath
19074
20014
  };
20015
+ await assertRegularWriteTarget(context, targetPath);
19075
20016
  if (mutation.once && await findLatestGeneratedBackup(context.fs, targetPath) !== null) {
19076
20017
  return {
19077
20018
  outcome: { changed: false, effect: "none", detail: "noop" },
@@ -19138,13 +20079,13 @@ async function applyRestoreBackup(mutation, context, options) {
19138
20079
  }
19139
20080
  return { outcome: { changed: true, effect: "copy", detail: "restore" }, details };
19140
20081
  }
19141
- async function findLatestGeneratedBackup(fs4, targetPath) {
20082
+ async function findLatestGeneratedBackup(fs5, targetPath) {
19142
20083
  const separatorIndex = targetPath.lastIndexOf("/");
19143
20084
  const directoryPath = separatorIndex <= 0 ? "/" : targetPath.slice(0, separatorIndex);
19144
20085
  const targetName = targetPath.slice(separatorIndex + 1);
19145
20086
  let entries;
19146
20087
  try {
19147
- entries = await fs4.readdir(directoryPath);
20088
+ entries = await fs5.readdir(directoryPath);
19148
20089
  } catch (error3) {
19149
20090
  if (isNotFound(error3)) {
19150
20091
  return null;
@@ -19208,6 +20149,9 @@ async function applyConfigMerge(mutation, context, options) {
19208
20149
  preserveContent = null;
19209
20150
  }
19210
20151
  const value = resolveValue(mutation.value, options);
20152
+ if (!isConfigObject4(value)) {
20153
+ throw new Error(`configMerge value must be an object for "${rawPath}".`);
20154
+ }
19211
20155
  let merged;
19212
20156
  if (mutation.pruneByPrefix) {
19213
20157
  merged = mergeWithPruneByPrefix(current, value, mutation.pruneByPrefix);
@@ -19341,6 +20285,13 @@ async function applyConfigTransform(mutation, context, options) {
19341
20285
  };
19342
20286
  }
19343
20287
  const serialized = serializeConfigUpdate(format, preserveContent, current, transformed);
20288
+ const serializedChanged = serialized !== rawContent;
20289
+ if (!serializedChanged) {
20290
+ return {
20291
+ outcome: { changed: false, effect: "none", detail: "noop" },
20292
+ details
20293
+ };
20294
+ }
19344
20295
  if (!context.dryRun) {
19345
20296
  await writeAtomically2(context, targetPath, serialized);
19346
20297
  }
@@ -19457,25 +20408,14 @@ async function runMutations(mutations, context, options) {
19457
20408
  };
19458
20409
  }
19459
20410
  async function executeMutation(mutation, context, options) {
19460
- context.observers?.onStart?.({
19461
- kind: mutation.kind,
19462
- label: mutation.label ?? mutation.kind,
19463
- targetPath: void 0
19464
- // Will be resolved during apply
19465
- });
20411
+ const pendingDetails = resolveMutationDetails(mutation, context, options);
20412
+ context.observers?.onStart?.(pendingDetails);
19466
20413
  try {
19467
20414
  const { outcome, details } = await applyMutation(mutation, context, options);
19468
20415
  context.observers?.onComplete?.(details, outcome);
19469
20416
  return { outcome, details };
19470
20417
  } catch (error3) {
19471
- context.observers?.onError?.(
19472
- {
19473
- kind: mutation.kind,
19474
- label: mutation.label ?? mutation.kind,
19475
- targetPath: void 0
19476
- },
19477
- error3
19478
- );
20418
+ context.observers?.onError?.(pendingDetails, error3);
19479
20419
  throw error3;
19480
20420
  }
19481
20421
  }
@@ -19486,8 +20426,8 @@ function hasOwnErrorCode6(error3, code) {
19486
20426
  }
19487
20427
 
19488
20428
  // ../agent-skill-config/src/templates.ts
19489
- import { readFile as readFile5, stat } from "node:fs/promises";
19490
- import path18 from "node:path";
20429
+ import { readFile as readFile6, stat } from "node:fs/promises";
20430
+ import path19 from "node:path";
19491
20431
  import { fileURLToPath as fileURLToPath3 } from "node:url";
19492
20432
 
19493
20433
  // ../agent-skill-config/src/apply.ts
@@ -19504,9 +20444,9 @@ function toHomeRelative(localSkillDir) {
19504
20444
  const normalized = localSkillDir.startsWith("./") ? localSkillDir.slice(2) : localSkillDir;
19505
20445
  return `~/${normalized}`;
19506
20446
  }
19507
- async function pathExists2(fs4, targetPath) {
20447
+ async function pathExists2(fs5, targetPath) {
19508
20448
  try {
19509
- await fs4.stat(targetPath);
20449
+ await fs5.stat(targetPath);
19510
20450
  return true;
19511
20451
  } catch (error3) {
19512
20452
  if (hasOwnErrorCode6(error3, "ENOENT")) {
@@ -19523,7 +20463,7 @@ async function installSkill(agentId, skill, options) {
19523
20463
  }
19524
20464
  const scope = options.scope ?? "local";
19525
20465
  const config2 = support.config;
19526
- if (skill.name.length === 0 || skill.name === "." || skill.name === ".." || skill.name.includes("/") || skill.name.includes("\\") || skill.name.includes("\n") || skill.name.includes("\r")) {
20466
+ if (skill.name.length === 0 || skill.name !== skill.name.trim() || skill.name === "." || skill.name === ".." || skill.name.includes("/") || skill.name.includes("\\") || skill.name.includes("\n") || skill.name.includes("\r")) {
19527
20467
  throw new Error(`Invalid skill name: ${skill.name}`);
19528
20468
  }
19529
20469
  const skillDir = scope === "global" ? config2.globalSkillDir : toHomeRelative(config2.localSkillDir);
@@ -19559,29 +20499,29 @@ async function installSkill(agentId, skill, options) {
19559
20499
  }
19560
20500
  }
19561
20501
  );
19562
- return { skillPath: skillFilePath, displayPath };
20502
+ return { skillPath: absoluteSkillPath, displayPath };
19563
20503
  }
19564
20504
 
19565
20505
  // ../agent-skill-config/src/resolve-skill-reference.ts
19566
- import { statSync as statSync2 } from "node:fs";
19567
- import path19 from "node:path";
20506
+ import * as fs2 from "node:fs";
20507
+ import path20 from "node:path";
19568
20508
 
19569
20509
  // ../agent-skill-config/src/git-exclude.ts
19570
20510
  import { execFileSync } from "node:child_process";
19571
20511
  import { randomUUID as randomUUID8 } from "node:crypto";
19572
- import * as fs2 from "node:fs";
19573
- import path20 from "node:path";
20512
+ import * as fs3 from "node:fs";
20513
+ import path21 from "node:path";
19574
20514
 
19575
20515
  // ../agent-skill-config/src/bridge-active-skills.ts
19576
- import * as fs3 from "node:fs";
20516
+ import * as fs4 from "node:fs";
19577
20517
  import { createHash as createHash4, randomUUID as randomUUID9 } from "node:crypto";
19578
- import path21 from "node:path";
20518
+ import path22 from "node:path";
19579
20519
 
19580
20520
  // src/commands/installer.ts
19581
20521
  import os3 from "node:os";
19582
- import path22 from "node:path";
20522
+ import path23 from "node:path";
19583
20523
  import * as nodeFs2 from "node:fs/promises";
19584
- import { readFile as readFile6 } from "node:fs/promises";
20524
+ import { readFile as readFile7 } from "node:fs/promises";
19585
20525
  var DEFAULT_INSTALL_AGENT = "claude-code";
19586
20526
  var DEFAULT_INSTALL_SCOPE = "local";
19587
20527
  var TERMINAL_PILOT_SKILL_NAME = "terminal-pilot";
@@ -19631,7 +20571,7 @@ async function loadTerminalPilotTemplate() {
19631
20571
  ];
19632
20572
  for (const candidate of candidates) {
19633
20573
  try {
19634
- terminalPilotTemplateCache = await readFile6(candidate, "utf8");
20574
+ terminalPilotTemplateCache = await readFile7(candidate, "utf8");
19635
20575
  return terminalPilotTemplateCache;
19636
20576
  } catch (error3) {
19637
20577
  if (!isNotFoundError2(error3)) {
@@ -19646,7 +20586,7 @@ function resolveHomeRelativePath(targetPath, homeDir) {
19646
20586
  return homeDir;
19647
20587
  }
19648
20588
  if (targetPath.startsWith("~/")) {
19649
- return path22.join(homeDir, targetPath.slice(2));
20589
+ return path23.join(homeDir, targetPath.slice(2));
19650
20590
  }
19651
20591
  return targetPath;
19652
20592
  }
@@ -19656,22 +20596,22 @@ function getSkillFolderWithHome(agent, scope, cwd, homeDir) {
19656
20596
  throwUnsupportedAgent(agent);
19657
20597
  }
19658
20598
  return {
19659
- displayPath: path22.join(
20599
+ displayPath: path23.join(
19660
20600
  scope === "global" ? config2.globalSkillDir : config2.localSkillDir,
19661
20601
  TERMINAL_PILOT_SKILL_NAME
19662
20602
  ),
19663
- fullPath: path22.join(
19664
- scope === "global" ? resolveHomeRelativePath(config2.globalSkillDir, homeDir) : path22.resolve(cwd, config2.localSkillDir),
20603
+ fullPath: path23.join(
20604
+ scope === "global" ? resolveHomeRelativePath(config2.globalSkillDir, homeDir) : path23.resolve(cwd, config2.localSkillDir),
19665
20605
  TERMINAL_PILOT_SKILL_NAME
19666
20606
  )
19667
20607
  };
19668
20608
  }
19669
- async function assertNoSymbolicLinkPath(fs4, targetPath) {
19670
- const rootPath = path22.parse(targetPath).root;
20609
+ async function assertNoSymbolicLinkPath(fs5, targetPath) {
20610
+ const rootPath = path23.parse(targetPath).root;
19671
20611
  let currentPath = targetPath;
19672
20612
  while (currentPath !== rootPath) {
19673
20613
  try {
19674
- if ((await fs4.lstat(currentPath)).isSymbolicLink()) {
20614
+ if ((await fs5.lstat(currentPath)).isSymbolicLink()) {
19675
20615
  throw new UserError(`Refusing terminal-pilot skill operation through symbolic link: ${currentPath}`);
19676
20616
  }
19677
20617
  } catch (error3) {
@@ -19679,7 +20619,7 @@ async function assertNoSymbolicLinkPath(fs4, targetPath) {
19679
20619
  throw error3;
19680
20620
  }
19681
20621
  }
19682
- currentPath = path22.dirname(currentPath);
20622
+ currentPath = path23.dirname(currentPath);
19683
20623
  }
19684
20624
  }
19685
20625
 
@@ -20378,11 +21318,11 @@ import { Resvg } from "@resvg/resvg-js";
20378
21318
 
20379
21319
  // ../terminal-png/src/font.ts
20380
21320
  import { readFileSync as readFileSync4 } from "node:fs";
20381
- import { createRequire as createRequire2 } from "node:module";
21321
+ import { createRequire as createRequire3 } from "node:module";
20382
21322
  import { dirname as dirname2, join as join2 } from "node:path";
20383
21323
  import { fileURLToPath as fileURLToPath4 } from "node:url";
20384
- var require2 = createRequire2(import.meta.url);
20385
- var fontPackageRoot = dirname2(require2.resolve("jetbrains-mono/package.json"));
21324
+ var require3 = createRequire3(import.meta.url);
21325
+ var fontPackageRoot = dirname2(require3.resolve("jetbrains-mono/package.json"));
20386
21326
  var webfontRoot = join2(fontPackageRoot, "fonts/webfonts");
20387
21327
  function readWebfontBase64(filename) {
20388
21328
  return readFileSync4(join2(webfontRoot, filename)).toString("base64");
@@ -21092,9 +22032,9 @@ var uninstall = defineCommand({
21092
22032
  };
21093
22033
  }
21094
22034
  });
21095
- async function folderExists(fs4, folderPath) {
22035
+ async function folderExists(fs5, folderPath) {
21096
22036
  try {
21097
- await fs4.stat(folderPath);
22037
+ await fs5.stat(folderPath);
21098
22038
  return true;
21099
22039
  } catch (error3) {
21100
22040
  if (hasOwnErrorCode4(error3, "ENOENT")) {
@@ -21239,7 +22179,7 @@ async function isDirectExecution(argv) {
21239
22179
  try {
21240
22180
  const modulePath = fileURLToPath5(import.meta.url);
21241
22181
  const [resolvedEntryPoint, resolvedModulePath] = await Promise.all([
21242
- realpath3(path23.resolve(entryPoint)),
22182
+ realpath3(path24.resolve(entryPoint)),
21243
22183
  realpath3(modulePath)
21244
22184
  ]);
21245
22185
  return resolvedEntryPoint === resolvedModulePath;