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
@@ -79,12 +79,12 @@ function consumeTerminatedString(input, index, allowBellTerminator) {
79
79
 
80
80
  // src/cli.ts
81
81
  import { realpath as realpath3 } from "node:fs/promises";
82
- import path23 from "node:path";
82
+ import path24 from "node:path";
83
83
  import { fileURLToPath as fileURLToPath5 } from "node:url";
84
84
 
85
85
  // ../toolcraft/src/cli.ts
86
- import { access as access2, lstat as lstat3, readFile as readFile4, rename as rename3, unlink as unlink3, writeFile as writeFile5 } from "node:fs/promises";
87
- import path14 from "node:path";
86
+ import { access as access2, lstat as lstat3, readFile as readFile5, rename as rename3, unlink as unlink3, writeFile as writeFile5 } from "node:fs/promises";
87
+ import path15 from "node:path";
88
88
  import {
89
89
  Command as CommanderCommand,
90
90
  CommanderError as CommanderError2,
@@ -450,7 +450,8 @@ function renderMarkdownCode(content) {
450
450
  currentRun = 0;
451
451
  }
452
452
  const delimiter = "`".repeat(longestRun + 1);
453
- return `${delimiter}${value}${delimiter}`;
453
+ const paddedValue = value.startsWith("`") || value.endsWith("`") ? ` ${value} ` : value;
454
+ return `${delimiter}${paddedValue}${delimiter}`;
454
455
  }
455
456
  function renderMarkdownLink(content) {
456
457
  const value = renderMarkdownInline(content);
@@ -605,7 +606,54 @@ var symbols = {
605
606
 
606
607
  // ../toolcraft-design/src/internal/strip-ansi.ts
607
608
  function stripAnsi2(value) {
608
- return value.replace(/\u001b\[[0-9;]*m/g, "");
609
+ let output = "";
610
+ let index = 0;
611
+ while (index < value.length) {
612
+ const char = value[index];
613
+ if (char === "\x1B") {
614
+ index = skipEscapeSequence(value, index);
615
+ continue;
616
+ }
617
+ if (char === "\x9B") {
618
+ index = skipCsiSequence(value, index + 1);
619
+ continue;
620
+ }
621
+ output += char;
622
+ index += char.length;
623
+ }
624
+ return output;
625
+ }
626
+ function skipEscapeSequence(value, index) {
627
+ const next = value[index + 1];
628
+ if (next === "[") {
629
+ return skipCsiSequence(value, index + 2);
630
+ }
631
+ if (next === "]") {
632
+ return skipOscSequence(value, index + 2);
633
+ }
634
+ return Math.min(value.length, index + 2);
635
+ }
636
+ function skipCsiSequence(value, index) {
637
+ while (index < value.length) {
638
+ const codePoint = value.charCodeAt(index);
639
+ index += 1;
640
+ if (codePoint >= 64 && codePoint <= 126) {
641
+ break;
642
+ }
643
+ }
644
+ return index;
645
+ }
646
+ function skipOscSequence(value, index) {
647
+ while (index < value.length) {
648
+ if (value[index] === "\x07") {
649
+ return index + 1;
650
+ }
651
+ if (value[index] === "\x1B" && value[index + 1] === "\\") {
652
+ return index + 2;
653
+ }
654
+ index += 1;
655
+ }
656
+ return index;
609
657
  }
610
658
 
611
659
  // ../toolcraft-design/src/prompts/primitives/log.ts
@@ -1394,38 +1442,14 @@ function renderTable(options) {
1394
1442
  }
1395
1443
 
1396
1444
  // ../toolcraft-design/src/components/detail-card.ts
1445
+ import stringWidth from "fast-string-width";
1446
+ import { wrapAnsi } from "fast-wrap-ansi";
1397
1447
  function wrap(value, width) {
1398
- const lines = [];
1399
- for (const paragraph of value.split("\n")) {
1400
- let line = "";
1401
- for (const rawWord of paragraph.split(" ")) {
1402
- const words = [];
1403
- let word = rawWord;
1404
- while (word.length > width) {
1405
- words.push(word.slice(0, width));
1406
- word = word.slice(width);
1407
- }
1408
- words.push(word);
1409
- for (const word2 of words) {
1410
- if (line.length === 0) {
1411
- line = word2;
1412
- continue;
1413
- }
1414
- if (`${line} ${word2}`.length <= width) {
1415
- line = `${line} ${word2}`;
1416
- continue;
1417
- }
1418
- lines.push(line);
1419
- line = word2;
1420
- }
1421
- }
1422
- lines.push(line);
1423
- }
1424
- return lines;
1448
+ return wrapAnsi(value, Math.max(1, width), { hard: true, trim: true }).split("\n");
1425
1449
  }
1426
1450
  function renderRows(rows, theme, width) {
1427
1451
  if (rows.length === 0) return [];
1428
- const labelWidth = Math.max(...rows.map((row) => row.label.length));
1452
+ const labelWidth = Math.max(...rows.map((row) => stringWidth(row.label)));
1429
1453
  const valueWidth = Math.max(20, width - labelWidth - 2);
1430
1454
  const continuation = " ".repeat(labelWidth + 2);
1431
1455
  return rows.flatMap((row) => {
@@ -1446,12 +1470,16 @@ function renderDetailCard(options) {
1446
1470
  ${options.theme.muted(options.badges.map((badge) => badge[0] + badge.slice(1).toLowerCase()).join(" \xB7 "))}` : identity;
1447
1471
  const blocks = [hero];
1448
1472
  for (const prose of options.prose ?? []) {
1449
- blocks.push(prose.title ? [options.theme.header(prose.title), wrap(prose.value, width).join("\n")].join("\n") : wrap(prose.value, width).join("\n"));
1473
+ blocks.push(
1474
+ prose.title ? [options.theme.header(prose.title), wrap(prose.value, width).join("\n")].join("\n") : wrap(prose.value, width).join("\n")
1475
+ );
1450
1476
  }
1451
1477
  for (const section of options.sections ?? []) {
1452
1478
  if (section.rows.length === 0) continue;
1453
1479
  const rows = renderRows(section.rows, options.theme, width);
1454
- blocks.push(section.title ? [options.theme.header(section.title), ...rows].join("\n") : rows.join("\n"));
1480
+ blocks.push(
1481
+ section.title ? [options.theme.header(section.title), ...rows].join("\n") : rows.join("\n")
1482
+ );
1455
1483
  }
1456
1484
  return blocks.join("\n\n");
1457
1485
  }
@@ -1878,13 +1906,13 @@ import { LineCounter, parse, parseDocument } from "yaml";
1878
1906
  // ../frontmatter/src/stringify.ts
1879
1907
  import { stringify } from "yaml";
1880
1908
 
1909
+ // ../toolcraft-design/src/dashboard/terminal-width.ts
1910
+ var graphemeSegmenter3 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
1911
+
1881
1912
  // ../toolcraft-design/src/acp/writer.ts
1882
1913
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
1883
1914
  var storage = new AsyncLocalStorage2();
1884
1915
 
1885
- // ../toolcraft-design/src/dashboard/terminal-width.ts
1886
- var graphemeSegmenter3 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
1887
-
1888
1916
  // ../toolcraft-design/src/dashboard/terminal.ts
1889
1917
  import readline from "node:readline";
1890
1918
  import { PassThrough } from "node:stream";
@@ -1981,8 +2009,8 @@ function mapKey(name, char) {
1981
2009
  }
1982
2010
 
1983
2011
  // ../toolcraft-design/src/prompts/interactive/wrap.ts
1984
- import { wrapAnsi } from "fast-wrap-ansi";
1985
- import stringWidth from "fast-string-width";
2012
+ import { wrapAnsi as wrapAnsi2 } from "fast-wrap-ansi";
2013
+ import stringWidth2 from "fast-string-width";
1986
2014
  function getColumns(output) {
1987
2015
  return Math.max(1, output.columns ?? 80);
1988
2016
  }
@@ -1990,7 +2018,7 @@ function getRows(output) {
1990
2018
  return Math.max(1, output.rows ?? 20);
1991
2019
  }
1992
2020
  function wrapFrame(output, frame) {
1993
- return wrapAnsi(frame, getColumns(output), { hard: true, trim: false });
2021
+ return wrapAnsi2(frame, getColumns(output), { hard: true, trim: false });
1994
2022
  }
1995
2023
 
1996
2024
  // ../toolcraft-design/src/prompts/interactive/core.ts
@@ -2311,7 +2339,7 @@ function confirmPrompt(opts) {
2311
2339
  }
2312
2340
 
2313
2341
  // ../toolcraft-design/src/prompts/interactive/pagination.ts
2314
- import { wrapAnsi as wrapAnsi2 } from "fast-wrap-ansi";
2342
+ import { wrapAnsi as wrapAnsi3 } from "fast-wrap-ansi";
2315
2343
  function countLines(values) {
2316
2344
  return values.reduce((sum, value) => sum + value.split("\n").length, 0);
2317
2345
  }
@@ -2354,7 +2382,7 @@ function limitOptions(opts) {
2354
2382
  }
2355
2383
  const hasTopMarker = cappedVisibleCount < options.length && start > 0;
2356
2384
  const hasBottomMarker = cappedVisibleCount < options.length && start + cappedVisibleCount < options.length;
2357
- const visible = options.slice(start, start + cappedVisibleCount).map((option, index) => wrapAnsi2(style(option, start + index === cursor2), columns, { hard: true, trim: false }));
2385
+ const visible = options.slice(start, start + cappedVisibleCount).map((option, index) => wrapAnsi3(style(option, start + index === cursor2), columns, { hard: true, trim: false }));
2358
2386
  const trimmed = trimToRows(
2359
2387
  visible,
2360
2388
  Math.max(cursor2 - start, 0),
@@ -2737,6 +2765,9 @@ function isOptionalSchema(schema) {
2737
2765
  function getRequiredKeys(schema) {
2738
2766
  return Object.keys(schema.shape).filter((key2) => !isOptionalSchema(schema.shape[key2])).sort();
2739
2767
  }
2768
+ function getRequiredKeyFingerprint(schema) {
2769
+ return getRequiredKeys(schema).join("+");
2770
+ }
2740
2771
  function assertUniqueRequiredKeyFingerprints(branches) {
2741
2772
  const fingerprints = /* @__PURE__ */ new Map();
2742
2773
  branches.forEach((branch, index) => {
@@ -2774,6 +2805,451 @@ function Union(branches) {
2774
2805
  };
2775
2806
  }
2776
2807
 
2808
+ // ../toolcraft-schema/src/validate.ts
2809
+ var missingValue = /* @__PURE__ */ Symbol("missingValue");
2810
+ function validate(schema, value) {
2811
+ const state = { issues: [] };
2812
+ const result = walkSchema(schema, value, [], state);
2813
+ if (state.issues.length > 0) {
2814
+ return { ok: false, issues: state.issues };
2815
+ }
2816
+ return { ok: true, value: result.present ? result.value : void 0 };
2817
+ }
2818
+ function walkSchema(schema, value, path25, state) {
2819
+ if (schema.kind === "optional") {
2820
+ return walkOptional(schema, value, path25, state);
2821
+ }
2822
+ if (value === missingValue) {
2823
+ addIssue(
2824
+ state,
2825
+ path25,
2826
+ expectedFor(schema),
2827
+ "missing",
2828
+ `Expected ${expectedFor(schema)} at ${formatPath(path25)}`
2829
+ );
2830
+ return { present: false };
2831
+ }
2832
+ if (value === null && schema.nullable === true) {
2833
+ return { present: true, value };
2834
+ }
2835
+ switch (schema.kind) {
2836
+ case "string":
2837
+ return walkString(schema, value, path25, state);
2838
+ case "number":
2839
+ return walkNumber(schema, value, path25, state);
2840
+ case "boolean":
2841
+ return walkBoolean(value, path25, state);
2842
+ case "enum":
2843
+ return walkEnum(schema, value, path25, state);
2844
+ case "array":
2845
+ return walkArray(schema, value, path25, state);
2846
+ case "object":
2847
+ return walkObject(schema, value, path25, state);
2848
+ case "oneOf":
2849
+ return walkOneOf(schema, value, path25, state);
2850
+ case "union":
2851
+ return walkUnion(schema, value, path25, state);
2852
+ case "record":
2853
+ return walkRecord(schema, value, path25, state);
2854
+ case "json":
2855
+ return walkJson(value, path25, state);
2856
+ }
2857
+ }
2858
+ function walkOptional(schema, value, path25, state) {
2859
+ if (value === missingValue || value === void 0) {
2860
+ const defaultValue = getDefault(schema.inner);
2861
+ if (defaultValue.present) {
2862
+ return walkSchema(schema.inner, cloneDefault(defaultValue.value), path25, state);
2863
+ }
2864
+ return { present: false };
2865
+ }
2866
+ return walkSchema(schema.inner, value, path25, state);
2867
+ }
2868
+ function walkString(schema, value, path25, state) {
2869
+ if (typeof value !== "string") {
2870
+ addExpectedIssue(state, path25, "string", value);
2871
+ return { present: true, value };
2872
+ }
2873
+ if (schema.minLength !== void 0 && value.length < schema.minLength) {
2874
+ const expected = `string with length at least ${schema.minLength}`;
2875
+ addIssue(
2876
+ state,
2877
+ path25,
2878
+ expected,
2879
+ `string with length ${value.length}`,
2880
+ `Expected ${expected} at ${formatPath(path25)}`
2881
+ );
2882
+ }
2883
+ if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
2884
+ const expected = `string with length at most ${schema.maxLength}`;
2885
+ addIssue(
2886
+ state,
2887
+ path25,
2888
+ expected,
2889
+ `string with length ${value.length}`,
2890
+ `Expected ${expected} at ${formatPath(path25)}`
2891
+ );
2892
+ }
2893
+ if (schema.pattern !== void 0) {
2894
+ const pattern = compilePattern(schema.pattern);
2895
+ if (pattern === void 0 || !pattern.test(value)) {
2896
+ const expected = `string matching pattern ${schema.pattern}`;
2897
+ addIssue(state, path25, expected, value, `Expected ${expected} at ${formatPath(path25)}`);
2898
+ }
2899
+ }
2900
+ return { present: true, value };
2901
+ }
2902
+ function walkNumber(schema, value, path25, state) {
2903
+ if (typeof value !== "number" || !Number.isFinite(value)) {
2904
+ addExpectedIssue(state, path25, schema.jsonType === "integer" ? "integer" : "number", value);
2905
+ return { present: true, value };
2906
+ }
2907
+ if (schema.jsonType === "integer" && !Number.isInteger(value)) {
2908
+ addExpectedIssue(state, path25, "integer", value);
2909
+ }
2910
+ if (schema.minimum !== void 0 && value < schema.minimum) {
2911
+ const expected = `number greater than or equal to ${schema.minimum}`;
2912
+ addIssue(state, path25, expected, String(value), `Expected ${expected} at ${formatPath(path25)}`);
2913
+ }
2914
+ if (schema.maximum !== void 0 && value > schema.maximum) {
2915
+ const expected = `number less than or equal to ${schema.maximum}`;
2916
+ addIssue(state, path25, expected, String(value), `Expected ${expected} at ${formatPath(path25)}`);
2917
+ }
2918
+ return { present: true, value };
2919
+ }
2920
+ function walkBoolean(value, path25, state) {
2921
+ if (typeof value !== "boolean") {
2922
+ addExpectedIssue(state, path25, "boolean", value);
2923
+ }
2924
+ return { present: true, value };
2925
+ }
2926
+ function walkEnum(schema, value, path25, state) {
2927
+ if (!schema.values.includes(value)) {
2928
+ const expected = `one of ${schema.values.join(", ")}`;
2929
+ addIssue(
2930
+ state,
2931
+ path25,
2932
+ expected,
2933
+ receivedValue(value),
2934
+ `Expected ${expected} at ${formatPath(path25)}`
2935
+ );
2936
+ }
2937
+ return { present: true, value };
2938
+ }
2939
+ function walkArray(schema, value, path25, state) {
2940
+ if (!Array.isArray(value)) {
2941
+ addExpectedIssue(state, path25, "array", value);
2942
+ return { present: true, value };
2943
+ }
2944
+ if (schema.minItems !== void 0 && value.length < schema.minItems) {
2945
+ const expected = `array with at least ${schema.minItems} items`;
2946
+ addIssue(
2947
+ state,
2948
+ path25,
2949
+ expected,
2950
+ `array with ${value.length} items`,
2951
+ `Expected ${expected} at ${formatPath(path25)}`
2952
+ );
2953
+ }
2954
+ if (schema.maxItems !== void 0 && value.length > schema.maxItems) {
2955
+ const expected = `array with at most ${schema.maxItems} items`;
2956
+ addIssue(
2957
+ state,
2958
+ path25,
2959
+ expected,
2960
+ `array with ${value.length} items`,
2961
+ `Expected ${expected} at ${formatPath(path25)}`
2962
+ );
2963
+ }
2964
+ const nextValue = value.map((item, index) => {
2965
+ const result = walkSchema(schema.item, item, [...path25, String(index)], state);
2966
+ return result.present ? result.value : item;
2967
+ });
2968
+ return { present: true, value: nextValue };
2969
+ }
2970
+ function walkObject(schema, value, path25, state, injectedProperties = {}) {
2971
+ if (!isPlainRecord(value)) {
2972
+ addExpectedIssue(state, path25, "object", value);
2973
+ return { present: true, value };
2974
+ }
2975
+ const nextValue = {};
2976
+ const allowedKeys = /* @__PURE__ */ new Set([...Object.keys(schema.shape), ...Object.keys(injectedProperties)]);
2977
+ for (const [key2, propertySchema] of Object.entries(schema.shape)) {
2978
+ const propertyValue = Object.hasOwn(value, key2) ? value[key2] : missingValue;
2979
+ const result = walkSchema(propertySchema, propertyValue, [...path25, key2], state);
2980
+ if (result.present) {
2981
+ setOwnValue(nextValue, key2, result.value);
2982
+ }
2983
+ }
2984
+ for (const [key2, injectedValue] of Object.entries(injectedProperties)) {
2985
+ if (Object.hasOwn(value, key2)) {
2986
+ setOwnValue(nextValue, key2, value[key2]);
2987
+ } else {
2988
+ setOwnValue(nextValue, key2, injectedValue);
2989
+ }
2990
+ }
2991
+ for (const [key2, propertyValue] of Object.entries(value)) {
2992
+ if (allowedKeys.has(key2)) {
2993
+ continue;
2994
+ }
2995
+ if (schema.additionalProperties === true) {
2996
+ setOwnValue(nextValue, key2, propertyValue);
2997
+ } else {
2998
+ addUnexpectedPropertyIssue(state, [...path25, key2]);
2999
+ }
3000
+ }
3001
+ return { present: true, value: nextValue };
3002
+ }
3003
+ function walkOneOf(schema, value, path25, state) {
3004
+ if (!isPlainRecord(value)) {
3005
+ addExpectedIssue(state, path25, "object", value);
3006
+ return { present: true, value };
3007
+ }
3008
+ const discriminatorValue = value[schema.discriminator];
3009
+ const discriminatorPath = [...path25, schema.discriminator];
3010
+ const branchValues = Object.keys(schema.branches);
3011
+ const expected = `one of ${branchValues.join(", ")}`;
3012
+ if (!Object.hasOwn(value, schema.discriminator)) {
3013
+ addIssueWithMessage(
3014
+ state,
3015
+ discriminatorPath,
3016
+ expected,
3017
+ "missing",
3018
+ `Missing discriminator "${schema.discriminator}" at ${formatPath(path25)}. Expected one of: ${branchValues.join(", ")}.`
3019
+ );
3020
+ return { present: true, value };
3021
+ }
3022
+ if (typeof discriminatorValue !== "string" || !Object.hasOwn(schema.branches, discriminatorValue)) {
3023
+ addIssueWithMessage(
3024
+ state,
3025
+ discriminatorPath,
3026
+ expected,
3027
+ receivedValue(discriminatorValue),
3028
+ `Expected ${expected} at ${formatPath(discriminatorPath)}, got ${formatReceivedDiscriminator(discriminatorValue)}`
3029
+ );
3030
+ return { present: true, value };
3031
+ }
3032
+ return walkObject(schema.branches[discriminatorValue], value, path25, state, {
3033
+ [schema.discriminator]: discriminatorValue
3034
+ });
3035
+ }
3036
+ function walkUnion(schema, value, path25, state) {
3037
+ if (isPlainRecord(value)) {
3038
+ const candidateBranches = schema.branches.filter((branch) => hasRequiredKeys(branch, value));
3039
+ if (candidateBranches.length === 1) {
3040
+ return walkObject(candidateBranches[0], value, path25, state);
3041
+ }
3042
+ }
3043
+ const matches = [];
3044
+ for (const branch of schema.branches) {
3045
+ const branchState = { issues: [] };
3046
+ const result = walkObject(branch, value, path25, branchState);
3047
+ if (branchState.issues.length === 0 && result.present) {
3048
+ matches.push({ fingerprint: getRequiredKeyFingerprint(branch), value: result.value });
3049
+ }
3050
+ }
3051
+ if (matches.length === 1) {
3052
+ return { present: true, value: matches[0].value };
3053
+ }
3054
+ if (matches.length === 0) {
3055
+ const branchDescriptions = schema.branches.map((branch) => getRequiredKeyFingerprint(branch));
3056
+ addIssueWithMessage(
3057
+ state,
3058
+ path25,
3059
+ "exactly one union branch",
3060
+ "0 matching branches",
3061
+ `No union branch matched at ${formatPath(path25)}. Tried ${schema.branches.length} branches. Expected one of: ${branchDescriptions.join(" | ")}.`
3062
+ );
3063
+ return { present: true, value };
3064
+ }
3065
+ addIssueWithMessage(
3066
+ state,
3067
+ path25,
3068
+ "exactly one union branch",
3069
+ `${matches.length} matching branches`,
3070
+ `Expected exactly one union branch at ${formatPath(path25)}, but matched more than one branch: ${matches.map((match) => match.fingerprint).join(" | ")}`
3071
+ );
3072
+ return { present: true, value };
3073
+ }
3074
+ function hasRequiredKeys(schema, value) {
3075
+ for (const [key2, propertySchema] of Object.entries(schema.shape)) {
3076
+ if (propertySchema.kind !== "optional" && !Object.hasOwn(value, key2)) {
3077
+ return false;
3078
+ }
3079
+ }
3080
+ return true;
3081
+ }
3082
+ function walkRecord(schema, value, path25, state) {
3083
+ if (!isPlainRecord(value)) {
3084
+ addExpectedIssue(state, path25, "object", value);
3085
+ return { present: true, value };
3086
+ }
3087
+ const nextValue = {};
3088
+ for (const [key2, propertyValue] of Object.entries(value)) {
3089
+ const result = walkSchema(schema.value, propertyValue, [...path25, key2], state);
3090
+ if (result.present) {
3091
+ setOwnValue(nextValue, key2, result.value);
3092
+ }
3093
+ }
3094
+ return { present: true, value: nextValue };
3095
+ }
3096
+ function walkJson(value, path25, state) {
3097
+ if (isJsonValue(value)) {
3098
+ return { present: true, value };
3099
+ }
3100
+ addExpectedIssue(state, path25, "JSON value", value);
3101
+ return { present: true, value };
3102
+ }
3103
+ function getDefault(schema) {
3104
+ if (schema.default !== void 0) {
3105
+ return { present: true, value: schema.default };
3106
+ }
3107
+ if (schema.kind === "optional") {
3108
+ return getDefault(schema.inner);
3109
+ }
3110
+ return { present: false };
3111
+ }
3112
+ function isPlainRecord(value) {
3113
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
3114
+ return false;
3115
+ }
3116
+ const prototype = Object.getPrototypeOf(value);
3117
+ return prototype === Object.prototype || prototype === null;
3118
+ }
3119
+ function isJsonValue(value, ancestors = /* @__PURE__ */ new Set()) {
3120
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
3121
+ return typeof value !== "number" || Number.isFinite(value);
3122
+ }
3123
+ if (Array.isArray(value)) {
3124
+ if (ancestors.has(value)) {
3125
+ return false;
3126
+ }
3127
+ ancestors.add(value);
3128
+ const result = value.every((item) => isJsonValue(item, ancestors));
3129
+ ancestors.delete(value);
3130
+ return result;
3131
+ }
3132
+ if (isPlainRecord(value)) {
3133
+ if (ancestors.has(value)) {
3134
+ return false;
3135
+ }
3136
+ ancestors.add(value);
3137
+ const result = Object.values(value).every((item) => isJsonValue(item, ancestors));
3138
+ ancestors.delete(value);
3139
+ return result;
3140
+ }
3141
+ return false;
3142
+ }
3143
+ function cloneDefault(value) {
3144
+ return structuredClone(value);
3145
+ }
3146
+ function setOwnValue(target, key2, value) {
3147
+ Object.defineProperty(target, key2, {
3148
+ configurable: true,
3149
+ enumerable: true,
3150
+ writable: true,
3151
+ value
3152
+ });
3153
+ }
3154
+ function expectedFor(schema) {
3155
+ switch (schema.kind) {
3156
+ case "string":
3157
+ return "string";
3158
+ case "number":
3159
+ return schema.jsonType === "integer" ? "integer" : "number";
3160
+ case "boolean":
3161
+ return "boolean";
3162
+ case "enum":
3163
+ return `one of ${schema.values.join(", ")}`;
3164
+ case "array":
3165
+ return "array";
3166
+ case "object":
3167
+ case "oneOf":
3168
+ case "record":
3169
+ return "object";
3170
+ case "union":
3171
+ return "exactly one union branch";
3172
+ case "json":
3173
+ return "JSON value";
3174
+ case "optional":
3175
+ return expectedFor(schema.inner);
3176
+ }
3177
+ }
3178
+ function addExpectedIssue(state, path25, expected, value) {
3179
+ addIssue(
3180
+ state,
3181
+ path25,
3182
+ expected,
3183
+ receivedType(value),
3184
+ `Expected ${expected} at ${formatPath(path25)}`
3185
+ );
3186
+ }
3187
+ function addUnexpectedPropertyIssue(state, path25) {
3188
+ addIssue(
3189
+ state,
3190
+ path25,
3191
+ "no additional properties",
3192
+ "unknown property",
3193
+ `Unexpected property ${formatPath(path25)}`
3194
+ );
3195
+ }
3196
+ function addIssue(state, path25, expected, received, _message) {
3197
+ state.issues.push({
3198
+ path: path25,
3199
+ expected,
3200
+ received,
3201
+ message: formatIssueMessage(expected, path25, received)
3202
+ });
3203
+ }
3204
+ function addIssueWithMessage(state, path25, expected, received, message2) {
3205
+ state.issues.push({
3206
+ path: path25,
3207
+ expected,
3208
+ received,
3209
+ message: message2
3210
+ });
3211
+ }
3212
+ function formatIssueMessage(expected, path25, received) {
3213
+ return `Expected ${expected} at ${formatPath(path25)}, got ${received}`;
3214
+ }
3215
+ function formatPath(path25) {
3216
+ return path25.length === 0 ? "value" : path25.join(".");
3217
+ }
3218
+ function compilePattern(pattern) {
3219
+ try {
3220
+ return new RegExp(pattern);
3221
+ } catch {
3222
+ return void 0;
3223
+ }
3224
+ }
3225
+ function receivedType(value) {
3226
+ if (value === null) {
3227
+ return "null";
3228
+ }
3229
+ if (Array.isArray(value)) {
3230
+ return "array";
3231
+ }
3232
+ if (typeof value === "number" && Number.isInteger(value)) {
3233
+ return "integer";
3234
+ }
3235
+ return typeof value;
3236
+ }
3237
+ function receivedValue(value) {
3238
+ if (typeof value === "string") {
3239
+ return value;
3240
+ }
3241
+ if (value === void 0) {
3242
+ return "undefined";
3243
+ }
3244
+ return String(value);
3245
+ }
3246
+ function formatReceivedDiscriminator(value) {
3247
+ if (typeof value === "string") {
3248
+ return JSON.stringify(value);
3249
+ }
3250
+ return receivedValue(value);
3251
+ }
3252
+
2777
3253
  // ../toolcraft-schema/src/index.ts
2778
3254
  function assertValidEnumValues(values) {
2779
3255
  if (values.length === 0) {
@@ -2797,6 +3273,22 @@ function assertFiniteNumber(value, name) {
2797
3273
  throw new Error(`${name} must be finite`);
2798
3274
  }
2799
3275
  }
3276
+ function assertMinMaxOrder(minimum, maximum, minimumName, maximumName) {
3277
+ if (minimum !== void 0 && maximum !== void 0 && minimum > maximum) {
3278
+ throw new Error(`${minimumName} must be less than or equal to ${maximumName}`);
3279
+ }
3280
+ }
3281
+ function assertValidDefault(schema) {
3282
+ if (schema.default === void 0) {
3283
+ return;
3284
+ }
3285
+ const result = validate(schema, schema.default);
3286
+ if (!result.ok) {
3287
+ throw new Error(
3288
+ `default must satisfy schema: ${result.issues[0]?.message ?? "invalid default"}`
3289
+ );
3290
+ }
3291
+ }
2800
3292
  function assertPattern(pattern) {
2801
3293
  if (pattern === void 0) {
2802
3294
  return;
@@ -2811,56 +3303,71 @@ var S = {
2811
3303
  String(options = {}) {
2812
3304
  assertNonNegativeInteger(options.minLength, "minLength");
2813
3305
  assertNonNegativeInteger(options.maxLength, "maxLength");
3306
+ assertMinMaxOrder(options.minLength, options.maxLength, "minLength", "maxLength");
2814
3307
  assertPattern(options.pattern);
2815
- return {
3308
+ const schema = {
2816
3309
  kind: "string",
2817
3310
  ...options
2818
3311
  };
3312
+ assertValidDefault(schema);
3313
+ return schema;
2819
3314
  },
2820
3315
  Number(options = {}) {
2821
3316
  assertFiniteNumber(options.minimum, "minimum");
2822
3317
  assertFiniteNumber(options.maximum, "maximum");
3318
+ assertMinMaxOrder(options.minimum, options.maximum, "minimum", "maximum");
2823
3319
  assertFiniteNumber(options.default, "default");
2824
3320
  if (options.jsonType === "integer" && options.default !== void 0 && !Number.isInteger(options.default)) {
2825
3321
  throw new Error("default must be an integer");
2826
3322
  }
2827
- return {
3323
+ const schema = {
2828
3324
  kind: "number",
2829
3325
  ...options
2830
3326
  };
3327
+ assertValidDefault(schema);
3328
+ return schema;
2831
3329
  },
2832
3330
  Boolean(options = {}) {
2833
- return {
3331
+ const schema = {
2834
3332
  kind: "boolean",
2835
3333
  ...options
2836
3334
  };
3335
+ assertValidDefault(schema);
3336
+ return schema;
2837
3337
  },
2838
3338
  Enum(values, options = {}) {
2839
3339
  assertValidEnumValues(values);
2840
3340
  if (options.jsonType === "integer" && values.some((value) => typeof value !== "number" || !Number.isInteger(value))) {
2841
3341
  throw new Error("Integer enum values must be integers");
2842
3342
  }
2843
- return {
3343
+ const schema = {
2844
3344
  kind: "enum",
2845
3345
  values,
2846
3346
  ...options
2847
3347
  };
3348
+ assertValidDefault(schema);
3349
+ return schema;
2848
3350
  },
2849
3351
  Array(item, options = {}) {
2850
3352
  assertNonNegativeInteger(options.minItems, "minItems");
2851
3353
  assertNonNegativeInteger(options.maxItems, "maxItems");
2852
- return {
3354
+ assertMinMaxOrder(options.minItems, options.maxItems, "minItems", "maxItems");
3355
+ const schema = {
2853
3356
  kind: "array",
2854
3357
  item,
2855
3358
  ...options
2856
3359
  };
3360
+ assertValidDefault(schema);
3361
+ return schema;
2857
3362
  },
2858
3363
  Object(shape, options = {}) {
2859
- return {
3364
+ const schema = {
2860
3365
  kind: "object",
2861
3366
  shape,
2862
3367
  ...options
2863
3368
  };
3369
+ assertValidDefault(schema);
3370
+ return schema;
2864
3371
  },
2865
3372
  Optional(inner) {
2866
3373
  return {
@@ -3432,6 +3939,9 @@ function isRecord(value) {
3432
3939
  function isStateList(value) {
3433
3940
  return Array.isArray(value) && value.every((entry) => typeof entry === "string");
3434
3941
  }
3942
+ function hasVisibleName(value) {
3943
+ return value.trim().length > 0;
3944
+ }
3435
3945
  function canFireFromState(event, fromState) {
3436
3946
  if (event.from === "*") {
3437
3947
  return event.to !== fromState;
@@ -3446,6 +3956,9 @@ function validateMachine(machine) {
3446
3956
  throw new TypeError("State machine states must be a string array.");
3447
3957
  }
3448
3958
  const states = new Set(machine.states);
3959
+ if (machine.states.some((state) => !hasVisibleName(state))) {
3960
+ throw new Error("State names must not be empty.");
3961
+ }
3449
3962
  if (!hasOwnRecordField(machine, "initial") || typeof machine.initial !== "string") {
3450
3963
  throw new TypeError("State machine initial must be a string.");
3451
3964
  }
@@ -3456,6 +3969,9 @@ function validateMachine(machine) {
3456
3969
  throw new TypeError("State machine events must be an object.");
3457
3970
  }
3458
3971
  for (const [eventName, event] of Object.entries(machine.events)) {
3972
+ if (!hasVisibleName(eventName)) {
3973
+ throw new Error("Event names must not be empty.");
3974
+ }
3459
3975
  if (!isRecord(event)) {
3460
3976
  throw new TypeError(`Event "${eventName}" must be an object.`);
3461
3977
  }
@@ -3565,6 +4081,13 @@ import { text as text3 } from "node:stream/consumers";
3565
4081
  // ../process-runner/src/docker/context.ts
3566
4082
  import { execSync } from "node:child_process";
3567
4083
 
4084
+ // ../process-runner/src/docker/build-context.ts
4085
+ import { readdir, readFile } from "node:fs/promises";
4086
+ import { createRequire } from "node:module";
4087
+ import path2 from "node:path";
4088
+ var require2 = createRequire(import.meta.url);
4089
+ var createIgnore = require2("ignore");
4090
+
3568
4091
  // ../process-runner/src/docker/engine.ts
3569
4092
  import { execSync as execSync2 } from "node:child_process";
3570
4093
 
@@ -3573,19 +4096,19 @@ import * as childProcess from "node:child_process";
3573
4096
  import { randomBytes } from "node:crypto";
3574
4097
 
3575
4098
  // ../process-runner/src/docker/args.ts
3576
- import path2 from "node:path";
4099
+ import path3 from "node:path";
3577
4100
 
3578
4101
  // ../process-runner/src/docker/env-file.ts
3579
4102
  import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3580
4103
  import { tmpdir } from "node:os";
3581
- import path3 from "node:path";
4104
+ import path4 from "node:path";
3582
4105
 
3583
4106
  // ../process-runner/src/docker/docker-execution-env.ts
3584
4107
  import { createHash as createHash2, randomBytes as randomBytes2 } from "node:crypto";
3585
4108
  import { mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "node:fs";
3586
- import { readdir, readFile, realpath, writeFile } from "node:fs/promises";
4109
+ import { readFile as readFile2, realpath, writeFile } from "node:fs/promises";
3587
4110
  import { tmpdir as tmpdir2 } from "node:os";
3588
- import path5 from "node:path";
4111
+ import path6 from "node:path";
3589
4112
 
3590
4113
  // ../process-runner/src/host/host-runner.ts
3591
4114
  import { spawn as spawnChildProcess } from "node:child_process";
@@ -3718,7 +4241,7 @@ function bindAbortSignal(signal, onAbort) {
3718
4241
  // ../process-runner/src/workspace-transfer.ts
3719
4242
  import { createHash, randomUUID } from "node:crypto";
3720
4243
  import { promises as nodeFs } from "node:fs";
3721
- import path4 from "node:path";
4244
+ import path5 from "node:path";
3722
4245
 
3723
4246
  // ../process-runner/src/testing/mock-runner.ts
3724
4247
  import { Readable, Writable } from "node:stream";
@@ -3790,7 +4313,7 @@ function resolveEndpoint(options = {}) {
3790
4313
 
3791
4314
  // ../task-list/src/backends/utils.ts
3792
4315
  import { randomUUID as randomUUID2 } from "node:crypto";
3793
- import path6 from "node:path";
4316
+ import path7 from "node:path";
3794
4317
  function compareCreated(left, right) {
3795
4318
  const leftCreated = typeof left.raw.created === "string" ? left.raw.created : "";
3796
4319
  const rightCreated = typeof right.raw.created === "string" ? right.raw.created : "";
@@ -3822,15 +4345,33 @@ function sortStrings(values) {
3822
4345
  function sortTasks(tasks) {
3823
4346
  return [...tasks].sort((left, right) => left.qualifiedId.localeCompare(right.qualifiedId));
3824
4347
  }
4348
+ function isTrimmedPrintableIdentifier(value) {
4349
+ if (value.length === 0 || value !== value.trim()) {
4350
+ return false;
4351
+ }
4352
+ for (let index = 0; index < value.length; index += 1) {
4353
+ const code = value.charCodeAt(index);
4354
+ if (code < 32 || code === 127) {
4355
+ return false;
4356
+ }
4357
+ }
4358
+ return true;
4359
+ }
3825
4360
  function validateTaskId(id) {
3826
- if (id.length === 0 || id.startsWith(".") || id.includes("/") || id.includes("\\") || id.includes("..")) {
4361
+ if (!isTrimmedPrintableIdentifier(id) || id.startsWith(".") || id.includes("/") || id.includes("\\") || id.includes("..")) {
3827
4362
  throw new Error(`Invalid task id "${id}".`);
3828
4363
  }
3829
4364
  return id;
3830
4365
  }
3831
- async function statIfExists(fs4, filePath) {
4366
+ function validateTaskName(name) {
4367
+ if (name.trim().length === 0) {
4368
+ throw new Error("Task name must not be empty.");
4369
+ }
4370
+ return name;
4371
+ }
4372
+ async function statIfExists(fs5, filePath) {
3832
4373
  try {
3833
- return await fs4.stat(filePath);
4374
+ return await fs5.stat(filePath);
3834
4375
  } catch (error3) {
3835
4376
  if (hasErrorCode(error3, "ENOENT")) {
3836
4377
  return void 0;
@@ -3838,15 +4379,18 @@ async function statIfExists(fs4, filePath) {
3838
4379
  throw error3;
3839
4380
  }
3840
4381
  }
3841
- async function rejectSymbolicLinkComponents(fs4, filePath) {
3842
- const resolvedPath = path6.resolve(filePath);
3843
- const rootPath = path6.parse(resolvedPath).root;
3844
- const components = resolvedPath.slice(rootPath.length).split(path6.sep).filter(Boolean);
4382
+ async function rejectSymbolicLinkComponents(fs5, filePath) {
4383
+ const resolvedPath = path7.resolve(filePath);
4384
+ const rootPath = path7.parse(resolvedPath).root;
4385
+ const components = resolvedPath.slice(rootPath.length).split(path7.sep).filter(Boolean);
3845
4386
  let currentPath = rootPath;
3846
4387
  for (const component of components) {
3847
- currentPath = path6.join(currentPath, component);
4388
+ currentPath = path7.join(currentPath, component);
3848
4389
  try {
3849
- if ((await fs4.lstat(currentPath)).isSymbolicLink()) {
4390
+ if ((await fs5.lstat(currentPath)).isSymbolicLink()) {
4391
+ if (currentPath === "/tmp") {
4392
+ continue;
4393
+ }
3850
4394
  throw new Error(`Path "${filePath}" contains a symbolic link.`);
3851
4395
  }
3852
4396
  } catch (error3) {
@@ -3857,19 +4401,19 @@ async function rejectSymbolicLinkComponents(fs4, filePath) {
3857
4401
  }
3858
4402
  }
3859
4403
  }
3860
- async function writeAtomically(fs4, filePath, content) {
4404
+ async function writeAtomically(fs5, filePath, content) {
3861
4405
  const tempPath = `${filePath}.${process.pid}.${randomUUID2()}.tmp`;
3862
4406
  let tempCreated = false;
3863
- await fs4.mkdir(path6.dirname(filePath), { recursive: true });
4407
+ await fs5.mkdir(path7.dirname(filePath), { recursive: true });
3864
4408
  try {
3865
- await fs4.writeFile(tempPath, content, { encoding: "utf8", flag: "wx" });
4409
+ await fs5.writeFile(tempPath, content, { encoding: "utf8", flag: "wx" });
3866
4410
  tempCreated = true;
3867
- await fs4.rename(tempPath, filePath);
4411
+ await fs5.rename(tempPath, filePath);
3868
4412
  tempCreated = false;
3869
4413
  } catch (error3) {
3870
4414
  if (tempCreated || !hasErrorCode(error3, "EEXIST")) {
3871
4415
  try {
3872
- await fs4.unlink(tempPath);
4416
+ await fs5.unlink(tempPath);
3873
4417
  } catch (unlinkError) {
3874
4418
  if (!hasErrorCode(unlinkError, "ENOENT")) {
3875
4419
  throw unlinkError;
@@ -3879,18 +4423,18 @@ async function writeAtomically(fs4, filePath, content) {
3879
4423
  throw error3;
3880
4424
  }
3881
4425
  }
3882
- async function withFileLock(fs4, lockPath, operation) {
3883
- await fs4.mkdir(path6.dirname(lockPath), { recursive: true });
4426
+ async function withFileLock(fs5, lockPath, operation) {
4427
+ await fs5.mkdir(path7.dirname(lockPath), { recursive: true });
3884
4428
  for (; ; ) {
3885
4429
  try {
3886
- await fs4.writeFile(lockPath, String(process.pid), { encoding: "utf8", flag: "wx" });
4430
+ await fs5.writeFile(lockPath, String(process.pid), { encoding: "utf8", flag: "wx" });
3887
4431
  break;
3888
4432
  } catch (error3) {
3889
4433
  if (!hasErrorCode(error3, "EEXIST")) {
3890
- await fs4.unlink(lockPath).catch(() => void 0);
4434
+ await fs5.unlink(lockPath).catch(() => void 0);
3891
4435
  throw error3;
3892
4436
  }
3893
- if (await removeAbandonedLock(fs4, lockPath)) {
4437
+ if (await removeAbandonedLock(fs5, lockPath)) {
3894
4438
  continue;
3895
4439
  }
3896
4440
  await Promise.resolve();
@@ -3899,13 +4443,13 @@ async function withFileLock(fs4, lockPath, operation) {
3899
4443
  try {
3900
4444
  return await operation();
3901
4445
  } finally {
3902
- await fs4.unlink(lockPath);
4446
+ await fs5.unlink(lockPath);
3903
4447
  }
3904
4448
  }
3905
- async function removeAbandonedLock(fs4, lockPath) {
4449
+ async function removeAbandonedLock(fs5, lockPath) {
3906
4450
  let content;
3907
4451
  try {
3908
- content = await fs4.readFile(lockPath, "utf8");
4452
+ content = await fs5.readFile(lockPath, "utf8");
3909
4453
  } catch (error3) {
3910
4454
  if (hasErrorCode(error3, "ENOENT")) {
3911
4455
  return true;
@@ -3913,11 +4457,11 @@ async function removeAbandonedLock(fs4, lockPath) {
3913
4457
  throw error3;
3914
4458
  }
3915
4459
  const owner = Number(content);
3916
- if (!Number.isInteger(owner) || owner <= 0 || isProcessRunning(owner)) {
4460
+ if (Number.isInteger(owner) && owner > 0 && isProcessRunning(owner)) {
3917
4461
  return false;
3918
4462
  }
3919
4463
  try {
3920
- await fs4.unlink(lockPath);
4464
+ await fs5.unlink(lockPath);
3921
4465
  return true;
3922
4466
  } catch (error3) {
3923
4467
  if (hasErrorCode(error3, "ENOENT")) {
@@ -4185,6 +4729,9 @@ async function ghIssuesBackend(deps) {
4185
4729
  if (deps.state?.labelPrefix === "") {
4186
4730
  throw new Error("gh-issues state.labelPrefix must be a non-empty string when configured.");
4187
4731
  }
4732
+ if (deps.stateMachine !== void 0) {
4733
+ validateMachine(deps.stateMachine);
4734
+ }
4188
4735
  const client = createGhClient({
4189
4736
  token: deps.token,
4190
4737
  endpoint: deps.endpoint,
@@ -4344,7 +4891,9 @@ function createTasksView(name, session, context) {
4344
4891
  );
4345
4892
  projectItemId = added.addProjectV2ItemById?.item?.id ?? void 0;
4346
4893
  if (projectItemId === void 0) {
4347
- throw new Error("GitHub addProjectV2ItemById response did not include project item id.");
4894
+ throw new Error(
4895
+ "GitHub addProjectV2ItemById response did not include project item id."
4896
+ );
4348
4897
  }
4349
4898
  }
4350
4899
  if (session.labelPrefix === void 0) {
@@ -4573,12 +5122,15 @@ async function resolveProjectItemId(id, listName, session, context) {
4573
5122
  const issueNumber = parseIssueNumber(id, listName);
4574
5123
  let after;
4575
5124
  while (true) {
4576
- const result = await context.client.graphql(ISSUE_STATE_LABELS_QUERY, {
4577
- owner: context.repoOwner,
4578
- repo: context.repoName,
4579
- number: issueNumber,
4580
- after
4581
- });
5125
+ const result = await context.client.graphql(
5126
+ ISSUE_STATE_LABELS_QUERY,
5127
+ {
5128
+ owner: context.repoOwner,
5129
+ repo: context.repoName,
5130
+ number: issueNumber,
5131
+ after
5132
+ }
5133
+ );
4582
5134
  const issue = result.repository?.issue ?? null;
4583
5135
  if (issue === null) {
4584
5136
  throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
@@ -4855,12 +5407,27 @@ async function fetchIssueTask(id, listName, session, context) {
4855
5407
  });
4856
5408
  }
4857
5409
  function parseIssueNumber(id, listName) {
5410
+ if (!isCanonicalDecimalIssueId(id)) {
5411
+ throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
5412
+ }
4858
5413
  const issueNumber = Number(id);
4859
- if (!Number.isInteger(issueNumber) || issueNumber < 1) {
5414
+ if (!Number.isSafeInteger(issueNumber) || issueNumber < 1) {
4860
5415
  throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
4861
5416
  }
4862
5417
  return issueNumber;
4863
5418
  }
5419
+ function isCanonicalDecimalIssueId(id) {
5420
+ if (id.length === 0 || id[0] === "0") {
5421
+ return false;
5422
+ }
5423
+ for (let index = 0; index < id.length; index += 1) {
5424
+ const charCode = id.charCodeAt(index);
5425
+ if (charCode < 48 || charCode > 57) {
5426
+ return false;
5427
+ }
5428
+ }
5429
+ return true;
5430
+ }
4864
5431
  function mapProjectItemToTask(item, listName, session) {
4865
5432
  const content = item.content;
4866
5433
  if (!isIssueNode(content)) {
@@ -4968,7 +5535,7 @@ function parseQualifiedId(qualifiedId, listName) {
4968
5535
  }
4969
5536
 
4970
5537
  // ../task-list/src/backends/markdown-dir.ts
4971
- import path7 from "node:path";
5538
+ import path8 from "node:path";
4972
5539
  import { parseDocument as parseDocument2, stringify as stringify2 } from "yaml";
4973
5540
 
4974
5541
  // ../task-list/src/schema/task.schema.json
@@ -5071,7 +5638,7 @@ function resolveListLayout(deps) {
5071
5638
  return deps.singleList ? { kind: "single", name: deps.singleList } : { kind: "multi" };
5072
5639
  }
5073
5640
  function validateListName(name) {
5074
- if (name.length === 0 || name === ARCHIVE_DIRECTORY_NAME || name.startsWith(".") || name.includes("/") || name.includes("\\") || name.includes("..")) {
5641
+ if (!isTrimmedPrintableIdentifier(name) || name === ARCHIVE_DIRECTORY_NAME || name.startsWith(".") || name.includes("/") || name.includes("\\") || name.includes("..")) {
5075
5642
  throw new Error(`Invalid task list name "${name}".`);
5076
5643
  }
5077
5644
  return name;
@@ -5087,16 +5654,16 @@ function parseQualifiedId2(qualifiedId) {
5087
5654
  };
5088
5655
  }
5089
5656
  function listPath(rootPath, layout, list) {
5090
- return layout.kind === "single" ? rootPath : path7.join(rootPath, list);
5657
+ return layout.kind === "single" ? rootPath : path8.join(rootPath, list);
5091
5658
  }
5092
5659
  function archiveDirectoryPath(rootPath, layout, list) {
5093
- return layout.kind === "single" ? path7.join(rootPath, ARCHIVE_DIRECTORY_NAME) : path7.join(rootPath, list, ARCHIVE_DIRECTORY_NAME);
5660
+ return layout.kind === "single" ? path8.join(rootPath, ARCHIVE_DIRECTORY_NAME) : path8.join(rootPath, list, ARCHIVE_DIRECTORY_NAME);
5094
5661
  }
5095
5662
  function activeTaskFilename(id, order, width) {
5096
5663
  return `${String(order).padStart(width, "0")}-${id}${MARKDOWN_EXTENSION}`;
5097
5664
  }
5098
5665
  function archivedTaskPath(rootPath, layout, list, id) {
5099
- return path7.join(archiveDirectoryPath(rootPath, layout, list), `${id}${MARKDOWN_EXTENSION}`);
5666
+ return path8.join(archiveDirectoryPath(rootPath, layout, list), `${id}${MARKDOWN_EXTENSION}`);
5100
5667
  }
5101
5668
  function isMarkdownFile(entryName) {
5102
5669
  return entryName.endsWith(MARKDOWN_EXTENSION);
@@ -5198,7 +5765,7 @@ function hasOwnTaskField(frontmatter, key2) {
5198
5765
  function reservedFrontmatterKeys(mode) {
5199
5766
  return mode === "passthrough" ? PASSTHROUGH_RESERVED_FRONTMATTER_KEYS : RESERVED_FRONTMATTER_KEYS;
5200
5767
  }
5201
- function setOwnValue(record, key2, value) {
5768
+ function setOwnValue2(record, key2, value) {
5202
5769
  Object.defineProperty(record, key2, {
5203
5770
  value,
5204
5771
  enumerable: true,
@@ -5211,7 +5778,7 @@ function metadataFromFrontmatter(frontmatter, mode) {
5211
5778
  const reservedKeys = reservedFrontmatterKeys(mode);
5212
5779
  for (const [key2, value] of Object.entries(frontmatter)) {
5213
5780
  if (!reservedKeys.has(key2)) {
5214
- setOwnValue(metadata, key2, value);
5781
+ setOwnValue2(metadata, key2, value);
5215
5782
  }
5216
5783
  }
5217
5784
  return metadata;
@@ -5225,7 +5792,7 @@ function createTask(list, id, frontmatter, body, mode, sourcePath) {
5225
5792
  state: frontmatter.state,
5226
5793
  description: body,
5227
5794
  metadata: metadataFromFrontmatter(frontmatter, mode),
5228
- ...sourcePath !== void 0 && { sourcePath: path7.resolve(sourcePath) }
5795
+ ...sourcePath !== void 0 && { sourcePath: path8.resolve(sourcePath) }
5229
5796
  };
5230
5797
  }
5231
5798
  function serializeTaskDocument(frontmatter, description) {
@@ -5234,9 +5801,9 @@ ${stringify2(frontmatter)}---
5234
5801
 
5235
5802
  ${description}`;
5236
5803
  }
5237
- async function readDirectoryNames(fs4, directoryPath) {
5804
+ async function readDirectoryNames(fs5, directoryPath) {
5238
5805
  try {
5239
- return sortStrings(await fs4.readdir(directoryPath));
5806
+ return sortStrings(await fs5.readdir(directoryPath));
5240
5807
  } catch (error3) {
5241
5808
  if (hasErrorCode(error3, "ENOENT")) {
5242
5809
  return [];
@@ -5252,9 +5819,9 @@ async function ensureRootPath(deps) {
5252
5819
  }
5253
5820
  await deps.fs.stat(deps.path);
5254
5821
  }
5255
- async function readTaskFile(fs4, list, id, filePath, validStates, initialState, mode) {
5256
- await rejectSymbolicLinkComponents(fs4, filePath);
5257
- const content = await fs4.readFile(filePath, "utf8");
5822
+ async function readTaskFile(fs5, list, id, filePath, validStates, initialState, mode) {
5823
+ await rejectSymbolicLinkComponents(fs5, filePath);
5824
+ const content = await fs5.readFile(filePath, "utf8");
5258
5825
  const document = splitTaskDocument(content, filePath, mode);
5259
5826
  const frontmatter = mode === "passthrough" && document.frontmatter.trim().length === 0 ? {} : readFrontmatter(document.frontmatter, filePath);
5260
5827
  if (mode !== "passthrough") {
@@ -5265,57 +5832,106 @@ async function readTaskFile(fs4, list, id, filePath, validStates, initialState,
5265
5832
  task: createTask(list, id, frontmatter, document.body, mode, filePath)
5266
5833
  };
5267
5834
  }
5268
- const parsedFilename = parseActiveFilename(path7.basename(filePath));
5269
- const defaultName = parsedFilename?.id ?? id;
5270
5835
  const effectiveFrontmatter = {
5271
5836
  ...frontmatter,
5272
- name: typeof frontmatter.name === "string" ? frontmatter.name : defaultName,
5837
+ name: typeof frontmatter.name === "string" ? frontmatter.name : id,
5273
5838
  state: typeof frontmatter.state === "string" && validStates.has(frontmatter.state) ? frontmatter.state : initialState
5274
5839
  };
5275
5840
  return {
5276
- path: filePath,
5277
- frontmatter,
5278
- task: createTask(list, id, effectiveFrontmatter, document.body, mode, filePath)
5841
+ path: filePath,
5842
+ frontmatter,
5843
+ task: createTask(list, id, effectiveFrontmatter, document.body, mode, filePath)
5844
+ };
5845
+ }
5846
+ async function readPassthroughFrontmatter(fs5, filePath, mode) {
5847
+ if (mode !== "passthrough") {
5848
+ return {};
5849
+ }
5850
+ const content = await fs5.readFile(filePath, "utf8");
5851
+ const document = splitTaskDocument(content, filePath, mode);
5852
+ if (document.frontmatter.trim().length === 0) {
5853
+ return {};
5854
+ }
5855
+ return readFrontmatter(document.frontmatter, filePath);
5856
+ }
5857
+ async function resolveActiveFilenameEntry(fs5, entryName, entryPath, parsed, mode) {
5858
+ if (mode !== "passthrough" || parsed.order === null) {
5859
+ return parsed;
5860
+ }
5861
+ const frontmatter = await readPassthroughFrontmatter(fs5, entryPath, mode);
5862
+ if (Object.keys(frontmatter).length === 0 && orderedFilenamePrefixLength(entryName) <= MIN_PREFIX_WIDTH) {
5863
+ return parsed;
5864
+ }
5865
+ if (typeof frontmatter.state === "string" || hasOwnTaskField(frontmatter, "$schema") || hasOwnTaskField(frontmatter, "kind") || hasOwnTaskField(frontmatter, "version")) {
5866
+ return parsed;
5867
+ }
5868
+ return {
5869
+ id: entryName.slice(0, -MARKDOWN_EXTENSION.length),
5870
+ order: null,
5871
+ filename: parsed.filename
5279
5872
  };
5280
5873
  }
5281
- async function findActiveTaskFilename(fs4, listDirectoryPath, id) {
5282
- const entries = await readDirectoryNames(fs4, listDirectoryPath);
5874
+ function orderedFilenamePrefixLength(entryName) {
5875
+ const stem = entryName.slice(0, -MARKDOWN_EXTENSION.length);
5876
+ const separatorIndex = stem.indexOf("-");
5877
+ if (separatorIndex <= 0) {
5878
+ return Number.POSITIVE_INFINITY;
5879
+ }
5880
+ for (let index = 0; index < separatorIndex; index += 1) {
5881
+ const code = stem.charCodeAt(index);
5882
+ if (code < 48 || code > 57) {
5883
+ return Number.POSITIVE_INFINITY;
5884
+ }
5885
+ }
5886
+ return separatorIndex;
5887
+ }
5888
+ async function findActiveTaskFilename(fs5, listDirectoryPath, id, mode) {
5889
+ const entries = await readDirectoryNames(fs5, listDirectoryPath);
5283
5890
  for (const entryName of entries) {
5284
5891
  if (isHiddenEntry(entryName)) continue;
5285
5892
  const parsed = parseActiveFilename(entryName);
5286
- if (parsed?.id === id) {
5893
+ if (!parsed) continue;
5894
+ const entryPath = path8.join(listDirectoryPath, entryName);
5895
+ const resolved = await resolveActiveFilenameEntry(
5896
+ fs5,
5897
+ entryName,
5898
+ entryPath,
5899
+ { id: parsed.id, order: parsed.order, filename: entryName },
5900
+ mode
5901
+ );
5902
+ if (resolved.id === id) {
5287
5903
  return entryName;
5288
5904
  }
5289
5905
  }
5290
5906
  return void 0;
5291
5907
  }
5292
- async function findTaskLocation(fs4, rootPath, layout, list, id) {
5908
+ async function findTaskLocation(fs5, rootPath, layout, list, id, mode) {
5293
5909
  const listDirectoryPath = listPath(rootPath, layout, list);
5294
- await rejectSymbolicLinkComponents(fs4, listDirectoryPath);
5295
- const activeName = await findActiveTaskFilename(fs4, listDirectoryPath, id);
5910
+ await rejectSymbolicLinkComponents(fs5, listDirectoryPath);
5911
+ const activeName = await findActiveTaskFilename(fs5, listDirectoryPath, id, mode);
5296
5912
  if (activeName) {
5297
- const activePath = path7.join(listDirectoryPath, activeName);
5298
- await rejectSymbolicLinkComponents(fs4, activePath);
5299
- const activeStat = await statIfExists(fs4, activePath);
5913
+ const activePath = path8.join(listDirectoryPath, activeName);
5914
+ await rejectSymbolicLinkComponents(fs5, activePath);
5915
+ const activeStat = await statIfExists(fs5, activePath);
5300
5916
  if (activeStat?.isFile()) {
5301
5917
  return { archived: false, path: activePath };
5302
5918
  }
5303
5919
  }
5304
5920
  const archivedPath = archivedTaskPath(rootPath, layout, list, id);
5305
- await rejectSymbolicLinkComponents(fs4, archiveDirectoryPath(rootPath, layout, list));
5306
- await rejectSymbolicLinkComponents(fs4, archivedPath);
5307
- const archivedStat = await statIfExists(fs4, archivedPath);
5921
+ await rejectSymbolicLinkComponents(fs5, archiveDirectoryPath(rootPath, layout, list));
5922
+ await rejectSymbolicLinkComponents(fs5, archivedPath);
5923
+ const archivedStat = await statIfExists(fs5, archivedPath);
5308
5924
  if (archivedStat?.isFile()) {
5309
5925
  return { archived: true, path: archivedPath };
5310
5926
  }
5311
5927
  return void 0;
5312
5928
  }
5313
- async function readTaskAtLocation(fs4, rootPath, layout, list, id, validStates, initialState, mode) {
5314
- const location = await findTaskLocation(fs4, rootPath, layout, list, id);
5929
+ async function readTaskAtLocation(fs5, rootPath, layout, list, id, validStates, initialState, mode) {
5930
+ const location = await findTaskLocation(fs5, rootPath, layout, list, id, mode);
5315
5931
  if (!location) {
5316
5932
  throw new TaskNotFoundError(`Task "${list}/${id}" not found.`);
5317
5933
  }
5318
- return readTaskFile(fs4, list, id, location.path, validStates, initialState, mode);
5934
+ return readTaskFile(fs5, list, id, location.path, validStates, initialState, mode);
5319
5935
  }
5320
5936
  function createdFrontmatter(defaults2, input, initialState, mode) {
5321
5937
  const frontmatter = mode !== "passthrough" ? {
@@ -5331,12 +5947,12 @@ function createdFrontmatter(defaults2, input, initialState, mode) {
5331
5947
  const reservedKeys = reservedFrontmatterKeys(mode);
5332
5948
  for (const [key2, value] of Object.entries(defaults2.metadata)) {
5333
5949
  if (!reservedKeys.has(key2)) {
5334
- setOwnValue(frontmatter, key2, value);
5950
+ setOwnValue2(frontmatter, key2, value);
5335
5951
  }
5336
5952
  }
5337
5953
  for (const [key2, value] of Object.entries(input.metadata ?? {})) {
5338
5954
  if (!reservedKeys.has(key2)) {
5339
- setOwnValue(frontmatter, key2, value);
5955
+ setOwnValue2(frontmatter, key2, value);
5340
5956
  }
5341
5957
  }
5342
5958
  frontmatter.created = (/* @__PURE__ */ new Date()).toISOString();
@@ -5358,7 +5974,7 @@ function updatedFrontmatter(existingFrontmatter, task, patch, mode) {
5358
5974
  const reservedKeys = reservedFrontmatterKeys(mode);
5359
5975
  for (const [key2, value] of Object.entries(patch.metadata ?? {})) {
5360
5976
  if (!reservedKeys.has(key2)) {
5361
- setOwnValue(nextFrontmatter, key2, value);
5977
+ setOwnValue2(nextFrontmatter, key2, value);
5362
5978
  }
5363
5979
  }
5364
5980
  return nextFrontmatter;
@@ -5382,7 +5998,7 @@ function firedFrontmatter(existingFrontmatter, task, to, mode, metadataPatch) {
5382
5998
  const reservedKeys = reservedFrontmatterKeys(mode);
5383
5999
  for (const [key2, value] of Object.entries(metadataPatch ?? {})) {
5384
6000
  if (!reservedKeys.has(key2)) {
5385
- setOwnValue(nextFrontmatter, key2, value);
6001
+ setOwnValue2(nextFrontmatter, key2, value);
5386
6002
  }
5387
6003
  }
5388
6004
  return nextFrontmatter;
@@ -5416,11 +6032,19 @@ function createTasksView2(deps, layout, list) {
5416
6032
  if (isHiddenEntry(entryName)) continue;
5417
6033
  const parsed = parseActiveFilename(entryName);
5418
6034
  if (!parsed) continue;
5419
- const entryPath = path7.join(listDirectoryPath, entryName);
6035
+ const entryPath = path8.join(listDirectoryPath, entryName);
5420
6036
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
5421
6037
  const entryStat = await statIfExists(deps.fs, entryPath);
5422
6038
  if (!entryStat?.isFile()) continue;
5423
- result.push({ id: parsed.id, order: parsed.order, filename: entryName });
6039
+ result.push(
6040
+ await resolveActiveFilenameEntry(
6041
+ deps.fs,
6042
+ entryName,
6043
+ entryPath,
6044
+ { id: parsed.id, order: parsed.order, filename: entryName },
6045
+ deps.frontmatterMode
6046
+ )
6047
+ );
5424
6048
  }
5425
6049
  result.sort((left, right) => {
5426
6050
  const leftOrder = left.order ?? Number.POSITIVE_INFINITY;
@@ -5434,7 +6058,7 @@ function createTasksView2(deps, layout, list) {
5434
6058
  const entries = await readActiveEntries();
5435
6059
  const tasks = /* @__PURE__ */ new Map();
5436
6060
  for (const entry of entries) {
5437
- const filePath = path7.join(listDirectoryPath, entry.filename);
6061
+ const filePath = path8.join(listDirectoryPath, entry.filename);
5438
6062
  const file = await readTaskFile(
5439
6063
  deps.fs,
5440
6064
  list,
@@ -5455,7 +6079,7 @@ function createTasksView2(deps, layout, list) {
5455
6079
  const result = [];
5456
6080
  for (const entryName of entries) {
5457
6081
  if (isHiddenEntry(entryName) || !isMarkdownFile(entryName)) continue;
5458
- const entryPath = path7.join(archivePath, entryName);
6082
+ const entryPath = path8.join(archivePath, entryName);
5459
6083
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
5460
6084
  const entryStat = await statIfExists(deps.fs, entryPath);
5461
6085
  if (!entryStat?.isFile()) continue;
@@ -5485,15 +6109,20 @@ function createTasksView2(deps, layout, list) {
5485
6109
  if (desiredOrder === void 0) continue;
5486
6110
  const desiredFilename = activeTaskFilename(entry.id, desiredOrder, width);
5487
6111
  if (entry.filename !== desiredFilename) {
5488
- const fromPath = path7.join(listDirectoryPath, entry.filename);
5489
- const stagingPath = path7.join(
6112
+ const fromPath = path8.join(listDirectoryPath, entry.filename);
6113
+ const stagingPath = path8.join(
5490
6114
  listDirectoryPath,
5491
6115
  `${desiredFilename}.staging-${process.pid}-${index}`
5492
6116
  );
5493
- const targetPath = path7.join(listDirectoryPath, desiredFilename);
6117
+ const targetPath = path8.join(listDirectoryPath, desiredFilename);
5494
6118
  try {
5495
6119
  await deps.fs.rename(fromPath, stagingPath);
5496
- staged.push({ original: fromPath, staging: stagingPath, target: targetPath, finalized: false });
6120
+ staged.push({
6121
+ original: fromPath,
6122
+ staging: stagingPath,
6123
+ target: targetPath,
6124
+ finalized: false
6125
+ });
5497
6126
  } catch (error3) {
5498
6127
  for (const stagedEntry of staged.reverse()) {
5499
6128
  await deps.fs.rename(stagedEntry.staging, stagedEntry.original);
@@ -5628,8 +6257,7 @@ function createTasksView2(deps, layout, list) {
5628
6257
  if (filter?.state && entry.task.state !== filter.state) return false;
5629
6258
  return true;
5630
6259
  });
5631
- const orderedActiveTasks = applyOrder(orderedActive, filter?.order);
5632
- return [...orderedActiveTasks, ...filteredArchived.map((entry) => entry.task)];
6260
+ return applyOrder([...orderedActive, ...filteredArchived], filter?.order);
5633
6261
  },
5634
6262
  async get(id) {
5635
6263
  return (await getTaskFile(id)).task;
@@ -5638,9 +6266,17 @@ function createTasksView2(deps, layout, list) {
5638
6266
  assertCreateDoesNotSetState(input);
5639
6267
  assertCreateHasId(input);
5640
6268
  validateTaskId(input.id);
6269
+ validateTaskName(input.name);
5641
6270
  await rejectSymbolicLinkComponents(deps.fs, listDirectoryPath);
5642
- return withFileLock(deps.fs, path7.join(listDirectoryPath, ".transition.lock"), async () => {
5643
- const existing = await findTaskLocation(deps.fs, deps.path, layout, list, input.id);
6271
+ return withFileLock(deps.fs, path8.join(listDirectoryPath, ".transition.lock"), async () => {
6272
+ const existing = await findTaskLocation(
6273
+ deps.fs,
6274
+ deps.path,
6275
+ layout,
6276
+ list,
6277
+ input.id,
6278
+ deps.frontmatterMode
6279
+ );
5644
6280
  if (existing) {
5645
6281
  throw new TaskAlreadyExistsError(`Task "${list}/${input.id}" already exists.`);
5646
6282
  }
@@ -5652,7 +6288,7 @@ function createTasksView2(deps, layout, list) {
5652
6288
  const nextOrder = maxOrder + 1;
5653
6289
  const width = padWidthForCount(activeEntries.length + 1);
5654
6290
  const filename = activeTaskFilename(input.id, nextOrder, width);
5655
- const targetPath = path7.join(listDirectoryPath, filename);
6291
+ const targetPath = path8.join(listDirectoryPath, filename);
5656
6292
  const frontmatter = createdFrontmatter(
5657
6293
  deps.defaults,
5658
6294
  input,
@@ -5661,12 +6297,22 @@ function createTasksView2(deps, layout, list) {
5661
6297
  );
5662
6298
  const description = input.description ?? "";
5663
6299
  await writeAtomically(deps.fs, targetPath, serializeTaskDocument(frontmatter, description));
5664
- return createTask(list, input.id, frontmatter, description, deps.frontmatterMode, targetPath);
6300
+ return createTask(
6301
+ list,
6302
+ input.id,
6303
+ frontmatter,
6304
+ description,
6305
+ deps.frontmatterMode,
6306
+ targetPath
6307
+ );
5665
6308
  });
5666
6309
  },
5667
6310
  async update(id, patch) {
5668
6311
  assertUpdateDoesNotSetState(patch);
5669
6312
  validateTaskId(id);
6313
+ if (patch.name !== void 0) {
6314
+ validateTaskName(patch.name);
6315
+ }
5670
6316
  const existing = await getTaskFile(id);
5671
6317
  const nextFrontmatter = updatedFrontmatter(
5672
6318
  existing.frontmatter,
@@ -5752,7 +6398,14 @@ function createTasksView2(deps, layout, list) {
5752
6398
  };
5753
6399
  if (stateMachine.events[eventName]?.to === "archived") {
5754
6400
  validateTaskId(id);
5755
- const location = await findTaskLocation(deps.fs, deps.path, layout, list, id);
6401
+ const location = await findTaskLocation(
6402
+ deps.fs,
6403
+ deps.path,
6404
+ layout,
6405
+ list,
6406
+ id,
6407
+ deps.frontmatterMode
6408
+ );
5756
6409
  if (!location) {
5757
6410
  throw new TaskNotFoundError(`Task "${list}/${id}" not found.`);
5758
6411
  }
@@ -5760,7 +6413,7 @@ function createTasksView2(deps, layout, list) {
5760
6413
  validateTaskId(id);
5761
6414
  const { event, nextTask } = await withFileLock(
5762
6415
  deps.fs,
5763
- path7.join(listDirectoryPath, ".transition.lock"),
6416
+ path8.join(listDirectoryPath, ".transition.lock"),
5764
6417
  fireTask
5765
6418
  );
5766
6419
  await event.onEnter?.(nextTask);
@@ -5780,7 +6433,14 @@ function createTasksView2(deps, layout, list) {
5780
6433
  },
5781
6434
  async delete(id) {
5782
6435
  validateTaskId(id);
5783
- const location = await findTaskLocation(deps.fs, deps.path, layout, list, id);
6436
+ const location = await findTaskLocation(
6437
+ deps.fs,
6438
+ deps.path,
6439
+ layout,
6440
+ list,
6441
+ id,
6442
+ deps.frontmatterMode
6443
+ );
5784
6444
  if (!location) {
5785
6445
  throw new TaskNotFoundError(`Task "${list}/${id}" not found.`);
5786
6446
  }
@@ -5853,7 +6513,7 @@ async function markdownDirBackend(deps) {
5853
6513
  if (entryName === ARCHIVE_DIRECTORY_NAME || isHiddenEntry(entryName)) {
5854
6514
  continue;
5855
6515
  }
5856
- const entryPath = path7.join(deps.path, entryName);
6516
+ const entryPath = path8.join(deps.path, entryName);
5857
6517
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
5858
6518
  const entryStat = await statIfExists(deps.fs, entryPath);
5859
6519
  if (entryStat?.isDirectory()) {
@@ -5895,12 +6555,26 @@ async function markdownDirBackend(deps) {
5895
6555
  }
5896
6556
  const targetListDir = listPath(deps.path, layout, targetListName);
5897
6557
  await rejectSymbolicLinkComponents(deps.fs, targetListDir);
5898
- return withFileLock(deps.fs, path7.join(targetListDir, ".transition.lock"), async () => {
5899
- const targetExisting = await findTaskLocation(deps.fs, deps.path, layout, targetListName, id);
6558
+ return withFileLock(deps.fs, path8.join(targetListDir, ".transition.lock"), async () => {
6559
+ const targetExisting = await findTaskLocation(
6560
+ deps.fs,
6561
+ deps.path,
6562
+ layout,
6563
+ targetListName,
6564
+ id,
6565
+ deps.frontmatterMode
6566
+ );
5900
6567
  if (targetExisting) {
5901
6568
  throw new TaskAlreadyExistsError(`Task "${targetListName}/${id}" already exists.`);
5902
6569
  }
5903
- const sourceLocation = await findTaskLocation(deps.fs, deps.path, layout, sourceListName, id);
6570
+ const sourceLocation = await findTaskLocation(
6571
+ deps.fs,
6572
+ deps.path,
6573
+ layout,
6574
+ sourceListName,
6575
+ id,
6576
+ deps.frontmatterMode
6577
+ );
5904
6578
  if (!sourceLocation) {
5905
6579
  throw new TaskNotFoundError(`Task "${sourceListName}/${id}" not found.`);
5906
6580
  }
@@ -5945,7 +6619,7 @@ async function markdownDirBackend(deps) {
5945
6619
  );
5946
6620
  const width = padWidthForCount(targetEntries.length + 1);
5947
6621
  const targetFilename = activeTaskFilename(id, maxOrder + 1, width);
5948
- const targetPath = path7.join(targetListDir, targetFilename);
6622
+ const targetPath = path8.join(targetListDir, targetFilename);
5949
6623
  await deps.fs.rename(sourceLocation.path, targetPath);
5950
6624
  return createTask(
5951
6625
  targetListName,
@@ -5967,7 +6641,7 @@ async function markdownDirBackend(deps) {
5967
6641
  }
5968
6642
 
5969
6643
  // ../task-list/src/backends/yaml-file.ts
5970
- import path8 from "node:path";
6644
+ import path9 from "node:path";
5971
6645
  import { isMap, parseDocument as parseDocument3 } from "yaml";
5972
6646
 
5973
6647
  // ../task-list/src/schema/store.schema.json
@@ -6027,7 +6701,7 @@ function malformedTask2(list, id, field) {
6027
6701
  return new MalformedTaskError(`Malformed task "${list}/${id}": invalid "${field}".`);
6028
6702
  }
6029
6703
  function validateListName2(name) {
6030
- if (name.length === 0 || name.startsWith(".") || name.includes("/") || name.includes("\\") || name.includes("..")) {
6704
+ if (!isTrimmedPrintableIdentifier(name) || name.startsWith(".") || name.includes("/") || name.includes("\\") || name.includes("..")) {
6031
6705
  throw new Error(`Invalid task list name "${name}".`);
6032
6706
  }
6033
6707
  return name;
@@ -6064,7 +6738,7 @@ function createTask2(list, id, taskRecord, sourcePath) {
6064
6738
  state: getOwnEntry(taskRecord, "state"),
6065
6739
  description: descriptionFromTaskRecord(taskRecord),
6066
6740
  metadata: metadataFromTaskRecord(taskRecord),
6067
- ...sourcePath !== void 0 && { sourcePath: path8.resolve(sourcePath) }
6741
+ ...sourcePath !== void 0 && { sourcePath: path9.resolve(sourcePath) }
6068
6742
  };
6069
6743
  }
6070
6744
  function matchesFilter(task, filter) {
@@ -6235,8 +6909,8 @@ function serializeDocument(document) {
6235
6909
  return serialized.endsWith("\n") ? serialized : `${serialized}
6236
6910
  `;
6237
6911
  }
6238
- async function readStore(fs4, filePath, validStates) {
6239
- const content = await fs4.readFile(filePath, "utf8");
6912
+ async function readStore(fs5, filePath, validStates) {
6913
+ const content = await fs5.readFile(filePath, "utf8");
6240
6914
  const document = parseStoreDocument(filePath, content);
6241
6915
  const store = document.toJS();
6242
6916
  assertValidStoreRecord(store, filePath);
@@ -6376,6 +7050,7 @@ function createTasksView3(deps, list) {
6376
7050
  assertCreateDoesNotSetState2(input);
6377
7051
  assertCreateHasId2(input);
6378
7052
  validateTaskId(input.id);
7053
+ validateTaskName(input.name);
6379
7054
  const { document, store } = await readStore(deps.fs, deps.path, validStates);
6380
7055
  if (getTaskRecord(store, list, input.id)) {
6381
7056
  throw new TaskAlreadyExistsError(`Task "${list}/${input.id}" already exists.`);
@@ -6388,6 +7063,9 @@ function createTasksView3(deps, list) {
6388
7063
  async update(id, patch) {
6389
7064
  assertUpdateDoesNotSetState2(patch);
6390
7065
  validateTaskId(id);
7066
+ if (patch.name !== void 0) {
7067
+ validateTaskName(patch.name);
7068
+ }
6391
7069
  const { document, store } = await readStore(deps.fs, deps.path, validStates);
6392
7070
  const existing = getTaskOrThrow(store, list, id);
6393
7071
  const nextTaskRecord = buildUpdatedTaskRecord(existing, patch);
@@ -6479,6 +7157,11 @@ function createTasksView3(deps, list) {
6479
7157
  insertIndex = anchor.position === "top" ? 0 : listNode.items.length;
6480
7158
  } else {
6481
7159
  const anchorId = "before" in anchor ? anchor.before : anchor.after;
7160
+ const activeIds = new Set(activeItemIds(listNode, validStates));
7161
+ if (!activeIds.has(anchorId)) {
7162
+ listNode.items.splice(fromIndex, 0, movedPair);
7163
+ throw new AnchorNotFoundError(anchorId);
7164
+ }
6482
7165
  const anchorIndex = findItemIndex(listNode, anchorId);
6483
7166
  if (anchorIndex < 0) {
6484
7167
  listNode.items.splice(fromIndex, 0, movedPair);
@@ -6663,7 +7346,7 @@ function isRecord4(value) {
6663
7346
 
6664
7347
  // ../task-list/src/move.ts
6665
7348
  import * as fsPromises2 from "node:fs/promises";
6666
- import path9 from "node:path";
7349
+ import path10 from "node:path";
6667
7350
 
6668
7351
  // ../toolcraft/src/human-in-loop/approval-tasks.ts
6669
7352
  import { randomBytes as randomBytes3 } from "node:crypto";
@@ -6850,7 +7533,7 @@ function areEqualStrings(left, right) {
6850
7533
  }
6851
7534
 
6852
7535
  // ../toolcraft/src/human-in-loop/runner.ts
6853
- import { access, lstat, readFile as readFile2, rename, unlink, writeFile as writeFile2 } from "node:fs/promises";
7536
+ import { access, lstat, readFile as readFile3, rename, unlink, writeFile as writeFile2 } from "node:fs/promises";
6854
7537
 
6855
7538
  // ../toolcraft/src/human-in-loop/default-provider.ts
6856
7539
  import process3 from "node:process";
@@ -6882,7 +7565,7 @@ on error number -128
6882
7565
  end try`;
6883
7566
  }
6884
7567
  function parseStdout(out) {
6885
- const value = out.endsWith("\r\n") ? out.slice(0, -2) : out.endsWith("\n") ? out.slice(0, -1) : out;
7568
+ 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;
6886
7569
  switch (value) {
6887
7570
  case "Approve":
6888
7571
  case "APPROVED":
@@ -7162,13 +7845,13 @@ function formatAvailableApprovalCommandPaths(root) {
7162
7845
  }
7163
7846
  function enumerateApprovalCommandPaths(root) {
7164
7847
  const paths = [];
7165
- const visit = (node, path24) => {
7848
+ const visit = (node, path25) => {
7166
7849
  if (node.kind === "command") {
7167
- paths.push(path24.join("."));
7850
+ paths.push(path25.join("."));
7168
7851
  return;
7169
7852
  }
7170
7853
  for (const child of getVisibleCliChildren(node)) {
7171
- visit(child, [...path24, child.name]);
7854
+ visit(child, [...path25, child.name]);
7172
7855
  }
7173
7856
  };
7174
7857
  if (root.kind === "command") {
@@ -7203,21 +7886,21 @@ function createHandlerContext(command, params17) {
7203
7886
  }
7204
7887
  function createFs() {
7205
7888
  return {
7206
- readFile: async (path24, encoding = "utf8") => readFile2(path24, { encoding }),
7207
- writeFile: async (path24, contents, options) => {
7208
- await writeFile2(path24, contents, options);
7889
+ readFile: async (path25, encoding = "utf8") => readFile3(path25, { encoding }),
7890
+ writeFile: async (path25, contents, options) => {
7891
+ await writeFile2(path25, contents, options);
7209
7892
  },
7210
- exists: async (path24) => {
7893
+ exists: async (path25) => {
7211
7894
  try {
7212
- await access(path24);
7895
+ await access(path25);
7213
7896
  return true;
7214
7897
  } catch {
7215
7898
  return false;
7216
7899
  }
7217
7900
  },
7218
- lstat: async (path24) => lstat(path24),
7901
+ lstat: async (path25) => lstat(path25),
7219
7902
  rename: async (fromPath, toPath) => rename(fromPath, toPath),
7220
- unlink: async (path24) => unlink(path24)
7903
+ unlink: async (path25) => unlink(path25)
7221
7904
  };
7222
7905
  }
7223
7906
  function createEnv(values = process.env) {
@@ -7496,13 +8179,13 @@ function isMissingStateError(error3) {
7496
8179
  import { mkdir as mkdir2, realpath as realpath2, writeFile as writeFile4 } from "node:fs/promises";
7497
8180
  import { randomUUID as randomUUID5 } from "node:crypto";
7498
8181
  import os from "node:os";
7499
- import path13 from "node:path";
8182
+ import path14 from "node:path";
7500
8183
  import { CommanderError } from "commander";
7501
8184
 
7502
8185
  // ../toolcraft/src/mcp-proxy.ts
7503
8186
  import { existsSync as existsSync2 } from "node:fs";
7504
- import { lstat as lstat2, mkdir, readFile as readFile3, rename as rename2, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
7505
- import path12 from "node:path";
8187
+ import { lstat as lstat2, mkdir, readFile as readFile4, rename as rename2, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
8188
+ import path13 from "node:path";
7506
8189
  import { createHash as createHash3, randomUUID as randomUUID4 } from "node:crypto";
7507
8190
 
7508
8191
  // ../tiny-mcp-client/src/internal.ts
@@ -7511,13 +8194,13 @@ import { PassThrough as PassThrough2 } from "node:stream";
7511
8194
 
7512
8195
  // ../mcp-oauth/src/client/auth-store-session-store.ts
7513
8196
  import crypto from "node:crypto";
7514
- import path11 from "node:path";
8197
+ import path12 from "node:path";
7515
8198
 
7516
8199
  // ../auth-store/src/encrypted-file-store.ts
7517
8200
  import { createCipheriv, createDecipheriv, randomBytes as randomBytes4, randomUUID as randomUUID3, scrypt } from "node:crypto";
7518
8201
  import { promises as fs } from "node:fs";
7519
8202
  import { homedir, hostname, userInfo } from "node:os";
7520
- import path10 from "node:path";
8203
+ import path11 from "node:path";
7521
8204
 
7522
8205
  // ../auth-store/src/error-codes.ts
7523
8206
  function hasOwnErrorCode3(error3, code) {
@@ -7546,10 +8229,13 @@ var EncryptedFileStore = class {
7546
8229
  if (input.filePath === void 0) {
7547
8230
  const homeDirectory = (input.getHomeDirectory ?? homedir)();
7548
8231
  const defaultDirectory = input.defaultDirectory ?? ".auth-store";
7549
- this.filePath = path10.join(
8232
+ const defaultFileName = input.defaultFileName ?? "credentials.enc";
8233
+ assertSafeDefaultDirectory(defaultDirectory);
8234
+ assertSafeDefaultFileName(defaultFileName);
8235
+ this.filePath = path11.join(
7550
8236
  homeDirectory,
7551
8237
  defaultDirectory,
7552
- input.defaultFileName ?? "credentials.enc"
8238
+ defaultFileName
7553
8239
  );
7554
8240
  this.symbolicLinkCheckStartPath = resolveDefaultDirectoryCheckStart(
7555
8241
  homeDirectory,
@@ -7609,7 +8295,7 @@ var EncryptedFileStore = class {
7609
8295
  authTag: authTag.toString("base64"),
7610
8296
  ciphertext: ciphertext.toString("base64")
7611
8297
  };
7612
- await this.fs.mkdir(path10.dirname(this.filePath), { recursive: true });
8298
+ await this.fs.mkdir(path11.dirname(this.filePath), { recursive: true });
7613
8299
  await this.assertCredentialPathHasNoSymbolicLinks(this.filePath);
7614
8300
  const temporaryPath = `${this.filePath}.${process.pid}.${randomUUID3()}.tmp`;
7615
8301
  let temporaryCreated = false;
@@ -7641,7 +8327,7 @@ var EncryptedFileStore = class {
7641
8327
  }
7642
8328
  }
7643
8329
  async assertCredentialPathHasNoSymbolicLinks(targetPath) {
7644
- const resolvedPath = path10.resolve(targetPath);
8330
+ const resolvedPath = path11.resolve(targetPath);
7645
8331
  const protectedPaths = getProtectedCredentialPaths(
7646
8332
  resolvedPath,
7647
8333
  this.symbolicLinkCheckStartPath
@@ -7675,27 +8361,62 @@ var EncryptedFileStore = class {
7675
8361
  };
7676
8362
  function resolveDefaultDirectoryCheckStart(homeDirectory, defaultDirectory) {
7677
8363
  const [firstSegment] = defaultDirectory.split(/[\\/]+/).filter(Boolean);
7678
- return path10.resolve(homeDirectory, firstSegment ?? ".");
8364
+ return path11.resolve(homeDirectory, firstSegment ?? ".");
7679
8365
  }
7680
8366
  function getProtectedCredentialPaths(resolvedPath, symbolicLinkCheckStartPath) {
7681
8367
  if (symbolicLinkCheckStartPath === null) {
7682
- return [path10.dirname(resolvedPath), resolvedPath];
8368
+ return getExplicitProtectedCredentialPaths(resolvedPath);
7683
8369
  }
7684
- const resolvedStartPath = path10.resolve(symbolicLinkCheckStartPath);
8370
+ const resolvedStartPath = path11.resolve(symbolicLinkCheckStartPath);
7685
8371
  if (!isPathInsideOrEqual(resolvedPath, resolvedStartPath)) {
7686
- return [path10.dirname(resolvedPath), resolvedPath];
8372
+ return [path11.dirname(resolvedPath), resolvedPath];
7687
8373
  }
7688
8374
  const protectedPaths = [resolvedStartPath];
7689
8375
  let currentPath = resolvedStartPath;
7690
- for (const segment of path10.relative(resolvedStartPath, resolvedPath).split(path10.sep).filter(Boolean)) {
7691
- currentPath = path10.join(currentPath, segment);
8376
+ for (const segment of path11.relative(resolvedStartPath, resolvedPath).split(path11.sep).filter(Boolean)) {
8377
+ currentPath = path11.join(currentPath, segment);
8378
+ protectedPaths.push(currentPath);
8379
+ }
8380
+ return protectedPaths;
8381
+ }
8382
+ function assertSafeDefaultDirectory(defaultDirectory) {
8383
+ if (path11.isAbsolute(defaultDirectory) || path11.win32.isAbsolute(defaultDirectory)) {
8384
+ throw new Error("defaultDirectory must be a relative path inside the home directory");
8385
+ }
8386
+ for (const segment of splitPathSegments(defaultDirectory)) {
8387
+ if (segment === "..") {
8388
+ throw new Error("defaultDirectory must be a relative path inside the home directory");
8389
+ }
8390
+ }
8391
+ }
8392
+ function assertSafeDefaultFileName(defaultFileName) {
8393
+ if (defaultFileName.trim().length === 0 || defaultFileName === "." || defaultFileName === ".." || splitPathSegments(defaultFileName).length !== 1) {
8394
+ throw new Error("defaultFileName must be a file name without path separators");
8395
+ }
8396
+ }
8397
+ function splitPathSegments(value) {
8398
+ return value.split("/").flatMap((segment) => segment.split("\\")).filter((segment) => segment.length > 0);
8399
+ }
8400
+ function getExplicitProtectedCredentialPaths(resolvedPath) {
8401
+ const parsed = path11.parse(resolvedPath);
8402
+ const segments = resolvedPath.slice(parsed.root.length).split(path11.sep).filter((segment) => segment.length > 0);
8403
+ if (segments.length <= 1) {
8404
+ return [resolvedPath];
8405
+ }
8406
+ const protectedPaths = [];
8407
+ let currentPath = parsed.root;
8408
+ for (const [index, segment] of segments.entries()) {
8409
+ currentPath = path11.join(currentPath, segment);
8410
+ if (index === 0) {
8411
+ continue;
8412
+ }
7692
8413
  protectedPaths.push(currentPath);
7693
8414
  }
7694
8415
  return protectedPaths;
7695
8416
  }
7696
8417
  function isPathInsideOrEqual(childPath, parentPath) {
7697
- const relativePath = path10.relative(parentPath, childPath);
7698
- return relativePath === "" || !relativePath.startsWith("..") && !path10.isAbsolute(relativePath);
8418
+ const relativePath = path11.relative(parentPath, childPath);
8419
+ return relativePath === "" || !relativePath.startsWith("..") && !path11.isAbsolute(relativePath);
7699
8420
  }
7700
8421
  async function removeIfPresent(fileSystem, filePath) {
7701
8422
  try {
@@ -7786,8 +8507,14 @@ var KeychainStore = class {
7786
8507
  account;
7787
8508
  constructor(input) {
7788
8509
  this.runCommand = input.runCommand ?? runSecurityCommand;
7789
- this.service = input.service;
7790
- this.account = input.account;
8510
+ this.service = input.service.trim();
8511
+ this.account = input.account.trim();
8512
+ if (this.service.length === 0) {
8513
+ throw new Error("Keychain service must not be empty");
8514
+ }
8515
+ if (this.account.length === 0) {
8516
+ throw new Error("Keychain account must not be empty");
8517
+ }
7791
8518
  }
7792
8519
  async get() {
7793
8520
  const result = await this.executeSecurityCommand(
@@ -7814,10 +8541,10 @@ var KeychainStore = class {
7814
8541
  "-a",
7815
8542
  this.account,
7816
8543
  "-U",
7817
- "-w"
8544
+ "-w",
8545
+ value
7818
8546
  ],
7819
- "store secret in macOS Keychain",
7820
- { stdin: value }
8547
+ "store secret in macOS Keychain"
7821
8548
  );
7822
8549
  if (getCommandExitCode(result) !== 0) {
7823
8550
  throw createSecurityCliFailure("store secret in macOS Keychain", result);
@@ -7962,13 +8689,14 @@ function createSecretStore(input) {
7962
8689
  function resolveBackend(input) {
7963
8690
  const envVar = input.backendEnvVar ?? DEFAULT_BACKEND_ENV_VAR;
7964
8691
  const configuredBackend = input.backend ?? getOwnEnvValue(input.env, envVar) ?? getOwnEnvValue(process.env, envVar);
7965
- if (configuredBackend === "keychain") {
8692
+ const backend = configuredBackend?.trim();
8693
+ if (backend === "keychain") {
7966
8694
  return "keychain";
7967
8695
  }
7968
- if (configuredBackend === void 0 || configuredBackend === "file") {
8696
+ if (backend === void 0 || backend === "file") {
7969
8697
  return "file";
7970
8698
  }
7971
- throw new Error(`Unsupported auth store backend: ${configuredBackend}`);
8699
+ throw new Error(`Unsupported auth store backend: ${backend}`);
7972
8700
  }
7973
8701
  function getOwnEnvValue(env, key2) {
7974
8702
  return env !== void 0 && Object.prototype.hasOwnProperty.call(env, key2) ? env[key2] : void 0;
@@ -7993,6 +8721,7 @@ var DEFAULT_KEYCHAIN_SERVICE = "poe-code-mcp-oauth";
7993
8721
  var DEFAULT_CLIENT_FILE_SALT = "poe-code:mcp-oauth:clients:v1";
7994
8722
  var DEFAULT_CLIENT_FILE_DIRECTORY = ".poe-code/mcp-oauth/clients";
7995
8723
  var DEFAULT_CLIENT_KEYCHAIN_SERVICE = "poe-code-mcp-oauth-clients";
8724
+ var MAX_JS_DATE_MS = 864e13;
7996
8725
  function createAuthStoreSessionStore(options = {}) {
7997
8726
  return {
7998
8727
  async load(resource) {
@@ -8002,10 +8731,10 @@ function createAuthStoreSessionStore(options = {}) {
8002
8731
  return null;
8003
8732
  }
8004
8733
  const parsed = JSON.parse(value);
8005
- if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
8734
+ if (isStoredOAuthSession(parsed)) {
8006
8735
  return parsed;
8007
8736
  }
8008
- throw new Error("Stored OAuth session must be a JSON object");
8737
+ throw new Error("Stored OAuth session must match the expected shape");
8009
8738
  },
8010
8739
  async save(resource, session) {
8011
8740
  const store = createResourceSecretStore(resource, options);
@@ -8049,10 +8778,10 @@ function createAuthStoreClientStore(options) {
8049
8778
  function createNamedSecretStore(key2, options, defaults2) {
8050
8779
  const hash = crypto.createHash("sha256").update(key2).digest("hex");
8051
8780
  const configuredFilePath = options.fileStore?.filePath;
8052
- const parsedFilePath = configuredFilePath === void 0 ? null : path11.parse(configuredFilePath);
8781
+ const parsedFilePath = configuredFilePath === void 0 ? null : path12.parse(configuredFilePath);
8053
8782
  const fileStore = {
8054
8783
  ...options.fileStore,
8055
- filePath: parsedFilePath === null ? void 0 : path11.join(
8784
+ filePath: parsedFilePath === null ? void 0 : path12.join(
8056
8785
  parsedFilePath.dir,
8057
8786
  `${parsedFilePath.name}-${hash}${parsedFilePath.ext || ".enc"}`
8058
8787
  ),
@@ -8068,28 +8797,20 @@ function createNamedSecretStore(key2, options, defaults2) {
8068
8797
  return createSecretStore({ ...options, fileStore, keychainStore }).store;
8069
8798
  }
8070
8799
  function createResourceSecretStore(resource, options) {
8071
- return createNamedSecretStore(
8072
- canonicalizeResourceIndicator(resource),
8073
- options,
8074
- {
8075
- salt: DEFAULT_FILE_SALT,
8076
- directory: DEFAULT_FILE_DIRECTORY,
8077
- service: DEFAULT_KEYCHAIN_SERVICE,
8078
- accountPrefix: "provider"
8079
- }
8080
- );
8800
+ return createNamedSecretStore(canonicalizeResourceIndicator(resource), options, {
8801
+ salt: DEFAULT_FILE_SALT,
8802
+ directory: DEFAULT_FILE_DIRECTORY,
8803
+ service: DEFAULT_KEYCHAIN_SERVICE,
8804
+ accountPrefix: "provider"
8805
+ });
8081
8806
  }
8082
8807
  function createIssuerSecretStore(issuer, options) {
8083
- return createNamedSecretStore(
8084
- issuer,
8085
- options,
8086
- {
8087
- salt: DEFAULT_CLIENT_FILE_SALT,
8088
- directory: DEFAULT_CLIENT_FILE_DIRECTORY,
8089
- service: DEFAULT_CLIENT_KEYCHAIN_SERVICE,
8090
- accountPrefix: "issuer"
8091
- }
8092
- );
8808
+ return createNamedSecretStore(issuer, options, {
8809
+ salt: DEFAULT_CLIENT_FILE_SALT,
8810
+ directory: DEFAULT_CLIENT_FILE_DIRECTORY,
8811
+ service: DEFAULT_CLIENT_KEYCHAIN_SERVICE,
8812
+ accountPrefix: "issuer"
8813
+ });
8093
8814
  }
8094
8815
  function isObjectRecord(value) {
8095
8816
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -8101,6 +8822,50 @@ function getOwnString(record, key2) {
8101
8822
  const value = getOwnEntry4(record, key2);
8102
8823
  return typeof value === "string" ? value : void 0;
8103
8824
  }
8825
+ function isStoredOAuthSession(value) {
8826
+ if (!isObjectRecord(value)) {
8827
+ return false;
8828
+ }
8829
+ return isNonBlankOwnString(value, "resource") && isNonBlankOwnString(value, "authorizationServer") && isStoredOAuthClient(getOwnEntry4(value, "client")) && isStoredOAuthDiscovery(getOwnEntry4(value, "discovery")) && isStoredOAuthTokensOrMissing(getOwnEntry4(value, "tokens"));
8830
+ }
8831
+ function isStoredOAuthClient(value) {
8832
+ if (!isObjectRecord(value) || !isNonBlankOwnString(value, "clientId")) {
8833
+ return false;
8834
+ }
8835
+ const clientSecret = getOwnEntry4(value, "clientSecret");
8836
+ return clientSecret === void 0 || typeof clientSecret === "string" && clientSecret.trim().length > 0;
8837
+ }
8838
+ function isStoredOAuthDiscovery(value) {
8839
+ if (!isObjectRecord(value)) {
8840
+ return false;
8841
+ }
8842
+ return isNonBlankOwnString(value, "resourceMetadataUrl") && isObjectRecord(getOwnEntry4(value, "resourceMetadata")) && isObjectRecord(getOwnEntry4(value, "authorizationServerMetadata"));
8843
+ }
8844
+ function isStoredOAuthTokensOrMissing(value) {
8845
+ if (value === void 0) {
8846
+ return true;
8847
+ }
8848
+ if (!isObjectRecord(value)) {
8849
+ return false;
8850
+ }
8851
+ if (!isNonBlankOwnString(value, "accessToken") || getOwnString(value, "tokenType") !== "Bearer") {
8852
+ return false;
8853
+ }
8854
+ const expiresAt = getOwnEntry4(value, "expiresAt");
8855
+ if (expiresAt !== null && (typeof expiresAt !== "number" || !Number.isSafeInteger(expiresAt) || expiresAt > MAX_JS_DATE_MS || !Number.isFinite(new Date(expiresAt).getTime()))) {
8856
+ return false;
8857
+ }
8858
+ const refreshToken = getOwnEntry4(value, "refreshToken");
8859
+ if (refreshToken !== void 0 && (typeof refreshToken !== "string" || refreshToken.trim().length === 0)) {
8860
+ return false;
8861
+ }
8862
+ const scope = getOwnEntry4(value, "scope");
8863
+ return scope === void 0 || typeof scope === "string" && scope.trim().length > 0;
8864
+ }
8865
+ function isNonBlankOwnString(record, key2) {
8866
+ const value = getOwnString(record, key2);
8867
+ return value !== void 0 && value.trim().length > 0;
8868
+ }
8104
8869
 
8105
8870
  // ../mcp-oauth/src/client/default-oauth-client-provider.ts
8106
8871
  import { URL as URL2 } from "node:url";
@@ -8211,9 +8976,7 @@ function waitForAuthorizationCode(server, authorizationUrl, options, callbackPat
8211
8976
  } catch (error3) {
8212
8977
  res.writeHead(400);
8213
8978
  res.end(error3 instanceof Error ? error3.message : "Invalid OAuth callback");
8214
- if (callbackParameters.error === null) {
8215
- settle(() => reject(error3 instanceof Error ? error3 : new Error(String(error3))));
8216
- }
8979
+ settle(() => reject(error3 instanceof Error ? error3 : new Error(String(error3))));
8217
8980
  return;
8218
8981
  }
8219
8982
  const authorizationError = callbackParameters.error;
@@ -8225,7 +8988,10 @@ function waitForAuthorizationCode(server, authorizationUrl, options, callbackPat
8225
8988
  return;
8226
8989
  }
8227
8990
  try {
8228
- const code = validateAuthorizationCallbackParameters(callbackParameters, expectedAuthorization);
8991
+ const code = validateAuthorizationCallbackParameters(
8992
+ callbackParameters,
8993
+ expectedAuthorization
8994
+ );
8229
8995
  res.writeHead(200, { "Content-Type": "text/html" });
8230
8996
  res.end(buildSuccessPage(options.landingPage));
8231
8997
  settle(() => resolve(code));
@@ -8248,7 +9014,10 @@ function waitForAuthorizationCode(server, authorizationUrl, options, callbackPat
8248
9014
  const description = callbackParameters.errorDescription ?? callbackParameters.error;
8249
9015
  throw createAuthorizationError(callbackParameters.error, description);
8250
9016
  }
8251
- const code = validateAuthorizationCallbackParameters(callbackParameters, expectedAuthorization);
9017
+ const code = validateAuthorizationCallbackParameters(
9018
+ callbackParameters,
9019
+ expectedAuthorization
9020
+ );
8252
9021
  settle(() => resolve(code));
8253
9022
  } catch (error3) {
8254
9023
  settle(() => reject(error3 instanceof Error ? error3 : new Error(String(error3))));
@@ -8353,6 +9122,7 @@ function generateCodeChallenge(verifier) {
8353
9122
  }
8354
9123
 
8355
9124
  // ../mcp-oauth/src/client/token-endpoint.ts
9125
+ var MAX_JS_DATE_MS2 = 864e13;
8356
9126
  var OAuthError = class extends Error {
8357
9127
  error;
8358
9128
  errorDescription;
@@ -8430,22 +9200,32 @@ async function requestTokens(input) {
8430
9200
  if (typeof accessToken !== "string" || accessToken.trim().length === 0) {
8431
9201
  throw new Error("OAuth token response missing access_token");
8432
9202
  }
9203
+ const normalizedAccessToken = accessToken.trim();
8433
9204
  const tokenType = normalizeBearerTokenType(getOwnEntry6(payload, "token_type"));
8434
9205
  if (tokenType === null) {
8435
9206
  throw new Error("OAuth token response missing token_type=Bearer");
8436
9207
  }
8437
9208
  const expiresIn = getOwnEntry6(payload, "expires_in");
8438
- if (typeof expiresIn === "number" && Number.isFinite(expiresIn) && expiresIn < 0) {
8439
- throw new Error("OAuth token response has invalid expires_in");
9209
+ let expiresAt = null;
9210
+ if (expiresIn !== void 0) {
9211
+ if (typeof expiresIn !== "number" || !Number.isFinite(expiresIn) || !Number.isInteger(expiresIn) || expiresIn < 0) {
9212
+ throw new Error("OAuth token response has invalid expires_in");
9213
+ }
9214
+ expiresAt = input.now() + expiresIn * 1e3;
9215
+ if (!Number.isSafeInteger(expiresAt) || expiresAt > MAX_JS_DATE_MS2 || !Number.isFinite(new Date(expiresAt).getTime())) {
9216
+ throw new Error("OAuth token response has invalid expires_in");
9217
+ }
8440
9218
  }
8441
9219
  const refreshToken = getOwnEntry6(payload, "refresh_token");
8442
9220
  const scope = getOwnEntry6(payload, "scope");
9221
+ const normalizedRefreshToken = typeof refreshToken === "string" && refreshToken.trim().length > 0 ? refreshToken.trim() : void 0;
9222
+ const normalizedScope = typeof scope === "string" && scope.trim().length > 0 ? scope.trim() : void 0;
8443
9223
  return {
8444
- accessToken,
8445
- refreshToken: typeof refreshToken === "string" && refreshToken.length > 0 ? refreshToken : void 0,
9224
+ accessToken: normalizedAccessToken,
9225
+ refreshToken: normalizedRefreshToken === void 0 ? void 0 : normalizedRefreshToken,
8446
9226
  tokenType,
8447
- expiresAt: typeof expiresIn === "number" && Number.isFinite(expiresIn) ? input.now() + expiresIn * 1e3 : null,
8448
- scope: typeof scope === "string" && scope.length > 0 ? scope : void 0
9227
+ expiresAt,
9228
+ scope: normalizedScope === void 0 ? void 0 : normalizedScope
8449
9229
  };
8450
9230
  }
8451
9231
  async function readOAuthJsonObjectResponse(response) {
@@ -8496,6 +9276,7 @@ function normalizeBearerTokenType(value) {
8496
9276
  }
8497
9277
 
8498
9278
  // ../mcp-oauth/src/client/default-oauth-client-provider.ts
9279
+ var MAX_JS_DATE_MS3 = 864e13;
8499
9280
  function createOAuthClientProvider(options) {
8500
9281
  if (isProviderOptions(options)) {
8501
9282
  return options.provider;
@@ -8660,7 +9441,12 @@ function createDefaultOAuthClientProvider(options) {
8660
9441
  });
8661
9442
  let resolvedClient = null;
8662
9443
  try {
8663
- resolvedClient = await resolveClient(currentSession, discovery, loopback.redirectUri, fetch2);
9444
+ resolvedClient = await resolveClient(
9445
+ currentSession,
9446
+ discovery,
9447
+ loopback.redirectUri,
9448
+ fetch2
9449
+ );
8664
9450
  const sessionWithoutTokens = {
8665
9451
  resource,
8666
9452
  authorizationServer: discovery.authorizationServer,
@@ -8727,28 +9513,26 @@ function createDefaultOAuthClientProvider(options) {
8727
9513
  return finalPromise;
8728
9514
  }
8729
9515
  async function resolveClient(existingSession, discovery, redirectUri, fetch2) {
9516
+ const configuredClient = normalizeConfiguredClient(options.client);
8730
9517
  if (options.client.mode === "static") {
9518
+ if (configuredClient === null) {
9519
+ throw new Error("OAuth client_id must not be blank");
9520
+ }
8731
9521
  return {
8732
9522
  kind: "static",
8733
9523
  fromStoredRegistration: false,
8734
- client: {
8735
- clientId: options.client.clientId,
8736
- clientSecret: options.client.clientSecret
8737
- }
9524
+ client: configuredClient
8738
9525
  };
8739
9526
  }
8740
9527
  const registrationEndpoint = getOwnString2(
8741
9528
  discovery.authorizationServerMetadata,
8742
9529
  "registration_endpoint"
8743
9530
  );
8744
- if (registrationEndpoint === void 0 && options.client.clientId !== void 0) {
9531
+ if (registrationEndpoint === void 0 && configuredClient !== null) {
8745
9532
  return {
8746
9533
  kind: "static",
8747
9534
  fromStoredRegistration: false,
8748
- client: {
8749
- clientId: options.client.clientId,
8750
- clientSecret: options.client.clientSecret
8751
- }
9535
+ client: configuredClient
8752
9536
  };
8753
9537
  }
8754
9538
  const storedClient = await loadRegisteredClient(discovery.authorizationServer);
@@ -8770,7 +9554,7 @@ function createDefaultOAuthClientProvider(options) {
8770
9554
  throw new Error("Authorization server metadata is missing registration_endpoint");
8771
9555
  }
8772
9556
  if (existingSession !== null && existingSession.client.clientId.length > 0) {
8773
- const isConfiguredStaticFallback = options.client.clientId !== void 0 && existingSession.client.clientId === options.client.clientId && existingSession.client.clientSecret === options.client.clientSecret;
9557
+ const isConfiguredStaticFallback = configuredClient !== null && existingSession.client.clientId === configuredClient.clientId && existingSession.client.clientSecret === configuredClient.clientSecret;
8774
9558
  if (!isConfiguredStaticFallback) {
8775
9559
  await saveRegisteredClient(discovery.authorizationServer, existingSession.client);
8776
9560
  return {
@@ -8798,8 +9582,8 @@ function createDefaultOAuthClientProvider(options) {
8798
9582
  }
8799
9583
  const clientSecret = getOwnString2(payload, "client_secret");
8800
9584
  const registeredClient = {
8801
- clientId,
8802
- clientSecret: clientSecret !== void 0 && clientSecret.length > 0 ? clientSecret : void 0
9585
+ clientId: clientId.trim(),
9586
+ clientSecret: clientSecret !== void 0 && clientSecret.trim().length > 0 ? clientSecret.trim() : void 0
8803
9587
  };
8804
9588
  await saveRegisteredClient(discovery.authorizationServer, registeredClient);
8805
9589
  return {
@@ -8912,14 +9696,16 @@ function normalizeStoredClient(value) {
8912
9696
  if (clientId === void 0 || clientId.trim().length === 0) {
8913
9697
  return null;
8914
9698
  }
9699
+ const normalizedClientId = clientId.trim();
8915
9700
  const clientSecret = getOwnEntry7(value, "clientSecret");
8916
9701
  if (clientSecret === void 0) {
8917
- return { clientId };
9702
+ return { clientId: normalizedClientId };
8918
9703
  }
8919
9704
  if (typeof clientSecret !== "string" || clientSecret.trim().length === 0) {
8920
9705
  return null;
8921
9706
  }
8922
- return { clientId, clientSecret };
9707
+ const normalizedClientSecret = clientSecret.trim();
9708
+ return { clientId: normalizedClientId, clientSecret: normalizedClientSecret };
8923
9709
  }
8924
9710
  function normalizeStoredTokens(value) {
8925
9711
  if (value === void 0 || !isObjectRecord3(value)) {
@@ -8930,20 +9716,45 @@ function normalizeStoredTokens(value) {
8930
9716
  const expiresAt = getOwnEntry7(value, "expiresAt");
8931
9717
  const refreshToken = getOwnEntry7(value, "refreshToken");
8932
9718
  const scope = getOwnString2(value, "scope");
8933
- const normalizedRefreshToken = typeof refreshToken === "string" ? refreshToken : void 0;
8934
- 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)) {
9719
+ const normalizedAccessToken = accessToken?.trim();
9720
+ const normalizedRefreshToken = typeof refreshToken === "string" ? refreshToken.trim() : void 0;
9721
+ const normalizedScope = scope?.trim();
9722
+ 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)) {
8935
9723
  return void 0;
8936
9724
  }
8937
9725
  return {
8938
- accessToken,
9726
+ accessToken: normalizedAccessToken,
8939
9727
  tokenType,
8940
9728
  expiresAt,
8941
9729
  ...normalizedRefreshToken === void 0 ? {} : { refreshToken: normalizedRefreshToken },
8942
- ...scope === void 0 || scope.length === 0 ? {} : { scope }
9730
+ ...normalizedScope === void 0 || normalizedScope.length === 0 ? {} : { scope: normalizedScope }
8943
9731
  };
8944
9732
  }
8945
9733
  function getClientMetadata(client) {
8946
- return client.metadata;
9734
+ if (client.metadata === void 0) {
9735
+ return void 0;
9736
+ }
9737
+ return {
9738
+ clientName: normalizeOptionalOAuthString(client.metadata.clientName),
9739
+ scope: normalizeOptionalOAuthString(client.metadata.scope),
9740
+ softwareId: normalizeOptionalOAuthString(client.metadata.softwareId),
9741
+ softwareVersion: normalizeOptionalOAuthString(client.metadata.softwareVersion)
9742
+ };
9743
+ }
9744
+ function normalizeConfiguredClient(client) {
9745
+ const clientId = normalizeOptionalOAuthString(client.clientId);
9746
+ if (clientId === void 0) {
9747
+ return null;
9748
+ }
9749
+ const clientSecret = normalizeOptionalOAuthString(client.clientSecret);
9750
+ return clientSecret === void 0 ? { clientId } : { clientId, clientSecret };
9751
+ }
9752
+ function normalizeOptionalOAuthString(value) {
9753
+ if (value === void 0) {
9754
+ return void 0;
9755
+ }
9756
+ const trimmed = value.trim();
9757
+ return trimmed.length === 0 ? void 0 : trimmed;
8947
9758
  }
8948
9759
  function getOwnEntry7(record, key2) {
8949
9760
  return Object.prototype.hasOwnProperty.call(record, key2) ? record[key2] : void 0;
@@ -8972,11 +9783,7 @@ function buildAuthorizationUrl(input) {
8972
9783
  "authorization_endpoint",
8973
9784
  "Authorization server metadata"
8974
9785
  );
8975
- const issuer = requireOwnString(
8976
- input.metadata,
8977
- "issuer",
8978
- "Authorization server metadata"
8979
- );
9786
+ const issuer = requireOwnString(input.metadata, "issuer", "Authorization server metadata");
8980
9787
  const url = new URL2(authorizationEndpoint);
8981
9788
  const resource = canonicalizeResourceIndicator(input.resource);
8982
9789
  const state = createAuthorizationState({
@@ -9584,7 +10391,7 @@ var McpClient = class {
9584
10391
  await onToolsChanged();
9585
10392
  });
9586
10393
  messageLayer.onNotification("notifications/resources/list_changed", async () => {
9587
- if (onResourcesChanged === void 0) {
10394
+ if (onResourcesChanged === void 0 || this.currentServerCapabilities?.resources?.listChanged !== true) {
9588
10395
  return;
9589
10396
  }
9590
10397
  await onResourcesChanged();
@@ -9603,7 +10410,7 @@ var McpClient = class {
9603
10410
  await onResourceUpdated(uri);
9604
10411
  });
9605
10412
  messageLayer.onNotification("notifications/prompts/list_changed", async () => {
9606
- if (onPromptsChanged === void 0) {
10413
+ if (onPromptsChanged === void 0 || this.currentServerCapabilities?.prompts?.listChanged !== true) {
9607
10414
  return;
9608
10415
  }
9609
10416
  await onPromptsChanged();
@@ -9834,7 +10641,11 @@ var McpClient = class {
9834
10641
  throw new Error("Server does not support resources");
9835
10642
  }
9836
10643
  const requestParams = params17.cursor === void 0 ? void 0 : { cursor: params17.cursor };
9837
- return await messageLayer.sendRequest("resources/list", requestParams);
10644
+ const result = await messageLayer.sendRequest("resources/list", requestParams);
10645
+ if (!isResourcesListResult(result)) {
10646
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid resources/list result");
10647
+ }
10648
+ return result;
9838
10649
  }
9839
10650
  async listResourceTemplates(params17 = {}) {
9840
10651
  const messageLayer = this.getMessageLayerOrThrow();
@@ -9843,7 +10654,11 @@ var McpClient = class {
9843
10654
  throw new Error("Server does not support resources");
9844
10655
  }
9845
10656
  const requestParams = params17.cursor === void 0 ? void 0 : { cursor: params17.cursor };
9846
- return await messageLayer.sendRequest("resources/templates/list", requestParams);
10657
+ const result = await messageLayer.sendRequest("resources/templates/list", requestParams);
10658
+ if (!isResourceTemplatesListResult(result)) {
10659
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid resources/templates/list result");
10660
+ }
10661
+ return result;
9847
10662
  }
9848
10663
  async readResource(params17) {
9849
10664
  const messageLayer = this.getMessageLayerOrThrow();
@@ -9851,7 +10666,11 @@ var McpClient = class {
9851
10666
  if (serverCapabilities.resources === void 0) {
9852
10667
  throw new Error("Server does not support resources");
9853
10668
  }
9854
- return await messageLayer.sendRequest("resources/read", params17);
10669
+ const result = await messageLayer.sendRequest("resources/read", params17);
10670
+ if (!isReadResourceResult(result)) {
10671
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid resources/read result");
10672
+ }
10673
+ return result;
9855
10674
  }
9856
10675
  async subscribe(uri) {
9857
10676
  const messageLayer = this.getMessageLayerOrThrow();
@@ -9886,7 +10705,11 @@ var McpClient = class {
9886
10705
  if (serverCapabilities.prompts === void 0) {
9887
10706
  throw new Error("Server does not support prompts");
9888
10707
  }
9889
- return await messageLayer.sendRequest("prompts/get", params17);
10708
+ const result = await messageLayer.sendRequest("prompts/get", params17);
10709
+ if (!isGetPromptResult(result)) {
10710
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid prompts/get result");
10711
+ }
10712
+ return result;
9890
10713
  }
9891
10714
  async complete(params17) {
9892
10715
  const messageLayer = this.getMessageLayerOrThrow();
@@ -9894,7 +10717,11 @@ var McpClient = class {
9894
10717
  if (serverCapabilities.completions === void 0) {
9895
10718
  throw new Error("Server does not support completions");
9896
10719
  }
9897
- return await messageLayer.sendRequest("completion/complete", params17);
10720
+ const result = await messageLayer.sendRequest("completion/complete", params17);
10721
+ if (!isCompleteResult(result)) {
10722
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid completion/complete result");
10723
+ }
10724
+ return result;
9898
10725
  }
9899
10726
  async setLogLevel(level) {
9900
10727
  const messageLayer = this.getMessageLayerOrThrow();
@@ -10885,6 +11712,44 @@ function isCallToolResult(value) {
10885
11712
  function isToolsListResult(value) {
10886
11713
  return isObjectRecord5(value) && Array.isArray(value.tools) && (value.nextCursor === void 0 || typeof value.nextCursor === "string");
10887
11714
  }
11715
+ function isResourcesListResult(value) {
11716
+ return isObjectRecord5(value) && Array.isArray(value.resources) && value.resources.every(isResource) && (value.nextCursor === void 0 || typeof value.nextCursor === "string");
11717
+ }
11718
+ function isResourceTemplatesListResult(value) {
11719
+ return isObjectRecord5(value) && Array.isArray(value.resourceTemplates) && value.resourceTemplates.every(isResourceTemplate) && (value.nextCursor === void 0 || typeof value.nextCursor === "string");
11720
+ }
11721
+ function isReadResourceResult(value) {
11722
+ return isObjectRecord5(value) && Array.isArray(value.contents) && value.contents.every(isResourceContents);
11723
+ }
11724
+ function isGetPromptResult(value) {
11725
+ return isObjectRecord5(value) && (value.description === void 0 || typeof value.description === "string") && Array.isArray(value.messages) && value.messages.every(isPromptMessage);
11726
+ }
11727
+ function isCompleteResult(value) {
11728
+ 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");
11729
+ }
11730
+ function isResource(value) {
11731
+ 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");
11732
+ }
11733
+ function isResourceTemplate(value) {
11734
+ 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");
11735
+ }
11736
+ function isResourceContents(value) {
11737
+ if (!isObjectRecord5(value) || typeof value.uri !== "string") {
11738
+ return false;
11739
+ }
11740
+ if (value.mimeType !== void 0 && typeof value.mimeType !== "string") {
11741
+ return false;
11742
+ }
11743
+ const hasText = value.text !== void 0;
11744
+ const hasBlob = value.blob !== void 0;
11745
+ if (!hasText && !hasBlob) {
11746
+ return false;
11747
+ }
11748
+ return (!hasText || typeof value.text === "string") && (!hasBlob || typeof value.blob === "string");
11749
+ }
11750
+ function isPromptMessage(value) {
11751
+ return isObjectRecord5(value) && (value.role === "user" || value.role === "assistant") && isContentItem(value.content);
11752
+ }
10888
11753
  function isContentItem(value) {
10889
11754
  if (!isObjectRecord5(value)) {
10890
11755
  return false;
@@ -10898,7 +11763,7 @@ function isContentItem(value) {
10898
11763
  if (value.type !== "resource" || !isObjectRecord5(value.resource)) {
10899
11764
  return false;
10900
11765
  }
10901
- 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");
11766
+ return isResourceContents(value.resource);
10902
11767
  }
10903
11768
  function hasOwn(value, property) {
10904
11769
  return Object.prototype.hasOwnProperty.call(value, property);
@@ -11038,13 +11903,13 @@ function convertJsonSchema(schema) {
11038
11903
  }
11039
11904
  return convertSchema(schema, schema, []);
11040
11905
  }
11041
- function convertSchema(schema, root, path24) {
11042
- const resolvedSchema = resolveReferencedSchema(schema, root, path24);
11906
+ function convertSchema(schema, root, path25) {
11907
+ const resolvedSchema = resolveReferencedSchema(schema, root, path25);
11043
11908
  const normalizedSchema = normalizeNullability(resolvedSchema);
11044
11909
  const composition = getComposition(normalizedSchema.schema);
11045
11910
  if (Array.isArray(normalizedSchema.schema.type)) {
11046
11911
  throw new Error(
11047
- `JSON Schema "${formatJsonSchemaPath(path24)}" has an unsupported type "${formatJsonSchemaType(
11912
+ `JSON Schema "${formatJsonSchemaPath(path25)}" has an unsupported type "${formatJsonSchemaType(
11048
11913
  normalizedSchema.schema.type
11049
11914
  )}". Supported: string, number, integer, boolean, array, object.`
11050
11915
  );
@@ -11056,13 +11921,13 @@ function convertSchema(schema, root, path24) {
11056
11921
  return convertEnumSchema(resolvedSchema, normalizedSchema.nullable);
11057
11922
  }
11058
11923
  if (composition !== void 0) {
11059
- return convertCompositionSchema(normalizedSchema.schema, root, normalizedSchema.nullable, path24);
11924
+ return convertCompositionSchema(normalizedSchema.schema, root, normalizedSchema.nullable, path25);
11060
11925
  }
11061
11926
  if (isRecordSchema(normalizedSchema.schema)) {
11062
11927
  return applyMetadata(
11063
11928
  S.Record(
11064
11929
  convertSchema(normalizedSchema.schema.additionalProperties, root, [
11065
- ...path24,
11930
+ ...path25,
11066
11931
  "additionalProperties"
11067
11932
  ])
11068
11933
  ),
@@ -11111,12 +11976,12 @@ function convertSchema(schema, root, path24) {
11111
11976
  if (normalizedSchema.schema.items === void 0) {
11112
11977
  throw new Error(
11113
11978
  `JSON Schema "${formatJsonSchemaPath(
11114
- path24
11979
+ path25
11115
11980
  )}" is an array but is missing the "items" field. Add "items": { ... } to declare the element type.`
11116
11981
  );
11117
11982
  }
11118
11983
  return S.Array(
11119
- convertSchema(normalizedSchema.schema.items, root, [...path24, "items"]),
11984
+ convertSchema(normalizedSchema.schema.items, root, [...path25, "items"]),
11120
11985
  createCommonOptions(
11121
11986
  normalizedSchema.schema,
11122
11987
  normalizedSchema.nullable,
@@ -11126,7 +11991,7 @@ function convertSchema(schema, root, path24) {
11126
11991
  case "object":
11127
11992
  return convertObjectSchema(normalizedSchema.schema, root, {
11128
11993
  nullable: normalizedSchema.nullable,
11129
- path: path24
11994
+ path: path25
11130
11995
  });
11131
11996
  case "null":
11132
11997
  return applyMetadata(S.Json(), normalizedSchema.schema, {
@@ -11141,12 +12006,12 @@ function convertSchema(schema, root, path24) {
11141
12006
  }
11142
12007
  throw new Error(
11143
12008
  `JSON Schema "${formatJsonSchemaPath(
11144
- path24
12009
+ path25
11145
12010
  )}" must declare one of: "type", "enum", "const", "oneOf", "anyOf", or "allOf".`
11146
12011
  );
11147
12012
  }
11148
12013
  throw new Error(
11149
- `JSON Schema "${formatJsonSchemaPath(path24)}" has an unsupported type "${formatJsonSchemaType(
12014
+ `JSON Schema "${formatJsonSchemaPath(path25)}" has an unsupported type "${formatJsonSchemaType(
11150
12015
  normalizedSchema.schema.type
11151
12016
  )}". Supported: string, number, integer, boolean, array, object.`
11152
12017
  );
@@ -11190,21 +12055,21 @@ function convertEnumSchema(schema, nullable) {
11190
12055
  )
11191
12056
  });
11192
12057
  }
11193
- function convertCompositionSchema(schema, root, nullable, path24) {
12058
+ function convertCompositionSchema(schema, root, nullable, path25) {
11194
12059
  const composition = getComposition(schema);
11195
12060
  const branchSchemas = composition?.branches ?? [];
11196
12061
  const keyword = composition?.keyword ?? "oneOf";
11197
12062
  const branches = branchSchemas.map(
11198
- (branch, index) => resolveReferencedSchema(branch, root, [...path24, keyword, String(index)])
12063
+ (branch, index) => resolveReferencedSchema(branch, root, [...path25, keyword, String(index)])
11199
12064
  );
11200
- const discriminator = findDiscriminator(branches, root, path24);
12065
+ const discriminator = findDiscriminator(branches, root, path25);
11201
12066
  if (discriminator !== void 0) {
11202
12067
  const convertedBranches = Object.fromEntries(
11203
12068
  branches.map((branch, index) => [
11204
12069
  getDiscriminatorLiteral(branch, discriminator, root),
11205
12070
  convertObjectSchema(branch, root, {
11206
12071
  omitProperty: discriminator,
11207
- path: [...path24, keyword, String(index)]
12072
+ path: [...path25, keyword, String(index)]
11208
12073
  })
11209
12074
  ])
11210
12075
  );
@@ -11223,7 +12088,7 @@ function convertCompositionSchema(schema, root, nullable, path24) {
11223
12088
  S.Union(
11224
12089
  branches.map(
11225
12090
  (branch, index) => convertObjectSchema(branch, root, {
11226
- path: [...path24, keyword, String(index)]
12091
+ path: [...path25, keyword, String(index)]
11227
12092
  })
11228
12093
  )
11229
12094
  ),
@@ -11337,11 +12202,11 @@ function getComposition(schema) {
11337
12202
  }
11338
12203
  return void 0;
11339
12204
  }
11340
- function formatJsonSchemaPath(path24) {
11341
- if (path24.length === 0) {
12205
+ function formatJsonSchemaPath(path25) {
12206
+ if (path25.length === 0) {
11342
12207
  return "#";
11343
12208
  }
11344
- return `#/${path24.map(escapeJsonPointerSegment).join("/")}`;
12209
+ return `#/${path25.map(escapeJsonPointerSegment).join("/")}`;
11345
12210
  }
11346
12211
  function formatJsonSchemaType(type2) {
11347
12212
  return Array.isArray(type2) ? JSON.stringify(type2) : String(type2);
@@ -11357,11 +12222,11 @@ function isRecordSchema(schema) {
11357
12222
  const propertyKeys = Object.keys(schema.properties ?? {});
11358
12223
  return schema.type === "object" && propertyKeys.length === 0 && typeof schema.additionalProperties === "object" && schema.additionalProperties !== null;
11359
12224
  }
11360
- function findDiscriminator(branches, root, path24) {
12225
+ function findDiscriminator(branches, root, path25) {
11361
12226
  const [firstBranch] = branches;
11362
12227
  if (firstBranch === void 0) {
11363
12228
  throw new Error(
11364
- `JSON Schema "${formatJsonSchemaPath(path24)}" uses oneOf/anyOf/allOf but has no branches.`
12229
+ `JSON Schema "${formatJsonSchemaPath(path25)}" uses oneOf/anyOf/allOf but has no branches.`
11365
12230
  );
11366
12231
  }
11367
12232
  const candidateKeys = Object.keys(firstBranch.properties ?? {});
@@ -11401,19 +12266,19 @@ function getDiscriminatorLiteral(branch, key2, root) {
11401
12266
  }
11402
12267
  return void 0;
11403
12268
  }
11404
- function resolveReferencedSchema(schema, root, path24) {
12269
+ function resolveReferencedSchema(schema, root, path25) {
11405
12270
  if (schema.$ref === void 0) {
11406
12271
  return schema;
11407
12272
  }
11408
12273
  const resolvedTarget = resolveLocalRef(root, schema.$ref);
11409
12274
  if (resolvedTarget === void 0) {
11410
12275
  throw new Error(
11411
- `JSON Schema "${formatJsonSchemaPath(path24)}" uses "$ref": ${schema.$ref}. toolcraft only supports internal refs like "#/components/schemas/Foo".`
12276
+ `JSON Schema "${formatJsonSchemaPath(path25)}" uses "$ref": ${schema.$ref}. toolcraft only supports internal refs like "#/components/schemas/Foo".`
11412
12277
  );
11413
12278
  }
11414
12279
  const { $ref: ignoredRef, ...siblingKeywords } = schema;
11415
12280
  void ignoredRef;
11416
- const resolvedSchema = resolveReferencedSchema(resolvedTarget, root, path24);
12281
+ const resolvedSchema = resolveReferencedSchema(resolvedTarget, root, path25);
11417
12282
  if (Object.keys(siblingKeywords).length === 0) {
11418
12283
  return resolvedSchema;
11419
12284
  }
@@ -11437,9 +12302,9 @@ function mergeJsonSchemas(base, overlay) {
11437
12302
  ...mergedRequired === void 0 ? {} : { required: mergedRequired }
11438
12303
  };
11439
12304
  }
11440
- function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__PURE__ */ new Set()) {
12305
+ function hasSelfReferencingRef(schema, root, path25 = "#", activePaths = /* @__PURE__ */ new Set()) {
11441
12306
  const nextActivePaths = new Set(activePaths);
11442
- nextActivePaths.add(path24);
12307
+ nextActivePaths.add(path25);
11443
12308
  const localRefPath = getLocalRefPath(schema.$ref);
11444
12309
  if (localRefPath !== void 0) {
11445
12310
  if (nextActivePaths.has(localRefPath)) {
@@ -11450,13 +12315,13 @@ function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__P
11450
12315
  return true;
11451
12316
  }
11452
12317
  }
11453
- if (schema.items !== void 0 && hasSelfReferencingRef(schema.items, root, `${path24}/items`, nextActivePaths)) {
12318
+ if (schema.items !== void 0 && hasSelfReferencingRef(schema.items, root, `${path25}/items`, nextActivePaths)) {
11454
12319
  return true;
11455
12320
  }
11456
12321
  if (typeof schema.additionalProperties === "object" && schema.additionalProperties !== null && hasSelfReferencingRef(
11457
12322
  schema.additionalProperties,
11458
12323
  root,
11459
- `${path24}/additionalProperties`,
12324
+ `${path25}/additionalProperties`,
11460
12325
  nextActivePaths
11461
12326
  )) {
11462
12327
  return true;
@@ -11465,7 +12330,7 @@ function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__P
11465
12330
  if (hasSelfReferencingRef(
11466
12331
  childSchema,
11467
12332
  root,
11468
- `${path24}/properties/${escapeJsonPointerSegment(key2)}`,
12333
+ `${path25}/properties/${escapeJsonPointerSegment(key2)}`,
11469
12334
  nextActivePaths
11470
12335
  )) {
11471
12336
  return true;
@@ -11475,24 +12340,24 @@ function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__P
11475
12340
  if (hasSelfReferencingRef(
11476
12341
  childSchema,
11477
12342
  root,
11478
- `${path24}/$defs/${escapeJsonPointerSegment(key2)}`,
12343
+ `${path25}/$defs/${escapeJsonPointerSegment(key2)}`,
11479
12344
  nextActivePaths
11480
12345
  )) {
11481
12346
  return true;
11482
12347
  }
11483
12348
  }
11484
12349
  for (const [index, childSchema] of (schema.oneOf ?? []).entries()) {
11485
- if (hasSelfReferencingRef(childSchema, root, `${path24}/oneOf/${index}`, nextActivePaths)) {
12350
+ if (hasSelfReferencingRef(childSchema, root, `${path25}/oneOf/${index}`, nextActivePaths)) {
11486
12351
  return true;
11487
12352
  }
11488
12353
  }
11489
12354
  for (const [index, childSchema] of (schema.anyOf ?? []).entries()) {
11490
- if (hasSelfReferencingRef(childSchema, root, `${path24}/anyOf/${index}`, nextActivePaths)) {
12355
+ if (hasSelfReferencingRef(childSchema, root, `${path25}/anyOf/${index}`, nextActivePaths)) {
11491
12356
  return true;
11492
12357
  }
11493
12358
  }
11494
12359
  for (const [index, childSchema] of (schema.allOf ?? []).entries()) {
11495
- if (hasSelfReferencingRef(childSchema, root, `${path24}/allOf/${index}`, nextActivePaths)) {
12360
+ if (hasSelfReferencingRef(childSchema, root, `${path25}/allOf/${index}`, nextActivePaths)) {
11496
12361
  return true;
11497
12362
  }
11498
12363
  }
@@ -11508,14 +12373,14 @@ function getLocalRefPath(ref) {
11508
12373
  return ref.startsWith("#/") ? ref : void 0;
11509
12374
  }
11510
12375
  function resolveLocalRef(root, ref) {
11511
- const path24 = getLocalRefPath(ref);
11512
- if (path24 === void 0) {
12376
+ const path25 = getLocalRefPath(ref);
12377
+ if (path25 === void 0) {
11513
12378
  return void 0;
11514
12379
  }
11515
- if (path24 === "#") {
12380
+ if (path25 === "#") {
11516
12381
  return root;
11517
12382
  }
11518
- const segments = path24.slice(2).split("/").map(unescapeJsonPointerSegment);
12383
+ const segments = path25.slice(2).split("/").map(unescapeJsonPointerSegment);
11519
12384
  let current = root;
11520
12385
  for (const segment of segments) {
11521
12386
  if (Array.isArray(current)) {
@@ -11561,15 +12426,15 @@ function getBooleanDefault(value) {
11561
12426
  return typeof value === "boolean" ? value : void 0;
11562
12427
  }
11563
12428
  function getArrayDefault(value) {
11564
- return Array.isArray(value) && value.every((item) => isJsonValue(item)) ? value : void 0;
12429
+ return Array.isArray(value) && value.every((item) => isJsonValue2(item)) ? value : void 0;
11565
12430
  }
11566
12431
  function getPrimitiveEnumDefault(value, candidates) {
11567
12432
  return isPrimitiveEnumValue(value) && candidates.includes(value) ? value : void 0;
11568
12433
  }
11569
12434
  function getJsonDefault(value) {
11570
- return isJsonValue(value) ? value : void 0;
12435
+ return isJsonValue2(value) ? value : void 0;
11571
12436
  }
11572
- function isJsonValue(value) {
12437
+ function isJsonValue2(value) {
11573
12438
  if (value === null) {
11574
12439
  return true;
11575
12440
  }
@@ -11577,12 +12442,12 @@ function isJsonValue(value) {
11577
12442
  return true;
11578
12443
  }
11579
12444
  if (Array.isArray(value)) {
11580
- return value.every((item) => isJsonValue(item));
12445
+ return value.every((item) => isJsonValue2(item));
11581
12446
  }
11582
12447
  if (!isPlainObject(value)) {
11583
12448
  return false;
11584
12449
  }
11585
- return Object.values(value).every((item) => isJsonValue(item));
12450
+ return Object.values(value).every((item) => isJsonValue2(item));
11586
12451
  }
11587
12452
  function isPlainObject(value) {
11588
12453
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -11772,7 +12637,7 @@ async function ensureConnected(connection) {
11772
12637
  async function readCache(cachePath) {
11773
12638
  try {
11774
12639
  await assertCachePathHasNoSymlinks(cachePath);
11775
- const raw = await readFile3(cachePath, "utf8");
12640
+ const raw = await readFile4(cachePath, "utf8");
11776
12641
  const parsed = JSON.parse(raw);
11777
12642
  if (parsed === null || typeof parsed !== "object" || !Array.isArray(parsed.tools) || parsed.upstream === void 0 || typeof parsed.upstream.name !== "string" || typeof parsed.upstream.version !== "string") {
11778
12643
  return void 0;
@@ -11793,7 +12658,7 @@ async function readCache(cachePath) {
11793
12658
  }
11794
12659
  }
11795
12660
  async function writeCache(cachePath, cache) {
11796
- const directory = path12.dirname(cachePath);
12661
+ const directory = path13.dirname(cachePath);
11797
12662
  const tempPath = `${cachePath}.tmp-${randomUUID4()}`;
11798
12663
  let tempCreated = false;
11799
12664
  await assertCachePathHasNoSymlinks(cachePath);
@@ -11990,13 +12855,13 @@ function collectProxyGroups(root) {
11990
12855
  function findProjectRoot(from = process.cwd()) {
11991
12856
  let current = process.cwd();
11992
12857
  if (from !== current) {
11993
- current = path12.resolve(from);
12858
+ current = path13.resolve(from);
11994
12859
  }
11995
12860
  while (true) {
11996
- if (existsSync2(path12.join(current, "package.json"))) {
12861
+ if (existsSync2(path13.join(current, "package.json"))) {
11997
12862
  return current;
11998
12863
  }
11999
- const parent = path12.dirname(current);
12864
+ const parent = path13.dirname(current);
12000
12865
  if (parent === current) {
12001
12866
  return void 0;
12002
12867
  }
@@ -12013,7 +12878,7 @@ function resolveCachePath(name, projectRoot) {
12013
12878
  if (name.length === 0 || name === "." || name === ".." || name.includes("/") || name.includes("\\")) {
12014
12879
  throw new Error(`MCP proxy group name must be a file-safe name: "${name}".`);
12015
12880
  }
12016
- return path12.join(resolvedProjectRoot, ".toolcraft", "mcp", `${name}.json`);
12881
+ return path13.join(resolvedProjectRoot, ".toolcraft", "mcp", `${name}.json`);
12017
12882
  }
12018
12883
  async function assertCachePathHasNoSymlinks(filePath) {
12019
12884
  let currentPath = filePath;
@@ -12027,10 +12892,10 @@ async function assertCachePathHasNoSymlinks(filePath) {
12027
12892
  throw error3;
12028
12893
  }
12029
12894
  }
12030
- if (path12.basename(currentPath) === ".toolcraft") {
12895
+ if (path13.basename(currentPath) === ".toolcraft") {
12031
12896
  return;
12032
12897
  }
12033
- const parentPath = path12.dirname(currentPath);
12898
+ const parentPath = path13.dirname(currentPath);
12034
12899
  if (parentPath === currentPath) {
12035
12900
  return;
12036
12901
  }
@@ -12176,20 +13041,20 @@ function reportsEnabled(option, env) {
12176
13041
  function resolveReportDir(option, projectRoot) {
12177
13042
  const configuredDir = typeof option === "object" ? option.dir : void 0;
12178
13043
  if (configuredDir === void 0 || configuredDir.length === 0) {
12179
- return path13.join(projectRoot, ".toolcraft", "errors");
13044
+ return path14.join(projectRoot, ".toolcraft", "errors");
12180
13045
  }
12181
- return path13.isAbsolute(configuredDir) ? configuredDir : path13.join(projectRoot, configuredDir);
13046
+ return path14.isAbsolute(configuredDir) ? configuredDir : path14.join(projectRoot, configuredDir);
12182
13047
  }
12183
13048
  function reportDirMustStayWithinProject(option) {
12184
13049
  const configuredDir = typeof option === "object" ? option.dir : void 0;
12185
- return configuredDir === void 0 || configuredDir.length === 0 || !path13.isAbsolute(configuredDir);
13050
+ return configuredDir === void 0 || configuredDir.length === 0 || !path14.isAbsolute(configuredDir);
12186
13051
  }
12187
13052
  function isWithinDirectory(parent, child) {
12188
- const relative = path13.relative(parent, child);
12189
- return relative === "" || !path13.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path13.sep}`);
13053
+ const relative = path14.relative(parent, child);
13054
+ return relative === "" || !path14.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path14.sep}`);
12190
13055
  }
12191
13056
  async function assertReportDirWithinProject(projectRoot, reportDir) {
12192
- if (!isWithinDirectory(path13.resolve(projectRoot), path13.resolve(reportDir))) {
13057
+ if (!isWithinDirectory(path14.resolve(projectRoot), path14.resolve(reportDir))) {
12193
13058
  throw new Error("Error report directory resolves outside project root.");
12194
13059
  }
12195
13060
  const [canonicalProjectRoot, canonicalReportDir] = await Promise.all([
@@ -12240,7 +13105,7 @@ function slugifyCommandPath(commandPath) {
12240
13105
  return output.length === 0 ? "root" : output;
12241
13106
  }
12242
13107
  function relativeDisplayPath(projectRoot, absolutePath) {
12243
- const relative = path13.relative(projectRoot, absolutePath);
13108
+ const relative = path14.relative(projectRoot, absolutePath);
12244
13109
  return relative.length === 0 || relative.startsWith("..") ? absolutePath : relative;
12245
13110
  }
12246
13111
  function redactValue(value) {
@@ -12560,7 +13425,7 @@ async function writeErrorReport(context) {
12560
13425
  const projectRoot = resolveProjectRoot(context.projectRoot);
12561
13426
  const reportDir = resolveReportDir(context.errorReports, projectRoot);
12562
13427
  const fileName = `${formatTimestamp(/* @__PURE__ */ new Date())}-${slugifyCommandPath(context.commandPath)}-${randomUUID5()}.log`;
12563
- const absolutePath = path13.join(reportDir, fileName);
13428
+ const absolutePath = path14.join(reportDir, fileName);
12564
13429
  await mkdir2(reportDir, { recursive: true });
12565
13430
  if (reportDirMustStayWithinProject(context.errorReports)) {
12566
13431
  await assertReportDirWithinProject(projectRoot, reportDir);
@@ -13030,7 +13895,7 @@ function inferProgramName(argv) {
13030
13895
  if (typeof entrypoint !== "string" || entrypoint.length === 0) {
13031
13896
  return "toolcraft";
13032
13897
  }
13033
- const parsed = path14.parse(entrypoint);
13898
+ const parsed = path15.parse(entrypoint);
13034
13899
  return parsed.name.length > 0 ? parsed.name : "toolcraft";
13035
13900
  }
13036
13901
  function normalizeRoots(roots, argv) {
@@ -13088,11 +13953,11 @@ function formatSegment(segment, casing) {
13088
13953
  const separator = casing === "snake" ? "_" : "-";
13089
13954
  return splitWords3(segment).join(separator);
13090
13955
  }
13091
- function toOptionFlag(path24, casing) {
13092
- return `--${path24.map((segment) => formatSegment(segment, casing)).join(".")}`;
13956
+ function toOptionFlag(path25, casing) {
13957
+ return `--${path25.map((segment) => formatSegment(segment, casing)).join(".")}`;
13093
13958
  }
13094
- function toOptionAttribute(path24, casing) {
13095
- return path24.map((segment) => {
13959
+ function toOptionAttribute(path25, casing) {
13960
+ return path25.map((segment) => {
13096
13961
  const formatted = formatSegment(segment, casing);
13097
13962
  if (casing === "snake") {
13098
13963
  return formatted;
@@ -13103,23 +13968,23 @@ function toOptionAttribute(path24, casing) {
13103
13968
  ).join("");
13104
13969
  }).join(".");
13105
13970
  }
13106
- function toDisplayPath(path24) {
13107
- return path24.join(".");
13971
+ function toDisplayPath(path25) {
13972
+ return path25.join(".");
13108
13973
  }
13109
- function toUnionKindControlPath(path24) {
13110
- if (path24.length === 0) {
13974
+ function toUnionKindControlPath(path25) {
13975
+ if (path25.length === 0) {
13111
13976
  return ["kind"];
13112
13977
  }
13113
- const head = path24.slice(0, -1);
13114
- const tail = path24[path24.length - 1] ?? "";
13978
+ const head = path25.slice(0, -1);
13979
+ const tail = path25[path25.length - 1] ?? "";
13115
13980
  return [...head, `${tail}Kind`];
13116
13981
  }
13117
- function toUnionKindDisplayPath(path24) {
13118
- if (path24.length === 0) {
13982
+ function toUnionKindDisplayPath(path25) {
13983
+ if (path25.length === 0) {
13119
13984
  return "kind";
13120
13985
  }
13121
- const head = path24.slice(0, -1);
13122
- const tail = path24[path24.length - 1] ?? "";
13986
+ const head = path25.slice(0, -1);
13987
+ const tail = path25[path25.length - 1] ?? "";
13123
13988
  return [...head, `${tail}-kind`].join(".");
13124
13989
  }
13125
13990
  function createSyntheticEnumSchema(values) {
@@ -13135,14 +14000,14 @@ function getRequiredBranchFingerprint(branch, casing) {
13135
14000
  const requiredKeys = Object.entries(branch.shape).filter(([, schema]) => schema.kind !== "optional").map(([key2]) => formatSegment(key2, casing)).sort();
13136
14001
  return requiredKeys.join("+");
13137
14002
  }
13138
- function collectFields(schema, casing, globalLongOptionFlags, path24 = [], inheritedOptional = false, variantContext) {
14003
+ function collectFields(schema, casing, globalLongOptionFlags, path25 = [], inheritedOptional = false, variantContext) {
13139
14004
  const collected = {
13140
14005
  dynamicFields: [],
13141
14006
  fields: [],
13142
14007
  variants: []
13143
14008
  };
13144
14009
  for (const [key2, rawChildSchema] of Object.entries(schema.shape)) {
13145
- const nextPath = [...path24, key2];
14010
+ const nextPath = [...path25, key2];
13146
14011
  const runtimeOptional = inheritedOptional || rawChildSchema.kind === "optional";
13147
14012
  const childSchema = unwrapOptional2(rawChildSchema);
13148
14013
  const requiredWhenActive = rawChildSchema.kind !== "optional" && childSchema.default === void 0;
@@ -13328,9 +14193,9 @@ function collectFields(schema, casing, globalLongOptionFlags, path24 = [], inher
13328
14193
  }
13329
14194
  return collected;
13330
14195
  }
13331
- function toCommanderOptionAttribute(path24, casing, globalLongOptionFlags) {
13332
- const optionAttribute = toOptionAttribute(path24, casing);
13333
- const optionFlag = toOptionFlag(path24, casing);
14196
+ function toCommanderOptionAttribute(path25, casing, globalLongOptionFlags) {
14197
+ const optionAttribute = toOptionAttribute(path25, casing);
14198
+ const optionFlag = toOptionFlag(path25, casing);
13334
14199
  if (!globalLongOptionFlags.has(optionFlag)) {
13335
14200
  return optionAttribute;
13336
14201
  }
@@ -13603,6 +14468,20 @@ function parseArrayValue(value, schema, label) {
13603
14468
  (item) => parseScalarValue(item, itemSchema, label)
13604
14469
  );
13605
14470
  }
14471
+ function isNegativeNumericArrayToken(token, schema) {
14472
+ if (!token.startsWith("-") || token.startsWith("--")) {
14473
+ return false;
14474
+ }
14475
+ const itemSchema = unwrapOptional2(schema.item);
14476
+ if (itemSchema.kind !== "number") {
14477
+ return false;
14478
+ }
14479
+ const items = splitArrayInput(token);
14480
+ return items.length > 0 && items.every((item) => isValidNumberSchemaValue(Number(item), itemSchema));
14481
+ }
14482
+ function isNextArrayOptionToken(token, schema) {
14483
+ return token.startsWith("-") && !isNegativeNumericArrayToken(token, schema);
14484
+ }
13606
14485
  function validateArrayBounds(value, schema, label) {
13607
14486
  if (schema.minItems !== void 0 && value.length < schema.minItems) {
13608
14487
  throw new UserError(
@@ -14410,10 +15289,10 @@ function parseDebugStackMode(value) {
14410
15289
  formatInvalidEnumMessage("--debug", String(value), ["raw"], { candidates: ["raw"] })
14411
15290
  );
14412
15291
  }
14413
- function setNestedValue(target, path24, value) {
15292
+ function setNestedValue(target, path25, value) {
14414
15293
  let cursor2 = target;
14415
- for (let index = 0; index < path24.length - 1; index += 1) {
14416
- const segment = path24[index] ?? "";
15294
+ for (let index = 0; index < path25.length - 1; index += 1) {
15295
+ const segment = path25[index] ?? "";
14417
15296
  const existing = Object.prototype.hasOwnProperty.call(cursor2, segment) ? cursor2[segment] : void 0;
14418
15297
  if (typeof existing === "object" && existing !== null) {
14419
15298
  cursor2 = existing;
@@ -14428,7 +15307,7 @@ function setNestedValue(target, path24, value) {
14428
15307
  });
14429
15308
  cursor2 = next;
14430
15309
  }
14431
- const leaf = path24[path24.length - 1];
15310
+ const leaf = path25[path25.length - 1];
14432
15311
  if (leaf !== void 0) {
14433
15312
  Object.defineProperty(cursor2, leaf, {
14434
15313
  value,
@@ -14545,21 +15424,21 @@ async function withOutputFormat2(output, fn) {
14545
15424
  }
14546
15425
  function createFs2() {
14547
15426
  return {
14548
- readFile: async (path24, encoding = "utf8") => readFile4(path24, { encoding }),
14549
- writeFile: async (path24, contents, options) => {
14550
- await writeFile5(path24, contents, options);
15427
+ readFile: async (path25, encoding = "utf8") => readFile5(path25, { encoding }),
15428
+ writeFile: async (path25, contents, options) => {
15429
+ await writeFile5(path25, contents, options);
14551
15430
  },
14552
- exists: async (path24) => {
15431
+ exists: async (path25) => {
14553
15432
  try {
14554
- await access2(path24);
15433
+ await access2(path25);
14555
15434
  return true;
14556
15435
  } catch {
14557
15436
  return false;
14558
15437
  }
14559
15438
  },
14560
- lstat: async (path24) => lstat3(path24),
15439
+ lstat: async (path25) => lstat3(path25),
14561
15440
  rename: async (fromPath, toPath) => rename3(fromPath, toPath),
14562
- unlink: async (path24) => unlink3(path24)
15441
+ unlink: async (path25) => unlink3(path25)
14563
15442
  };
14564
15443
  }
14565
15444
  function createEnv2(values = process.env) {
@@ -14575,9 +15454,9 @@ function isPlainObject4(value) {
14575
15454
  function hasFieldValue(value) {
14576
15455
  return value !== void 0;
14577
15456
  }
14578
- function hasNestedField(fields, path24) {
15457
+ function hasNestedField(fields, path25) {
14579
15458
  return fields.some(
14580
- (field) => path24.length < field.path.length && path24.every((segment, index) => field.path[index] === segment)
15459
+ (field) => path25.length < field.path.length && path25.every((segment, index) => field.path[index] === segment)
14581
15460
  );
14582
15461
  }
14583
15462
  function describeExpectedPresetValue(schema) {
@@ -14680,7 +15559,7 @@ function validatePresetFieldValue(value, field, presetPath) {
14680
15559
  async function loadPresetValues(fields, presetPath) {
14681
15560
  let rawPreset;
14682
15561
  try {
14683
- rawPreset = await readFile4(presetPath, {
15562
+ rawPreset = await readFile5(presetPath, {
14684
15563
  encoding: "utf8"
14685
15564
  });
14686
15565
  } catch (error3) {
@@ -14706,9 +15585,9 @@ async function loadPresetValues(fields, presetPath) {
14706
15585
  }
14707
15586
  const fieldByPath = new Map(fields.map((field) => [field.displayPath, field]));
14708
15587
  const presetValues = {};
14709
- function visitObject(current, path24) {
15588
+ function visitObject(current, path25) {
14710
15589
  for (const [key2, value] of Object.entries(current)) {
14711
- const nextPath = [...path24, key2];
15590
+ const nextPath = [...path25, key2];
14712
15591
  const displayPath = toDisplayPath(nextPath);
14713
15592
  const field = fieldByPath.get(displayPath);
14714
15593
  if (field !== void 0) {
@@ -14915,8 +15794,8 @@ function createFixtureService(definition) {
14915
15794
  );
14916
15795
  }
14917
15796
  function resolveFixturePath(commandPath) {
14918
- const parsed = path14.parse(commandPath);
14919
- return path14.join(parsed.dir, `${parsed.name}.fixture.json`);
15797
+ const parsed = path15.parse(commandPath);
15798
+ return path15.join(parsed.dir, `${parsed.name}.fixture.json`);
14920
15799
  }
14921
15800
  function selectFixtureScenario(scenarios, selector, fixturePath) {
14922
15801
  if (isNumericFixtureSelector(selector)) {
@@ -14947,7 +15826,7 @@ async function loadFixtureScenario(command, selector) {
14947
15826
  const fixturePath = resolveFixturePath(commandPath);
14948
15827
  let rawFixture;
14949
15828
  try {
14950
- rawFixture = await readFile4(fixturePath, {
15829
+ rawFixture = await readFile5(fixturePath, {
14951
15830
  encoding: "utf8"
14952
15831
  });
14953
15832
  } catch {
@@ -15050,8 +15929,8 @@ function validateServices(services) {
15050
15929
  }
15051
15930
  }
15052
15931
  }
15053
- function getNestedValue(target, path24) {
15054
- return path24.reduce(
15932
+ function getNestedValue(target, path25) {
15933
+ return path25.reduce(
15055
15934
  (current, segment) => current !== null && typeof current === "object" ? current[segment] : void 0,
15056
15935
  target
15057
15936
  );
@@ -15136,7 +16015,7 @@ function consumeFieldValue(args, index, schema, label, inlineValue) {
15136
16015
  let cursor2 = index + 1;
15137
16016
  while (cursor2 < args.length) {
15138
16017
  const token = args[cursor2] ?? "";
15139
- if (token.startsWith("-")) {
16018
+ if (isNextArrayOptionToken(token, schema)) {
15140
16019
  break;
15141
16020
  }
15142
16021
  const parsed = parseArrayValue(token, schema, label);
@@ -16012,6 +16891,12 @@ This is a bug in toolcraft or in the command definition; it cannot be worked aro
16012
16891
  );
16013
16892
  return;
16014
16893
  }
16894
+ logger2.error(
16895
+ appendUsagePointer(formatCommanderErrorMessage(error3), {
16896
+ rootUsageName: options.rootUsageName,
16897
+ commandPath: options.commandPath.length > 0 ? options.commandPath : findCurrentCommanderCommandPath(options.program, options.argv ?? process.argv)
16898
+ })
16899
+ );
16015
16900
  return;
16016
16901
  }
16017
16902
  if (isHttpErrorLike(error3)) {
@@ -16029,6 +16914,9 @@ This is a bug in toolcraft or in the command definition; it cannot be worked aro
16029
16914
  }
16030
16915
  process.exitCode = 1;
16031
16916
  }
16917
+ function formatCommanderErrorMessage(error3) {
16918
+ return error3.message.startsWith("error:") ? error3.message : `error: ${error3.message}`;
16919
+ }
16032
16920
  function formatInvalidEnumMessage(label, value, values, opts = {}) {
16033
16921
  const suggestions = suggest(
16034
16922
  value,
@@ -16353,7 +17241,7 @@ import { randomUUID as randomUUID6 } from "node:crypto";
16353
17241
  // src/terminal-session.ts
16354
17242
  import { EventEmitter as EventEmitter2 } from "node:events";
16355
17243
  import { accessSync, chmodSync, constants } from "node:fs";
16356
- import { createRequire } from "node:module";
17244
+ import { createRequire as createRequire2 } from "node:module";
16357
17245
  import { dirname, join } from "node:path";
16358
17246
  import * as nodePty from "node-pty";
16359
17247
 
@@ -17492,8 +18380,8 @@ var spawnHelperChecked = false;
17492
18380
  function ensureSpawnHelperExecutable() {
17493
18381
  if (spawnHelperChecked) return;
17494
18382
  spawnHelperChecked = true;
17495
- const require3 = createRequire(import.meta.url);
17496
- const nodePtyDir = dirname(require3.resolve("node-pty"));
18383
+ const require4 = createRequire2(import.meta.url);
18384
+ const nodePtyDir = dirname(require4.resolve("node-pty"));
17497
18385
  const helper = join(nodePtyDir, "..", "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper");
17498
18386
  try {
17499
18387
  accessSync(helper, constants.X_OK);
@@ -17913,7 +18801,7 @@ var getSession = defineCommand({
17913
18801
 
17914
18802
  // ../agent-skill-config/src/configs.ts
17915
18803
  import os2 from "node:os";
17916
- import path15 from "node:path";
18804
+ import path16 from "node:path";
17917
18805
 
17918
18806
  // ../agent-defs/src/agents/claude-code.ts
17919
18807
  var claudeCodeAgent = {
@@ -18277,7 +19165,7 @@ var templateMutation = {
18277
19165
 
18278
19166
  // ../config-mutations/src/execution/apply-mutation.ts
18279
19167
  import { randomUUID as randomUUID7 } from "node:crypto";
18280
- import path17 from "node:path";
19168
+ import path18 from "node:path";
18281
19169
 
18282
19170
  // ../config-mutations/src/formats/json.ts
18283
19171
  import * as jsonc from "jsonc-parser";
@@ -18400,22 +19288,22 @@ function prune(obj, shape) {
18400
19288
  }
18401
19289
  return { changed, result };
18402
19290
  }
18403
- function modifyAtPath(content, path24, value) {
19291
+ function modifyAtPath(content, path25, value) {
18404
19292
  const indent = detectIndent(content);
18405
19293
  const formattingOptions = {
18406
19294
  tabSize: indent === " " ? 1 : indent.length,
18407
19295
  insertSpaces: indent !== " ",
18408
19296
  eol: "\n"
18409
19297
  };
18410
- const edits = jsonc.modify(content, path24, value, { formattingOptions });
19298
+ const edits = jsonc.modify(content, path25, value, { formattingOptions });
18411
19299
  let result = jsonc.applyEdits(content, edits);
18412
19300
  if (!result.endsWith("\n")) {
18413
19301
  result += "\n";
18414
19302
  }
18415
19303
  return result;
18416
19304
  }
18417
- function removeAtPath(content, path24) {
18418
- return modifyAtPath(content, path24, void 0);
19305
+ function removeAtPath(content, path25) {
19306
+ return modifyAtPath(content, path25, void 0);
18419
19307
  }
18420
19308
  function serializeUpdate(content, current, next) {
18421
19309
  let result = content || "{}";
@@ -18425,15 +19313,15 @@ function serializeUpdate(content, current, next) {
18425
19313
  }
18426
19314
  return result;
18427
19315
  }
18428
- function applyObjectUpdate(content, path24, current, next) {
19316
+ function applyObjectUpdate(content, path25, current, next) {
18429
19317
  let result = content;
18430
19318
  for (const key2 of Object.keys(current)) {
18431
19319
  if (!hasConfigEntry(next, key2)) {
18432
- result = removeAtPath(result, [...path24, key2]);
19320
+ result = removeAtPath(result, [...path25, key2]);
18433
19321
  }
18434
19322
  }
18435
19323
  for (const [key2, nextValue] of Object.entries(next)) {
18436
- const nextPath = [...path24, key2];
19324
+ const nextPath = [...path25, key2];
18437
19325
  const hasCurrent = hasConfigEntry(current, key2);
18438
19326
  const currentValue = hasCurrent ? current[key2] : void 0;
18439
19327
  if (hasCurrent && isConfigObject(currentValue) && isConfigObject(nextValue)) {
@@ -18633,20 +19521,20 @@ function getConfigFormat(pathOrFormat) {
18633
19521
  }
18634
19522
  return formatRegistry[formatName];
18635
19523
  }
18636
- function detectFormat(path24) {
18637
- const ext = getExtension(path24);
19524
+ function detectFormat(path25) {
19525
+ const ext = getExtension(path25);
18638
19526
  return extensionMap[ext];
18639
19527
  }
18640
- function getExtension(path24) {
18641
- const lastDot = path24.lastIndexOf(".");
19528
+ function getExtension(path25) {
19529
+ const lastDot = path25.lastIndexOf(".");
18642
19530
  if (lastDot === -1) {
18643
19531
  return "";
18644
19532
  }
18645
- return path24.slice(lastDot).toLowerCase();
19533
+ return path25.slice(lastDot).toLowerCase();
18646
19534
  }
18647
19535
 
18648
19536
  // ../config-mutations/src/execution/path-utils.ts
18649
- import path16 from "node:path";
19537
+ import path17 from "node:path";
18650
19538
  function expandHome(targetPath, homeDir) {
18651
19539
  if (!targetPath?.startsWith("~")) {
18652
19540
  return targetPath;
@@ -18663,7 +19551,7 @@ function expandHome(targetPath, homeDir) {
18663
19551
  remainder = remainder.slice(1);
18664
19552
  }
18665
19553
  }
18666
- return remainder.length === 0 ? homeDir : path16.join(homeDir, remainder);
19554
+ return remainder.length === 0 ? homeDir : path17.join(homeDir, remainder);
18667
19555
  }
18668
19556
  function validateHomePath(targetPath) {
18669
19557
  if (typeof targetPath !== "string" || targetPath.length === 0) {
@@ -18678,21 +19566,21 @@ function validateHomePath(targetPath) {
18678
19566
  function resolvePath(rawPath, homeDir, pathMapper) {
18679
19567
  validateHomePath(rawPath);
18680
19568
  const expanded = expandHome(rawPath, homeDir);
18681
- const canonicalHome = path16.resolve(homeDir);
18682
- const canonicalExpanded = path16.resolve(expanded);
18683
- const relative = path16.relative(canonicalHome, canonicalExpanded);
18684
- if (relative === ".." || relative.startsWith(`..${path16.sep}`) || path16.isAbsolute(relative)) {
19569
+ const canonicalHome = path17.resolve(homeDir);
19570
+ const canonicalExpanded = path17.resolve(expanded);
19571
+ const relative = path17.relative(canonicalHome, canonicalExpanded);
19572
+ if (relative === ".." || relative.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative)) {
18685
19573
  throw new Error(`Target path resolves outside home directory: "${rawPath}"`);
18686
19574
  }
18687
19575
  if (!pathMapper) {
18688
19576
  return canonicalExpanded;
18689
19577
  }
18690
- const rawDirectory = path16.dirname(expanded);
19578
+ const rawDirectory = path17.dirname(expanded);
18691
19579
  const mappedDirectory = pathMapper.mapTargetDirectory({
18692
19580
  targetDirectory: rawDirectory
18693
19581
  });
18694
- const filename = path16.basename(expanded);
18695
- return filename.length === 0 ? mappedDirectory : path16.join(mappedDirectory, filename);
19582
+ const filename = path17.basename(expanded);
19583
+ return filename.length === 0 ? mappedDirectory : path17.join(mappedDirectory, filename);
18696
19584
  }
18697
19585
 
18698
19586
  // ../config-mutations/src/error-codes.ts
@@ -18704,9 +19592,9 @@ function hasOwnErrorCode5(error3, code) {
18704
19592
  function isNotFound(error3) {
18705
19593
  return hasOwnErrorCode5(error3, "ENOENT");
18706
19594
  }
18707
- async function readFileIfExists(fs4, target) {
19595
+ async function readFileIfExists(fs5, target) {
18708
19596
  try {
18709
- return await fs4.readFile(target, "utf8");
19597
+ return await fs5.readFile(target, "utf8");
18710
19598
  } catch (error3) {
18711
19599
  if (isNotFound(error3)) {
18712
19600
  return null;
@@ -18714,9 +19602,9 @@ async function readFileIfExists(fs4, target) {
18714
19602
  throw error3;
18715
19603
  }
18716
19604
  }
18717
- async function pathExists(fs4, target) {
19605
+ async function pathExists(fs5, target) {
18718
19606
  try {
18719
- await fs4.stat(target);
19607
+ await fs5.stat(target);
18720
19608
  return true;
18721
19609
  } catch (error3) {
18722
19610
  if (isNotFound(error3)) {
@@ -18762,8 +19650,8 @@ function isAlreadyExists(error3) {
18762
19650
  return hasOwnErrorCode5(error3, "EEXIST");
18763
19651
  }
18764
19652
  async function assertRegularWriteTarget(context, targetPath) {
18765
- const boundary = path17.dirname(path17.resolve(context.homeDir));
18766
- let currentPath = path17.resolve(targetPath);
19653
+ const boundary = path18.dirname(path18.resolve(context.homeDir));
19654
+ let currentPath = path18.resolve(targetPath);
18767
19655
  while (currentPath !== boundary) {
18768
19656
  try {
18769
19657
  if ((await context.fs.lstat(currentPath)).isSymbolicLink()) {
@@ -18774,7 +19662,7 @@ async function assertRegularWriteTarget(context, targetPath) {
18774
19662
  throw error3;
18775
19663
  }
18776
19664
  }
18777
- const parentPath = path17.dirname(currentPath);
19665
+ const parentPath = path18.dirname(currentPath);
18778
19666
  if (parentPath === currentPath) {
18779
19667
  return;
18780
19668
  }
@@ -18839,6 +19727,56 @@ function describeMutation(kind, targetPath) {
18839
19727
  return "Operation";
18840
19728
  }
18841
19729
  }
19730
+ function mutationTargetPath(mutation, options) {
19731
+ switch (mutation.kind) {
19732
+ case "ensureDirectory":
19733
+ case "removeDirectory":
19734
+ return resolveValue(mutation.path, options);
19735
+ case "removeFile":
19736
+ case "chmod":
19737
+ case "backup":
19738
+ case "restoreBackup":
19739
+ case "configMerge":
19740
+ case "configPrune":
19741
+ case "configTransform":
19742
+ case "templateWrite":
19743
+ case "templateMergeToml":
19744
+ case "templateMergeJson":
19745
+ return resolveValue(mutation.target, options);
19746
+ default:
19747
+ return void 0;
19748
+ }
19749
+ }
19750
+ function resolveMutationDetails(mutation, context, options) {
19751
+ try {
19752
+ const rawTarget = mutationTargetPath(mutation, options);
19753
+ if (rawTarget === void 0) {
19754
+ return {
19755
+ kind: mutation.kind,
19756
+ label: mutation.label ?? mutation.kind
19757
+ };
19758
+ }
19759
+ try {
19760
+ const targetPath = resolvePath(rawTarget, context.homeDir, context.pathMapper);
19761
+ return {
19762
+ kind: mutation.kind,
19763
+ label: mutation.label ?? describeMutation(mutation.kind, targetPath),
19764
+ targetPath
19765
+ };
19766
+ } catch {
19767
+ return {
19768
+ kind: mutation.kind,
19769
+ label: mutation.label ?? describeMutation(mutation.kind, rawTarget),
19770
+ targetPath: void 0
19771
+ };
19772
+ }
19773
+ } catch {
19774
+ return {
19775
+ kind: mutation.kind,
19776
+ label: mutation.label ?? mutation.kind
19777
+ };
19778
+ }
19779
+ }
18842
19780
  function pruneKeysByPrefix(table, prefix) {
18843
19781
  const result = {};
18844
19782
  for (const [key2, value] of Object.entries(table)) {
@@ -18929,6 +19867,7 @@ async function applyEnsureDirectory(mutation, context, options) {
18929
19867
  label: mutation.label ?? describeMutation(mutation.kind, targetPath),
18930
19868
  targetPath
18931
19869
  };
19870
+ await assertRegularWriteTarget(context, targetPath);
18932
19871
  const existed = await pathExists(context.fs, targetPath);
18933
19872
  if (!context.dryRun) {
18934
19873
  await context.fs.mkdir(targetPath, { recursive: true });
@@ -19045,6 +19984,7 @@ async function applyChmod(mutation, context, options) {
19045
19984
  };
19046
19985
  }
19047
19986
  try {
19987
+ await assertRegularWriteTarget(context, targetPath);
19048
19988
  const stat2 = await context.fs.stat(targetPath);
19049
19989
  const currentMode = typeof stat2.mode === "number" ? stat2.mode & 511 : null;
19050
19990
  if (currentMode === mutation.mode) {
@@ -19078,6 +20018,7 @@ async function applyBackup(mutation, context, options) {
19078
20018
  label: mutation.label ?? describeMutation(mutation.kind, targetPath),
19079
20019
  targetPath
19080
20020
  };
20021
+ await assertRegularWriteTarget(context, targetPath);
19081
20022
  if (mutation.once && await findLatestGeneratedBackup(context.fs, targetPath) !== null) {
19082
20023
  return {
19083
20024
  outcome: { changed: false, effect: "none", detail: "noop" },
@@ -19144,13 +20085,13 @@ async function applyRestoreBackup(mutation, context, options) {
19144
20085
  }
19145
20086
  return { outcome: { changed: true, effect: "copy", detail: "restore" }, details };
19146
20087
  }
19147
- async function findLatestGeneratedBackup(fs4, targetPath) {
20088
+ async function findLatestGeneratedBackup(fs5, targetPath) {
19148
20089
  const separatorIndex = targetPath.lastIndexOf("/");
19149
20090
  const directoryPath = separatorIndex <= 0 ? "/" : targetPath.slice(0, separatorIndex);
19150
20091
  const targetName = targetPath.slice(separatorIndex + 1);
19151
20092
  let entries;
19152
20093
  try {
19153
- entries = await fs4.readdir(directoryPath);
20094
+ entries = await fs5.readdir(directoryPath);
19154
20095
  } catch (error3) {
19155
20096
  if (isNotFound(error3)) {
19156
20097
  return null;
@@ -19214,6 +20155,9 @@ async function applyConfigMerge(mutation, context, options) {
19214
20155
  preserveContent = null;
19215
20156
  }
19216
20157
  const value = resolveValue(mutation.value, options);
20158
+ if (!isConfigObject4(value)) {
20159
+ throw new Error(`configMerge value must be an object for "${rawPath}".`);
20160
+ }
19217
20161
  let merged;
19218
20162
  if (mutation.pruneByPrefix) {
19219
20163
  merged = mergeWithPruneByPrefix(current, value, mutation.pruneByPrefix);
@@ -19347,6 +20291,13 @@ async function applyConfigTransform(mutation, context, options) {
19347
20291
  };
19348
20292
  }
19349
20293
  const serialized = serializeConfigUpdate(format, preserveContent, current, transformed);
20294
+ const serializedChanged = serialized !== rawContent;
20295
+ if (!serializedChanged) {
20296
+ return {
20297
+ outcome: { changed: false, effect: "none", detail: "noop" },
20298
+ details
20299
+ };
20300
+ }
19350
20301
  if (!context.dryRun) {
19351
20302
  await writeAtomically2(context, targetPath, serialized);
19352
20303
  }
@@ -19463,25 +20414,14 @@ async function runMutations(mutations, context, options) {
19463
20414
  };
19464
20415
  }
19465
20416
  async function executeMutation(mutation, context, options) {
19466
- context.observers?.onStart?.({
19467
- kind: mutation.kind,
19468
- label: mutation.label ?? mutation.kind,
19469
- targetPath: void 0
19470
- // Will be resolved during apply
19471
- });
20417
+ const pendingDetails = resolveMutationDetails(mutation, context, options);
20418
+ context.observers?.onStart?.(pendingDetails);
19472
20419
  try {
19473
20420
  const { outcome, details } = await applyMutation(mutation, context, options);
19474
20421
  context.observers?.onComplete?.(details, outcome);
19475
20422
  return { outcome, details };
19476
20423
  } catch (error3) {
19477
- context.observers?.onError?.(
19478
- {
19479
- kind: mutation.kind,
19480
- label: mutation.label ?? mutation.kind,
19481
- targetPath: void 0
19482
- },
19483
- error3
19484
- );
20424
+ context.observers?.onError?.(pendingDetails, error3);
19485
20425
  throw error3;
19486
20426
  }
19487
20427
  }
@@ -19492,8 +20432,8 @@ function hasOwnErrorCode6(error3, code) {
19492
20432
  }
19493
20433
 
19494
20434
  // ../agent-skill-config/src/templates.ts
19495
- import { readFile as readFile5, stat } from "node:fs/promises";
19496
- import path18 from "node:path";
20435
+ import { readFile as readFile6, stat } from "node:fs/promises";
20436
+ import path19 from "node:path";
19497
20437
  import { fileURLToPath as fileURLToPath3 } from "node:url";
19498
20438
 
19499
20439
  // ../agent-skill-config/src/apply.ts
@@ -19510,9 +20450,9 @@ function toHomeRelative(localSkillDir) {
19510
20450
  const normalized = localSkillDir.startsWith("./") ? localSkillDir.slice(2) : localSkillDir;
19511
20451
  return `~/${normalized}`;
19512
20452
  }
19513
- async function pathExists2(fs4, targetPath) {
20453
+ async function pathExists2(fs5, targetPath) {
19514
20454
  try {
19515
- await fs4.stat(targetPath);
20455
+ await fs5.stat(targetPath);
19516
20456
  return true;
19517
20457
  } catch (error3) {
19518
20458
  if (hasOwnErrorCode6(error3, "ENOENT")) {
@@ -19529,7 +20469,7 @@ async function installSkill(agentId, skill, options) {
19529
20469
  }
19530
20470
  const scope = options.scope ?? "local";
19531
20471
  const config2 = support.config;
19532
- if (skill.name.length === 0 || skill.name === "." || skill.name === ".." || skill.name.includes("/") || skill.name.includes("\\") || skill.name.includes("\n") || skill.name.includes("\r")) {
20472
+ 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")) {
19533
20473
  throw new Error(`Invalid skill name: ${skill.name}`);
19534
20474
  }
19535
20475
  const skillDir = scope === "global" ? config2.globalSkillDir : toHomeRelative(config2.localSkillDir);
@@ -19565,29 +20505,29 @@ async function installSkill(agentId, skill, options) {
19565
20505
  }
19566
20506
  }
19567
20507
  );
19568
- return { skillPath: skillFilePath, displayPath };
20508
+ return { skillPath: absoluteSkillPath, displayPath };
19569
20509
  }
19570
20510
 
19571
20511
  // ../agent-skill-config/src/resolve-skill-reference.ts
19572
- import { statSync as statSync2 } from "node:fs";
19573
- import path19 from "node:path";
20512
+ import * as fs2 from "node:fs";
20513
+ import path20 from "node:path";
19574
20514
 
19575
20515
  // ../agent-skill-config/src/git-exclude.ts
19576
20516
  import { execFileSync } from "node:child_process";
19577
20517
  import { randomUUID as randomUUID8 } from "node:crypto";
19578
- import * as fs2 from "node:fs";
19579
- import path20 from "node:path";
20518
+ import * as fs3 from "node:fs";
20519
+ import path21 from "node:path";
19580
20520
 
19581
20521
  // ../agent-skill-config/src/bridge-active-skills.ts
19582
- import * as fs3 from "node:fs";
20522
+ import * as fs4 from "node:fs";
19583
20523
  import { createHash as createHash4, randomUUID as randomUUID9 } from "node:crypto";
19584
- import path21 from "node:path";
20524
+ import path22 from "node:path";
19585
20525
 
19586
20526
  // src/commands/installer.ts
19587
20527
  import os3 from "node:os";
19588
- import path22 from "node:path";
20528
+ import path23 from "node:path";
19589
20529
  import * as nodeFs2 from "node:fs/promises";
19590
- import { readFile as readFile6 } from "node:fs/promises";
20530
+ import { readFile as readFile7 } from "node:fs/promises";
19591
20531
  var DEFAULT_INSTALL_AGENT = "claude-code";
19592
20532
  var DEFAULT_INSTALL_SCOPE = "local";
19593
20533
  var TERMINAL_PILOT_SKILL_NAME = "terminal-pilot";
@@ -19637,7 +20577,7 @@ async function loadTerminalPilotTemplate() {
19637
20577
  ];
19638
20578
  for (const candidate of candidates) {
19639
20579
  try {
19640
- terminalPilotTemplateCache = await readFile6(candidate, "utf8");
20580
+ terminalPilotTemplateCache = await readFile7(candidate, "utf8");
19641
20581
  return terminalPilotTemplateCache;
19642
20582
  } catch (error3) {
19643
20583
  if (!isNotFoundError2(error3)) {
@@ -19652,7 +20592,7 @@ function resolveHomeRelativePath(targetPath, homeDir) {
19652
20592
  return homeDir;
19653
20593
  }
19654
20594
  if (targetPath.startsWith("~/")) {
19655
- return path22.join(homeDir, targetPath.slice(2));
20595
+ return path23.join(homeDir, targetPath.slice(2));
19656
20596
  }
19657
20597
  return targetPath;
19658
20598
  }
@@ -19662,22 +20602,22 @@ function getSkillFolderWithHome(agent, scope, cwd, homeDir) {
19662
20602
  throwUnsupportedAgent(agent);
19663
20603
  }
19664
20604
  return {
19665
- displayPath: path22.join(
20605
+ displayPath: path23.join(
19666
20606
  scope === "global" ? config2.globalSkillDir : config2.localSkillDir,
19667
20607
  TERMINAL_PILOT_SKILL_NAME
19668
20608
  ),
19669
- fullPath: path22.join(
19670
- scope === "global" ? resolveHomeRelativePath(config2.globalSkillDir, homeDir) : path22.resolve(cwd, config2.localSkillDir),
20609
+ fullPath: path23.join(
20610
+ scope === "global" ? resolveHomeRelativePath(config2.globalSkillDir, homeDir) : path23.resolve(cwd, config2.localSkillDir),
19671
20611
  TERMINAL_PILOT_SKILL_NAME
19672
20612
  )
19673
20613
  };
19674
20614
  }
19675
- async function assertNoSymbolicLinkPath(fs4, targetPath) {
19676
- const rootPath = path22.parse(targetPath).root;
20615
+ async function assertNoSymbolicLinkPath(fs5, targetPath) {
20616
+ const rootPath = path23.parse(targetPath).root;
19677
20617
  let currentPath = targetPath;
19678
20618
  while (currentPath !== rootPath) {
19679
20619
  try {
19680
- if ((await fs4.lstat(currentPath)).isSymbolicLink()) {
20620
+ if ((await fs5.lstat(currentPath)).isSymbolicLink()) {
19681
20621
  throw new UserError(`Refusing terminal-pilot skill operation through symbolic link: ${currentPath}`);
19682
20622
  }
19683
20623
  } catch (error3) {
@@ -19685,7 +20625,7 @@ async function assertNoSymbolicLinkPath(fs4, targetPath) {
19685
20625
  throw error3;
19686
20626
  }
19687
20627
  }
19688
- currentPath = path22.dirname(currentPath);
20628
+ currentPath = path23.dirname(currentPath);
19689
20629
  }
19690
20630
  }
19691
20631
 
@@ -20384,11 +21324,11 @@ import { Resvg } from "@resvg/resvg-js";
20384
21324
 
20385
21325
  // ../terminal-png/src/font.ts
20386
21326
  import { readFileSync as readFileSync4 } from "node:fs";
20387
- import { createRequire as createRequire2 } from "node:module";
21327
+ import { createRequire as createRequire3 } from "node:module";
20388
21328
  import { dirname as dirname2, join as join2 } from "node:path";
20389
21329
  import { fileURLToPath as fileURLToPath4 } from "node:url";
20390
- var require2 = createRequire2(import.meta.url);
20391
- var fontPackageRoot = dirname2(require2.resolve("jetbrains-mono/package.json"));
21330
+ var require3 = createRequire3(import.meta.url);
21331
+ var fontPackageRoot = dirname2(require3.resolve("jetbrains-mono/package.json"));
20392
21332
  var webfontRoot = join2(fontPackageRoot, "fonts/webfonts");
20393
21333
  function readWebfontBase64(filename) {
20394
21334
  return readFileSync4(join2(webfontRoot, filename)).toString("base64");
@@ -21098,9 +22038,9 @@ var uninstall = defineCommand({
21098
22038
  };
21099
22039
  }
21100
22040
  });
21101
- async function folderExists(fs4, folderPath) {
22041
+ async function folderExists(fs5, folderPath) {
21102
22042
  try {
21103
- await fs4.stat(folderPath);
22043
+ await fs5.stat(folderPath);
21104
22044
  return true;
21105
22045
  } catch (error3) {
21106
22046
  if (hasOwnErrorCode4(error3, "ENOENT")) {
@@ -21245,7 +22185,7 @@ async function isDirectExecution(argv) {
21245
22185
  try {
21246
22186
  const modulePath = fileURLToPath5(import.meta.url);
21247
22187
  const [resolvedEntryPoint, resolvedModulePath] = await Promise.all([
21248
- realpath3(path23.resolve(entryPoint)),
22188
+ realpath3(path24.resolve(entryPoint)),
21249
22189
  realpath3(modulePath)
21250
22190
  ]);
21251
22191
  return resolvedEntryPoint === resolvedModulePath;