terminal-pilot 0.0.30 → 0.0.32

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 (329) hide show
  1. package/dist/cli.js +1599 -497
  2. package/dist/cli.js.map +4 -4
  3. package/dist/commands/close-session.js +489 -6
  4. package/dist/commands/close-session.js.map +4 -4
  5. package/dist/commands/create-session.js +489 -6
  6. package/dist/commands/create-session.js.map +4 -4
  7. package/dist/commands/fill.js +489 -6
  8. package/dist/commands/fill.js.map +4 -4
  9. package/dist/commands/get-session.js +489 -6
  10. package/dist/commands/get-session.js.map +4 -4
  11. package/dist/commands/index.js +630 -44
  12. package/dist/commands/index.js.map +4 -4
  13. package/dist/commands/install.js +626 -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 +489 -6
  18. package/dist/commands/list-sessions.js.map +4 -4
  19. package/dist/commands/press-key.js +489 -6
  20. package/dist/commands/press-key.js.map +4 -4
  21. package/dist/commands/read-history.js +489 -6
  22. package/dist/commands/read-history.js.map +4 -4
  23. package/dist/commands/read-screen.js +489 -6
  24. package/dist/commands/read-screen.js.map +4 -4
  25. package/dist/commands/resize.js +489 -6
  26. package/dist/commands/resize.js.map +4 -4
  27. package/dist/commands/runtime.js.map +1 -1
  28. package/dist/commands/screenshot.js +489 -6
  29. package/dist/commands/screenshot.js.map +4 -4
  30. package/dist/commands/send-signal.js +489 -6
  31. package/dist/commands/send-signal.js.map +4 -4
  32. package/dist/commands/type.js +489 -6
  33. package/dist/commands/type.js.map +4 -4
  34. package/dist/commands/uninstall.js +554 -20
  35. package/dist/commands/uninstall.js.map +4 -4
  36. package/dist/commands/wait-for-exit.js +489 -6
  37. package/dist/commands/wait-for-exit.js.map +4 -4
  38. package/dist/commands/wait-for.js +489 -6
  39. package/dist/commands/wait-for.js.map +4 -4
  40. package/dist/testing/cli-repl.js +1599 -497
  41. package/dist/testing/cli-repl.js.map +4 -4
  42. package/dist/testing/qa-cli.js +1609 -507
  43. package/dist/testing/qa-cli.js.map +4 -4
  44. package/node_modules/@poe-code/agent-defs/README.md +35 -0
  45. package/node_modules/@poe-code/agent-defs/dist/agents/claude-code.d.ts +2 -0
  46. package/node_modules/@poe-code/agent-defs/dist/agents/claude-code.js +21 -0
  47. package/node_modules/@poe-code/agent-defs/dist/agents/claude-desktop.d.ts +2 -0
  48. package/node_modules/@poe-code/agent-defs/dist/agents/claude-desktop.js +18 -0
  49. package/node_modules/@poe-code/agent-defs/dist/agents/codex.d.ts +2 -0
  50. package/node_modules/@poe-code/agent-defs/dist/agents/codex.js +25 -0
  51. package/node_modules/@poe-code/agent-defs/dist/agents/cursor.d.ts +2 -0
  52. package/node_modules/@poe-code/agent-defs/dist/agents/cursor.js +15 -0
  53. package/node_modules/@poe-code/agent-defs/dist/agents/gemini-cli.d.ts +2 -0
  54. package/node_modules/@poe-code/agent-defs/dist/agents/gemini-cli.js +16 -0
  55. package/node_modules/@poe-code/agent-defs/dist/agents/goose.d.ts +2 -0
  56. package/node_modules/@poe-code/agent-defs/dist/agents/goose.js +16 -0
  57. package/node_modules/@poe-code/agent-defs/dist/agents/index.d.ts +9 -0
  58. package/node_modules/@poe-code/agent-defs/dist/agents/index.js +9 -0
  59. package/node_modules/@poe-code/agent-defs/dist/agents/kimi.d.ts +2 -0
  60. package/node_modules/@poe-code/agent-defs/dist/agents/kimi.js +16 -0
  61. package/node_modules/@poe-code/agent-defs/dist/agents/opencode.d.ts +2 -0
  62. package/node_modules/@poe-code/agent-defs/dist/agents/opencode.js +20 -0
  63. package/node_modules/@poe-code/agent-defs/dist/agents/poe-agent.d.ts +2 -0
  64. package/node_modules/@poe-code/agent-defs/dist/agents/poe-agent.js +14 -0
  65. package/node_modules/@poe-code/agent-defs/dist/index.d.ts +5 -0
  66. package/node_modules/@poe-code/agent-defs/dist/index.js +3 -0
  67. package/node_modules/@poe-code/agent-defs/dist/registry.d.ts +3 -0
  68. package/node_modules/@poe-code/agent-defs/dist/registry.js +45 -0
  69. package/node_modules/@poe-code/agent-defs/dist/specifier.d.ts +7 -0
  70. package/node_modules/@poe-code/agent-defs/dist/specifier.js +40 -0
  71. package/node_modules/@poe-code/agent-defs/dist/types.d.ts +28 -0
  72. package/node_modules/@poe-code/agent-defs/dist/types.js +1 -0
  73. package/node_modules/@poe-code/agent-defs/package.json +20 -0
  74. package/node_modules/@poe-code/agent-skill-config/dist/apply.js +2 -1
  75. package/node_modules/@poe-code/agent-skill-config/dist/bridge-active-skills.d.ts +1 -0
  76. package/node_modules/@poe-code/agent-skill-config/dist/bridge-active-skills.js +37 -18
  77. package/node_modules/@poe-code/agent-skill-config/dist/resolve-skill-reference.js +8 -4
  78. package/node_modules/@poe-code/agent-skill-config/package.json +1 -5
  79. package/node_modules/@poe-code/config-mutations/README.md +55 -0
  80. package/node_modules/@poe-code/config-mutations/dist/error-codes.d.ts +1 -0
  81. package/node_modules/@poe-code/config-mutations/dist/error-codes.js +6 -0
  82. package/node_modules/@poe-code/config-mutations/dist/execution/apply-mutation.d.ts +6 -0
  83. package/node_modules/@poe-code/config-mutations/dist/execution/apply-mutation.js +829 -0
  84. package/node_modules/@poe-code/config-mutations/dist/execution/path-utils.d.ts +17 -0
  85. package/node_modules/@poe-code/config-mutations/dist/execution/path-utils.js +64 -0
  86. package/node_modules/@poe-code/config-mutations/dist/execution/run-mutations.d.ts +7 -0
  87. package/node_modules/@poe-code/config-mutations/dist/execution/run-mutations.js +39 -0
  88. package/node_modules/@poe-code/config-mutations/dist/formats/index.d.ts +13 -0
  89. package/node_modules/@poe-code/config-mutations/dist/formats/index.js +49 -0
  90. package/node_modules/@poe-code/config-mutations/dist/formats/json.d.ts +32 -0
  91. package/node_modules/@poe-code/config-mutations/dist/formats/json.js +171 -0
  92. package/node_modules/@poe-code/config-mutations/dist/formats/object.d.ts +4 -0
  93. package/node_modules/@poe-code/config-mutations/dist/formats/object.js +27 -0
  94. package/node_modules/@poe-code/config-mutations/dist/formats/toml.d.ts +2 -0
  95. package/node_modules/@poe-code/config-mutations/dist/formats/toml.js +75 -0
  96. package/node_modules/@poe-code/config-mutations/dist/formats/yaml.d.ts +2 -0
  97. package/node_modules/@poe-code/config-mutations/dist/formats/yaml.js +76 -0
  98. package/node_modules/@poe-code/config-mutations/dist/fs-utils.d.ts +18 -0
  99. package/node_modules/@poe-code/config-mutations/dist/fs-utils.js +43 -0
  100. package/node_modules/@poe-code/config-mutations/dist/index.d.ts +8 -0
  101. package/node_modules/@poe-code/config-mutations/dist/index.js +8 -0
  102. package/node_modules/@poe-code/config-mutations/dist/mutations/config-mutation.d.ts +47 -0
  103. package/node_modules/@poe-code/config-mutations/dist/mutations/config-mutation.js +34 -0
  104. package/node_modules/@poe-code/config-mutations/dist/mutations/file-mutation.d.ts +62 -0
  105. package/node_modules/@poe-code/config-mutations/dist/mutations/file-mutation.js +55 -0
  106. package/node_modules/@poe-code/config-mutations/dist/mutations/template-mutation.d.ts +40 -0
  107. package/node_modules/@poe-code/config-mutations/dist/mutations/template-mutation.js +32 -0
  108. package/node_modules/@poe-code/config-mutations/dist/template/render.d.ts +6 -0
  109. package/node_modules/@poe-code/config-mutations/dist/template/render.js +8 -0
  110. package/node_modules/@poe-code/config-mutations/dist/testing/format-utils.d.ts +7 -0
  111. package/node_modules/@poe-code/config-mutations/dist/testing/format-utils.js +21 -0
  112. package/node_modules/@poe-code/config-mutations/dist/testing/index.d.ts +3 -0
  113. package/node_modules/@poe-code/config-mutations/dist/testing/index.js +2 -0
  114. package/node_modules/@poe-code/config-mutations/dist/testing/mock-fs.d.ts +25 -0
  115. package/node_modules/@poe-code/config-mutations/dist/testing/mock-fs.js +194 -0
  116. package/node_modules/@poe-code/config-mutations/dist/types.d.ts +168 -0
  117. package/node_modules/@poe-code/config-mutations/dist/types.js +6 -0
  118. package/node_modules/@poe-code/config-mutations/package.json +29 -0
  119. package/node_modules/@poe-code/frontmatter/README.md +35 -0
  120. package/node_modules/@poe-code/frontmatter/dist/fences.d.ts +25 -0
  121. package/node_modules/@poe-code/frontmatter/dist/fences.js +100 -0
  122. package/node_modules/@poe-code/frontmatter/dist/index.d.ts +3 -0
  123. package/node_modules/@poe-code/frontmatter/dist/index.js +3 -0
  124. package/node_modules/@poe-code/frontmatter/dist/parse.d.ts +20 -0
  125. package/node_modules/@poe-code/frontmatter/dist/parse.js +209 -0
  126. package/node_modules/@poe-code/frontmatter/dist/stringify.d.ts +1 -0
  127. package/node_modules/@poe-code/frontmatter/dist/stringify.js +48 -0
  128. package/node_modules/@poe-code/frontmatter/package.json +25 -0
  129. package/node_modules/toolcraft-design/README.md +160 -0
  130. package/node_modules/toolcraft-design/dist/acp/components.d.ts +12 -0
  131. package/node_modules/toolcraft-design/dist/acp/components.js +137 -0
  132. package/node_modules/toolcraft-design/dist/acp/index.d.ts +3 -0
  133. package/node_modules/toolcraft-design/dist/acp/index.js +2 -0
  134. package/node_modules/toolcraft-design/dist/acp/writer.d.ts +13 -0
  135. package/node_modules/toolcraft-design/dist/acp/writer.js +21 -0
  136. package/node_modules/toolcraft-design/dist/components/browser.d.ts +15 -0
  137. package/node_modules/toolcraft-design/dist/components/browser.js +31 -0
  138. package/node_modules/toolcraft-design/dist/components/catalog.d.ts +26 -0
  139. package/node_modules/toolcraft-design/dist/components/catalog.js +95 -0
  140. package/node_modules/toolcraft-design/dist/components/color.d.ts +31 -0
  141. package/node_modules/toolcraft-design/dist/components/color.js +102 -0
  142. package/node_modules/toolcraft-design/dist/components/command-errors.d.ts +16 -0
  143. package/node_modules/toolcraft-design/dist/components/command-errors.js +23 -0
  144. package/node_modules/toolcraft-design/dist/components/detail-card.d.ts +22 -0
  145. package/node_modules/toolcraft-design/dist/components/detail-card.js +45 -0
  146. package/node_modules/toolcraft-design/dist/components/help-formatter-plain.d.ts +5 -0
  147. package/node_modules/toolcraft-design/dist/components/help-formatter-plain.js +132 -0
  148. package/node_modules/toolcraft-design/dist/components/help-formatter.d.ts +33 -0
  149. package/node_modules/toolcraft-design/dist/components/help-formatter.js +213 -0
  150. package/node_modules/toolcraft-design/dist/components/index.d.ts +16 -0
  151. package/node_modules/toolcraft-design/dist/components/index.js +10 -0
  152. package/node_modules/toolcraft-design/dist/components/logger.d.ts +11 -0
  153. package/node_modules/toolcraft-design/dist/components/logger.js +60 -0
  154. package/node_modules/toolcraft-design/dist/components/symbols.d.ts +12 -0
  155. package/node_modules/toolcraft-design/dist/components/symbols.js +71 -0
  156. package/node_modules/toolcraft-design/dist/components/table.d.ts +15 -0
  157. package/node_modules/toolcraft-design/dist/components/table.js +302 -0
  158. package/node_modules/toolcraft-design/dist/components/template.d.ts +10 -0
  159. package/node_modules/toolcraft-design/dist/components/template.js +437 -0
  160. package/node_modules/toolcraft-design/dist/components/text.d.ts +16 -0
  161. package/node_modules/toolcraft-design/dist/components/text.js +145 -0
  162. package/node_modules/toolcraft-design/dist/dashboard/ansi.d.ts +18 -0
  163. package/node_modules/toolcraft-design/dist/dashboard/ansi.js +343 -0
  164. package/node_modules/toolcraft-design/dist/dashboard/buffer.d.ts +25 -0
  165. package/node_modules/toolcraft-design/dist/dashboard/buffer.js +219 -0
  166. package/node_modules/toolcraft-design/dist/dashboard/components/border.d.ts +9 -0
  167. package/node_modules/toolcraft-design/dist/dashboard/components/border.js +123 -0
  168. package/node_modules/toolcraft-design/dist/dashboard/components/footer.d.ts +8 -0
  169. package/node_modules/toolcraft-design/dist/dashboard/components/footer.js +56 -0
  170. package/node_modules/toolcraft-design/dist/dashboard/components/output-pane.d.ts +12 -0
  171. package/node_modules/toolcraft-design/dist/dashboard/components/output-pane.js +268 -0
  172. package/node_modules/toolcraft-design/dist/dashboard/components/stats-pane.d.ts +7 -0
  173. package/node_modules/toolcraft-design/dist/dashboard/components/stats-pane.js +107 -0
  174. package/node_modules/toolcraft-design/dist/dashboard/dashboard.d.ts +20 -0
  175. package/node_modules/toolcraft-design/dist/dashboard/dashboard.js +167 -0
  176. package/node_modules/toolcraft-design/dist/dashboard/demo.d.ts +13 -0
  177. package/node_modules/toolcraft-design/dist/dashboard/demo.js +145 -0
  178. package/node_modules/toolcraft-design/dist/dashboard/index.d.ts +8 -0
  179. package/node_modules/toolcraft-design/dist/dashboard/index.js +4 -0
  180. package/node_modules/toolcraft-design/dist/dashboard/keymap.d.ts +8 -0
  181. package/node_modules/toolcraft-design/dist/dashboard/keymap.js +233 -0
  182. package/node_modules/toolcraft-design/dist/dashboard/layout.d.ts +25 -0
  183. package/node_modules/toolcraft-design/dist/dashboard/layout.js +79 -0
  184. package/node_modules/toolcraft-design/dist/dashboard/should-use-dashboard.d.ts +10 -0
  185. package/node_modules/toolcraft-design/dist/dashboard/should-use-dashboard.js +7 -0
  186. package/node_modules/toolcraft-design/dist/dashboard/snapshot.d.ts +10 -0
  187. package/node_modules/toolcraft-design/dist/dashboard/snapshot.js +68 -0
  188. package/node_modules/toolcraft-design/dist/dashboard/store.d.ts +8 -0
  189. package/node_modules/toolcraft-design/dist/dashboard/store.js +51 -0
  190. package/node_modules/toolcraft-design/dist/dashboard/terminal-width.d.ts +4 -0
  191. package/node_modules/toolcraft-design/dist/dashboard/terminal-width.js +71 -0
  192. package/node_modules/toolcraft-design/dist/dashboard/terminal.d.ts +37 -0
  193. package/node_modules/toolcraft-design/dist/dashboard/terminal.js +264 -0
  194. package/node_modules/toolcraft-design/dist/dashboard/types.d.ts +38 -0
  195. package/node_modules/toolcraft-design/dist/dashboard/types.js +1 -0
  196. package/node_modules/toolcraft-design/dist/explorer/actions.d.ts +16 -0
  197. package/node_modules/toolcraft-design/dist/explorer/actions.js +39 -0
  198. package/node_modules/toolcraft-design/dist/explorer/demo.d.ts +13 -0
  199. package/node_modules/toolcraft-design/dist/explorer/demo.js +297 -0
  200. package/node_modules/toolcraft-design/dist/explorer/events.d.ts +67 -0
  201. package/node_modules/toolcraft-design/dist/explorer/events.js +1 -0
  202. package/node_modules/toolcraft-design/dist/explorer/filter.d.ts +10 -0
  203. package/node_modules/toolcraft-design/dist/explorer/filter.js +95 -0
  204. package/node_modules/toolcraft-design/dist/explorer/index.d.ts +8 -0
  205. package/node_modules/toolcraft-design/dist/explorer/index.js +8 -0
  206. package/node_modules/toolcraft-design/dist/explorer/jobs.d.ts +7 -0
  207. package/node_modules/toolcraft-design/dist/explorer/jobs.js +59 -0
  208. package/node_modules/toolcraft-design/dist/explorer/keymap.d.ts +21 -0
  209. package/node_modules/toolcraft-design/dist/explorer/keymap.js +376 -0
  210. package/node_modules/toolcraft-design/dist/explorer/layout.d.ts +20 -0
  211. package/node_modules/toolcraft-design/dist/explorer/layout.js +73 -0
  212. package/node_modules/toolcraft-design/dist/explorer/reducer.d.ts +9 -0
  213. package/node_modules/toolcraft-design/dist/explorer/reducer.js +782 -0
  214. package/node_modules/toolcraft-design/dist/explorer/render/detail.d.ts +4 -0
  215. package/node_modules/toolcraft-design/dist/explorer/render/detail.js +97 -0
  216. package/node_modules/toolcraft-design/dist/explorer/render/footer.d.ts +4 -0
  217. package/node_modules/toolcraft-design/dist/explorer/render/footer.js +73 -0
  218. package/node_modules/toolcraft-design/dist/explorer/render/header.d.ts +4 -0
  219. package/node_modules/toolcraft-design/dist/explorer/render/header.js +49 -0
  220. package/node_modules/toolcraft-design/dist/explorer/render/index.d.ts +8 -0
  221. package/node_modules/toolcraft-design/dist/explorer/render/index.js +53 -0
  222. package/node_modules/toolcraft-design/dist/explorer/render/list.d.ts +4 -0
  223. package/node_modules/toolcraft-design/dist/explorer/render/list.js +116 -0
  224. package/node_modules/toolcraft-design/dist/explorer/render/modal.d.ts +3 -0
  225. package/node_modules/toolcraft-design/dist/explorer/render/modal.js +87 -0
  226. package/node_modules/toolcraft-design/dist/explorer/render/test-fixtures.d.ts +8 -0
  227. package/node_modules/toolcraft-design/dist/explorer/render/test-fixtures.js +156 -0
  228. package/node_modules/toolcraft-design/dist/explorer/render/text.d.ts +12 -0
  229. package/node_modules/toolcraft-design/dist/explorer/render/text.js +81 -0
  230. package/node_modules/toolcraft-design/dist/explorer/runtime.d.ts +2 -0
  231. package/node_modules/toolcraft-design/dist/explorer/runtime.js +340 -0
  232. package/node_modules/toolcraft-design/dist/explorer/runtime.test-helpers.d.ts +50 -0
  233. package/node_modules/toolcraft-design/dist/explorer/runtime.test-helpers.js +101 -0
  234. package/node_modules/toolcraft-design/dist/explorer/state.d.ts +137 -0
  235. package/node_modules/toolcraft-design/dist/explorer/state.js +86 -0
  236. package/node_modules/toolcraft-design/dist/explorer/theme.d.ts +27 -0
  237. package/node_modules/toolcraft-design/dist/explorer/theme.js +29 -0
  238. package/node_modules/toolcraft-design/dist/index.d.ts +50 -0
  239. package/node_modules/toolcraft-design/dist/index.js +43 -0
  240. package/node_modules/toolcraft-design/dist/internal/color-support.d.ts +9 -0
  241. package/node_modules/toolcraft-design/dist/internal/color-support.js +12 -0
  242. package/node_modules/toolcraft-design/dist/internal/output-format.d.ts +6 -0
  243. package/node_modules/toolcraft-design/dist/internal/output-format.js +22 -0
  244. package/node_modules/toolcraft-design/dist/internal/strip-ansi.d.ts +1 -0
  245. package/node_modules/toolcraft-design/dist/internal/strip-ansi.js +50 -0
  246. package/node_modules/toolcraft-design/dist/internal/theme-detect.d.ts +12 -0
  247. package/node_modules/toolcraft-design/dist/internal/theme-detect.js +71 -0
  248. package/node_modules/toolcraft-design/dist/internal/theme-state.d.ts +12 -0
  249. package/node_modules/toolcraft-design/dist/internal/theme-state.js +35 -0
  250. package/node_modules/toolcraft-design/dist/prompts/index.d.ts +91 -0
  251. package/node_modules/toolcraft-design/dist/prompts/index.js +137 -0
  252. package/node_modules/toolcraft-design/dist/prompts/interactive/cancel-symbol.d.ts +2 -0
  253. package/node_modules/toolcraft-design/dist/prompts/interactive/cancel-symbol.js +4 -0
  254. package/node_modules/toolcraft-design/dist/prompts/interactive/confirm.d.ts +9 -0
  255. package/node_modules/toolcraft-design/dist/prompts/interactive/confirm.js +47 -0
  256. package/node_modules/toolcraft-design/dist/prompts/interactive/core.d.ts +55 -0
  257. package/node_modules/toolcraft-design/dist/prompts/interactive/core.js +274 -0
  258. package/node_modules/toolcraft-design/dist/prompts/interactive/glyphs.d.ts +20 -0
  259. package/node_modules/toolcraft-design/dist/prompts/interactive/glyphs.js +53 -0
  260. package/node_modules/toolcraft-design/dist/prompts/interactive/index.d.ts +6 -0
  261. package/node_modules/toolcraft-design/dist/prompts/interactive/index.js +6 -0
  262. package/node_modules/toolcraft-design/dist/prompts/interactive/keys.d.ts +2 -0
  263. package/node_modules/toolcraft-design/dist/prompts/interactive/keys.js +28 -0
  264. package/node_modules/toolcraft-design/dist/prompts/interactive/multiselect.d.ts +13 -0
  265. package/node_modules/toolcraft-design/dist/prompts/interactive/multiselect.js +131 -0
  266. package/node_modules/toolcraft-design/dist/prompts/interactive/pagination.d.ts +10 -0
  267. package/node_modules/toolcraft-design/dist/prompts/interactive/pagination.js +52 -0
  268. package/node_modules/toolcraft-design/dist/prompts/interactive/password.d.ts +10 -0
  269. package/node_modules/toolcraft-design/dist/prompts/interactive/password.js +55 -0
  270. package/node_modules/toolcraft-design/dist/prompts/interactive/select.d.ts +18 -0
  271. package/node_modules/toolcraft-design/dist/prompts/interactive/select.js +89 -0
  272. package/node_modules/toolcraft-design/dist/prompts/interactive/test-helpers.d.ts +21 -0
  273. package/node_modules/toolcraft-design/dist/prompts/interactive/test-helpers.js +32 -0
  274. package/node_modules/toolcraft-design/dist/prompts/interactive/text.d.ts +12 -0
  275. package/node_modules/toolcraft-design/dist/prompts/interactive/text.js +60 -0
  276. package/node_modules/toolcraft-design/dist/prompts/interactive/wrap.d.ts +4 -0
  277. package/node_modules/toolcraft-design/dist/prompts/interactive/wrap.js +18 -0
  278. package/node_modules/toolcraft-design/dist/prompts/primitives/cancel.d.ts +2 -0
  279. package/node_modules/toolcraft-design/dist/prompts/primitives/cancel.js +9 -0
  280. package/node_modules/toolcraft-design/dist/prompts/primitives/intro.d.ts +1 -0
  281. package/node_modules/toolcraft-design/dist/prompts/primitives/intro.js +16 -0
  282. package/node_modules/toolcraft-design/dist/prompts/primitives/log.d.ts +18 -0
  283. package/node_modules/toolcraft-design/dist/prompts/primitives/log.js +104 -0
  284. package/node_modules/toolcraft-design/dist/prompts/primitives/note.d.ts +1 -0
  285. package/node_modules/toolcraft-design/dist/prompts/primitives/note.js +39 -0
  286. package/node_modules/toolcraft-design/dist/prompts/primitives/outro.d.ts +1 -0
  287. package/node_modules/toolcraft-design/dist/prompts/primitives/outro.js +16 -0
  288. package/node_modules/toolcraft-design/dist/prompts/primitives/spinner.d.ts +6 -0
  289. package/node_modules/toolcraft-design/dist/prompts/primitives/spinner.js +74 -0
  290. package/node_modules/toolcraft-design/dist/prompts/theme.d.ts +11 -0
  291. package/node_modules/toolcraft-design/dist/prompts/theme.js +15 -0
  292. package/node_modules/toolcraft-design/dist/static/index.d.ts +4 -0
  293. package/node_modules/toolcraft-design/dist/static/index.js +2 -0
  294. package/node_modules/toolcraft-design/dist/static/menu.d.ts +11 -0
  295. package/node_modules/toolcraft-design/dist/static/menu.js +42 -0
  296. package/node_modules/toolcraft-design/dist/static/spinner.d.ts +14 -0
  297. package/node_modules/toolcraft-design/dist/static/spinner.js +52 -0
  298. package/node_modules/toolcraft-design/dist/terminal-markdown/ast.d.ts +92 -0
  299. package/node_modules/toolcraft-design/dist/terminal-markdown/ast.js +1 -0
  300. package/node_modules/toolcraft-design/dist/terminal-markdown/demo-content.d.ts +2 -0
  301. package/node_modules/toolcraft-design/dist/terminal-markdown/demo-content.js +139 -0
  302. package/node_modules/toolcraft-design/dist/terminal-markdown/index.d.ts +6 -0
  303. package/node_modules/toolcraft-design/dist/terminal-markdown/index.js +8 -0
  304. package/node_modules/toolcraft-design/dist/terminal-markdown/parser/block.d.ts +7 -0
  305. package/node_modules/toolcraft-design/dist/terminal-markdown/parser/block.js +1495 -0
  306. package/node_modules/toolcraft-design/dist/terminal-markdown/parser/frontmatter.d.ts +8 -0
  307. package/node_modules/toolcraft-design/dist/terminal-markdown/parser/frontmatter.js +36 -0
  308. package/node_modules/toolcraft-design/dist/terminal-markdown/parser/inline.d.ts +10 -0
  309. package/node_modules/toolcraft-design/dist/terminal-markdown/parser/inline.js +1190 -0
  310. package/node_modules/toolcraft-design/dist/terminal-markdown/parser.d.ts +5 -0
  311. package/node_modules/toolcraft-design/dist/terminal-markdown/parser.js +42 -0
  312. package/node_modules/toolcraft-design/dist/terminal-markdown/renderer.d.ts +6 -0
  313. package/node_modules/toolcraft-design/dist/terminal-markdown/renderer.js +615 -0
  314. package/node_modules/toolcraft-design/dist/terminal-markdown/testing/theme-render-fixture.d.ts +1 -0
  315. package/node_modules/toolcraft-design/dist/terminal-markdown/testing/theme-render-fixture.js +27 -0
  316. package/node_modules/toolcraft-design/dist/tokens/brand.d.ts +5 -0
  317. package/node_modules/toolcraft-design/dist/tokens/brand.js +5 -0
  318. package/node_modules/toolcraft-design/dist/tokens/colors.d.ts +37 -0
  319. package/node_modules/toolcraft-design/dist/tokens/colors.js +85 -0
  320. package/node_modules/toolcraft-design/dist/tokens/index.d.ts +6 -0
  321. package/node_modules/toolcraft-design/dist/tokens/index.js +5 -0
  322. package/node_modules/toolcraft-design/dist/tokens/spacing.d.ts +6 -0
  323. package/node_modules/toolcraft-design/dist/tokens/spacing.js +6 -0
  324. package/node_modules/toolcraft-design/dist/tokens/typography.d.ts +7 -0
  325. package/node_modules/toolcraft-design/dist/tokens/typography.js +8 -0
  326. package/node_modules/toolcraft-design/dist/tokens/widths.d.ts +5 -0
  327. package/node_modules/toolcraft-design/dist/tokens/widths.js +5 -0
  328. package/node_modules/toolcraft-design/package.json +44 -0
  329. package/package.json +15 -5
package/dist/cli.js CHANGED
@@ -7,12 +7,12 @@ var __export = (target, all) => {
7
7
 
8
8
  // src/cli.ts
9
9
  import { realpath as realpath3 } from "node:fs/promises";
10
- import path23 from "node:path";
10
+ import path24 from "node:path";
11
11
  import { fileURLToPath as fileURLToPath5 } from "node:url";
12
12
 
13
13
  // ../toolcraft/src/cli.ts
14
- import { access as access2, lstat as lstat3, readFile as readFile4, rename as rename3, unlink as unlink3, writeFile as writeFile5 } from "node:fs/promises";
15
- import path14 from "node:path";
14
+ import { access as access2, lstat as lstat3, readFile as readFile5, rename as rename3, unlink as unlink3, writeFile as writeFile5 } from "node:fs/promises";
15
+ import path15 from "node:path";
16
16
  import {
17
17
  Command as CommanderCommand,
18
18
  CommanderError as CommanderError2,
@@ -378,7 +378,8 @@ function renderMarkdownCode(content) {
378
378
  currentRun = 0;
379
379
  }
380
380
  const delimiter = "`".repeat(longestRun + 1);
381
- return `${delimiter}${value}${delimiter}`;
381
+ const paddedValue = value.startsWith("`") || value.endsWith("`") ? ` ${value} ` : value;
382
+ return `${delimiter}${paddedValue}${delimiter}`;
382
383
  }
383
384
  function renderMarkdownLink(content) {
384
385
  const value = renderMarkdownInline(content);
@@ -533,7 +534,54 @@ var symbols = {
533
534
 
534
535
  // ../toolcraft-design/src/internal/strip-ansi.ts
535
536
  function stripAnsi(value) {
536
- return value.replace(/\u001b\[[0-9;]*m/g, "");
537
+ let output = "";
538
+ let index = 0;
539
+ while (index < value.length) {
540
+ const char = value[index];
541
+ if (char === "\x1B") {
542
+ index = skipEscapeSequence(value, index);
543
+ continue;
544
+ }
545
+ if (char === "\x9B") {
546
+ index = skipCsiSequence(value, index + 1);
547
+ continue;
548
+ }
549
+ output += char;
550
+ index += char.length;
551
+ }
552
+ return output;
553
+ }
554
+ function skipEscapeSequence(value, index) {
555
+ const next = value[index + 1];
556
+ if (next === "[") {
557
+ return skipCsiSequence(value, index + 2);
558
+ }
559
+ if (next === "]") {
560
+ return skipOscSequence(value, index + 2);
561
+ }
562
+ return Math.min(value.length, index + 2);
563
+ }
564
+ function skipCsiSequence(value, index) {
565
+ while (index < value.length) {
566
+ const codePoint = value.charCodeAt(index);
567
+ index += 1;
568
+ if (codePoint >= 64 && codePoint <= 126) {
569
+ break;
570
+ }
571
+ }
572
+ return index;
573
+ }
574
+ function skipOscSequence(value, index) {
575
+ while (index < value.length) {
576
+ if (value[index] === "\x07") {
577
+ return index + 1;
578
+ }
579
+ if (value[index] === "\x1B" && value[index + 1] === "\\") {
580
+ return index + 2;
581
+ }
582
+ index += 1;
583
+ }
584
+ return index;
537
585
  }
538
586
 
539
587
  // ../toolcraft-design/src/prompts/primitives/log.ts
@@ -1322,38 +1370,14 @@ function renderTable(options) {
1322
1370
  }
1323
1371
 
1324
1372
  // ../toolcraft-design/src/components/detail-card.ts
1373
+ import stringWidth from "fast-string-width";
1374
+ import { wrapAnsi } from "fast-wrap-ansi";
1325
1375
  function wrap(value, width) {
1326
- const lines = [];
1327
- for (const paragraph of value.split("\n")) {
1328
- let line = "";
1329
- for (const rawWord of paragraph.split(" ")) {
1330
- const words = [];
1331
- let word = rawWord;
1332
- while (word.length > width) {
1333
- words.push(word.slice(0, width));
1334
- word = word.slice(width);
1335
- }
1336
- words.push(word);
1337
- for (const word2 of words) {
1338
- if (line.length === 0) {
1339
- line = word2;
1340
- continue;
1341
- }
1342
- if (`${line} ${word2}`.length <= width) {
1343
- line = `${line} ${word2}`;
1344
- continue;
1345
- }
1346
- lines.push(line);
1347
- line = word2;
1348
- }
1349
- }
1350
- lines.push(line);
1351
- }
1352
- return lines;
1376
+ return wrapAnsi(value, Math.max(1, width), { hard: true, trim: true }).split("\n");
1353
1377
  }
1354
1378
  function renderRows(rows, theme, width) {
1355
1379
  if (rows.length === 0) return [];
1356
- const labelWidth = Math.max(...rows.map((row) => row.label.length));
1380
+ const labelWidth = Math.max(...rows.map((row) => stringWidth(row.label)));
1357
1381
  const valueWidth = Math.max(20, width - labelWidth - 2);
1358
1382
  const continuation = " ".repeat(labelWidth + 2);
1359
1383
  return rows.flatMap((row) => {
@@ -1374,12 +1398,16 @@ function renderDetailCard(options) {
1374
1398
  ${options.theme.muted(options.badges.map((badge) => badge[0] + badge.slice(1).toLowerCase()).join(" \xB7 "))}` : identity;
1375
1399
  const blocks = [hero];
1376
1400
  for (const prose of options.prose ?? []) {
1377
- blocks.push(prose.title ? [options.theme.header(prose.title), wrap(prose.value, width).join("\n")].join("\n") : wrap(prose.value, width).join("\n"));
1401
+ blocks.push(
1402
+ prose.title ? [options.theme.header(prose.title), wrap(prose.value, width).join("\n")].join("\n") : wrap(prose.value, width).join("\n")
1403
+ );
1378
1404
  }
1379
1405
  for (const section of options.sections ?? []) {
1380
1406
  if (section.rows.length === 0) continue;
1381
1407
  const rows = renderRows(section.rows, options.theme, width);
1382
- blocks.push(section.title ? [options.theme.header(section.title), ...rows].join("\n") : rows.join("\n"));
1408
+ blocks.push(
1409
+ section.title ? [options.theme.header(section.title), ...rows].join("\n") : rows.join("\n")
1410
+ );
1383
1411
  }
1384
1412
  return blocks.join("\n\n");
1385
1413
  }
@@ -1806,13 +1834,13 @@ import { LineCounter, parse, parseDocument } from "yaml";
1806
1834
  // ../frontmatter/src/stringify.ts
1807
1835
  import { stringify } from "yaml";
1808
1836
 
1837
+ // ../toolcraft-design/src/dashboard/terminal-width.ts
1838
+ var graphemeSegmenter3 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
1839
+
1809
1840
  // ../toolcraft-design/src/acp/writer.ts
1810
1841
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
1811
1842
  var storage = new AsyncLocalStorage2();
1812
1843
 
1813
- // ../toolcraft-design/src/dashboard/terminal-width.ts
1814
- var graphemeSegmenter3 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
1815
-
1816
1844
  // ../toolcraft-design/src/dashboard/terminal.ts
1817
1845
  import readline from "node:readline";
1818
1846
  import { PassThrough } from "node:stream";
@@ -1909,8 +1937,8 @@ function mapKey(name, char) {
1909
1937
  }
1910
1938
 
1911
1939
  // ../toolcraft-design/src/prompts/interactive/wrap.ts
1912
- import { wrapAnsi } from "fast-wrap-ansi";
1913
- import stringWidth from "fast-string-width";
1940
+ import { wrapAnsi as wrapAnsi2 } from "fast-wrap-ansi";
1941
+ import stringWidth2 from "fast-string-width";
1914
1942
  function getColumns(output) {
1915
1943
  return Math.max(1, output.columns ?? 80);
1916
1944
  }
@@ -1918,7 +1946,7 @@ function getRows(output) {
1918
1946
  return Math.max(1, output.rows ?? 20);
1919
1947
  }
1920
1948
  function wrapFrame(output, frame) {
1921
- return wrapAnsi(frame, getColumns(output), { hard: true, trim: false });
1949
+ return wrapAnsi2(frame, getColumns(output), { hard: true, trim: false });
1922
1950
  }
1923
1951
 
1924
1952
  // ../toolcraft-design/src/prompts/interactive/core.ts
@@ -2239,7 +2267,7 @@ function confirmPrompt(opts) {
2239
2267
  }
2240
2268
 
2241
2269
  // ../toolcraft-design/src/prompts/interactive/pagination.ts
2242
- import { wrapAnsi as wrapAnsi2 } from "fast-wrap-ansi";
2270
+ import { wrapAnsi as wrapAnsi3 } from "fast-wrap-ansi";
2243
2271
  function countLines(values) {
2244
2272
  return values.reduce((sum, value) => sum + value.split("\n").length, 0);
2245
2273
  }
@@ -2282,7 +2310,7 @@ function limitOptions(opts) {
2282
2310
  }
2283
2311
  const hasTopMarker = cappedVisibleCount < options.length && start > 0;
2284
2312
  const hasBottomMarker = cappedVisibleCount < options.length && start + cappedVisibleCount < options.length;
2285
- const visible = options.slice(start, start + cappedVisibleCount).map((option, index) => wrapAnsi2(style(option, start + index === cursor2), columns, { hard: true, trim: false }));
2313
+ const visible = options.slice(start, start + cappedVisibleCount).map((option, index) => wrapAnsi3(style(option, start + index === cursor2), columns, { hard: true, trim: false }));
2286
2314
  const trimmed = trimToRows(
2287
2315
  visible,
2288
2316
  Math.max(cursor2 - start, 0),
@@ -2665,6 +2693,9 @@ function isOptionalSchema(schema) {
2665
2693
  function getRequiredKeys(schema) {
2666
2694
  return Object.keys(schema.shape).filter((key2) => !isOptionalSchema(schema.shape[key2])).sort();
2667
2695
  }
2696
+ function getRequiredKeyFingerprint(schema) {
2697
+ return getRequiredKeys(schema).join("+");
2698
+ }
2668
2699
  function assertUniqueRequiredKeyFingerprints(branches) {
2669
2700
  const fingerprints = /* @__PURE__ */ new Map();
2670
2701
  branches.forEach((branch, index) => {
@@ -2702,6 +2733,451 @@ function Union(branches) {
2702
2733
  };
2703
2734
  }
2704
2735
 
2736
+ // ../toolcraft-schema/src/validate.ts
2737
+ var missingValue = /* @__PURE__ */ Symbol("missingValue");
2738
+ function validate(schema, value) {
2739
+ const state = { issues: [] };
2740
+ const result = walkSchema(schema, value, [], state);
2741
+ if (state.issues.length > 0) {
2742
+ return { ok: false, issues: state.issues };
2743
+ }
2744
+ return { ok: true, value: result.present ? result.value : void 0 };
2745
+ }
2746
+ function walkSchema(schema, value, path25, state) {
2747
+ if (schema.kind === "optional") {
2748
+ return walkOptional(schema, value, path25, state);
2749
+ }
2750
+ if (value === missingValue) {
2751
+ addIssue(
2752
+ state,
2753
+ path25,
2754
+ expectedFor(schema),
2755
+ "missing",
2756
+ `Expected ${expectedFor(schema)} at ${formatPath(path25)}`
2757
+ );
2758
+ return { present: false };
2759
+ }
2760
+ if (value === null && schema.nullable === true) {
2761
+ return { present: true, value };
2762
+ }
2763
+ switch (schema.kind) {
2764
+ case "string":
2765
+ return walkString(schema, value, path25, state);
2766
+ case "number":
2767
+ return walkNumber(schema, value, path25, state);
2768
+ case "boolean":
2769
+ return walkBoolean(value, path25, state);
2770
+ case "enum":
2771
+ return walkEnum(schema, value, path25, state);
2772
+ case "array":
2773
+ return walkArray(schema, value, path25, state);
2774
+ case "object":
2775
+ return walkObject(schema, value, path25, state);
2776
+ case "oneOf":
2777
+ return walkOneOf(schema, value, path25, state);
2778
+ case "union":
2779
+ return walkUnion(schema, value, path25, state);
2780
+ case "record":
2781
+ return walkRecord(schema, value, path25, state);
2782
+ case "json":
2783
+ return walkJson(value, path25, state);
2784
+ }
2785
+ }
2786
+ function walkOptional(schema, value, path25, state) {
2787
+ if (value === missingValue || value === void 0) {
2788
+ const defaultValue = getDefault(schema.inner);
2789
+ if (defaultValue.present) {
2790
+ return walkSchema(schema.inner, cloneDefault(defaultValue.value), path25, state);
2791
+ }
2792
+ return { present: false };
2793
+ }
2794
+ return walkSchema(schema.inner, value, path25, state);
2795
+ }
2796
+ function walkString(schema, value, path25, state) {
2797
+ if (typeof value !== "string") {
2798
+ addExpectedIssue(state, path25, "string", value);
2799
+ return { present: true, value };
2800
+ }
2801
+ if (schema.minLength !== void 0 && value.length < schema.minLength) {
2802
+ const expected = `string with length at least ${schema.minLength}`;
2803
+ addIssue(
2804
+ state,
2805
+ path25,
2806
+ expected,
2807
+ `string with length ${value.length}`,
2808
+ `Expected ${expected} at ${formatPath(path25)}`
2809
+ );
2810
+ }
2811
+ if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
2812
+ const expected = `string with length at most ${schema.maxLength}`;
2813
+ addIssue(
2814
+ state,
2815
+ path25,
2816
+ expected,
2817
+ `string with length ${value.length}`,
2818
+ `Expected ${expected} at ${formatPath(path25)}`
2819
+ );
2820
+ }
2821
+ if (schema.pattern !== void 0) {
2822
+ const pattern = compilePattern(schema.pattern);
2823
+ if (pattern === void 0 || !pattern.test(value)) {
2824
+ const expected = `string matching pattern ${schema.pattern}`;
2825
+ addIssue(state, path25, expected, value, `Expected ${expected} at ${formatPath(path25)}`);
2826
+ }
2827
+ }
2828
+ return { present: true, value };
2829
+ }
2830
+ function walkNumber(schema, value, path25, state) {
2831
+ if (typeof value !== "number" || !Number.isFinite(value)) {
2832
+ addExpectedIssue(state, path25, schema.jsonType === "integer" ? "integer" : "number", value);
2833
+ return { present: true, value };
2834
+ }
2835
+ if (schema.jsonType === "integer" && !Number.isInteger(value)) {
2836
+ addExpectedIssue(state, path25, "integer", value);
2837
+ }
2838
+ if (schema.minimum !== void 0 && value < schema.minimum) {
2839
+ const expected = `number greater than or equal to ${schema.minimum}`;
2840
+ addIssue(state, path25, expected, String(value), `Expected ${expected} at ${formatPath(path25)}`);
2841
+ }
2842
+ if (schema.maximum !== void 0 && value > schema.maximum) {
2843
+ const expected = `number less than or equal to ${schema.maximum}`;
2844
+ addIssue(state, path25, expected, String(value), `Expected ${expected} at ${formatPath(path25)}`);
2845
+ }
2846
+ return { present: true, value };
2847
+ }
2848
+ function walkBoolean(value, path25, state) {
2849
+ if (typeof value !== "boolean") {
2850
+ addExpectedIssue(state, path25, "boolean", value);
2851
+ }
2852
+ return { present: true, value };
2853
+ }
2854
+ function walkEnum(schema, value, path25, state) {
2855
+ if (!schema.values.includes(value)) {
2856
+ const expected = `one of ${schema.values.join(", ")}`;
2857
+ addIssue(
2858
+ state,
2859
+ path25,
2860
+ expected,
2861
+ receivedValue(value),
2862
+ `Expected ${expected} at ${formatPath(path25)}`
2863
+ );
2864
+ }
2865
+ return { present: true, value };
2866
+ }
2867
+ function walkArray(schema, value, path25, state) {
2868
+ if (!Array.isArray(value)) {
2869
+ addExpectedIssue(state, path25, "array", value);
2870
+ return { present: true, value };
2871
+ }
2872
+ if (schema.minItems !== void 0 && value.length < schema.minItems) {
2873
+ const expected = `array with at least ${schema.minItems} items`;
2874
+ addIssue(
2875
+ state,
2876
+ path25,
2877
+ expected,
2878
+ `array with ${value.length} items`,
2879
+ `Expected ${expected} at ${formatPath(path25)}`
2880
+ );
2881
+ }
2882
+ if (schema.maxItems !== void 0 && value.length > schema.maxItems) {
2883
+ const expected = `array with at most ${schema.maxItems} items`;
2884
+ addIssue(
2885
+ state,
2886
+ path25,
2887
+ expected,
2888
+ `array with ${value.length} items`,
2889
+ `Expected ${expected} at ${formatPath(path25)}`
2890
+ );
2891
+ }
2892
+ const nextValue = value.map((item, index) => {
2893
+ const result = walkSchema(schema.item, item, [...path25, String(index)], state);
2894
+ return result.present ? result.value : item;
2895
+ });
2896
+ return { present: true, value: nextValue };
2897
+ }
2898
+ function walkObject(schema, value, path25, state, injectedProperties = {}) {
2899
+ if (!isPlainRecord(value)) {
2900
+ addExpectedIssue(state, path25, "object", value);
2901
+ return { present: true, value };
2902
+ }
2903
+ const nextValue = {};
2904
+ const allowedKeys = /* @__PURE__ */ new Set([...Object.keys(schema.shape), ...Object.keys(injectedProperties)]);
2905
+ for (const [key2, propertySchema] of Object.entries(schema.shape)) {
2906
+ const propertyValue = Object.hasOwn(value, key2) ? value[key2] : missingValue;
2907
+ const result = walkSchema(propertySchema, propertyValue, [...path25, key2], state);
2908
+ if (result.present) {
2909
+ setOwnValue(nextValue, key2, result.value);
2910
+ }
2911
+ }
2912
+ for (const [key2, injectedValue] of Object.entries(injectedProperties)) {
2913
+ if (Object.hasOwn(value, key2)) {
2914
+ setOwnValue(nextValue, key2, value[key2]);
2915
+ } else {
2916
+ setOwnValue(nextValue, key2, injectedValue);
2917
+ }
2918
+ }
2919
+ for (const [key2, propertyValue] of Object.entries(value)) {
2920
+ if (allowedKeys.has(key2)) {
2921
+ continue;
2922
+ }
2923
+ if (schema.additionalProperties === true) {
2924
+ setOwnValue(nextValue, key2, propertyValue);
2925
+ } else {
2926
+ addUnexpectedPropertyIssue(state, [...path25, key2]);
2927
+ }
2928
+ }
2929
+ return { present: true, value: nextValue };
2930
+ }
2931
+ function walkOneOf(schema, value, path25, state) {
2932
+ if (!isPlainRecord(value)) {
2933
+ addExpectedIssue(state, path25, "object", value);
2934
+ return { present: true, value };
2935
+ }
2936
+ const discriminatorValue = value[schema.discriminator];
2937
+ const discriminatorPath = [...path25, schema.discriminator];
2938
+ const branchValues = Object.keys(schema.branches);
2939
+ const expected = `one of ${branchValues.join(", ")}`;
2940
+ if (!Object.hasOwn(value, schema.discriminator)) {
2941
+ addIssueWithMessage(
2942
+ state,
2943
+ discriminatorPath,
2944
+ expected,
2945
+ "missing",
2946
+ `Missing discriminator "${schema.discriminator}" at ${formatPath(path25)}. Expected one of: ${branchValues.join(", ")}.`
2947
+ );
2948
+ return { present: true, value };
2949
+ }
2950
+ if (typeof discriminatorValue !== "string" || !Object.hasOwn(schema.branches, discriminatorValue)) {
2951
+ addIssueWithMessage(
2952
+ state,
2953
+ discriminatorPath,
2954
+ expected,
2955
+ receivedValue(discriminatorValue),
2956
+ `Expected ${expected} at ${formatPath(discriminatorPath)}, got ${formatReceivedDiscriminator(discriminatorValue)}`
2957
+ );
2958
+ return { present: true, value };
2959
+ }
2960
+ return walkObject(schema.branches[discriminatorValue], value, path25, state, {
2961
+ [schema.discriminator]: discriminatorValue
2962
+ });
2963
+ }
2964
+ function walkUnion(schema, value, path25, state) {
2965
+ if (isPlainRecord(value)) {
2966
+ const candidateBranches = schema.branches.filter((branch) => hasRequiredKeys(branch, value));
2967
+ if (candidateBranches.length === 1) {
2968
+ return walkObject(candidateBranches[0], value, path25, state);
2969
+ }
2970
+ }
2971
+ const matches = [];
2972
+ for (const branch of schema.branches) {
2973
+ const branchState = { issues: [] };
2974
+ const result = walkObject(branch, value, path25, branchState);
2975
+ if (branchState.issues.length === 0 && result.present) {
2976
+ matches.push({ fingerprint: getRequiredKeyFingerprint(branch), value: result.value });
2977
+ }
2978
+ }
2979
+ if (matches.length === 1) {
2980
+ return { present: true, value: matches[0].value };
2981
+ }
2982
+ if (matches.length === 0) {
2983
+ const branchDescriptions = schema.branches.map((branch) => getRequiredKeyFingerprint(branch));
2984
+ addIssueWithMessage(
2985
+ state,
2986
+ path25,
2987
+ "exactly one union branch",
2988
+ "0 matching branches",
2989
+ `No union branch matched at ${formatPath(path25)}. Tried ${schema.branches.length} branches. Expected one of: ${branchDescriptions.join(" | ")}.`
2990
+ );
2991
+ return { present: true, value };
2992
+ }
2993
+ addIssueWithMessage(
2994
+ state,
2995
+ path25,
2996
+ "exactly one union branch",
2997
+ `${matches.length} matching branches`,
2998
+ `Expected exactly one union branch at ${formatPath(path25)}, but matched more than one branch: ${matches.map((match) => match.fingerprint).join(" | ")}`
2999
+ );
3000
+ return { present: true, value };
3001
+ }
3002
+ function hasRequiredKeys(schema, value) {
3003
+ for (const [key2, propertySchema] of Object.entries(schema.shape)) {
3004
+ if (propertySchema.kind !== "optional" && !Object.hasOwn(value, key2)) {
3005
+ return false;
3006
+ }
3007
+ }
3008
+ return true;
3009
+ }
3010
+ function walkRecord(schema, value, path25, state) {
3011
+ if (!isPlainRecord(value)) {
3012
+ addExpectedIssue(state, path25, "object", value);
3013
+ return { present: true, value };
3014
+ }
3015
+ const nextValue = {};
3016
+ for (const [key2, propertyValue] of Object.entries(value)) {
3017
+ const result = walkSchema(schema.value, propertyValue, [...path25, key2], state);
3018
+ if (result.present) {
3019
+ setOwnValue(nextValue, key2, result.value);
3020
+ }
3021
+ }
3022
+ return { present: true, value: nextValue };
3023
+ }
3024
+ function walkJson(value, path25, state) {
3025
+ if (isJsonValue(value)) {
3026
+ return { present: true, value };
3027
+ }
3028
+ addExpectedIssue(state, path25, "JSON value", value);
3029
+ return { present: true, value };
3030
+ }
3031
+ function getDefault(schema) {
3032
+ if (schema.default !== void 0) {
3033
+ return { present: true, value: schema.default };
3034
+ }
3035
+ if (schema.kind === "optional") {
3036
+ return getDefault(schema.inner);
3037
+ }
3038
+ return { present: false };
3039
+ }
3040
+ function isPlainRecord(value) {
3041
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
3042
+ return false;
3043
+ }
3044
+ const prototype = Object.getPrototypeOf(value);
3045
+ return prototype === Object.prototype || prototype === null;
3046
+ }
3047
+ function isJsonValue(value, ancestors = /* @__PURE__ */ new Set()) {
3048
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
3049
+ return typeof value !== "number" || Number.isFinite(value);
3050
+ }
3051
+ if (Array.isArray(value)) {
3052
+ if (ancestors.has(value)) {
3053
+ return false;
3054
+ }
3055
+ ancestors.add(value);
3056
+ const result = value.every((item) => isJsonValue(item, ancestors));
3057
+ ancestors.delete(value);
3058
+ return result;
3059
+ }
3060
+ if (isPlainRecord(value)) {
3061
+ if (ancestors.has(value)) {
3062
+ return false;
3063
+ }
3064
+ ancestors.add(value);
3065
+ const result = Object.values(value).every((item) => isJsonValue(item, ancestors));
3066
+ ancestors.delete(value);
3067
+ return result;
3068
+ }
3069
+ return false;
3070
+ }
3071
+ function cloneDefault(value) {
3072
+ return structuredClone(value);
3073
+ }
3074
+ function setOwnValue(target, key2, value) {
3075
+ Object.defineProperty(target, key2, {
3076
+ configurable: true,
3077
+ enumerable: true,
3078
+ writable: true,
3079
+ value
3080
+ });
3081
+ }
3082
+ function expectedFor(schema) {
3083
+ switch (schema.kind) {
3084
+ case "string":
3085
+ return "string";
3086
+ case "number":
3087
+ return schema.jsonType === "integer" ? "integer" : "number";
3088
+ case "boolean":
3089
+ return "boolean";
3090
+ case "enum":
3091
+ return `one of ${schema.values.join(", ")}`;
3092
+ case "array":
3093
+ return "array";
3094
+ case "object":
3095
+ case "oneOf":
3096
+ case "record":
3097
+ return "object";
3098
+ case "union":
3099
+ return "exactly one union branch";
3100
+ case "json":
3101
+ return "JSON value";
3102
+ case "optional":
3103
+ return expectedFor(schema.inner);
3104
+ }
3105
+ }
3106
+ function addExpectedIssue(state, path25, expected, value) {
3107
+ addIssue(
3108
+ state,
3109
+ path25,
3110
+ expected,
3111
+ receivedType(value),
3112
+ `Expected ${expected} at ${formatPath(path25)}`
3113
+ );
3114
+ }
3115
+ function addUnexpectedPropertyIssue(state, path25) {
3116
+ addIssue(
3117
+ state,
3118
+ path25,
3119
+ "no additional properties",
3120
+ "unknown property",
3121
+ `Unexpected property ${formatPath(path25)}`
3122
+ );
3123
+ }
3124
+ function addIssue(state, path25, expected, received, _message) {
3125
+ state.issues.push({
3126
+ path: path25,
3127
+ expected,
3128
+ received,
3129
+ message: formatIssueMessage(expected, path25, received)
3130
+ });
3131
+ }
3132
+ function addIssueWithMessage(state, path25, expected, received, message2) {
3133
+ state.issues.push({
3134
+ path: path25,
3135
+ expected,
3136
+ received,
3137
+ message: message2
3138
+ });
3139
+ }
3140
+ function formatIssueMessage(expected, path25, received) {
3141
+ return `Expected ${expected} at ${formatPath(path25)}, got ${received}`;
3142
+ }
3143
+ function formatPath(path25) {
3144
+ return path25.length === 0 ? "value" : path25.join(".");
3145
+ }
3146
+ function compilePattern(pattern) {
3147
+ try {
3148
+ return new RegExp(pattern);
3149
+ } catch {
3150
+ return void 0;
3151
+ }
3152
+ }
3153
+ function receivedType(value) {
3154
+ if (value === null) {
3155
+ return "null";
3156
+ }
3157
+ if (Array.isArray(value)) {
3158
+ return "array";
3159
+ }
3160
+ if (typeof value === "number" && Number.isInteger(value)) {
3161
+ return "integer";
3162
+ }
3163
+ return typeof value;
3164
+ }
3165
+ function receivedValue(value) {
3166
+ if (typeof value === "string") {
3167
+ return value;
3168
+ }
3169
+ if (value === void 0) {
3170
+ return "undefined";
3171
+ }
3172
+ return String(value);
3173
+ }
3174
+ function formatReceivedDiscriminator(value) {
3175
+ if (typeof value === "string") {
3176
+ return JSON.stringify(value);
3177
+ }
3178
+ return receivedValue(value);
3179
+ }
3180
+
2705
3181
  // ../toolcraft-schema/src/index.ts
2706
3182
  function assertValidEnumValues(values) {
2707
3183
  if (values.length === 0) {
@@ -2725,6 +3201,22 @@ function assertFiniteNumber(value, name) {
2725
3201
  throw new Error(`${name} must be finite`);
2726
3202
  }
2727
3203
  }
3204
+ function assertMinMaxOrder(minimum, maximum, minimumName, maximumName) {
3205
+ if (minimum !== void 0 && maximum !== void 0 && minimum > maximum) {
3206
+ throw new Error(`${minimumName} must be less than or equal to ${maximumName}`);
3207
+ }
3208
+ }
3209
+ function assertValidDefault(schema) {
3210
+ if (schema.default === void 0) {
3211
+ return;
3212
+ }
3213
+ const result = validate(schema, schema.default);
3214
+ if (!result.ok) {
3215
+ throw new Error(
3216
+ `default must satisfy schema: ${result.issues[0]?.message ?? "invalid default"}`
3217
+ );
3218
+ }
3219
+ }
2728
3220
  function assertPattern(pattern) {
2729
3221
  if (pattern === void 0) {
2730
3222
  return;
@@ -2739,56 +3231,71 @@ var S = {
2739
3231
  String(options = {}) {
2740
3232
  assertNonNegativeInteger(options.minLength, "minLength");
2741
3233
  assertNonNegativeInteger(options.maxLength, "maxLength");
3234
+ assertMinMaxOrder(options.minLength, options.maxLength, "minLength", "maxLength");
2742
3235
  assertPattern(options.pattern);
2743
- return {
3236
+ const schema = {
2744
3237
  kind: "string",
2745
3238
  ...options
2746
3239
  };
3240
+ assertValidDefault(schema);
3241
+ return schema;
2747
3242
  },
2748
3243
  Number(options = {}) {
2749
3244
  assertFiniteNumber(options.minimum, "minimum");
2750
3245
  assertFiniteNumber(options.maximum, "maximum");
3246
+ assertMinMaxOrder(options.minimum, options.maximum, "minimum", "maximum");
2751
3247
  assertFiniteNumber(options.default, "default");
2752
3248
  if (options.jsonType === "integer" && options.default !== void 0 && !Number.isInteger(options.default)) {
2753
3249
  throw new Error("default must be an integer");
2754
3250
  }
2755
- return {
3251
+ const schema = {
2756
3252
  kind: "number",
2757
3253
  ...options
2758
3254
  };
3255
+ assertValidDefault(schema);
3256
+ return schema;
2759
3257
  },
2760
3258
  Boolean(options = {}) {
2761
- return {
3259
+ const schema = {
2762
3260
  kind: "boolean",
2763
3261
  ...options
2764
3262
  };
3263
+ assertValidDefault(schema);
3264
+ return schema;
2765
3265
  },
2766
3266
  Enum(values, options = {}) {
2767
3267
  assertValidEnumValues(values);
2768
3268
  if (options.jsonType === "integer" && values.some((value) => typeof value !== "number" || !Number.isInteger(value))) {
2769
3269
  throw new Error("Integer enum values must be integers");
2770
3270
  }
2771
- return {
3271
+ const schema = {
2772
3272
  kind: "enum",
2773
3273
  values,
2774
3274
  ...options
2775
3275
  };
3276
+ assertValidDefault(schema);
3277
+ return schema;
2776
3278
  },
2777
3279
  Array(item, options = {}) {
2778
3280
  assertNonNegativeInteger(options.minItems, "minItems");
2779
3281
  assertNonNegativeInteger(options.maxItems, "maxItems");
2780
- return {
3282
+ assertMinMaxOrder(options.minItems, options.maxItems, "minItems", "maxItems");
3283
+ const schema = {
2781
3284
  kind: "array",
2782
3285
  item,
2783
3286
  ...options
2784
3287
  };
3288
+ assertValidDefault(schema);
3289
+ return schema;
2785
3290
  },
2786
3291
  Object(shape, options = {}) {
2787
- return {
3292
+ const schema = {
2788
3293
  kind: "object",
2789
3294
  shape,
2790
3295
  ...options
2791
3296
  };
3297
+ assertValidDefault(schema);
3298
+ return schema;
2792
3299
  },
2793
3300
  Optional(inner) {
2794
3301
  return {
@@ -3163,6 +3670,7 @@ function createBaseCommand(config2) {
3163
3670
  kind: "command",
3164
3671
  name: config2.name,
3165
3672
  description: config2.description,
3673
+ hidden: config2.hidden ?? false,
3166
3674
  examples: cloneCommandExamples(config2.examples),
3167
3675
  aliases: [...config2.aliases ?? []],
3168
3676
  positional: [...config2.positional ?? []],
@@ -3179,6 +3687,7 @@ function createBaseCommand(config2) {
3179
3687
  Object.defineProperty(command, commandConfigSymbol, {
3180
3688
  value: {
3181
3689
  scope: cloneScope(config2.scope),
3690
+ hidden: config2.hidden ?? false,
3182
3691
  examples: cloneCommandExamples(config2.examples),
3183
3692
  result: config2.result,
3184
3693
  humanInLoop: config2.humanInLoop,
@@ -3229,6 +3738,7 @@ function materializeCommand(command, inherited) {
3229
3738
  kind: "command",
3230
3739
  name: command.name,
3231
3740
  description: command.description,
3741
+ hidden: internal.hidden,
3232
3742
  examples: cloneCommandExamples(internal.examples),
3233
3743
  aliases: [...command.aliases],
3234
3744
  positional: [...command.positional],
@@ -3245,6 +3755,7 @@ function materializeCommand(command, inherited) {
3245
3755
  Object.defineProperty(materialized, commandConfigSymbol, {
3246
3756
  value: {
3247
3757
  scope: cloneScope(internal.scope),
3758
+ hidden: internal.hidden,
3248
3759
  examples: cloneCommandExamples(internal.examples),
3249
3760
  result: internal.result,
3250
3761
  humanInLoop: internal.humanInLoop,
@@ -3360,6 +3871,9 @@ function isRecord(value) {
3360
3871
  function isStateList(value) {
3361
3872
  return Array.isArray(value) && value.every((entry) => typeof entry === "string");
3362
3873
  }
3874
+ function hasVisibleName(value) {
3875
+ return value.trim().length > 0;
3876
+ }
3363
3877
  function canFireFromState(event, fromState) {
3364
3878
  if (event.from === "*") {
3365
3879
  return event.to !== fromState;
@@ -3374,6 +3888,9 @@ function validateMachine(machine) {
3374
3888
  throw new TypeError("State machine states must be a string array.");
3375
3889
  }
3376
3890
  const states = new Set(machine.states);
3891
+ if (machine.states.some((state) => !hasVisibleName(state))) {
3892
+ throw new Error("State names must not be empty.");
3893
+ }
3377
3894
  if (!hasOwnRecordField(machine, "initial") || typeof machine.initial !== "string") {
3378
3895
  throw new TypeError("State machine initial must be a string.");
3379
3896
  }
@@ -3384,6 +3901,9 @@ function validateMachine(machine) {
3384
3901
  throw new TypeError("State machine events must be an object.");
3385
3902
  }
3386
3903
  for (const [eventName, event] of Object.entries(machine.events)) {
3904
+ if (!hasVisibleName(eventName)) {
3905
+ throw new Error("Event names must not be empty.");
3906
+ }
3387
3907
  if (!isRecord(event)) {
3388
3908
  throw new TypeError(`Event "${eventName}" must be an object.`);
3389
3909
  }
@@ -3493,6 +4013,13 @@ import { text as text3 } from "node:stream/consumers";
3493
4013
  // ../process-runner/src/docker/context.ts
3494
4014
  import { execSync } from "node:child_process";
3495
4015
 
4016
+ // ../process-runner/src/docker/build-context.ts
4017
+ import { readdir, readFile } from "node:fs/promises";
4018
+ import { createRequire } from "node:module";
4019
+ import path2 from "node:path";
4020
+ var require2 = createRequire(import.meta.url);
4021
+ var createIgnore = require2("ignore");
4022
+
3496
4023
  // ../process-runner/src/docker/engine.ts
3497
4024
  import { execSync as execSync2 } from "node:child_process";
3498
4025
 
@@ -3501,19 +4028,19 @@ import * as childProcess from "node:child_process";
3501
4028
  import { randomBytes } from "node:crypto";
3502
4029
 
3503
4030
  // ../process-runner/src/docker/args.ts
3504
- import path2 from "node:path";
4031
+ import path3 from "node:path";
3505
4032
 
3506
4033
  // ../process-runner/src/docker/env-file.ts
3507
4034
  import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3508
4035
  import { tmpdir } from "node:os";
3509
- import path3 from "node:path";
4036
+ import path4 from "node:path";
3510
4037
 
3511
4038
  // ../process-runner/src/docker/docker-execution-env.ts
3512
4039
  import { createHash as createHash2, randomBytes as randomBytes2 } from "node:crypto";
3513
4040
  import { mkdtempSync as mkdtempSync2, rmSync as rmSync2 } from "node:fs";
3514
- import { readdir, readFile, realpath, writeFile } from "node:fs/promises";
4041
+ import { readFile as readFile2, realpath, writeFile } from "node:fs/promises";
3515
4042
  import { tmpdir as tmpdir2 } from "node:os";
3516
- import path5 from "node:path";
4043
+ import path6 from "node:path";
3517
4044
 
3518
4045
  // ../process-runner/src/host/host-runner.ts
3519
4046
  import { spawn as spawnChildProcess } from "node:child_process";
@@ -3646,7 +4173,7 @@ function bindAbortSignal(signal, onAbort) {
3646
4173
  // ../process-runner/src/workspace-transfer.ts
3647
4174
  import { createHash, randomUUID } from "node:crypto";
3648
4175
  import { promises as nodeFs } from "node:fs";
3649
- import path4 from "node:path";
4176
+ import path5 from "node:path";
3650
4177
 
3651
4178
  // ../process-runner/src/testing/mock-runner.ts
3652
4179
  import { Readable, Writable } from "node:stream";
@@ -3718,7 +4245,7 @@ function resolveEndpoint(options = {}) {
3718
4245
 
3719
4246
  // ../task-list/src/backends/utils.ts
3720
4247
  import { randomUUID as randomUUID2 } from "node:crypto";
3721
- import path6 from "node:path";
4248
+ import path7 from "node:path";
3722
4249
  function compareCreated(left, right) {
3723
4250
  const leftCreated = typeof left.raw.created === "string" ? left.raw.created : "";
3724
4251
  const rightCreated = typeof right.raw.created === "string" ? right.raw.created : "";
@@ -3750,15 +4277,33 @@ function sortStrings(values) {
3750
4277
  function sortTasks(tasks) {
3751
4278
  return [...tasks].sort((left, right) => left.qualifiedId.localeCompare(right.qualifiedId));
3752
4279
  }
4280
+ function isTrimmedPrintableIdentifier(value) {
4281
+ if (value.length === 0 || value !== value.trim()) {
4282
+ return false;
4283
+ }
4284
+ for (let index = 0; index < value.length; index += 1) {
4285
+ const code = value.charCodeAt(index);
4286
+ if (code < 32 || code === 127) {
4287
+ return false;
4288
+ }
4289
+ }
4290
+ return true;
4291
+ }
3753
4292
  function validateTaskId(id) {
3754
- if (id.length === 0 || id.startsWith(".") || id.includes("/") || id.includes("\\") || id.includes("..")) {
4293
+ if (!isTrimmedPrintableIdentifier(id) || id.startsWith(".") || id.includes("/") || id.includes("\\") || id.includes("..")) {
3755
4294
  throw new Error(`Invalid task id "${id}".`);
3756
4295
  }
3757
4296
  return id;
3758
4297
  }
3759
- async function statIfExists(fs4, filePath) {
4298
+ function validateTaskName(name) {
4299
+ if (name.trim().length === 0) {
4300
+ throw new Error("Task name must not be empty.");
4301
+ }
4302
+ return name;
4303
+ }
4304
+ async function statIfExists(fs5, filePath) {
3760
4305
  try {
3761
- return await fs4.stat(filePath);
4306
+ return await fs5.stat(filePath);
3762
4307
  } catch (error3) {
3763
4308
  if (hasErrorCode(error3, "ENOENT")) {
3764
4309
  return void 0;
@@ -3766,15 +4311,18 @@ async function statIfExists(fs4, filePath) {
3766
4311
  throw error3;
3767
4312
  }
3768
4313
  }
3769
- async function rejectSymbolicLinkComponents(fs4, filePath) {
3770
- const resolvedPath = path6.resolve(filePath);
3771
- const rootPath = path6.parse(resolvedPath).root;
3772
- const components = resolvedPath.slice(rootPath.length).split(path6.sep).filter(Boolean);
4314
+ async function rejectSymbolicLinkComponents(fs5, filePath) {
4315
+ const resolvedPath = path7.resolve(filePath);
4316
+ const rootPath = path7.parse(resolvedPath).root;
4317
+ const components = resolvedPath.slice(rootPath.length).split(path7.sep).filter(Boolean);
3773
4318
  let currentPath = rootPath;
3774
4319
  for (const component of components) {
3775
- currentPath = path6.join(currentPath, component);
4320
+ currentPath = path7.join(currentPath, component);
3776
4321
  try {
3777
- if ((await fs4.lstat(currentPath)).isSymbolicLink()) {
4322
+ if ((await fs5.lstat(currentPath)).isSymbolicLink()) {
4323
+ if (currentPath === "/tmp") {
4324
+ continue;
4325
+ }
3778
4326
  throw new Error(`Path "${filePath}" contains a symbolic link.`);
3779
4327
  }
3780
4328
  } catch (error3) {
@@ -3785,19 +4333,19 @@ async function rejectSymbolicLinkComponents(fs4, filePath) {
3785
4333
  }
3786
4334
  }
3787
4335
  }
3788
- async function writeAtomically(fs4, filePath, content) {
4336
+ async function writeAtomically(fs5, filePath, content) {
3789
4337
  const tempPath = `${filePath}.${process.pid}.${randomUUID2()}.tmp`;
3790
4338
  let tempCreated = false;
3791
- await fs4.mkdir(path6.dirname(filePath), { recursive: true });
4339
+ await fs5.mkdir(path7.dirname(filePath), { recursive: true });
3792
4340
  try {
3793
- await fs4.writeFile(tempPath, content, { encoding: "utf8", flag: "wx" });
4341
+ await fs5.writeFile(tempPath, content, { encoding: "utf8", flag: "wx" });
3794
4342
  tempCreated = true;
3795
- await fs4.rename(tempPath, filePath);
4343
+ await fs5.rename(tempPath, filePath);
3796
4344
  tempCreated = false;
3797
4345
  } catch (error3) {
3798
4346
  if (tempCreated || !hasErrorCode(error3, "EEXIST")) {
3799
4347
  try {
3800
- await fs4.unlink(tempPath);
4348
+ await fs5.unlink(tempPath);
3801
4349
  } catch (unlinkError) {
3802
4350
  if (!hasErrorCode(unlinkError, "ENOENT")) {
3803
4351
  throw unlinkError;
@@ -3807,18 +4355,18 @@ async function writeAtomically(fs4, filePath, content) {
3807
4355
  throw error3;
3808
4356
  }
3809
4357
  }
3810
- async function withFileLock(fs4, lockPath, operation) {
3811
- await fs4.mkdir(path6.dirname(lockPath), { recursive: true });
4358
+ async function withFileLock(fs5, lockPath, operation) {
4359
+ await fs5.mkdir(path7.dirname(lockPath), { recursive: true });
3812
4360
  for (; ; ) {
3813
4361
  try {
3814
- await fs4.writeFile(lockPath, String(process.pid), { encoding: "utf8", flag: "wx" });
4362
+ await fs5.writeFile(lockPath, String(process.pid), { encoding: "utf8", flag: "wx" });
3815
4363
  break;
3816
4364
  } catch (error3) {
3817
4365
  if (!hasErrorCode(error3, "EEXIST")) {
3818
- await fs4.unlink(lockPath).catch(() => void 0);
4366
+ await fs5.unlink(lockPath).catch(() => void 0);
3819
4367
  throw error3;
3820
4368
  }
3821
- if (await removeAbandonedLock(fs4, lockPath)) {
4369
+ if (await removeAbandonedLock(fs5, lockPath)) {
3822
4370
  continue;
3823
4371
  }
3824
4372
  await Promise.resolve();
@@ -3827,13 +4375,13 @@ async function withFileLock(fs4, lockPath, operation) {
3827
4375
  try {
3828
4376
  return await operation();
3829
4377
  } finally {
3830
- await fs4.unlink(lockPath);
4378
+ await fs5.unlink(lockPath);
3831
4379
  }
3832
4380
  }
3833
- async function removeAbandonedLock(fs4, lockPath) {
4381
+ async function removeAbandonedLock(fs5, lockPath) {
3834
4382
  let content;
3835
4383
  try {
3836
- content = await fs4.readFile(lockPath, "utf8");
4384
+ content = await fs5.readFile(lockPath, "utf8");
3837
4385
  } catch (error3) {
3838
4386
  if (hasErrorCode(error3, "ENOENT")) {
3839
4387
  return true;
@@ -3841,11 +4389,11 @@ async function removeAbandonedLock(fs4, lockPath) {
3841
4389
  throw error3;
3842
4390
  }
3843
4391
  const owner = Number(content);
3844
- if (!Number.isInteger(owner) || owner <= 0 || isProcessRunning(owner)) {
4392
+ if (Number.isInteger(owner) && owner > 0 && isProcessRunning(owner)) {
3845
4393
  return false;
3846
4394
  }
3847
4395
  try {
3848
- await fs4.unlink(lockPath);
4396
+ await fs5.unlink(lockPath);
3849
4397
  return true;
3850
4398
  } catch (error3) {
3851
4399
  if (hasErrorCode(error3, "ENOENT")) {
@@ -4113,6 +4661,9 @@ async function ghIssuesBackend(deps) {
4113
4661
  if (deps.state?.labelPrefix === "") {
4114
4662
  throw new Error("gh-issues state.labelPrefix must be a non-empty string when configured.");
4115
4663
  }
4664
+ if (deps.stateMachine !== void 0) {
4665
+ validateMachine(deps.stateMachine);
4666
+ }
4116
4667
  const client = createGhClient({
4117
4668
  token: deps.token,
4118
4669
  endpoint: deps.endpoint,
@@ -4272,7 +4823,9 @@ function createTasksView(name, session, context) {
4272
4823
  );
4273
4824
  projectItemId = added.addProjectV2ItemById?.item?.id ?? void 0;
4274
4825
  if (projectItemId === void 0) {
4275
- throw new Error("GitHub addProjectV2ItemById response did not include project item id.");
4826
+ throw new Error(
4827
+ "GitHub addProjectV2ItemById response did not include project item id."
4828
+ );
4276
4829
  }
4277
4830
  }
4278
4831
  if (session.labelPrefix === void 0) {
@@ -4501,12 +5054,15 @@ async function resolveProjectItemId(id, listName, session, context) {
4501
5054
  const issueNumber = parseIssueNumber(id, listName);
4502
5055
  let after;
4503
5056
  while (true) {
4504
- const result = await context.client.graphql(ISSUE_STATE_LABELS_QUERY, {
4505
- owner: context.repoOwner,
4506
- repo: context.repoName,
4507
- number: issueNumber,
4508
- after
4509
- });
5057
+ const result = await context.client.graphql(
5058
+ ISSUE_STATE_LABELS_QUERY,
5059
+ {
5060
+ owner: context.repoOwner,
5061
+ repo: context.repoName,
5062
+ number: issueNumber,
5063
+ after
5064
+ }
5065
+ );
4510
5066
  const issue = result.repository?.issue ?? null;
4511
5067
  if (issue === null) {
4512
5068
  throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
@@ -4783,12 +5339,27 @@ async function fetchIssueTask(id, listName, session, context) {
4783
5339
  });
4784
5340
  }
4785
5341
  function parseIssueNumber(id, listName) {
5342
+ if (!isCanonicalDecimalIssueId(id)) {
5343
+ throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
5344
+ }
4786
5345
  const issueNumber = Number(id);
4787
- if (!Number.isInteger(issueNumber) || issueNumber < 1) {
5346
+ if (!Number.isSafeInteger(issueNumber) || issueNumber < 1) {
4788
5347
  throw new TaskNotFoundError(`Task "${listName}/${id}" not found.`);
4789
5348
  }
4790
5349
  return issueNumber;
4791
5350
  }
5351
+ function isCanonicalDecimalIssueId(id) {
5352
+ if (id.length === 0 || id[0] === "0") {
5353
+ return false;
5354
+ }
5355
+ for (let index = 0; index < id.length; index += 1) {
5356
+ const charCode = id.charCodeAt(index);
5357
+ if (charCode < 48 || charCode > 57) {
5358
+ return false;
5359
+ }
5360
+ }
5361
+ return true;
5362
+ }
4792
5363
  function mapProjectItemToTask(item, listName, session) {
4793
5364
  const content = item.content;
4794
5365
  if (!isIssueNode(content)) {
@@ -4896,7 +5467,7 @@ function parseQualifiedId(qualifiedId, listName) {
4896
5467
  }
4897
5468
 
4898
5469
  // ../task-list/src/backends/markdown-dir.ts
4899
- import path7 from "node:path";
5470
+ import path8 from "node:path";
4900
5471
  import { parseDocument as parseDocument2, stringify as stringify2 } from "yaml";
4901
5472
 
4902
5473
  // ../task-list/src/schema/task.schema.json
@@ -4999,7 +5570,7 @@ function resolveListLayout(deps) {
4999
5570
  return deps.singleList ? { kind: "single", name: deps.singleList } : { kind: "multi" };
5000
5571
  }
5001
5572
  function validateListName(name) {
5002
- if (name.length === 0 || name === ARCHIVE_DIRECTORY_NAME || name.startsWith(".") || name.includes("/") || name.includes("\\") || name.includes("..")) {
5573
+ if (!isTrimmedPrintableIdentifier(name) || name === ARCHIVE_DIRECTORY_NAME || name.startsWith(".") || name.includes("/") || name.includes("\\") || name.includes("..")) {
5003
5574
  throw new Error(`Invalid task list name "${name}".`);
5004
5575
  }
5005
5576
  return name;
@@ -5015,16 +5586,16 @@ function parseQualifiedId2(qualifiedId) {
5015
5586
  };
5016
5587
  }
5017
5588
  function listPath(rootPath, layout, list) {
5018
- return layout.kind === "single" ? rootPath : path7.join(rootPath, list);
5589
+ return layout.kind === "single" ? rootPath : path8.join(rootPath, list);
5019
5590
  }
5020
5591
  function archiveDirectoryPath(rootPath, layout, list) {
5021
- return layout.kind === "single" ? path7.join(rootPath, ARCHIVE_DIRECTORY_NAME) : path7.join(rootPath, list, ARCHIVE_DIRECTORY_NAME);
5592
+ return layout.kind === "single" ? path8.join(rootPath, ARCHIVE_DIRECTORY_NAME) : path8.join(rootPath, list, ARCHIVE_DIRECTORY_NAME);
5022
5593
  }
5023
5594
  function activeTaskFilename(id, order, width) {
5024
5595
  return `${String(order).padStart(width, "0")}-${id}${MARKDOWN_EXTENSION}`;
5025
5596
  }
5026
5597
  function archivedTaskPath(rootPath, layout, list, id) {
5027
- return path7.join(archiveDirectoryPath(rootPath, layout, list), `${id}${MARKDOWN_EXTENSION}`);
5598
+ return path8.join(archiveDirectoryPath(rootPath, layout, list), `${id}${MARKDOWN_EXTENSION}`);
5028
5599
  }
5029
5600
  function isMarkdownFile(entryName) {
5030
5601
  return entryName.endsWith(MARKDOWN_EXTENSION);
@@ -5126,7 +5697,7 @@ function hasOwnTaskField(frontmatter, key2) {
5126
5697
  function reservedFrontmatterKeys(mode) {
5127
5698
  return mode === "passthrough" ? PASSTHROUGH_RESERVED_FRONTMATTER_KEYS : RESERVED_FRONTMATTER_KEYS;
5128
5699
  }
5129
- function setOwnValue(record, key2, value) {
5700
+ function setOwnValue2(record, key2, value) {
5130
5701
  Object.defineProperty(record, key2, {
5131
5702
  value,
5132
5703
  enumerable: true,
@@ -5139,7 +5710,7 @@ function metadataFromFrontmatter(frontmatter, mode) {
5139
5710
  const reservedKeys = reservedFrontmatterKeys(mode);
5140
5711
  for (const [key2, value] of Object.entries(frontmatter)) {
5141
5712
  if (!reservedKeys.has(key2)) {
5142
- setOwnValue(metadata, key2, value);
5713
+ setOwnValue2(metadata, key2, value);
5143
5714
  }
5144
5715
  }
5145
5716
  return metadata;
@@ -5153,7 +5724,7 @@ function createTask(list, id, frontmatter, body, mode, sourcePath) {
5153
5724
  state: frontmatter.state,
5154
5725
  description: body,
5155
5726
  metadata: metadataFromFrontmatter(frontmatter, mode),
5156
- ...sourcePath !== void 0 && { sourcePath: path7.resolve(sourcePath) }
5727
+ ...sourcePath !== void 0 && { sourcePath: path8.resolve(sourcePath) }
5157
5728
  };
5158
5729
  }
5159
5730
  function serializeTaskDocument(frontmatter, description) {
@@ -5162,9 +5733,9 @@ ${stringify2(frontmatter)}---
5162
5733
 
5163
5734
  ${description}`;
5164
5735
  }
5165
- async function readDirectoryNames(fs4, directoryPath) {
5736
+ async function readDirectoryNames(fs5, directoryPath) {
5166
5737
  try {
5167
- return sortStrings(await fs4.readdir(directoryPath));
5738
+ return sortStrings(await fs5.readdir(directoryPath));
5168
5739
  } catch (error3) {
5169
5740
  if (hasErrorCode(error3, "ENOENT")) {
5170
5741
  return [];
@@ -5180,9 +5751,9 @@ async function ensureRootPath(deps) {
5180
5751
  }
5181
5752
  await deps.fs.stat(deps.path);
5182
5753
  }
5183
- async function readTaskFile(fs4, list, id, filePath, validStates, initialState, mode) {
5184
- await rejectSymbolicLinkComponents(fs4, filePath);
5185
- const content = await fs4.readFile(filePath, "utf8");
5754
+ async function readTaskFile(fs5, list, id, filePath, validStates, initialState, mode) {
5755
+ await rejectSymbolicLinkComponents(fs5, filePath);
5756
+ const content = await fs5.readFile(filePath, "utf8");
5186
5757
  const document = splitTaskDocument(content, filePath, mode);
5187
5758
  const frontmatter = mode === "passthrough" && document.frontmatter.trim().length === 0 ? {} : readFrontmatter(document.frontmatter, filePath);
5188
5759
  if (mode !== "passthrough") {
@@ -5193,11 +5764,9 @@ async function readTaskFile(fs4, list, id, filePath, validStates, initialState,
5193
5764
  task: createTask(list, id, frontmatter, document.body, mode, filePath)
5194
5765
  };
5195
5766
  }
5196
- const parsedFilename = parseActiveFilename(path7.basename(filePath));
5197
- const defaultName = parsedFilename?.id ?? id;
5198
5767
  const effectiveFrontmatter = {
5199
5768
  ...frontmatter,
5200
- name: typeof frontmatter.name === "string" ? frontmatter.name : defaultName,
5769
+ name: typeof frontmatter.name === "string" ? frontmatter.name : id,
5201
5770
  state: typeof frontmatter.state === "string" && validStates.has(frontmatter.state) ? frontmatter.state : initialState
5202
5771
  };
5203
5772
  return {
@@ -5206,44 +5775,95 @@ async function readTaskFile(fs4, list, id, filePath, validStates, initialState,
5206
5775
  task: createTask(list, id, effectiveFrontmatter, document.body, mode, filePath)
5207
5776
  };
5208
5777
  }
5209
- async function findActiveTaskFilename(fs4, listDirectoryPath, id) {
5210
- const entries = await readDirectoryNames(fs4, listDirectoryPath);
5778
+ async function readPassthroughFrontmatter(fs5, filePath, mode) {
5779
+ if (mode !== "passthrough") {
5780
+ return {};
5781
+ }
5782
+ const content = await fs5.readFile(filePath, "utf8");
5783
+ const document = splitTaskDocument(content, filePath, mode);
5784
+ if (document.frontmatter.trim().length === 0) {
5785
+ return {};
5786
+ }
5787
+ return readFrontmatter(document.frontmatter, filePath);
5788
+ }
5789
+ async function resolveActiveFilenameEntry(fs5, entryName, entryPath, parsed, mode) {
5790
+ if (mode !== "passthrough" || parsed.order === null) {
5791
+ return parsed;
5792
+ }
5793
+ const frontmatter = await readPassthroughFrontmatter(fs5, entryPath, mode);
5794
+ if (Object.keys(frontmatter).length === 0 && orderedFilenamePrefixLength(entryName) <= MIN_PREFIX_WIDTH) {
5795
+ return parsed;
5796
+ }
5797
+ if (typeof frontmatter.state === "string" || hasOwnTaskField(frontmatter, "$schema") || hasOwnTaskField(frontmatter, "kind") || hasOwnTaskField(frontmatter, "version")) {
5798
+ return parsed;
5799
+ }
5800
+ return {
5801
+ id: entryName.slice(0, -MARKDOWN_EXTENSION.length),
5802
+ order: null,
5803
+ filename: parsed.filename
5804
+ };
5805
+ }
5806
+ function orderedFilenamePrefixLength(entryName) {
5807
+ const stem = entryName.slice(0, -MARKDOWN_EXTENSION.length);
5808
+ const separatorIndex = stem.indexOf("-");
5809
+ if (separatorIndex <= 0) {
5810
+ return Number.POSITIVE_INFINITY;
5811
+ }
5812
+ for (let index = 0; index < separatorIndex; index += 1) {
5813
+ const code = stem.charCodeAt(index);
5814
+ if (code < 48 || code > 57) {
5815
+ return Number.POSITIVE_INFINITY;
5816
+ }
5817
+ }
5818
+ return separatorIndex;
5819
+ }
5820
+ async function findActiveTaskFilename(fs5, listDirectoryPath, id, mode) {
5821
+ const entries = await readDirectoryNames(fs5, listDirectoryPath);
5211
5822
  for (const entryName of entries) {
5212
5823
  if (isHiddenEntry(entryName)) continue;
5213
5824
  const parsed = parseActiveFilename(entryName);
5214
- if (parsed?.id === id) {
5825
+ if (!parsed) continue;
5826
+ const entryPath = path8.join(listDirectoryPath, entryName);
5827
+ const resolved = await resolveActiveFilenameEntry(
5828
+ fs5,
5829
+ entryName,
5830
+ entryPath,
5831
+ { id: parsed.id, order: parsed.order, filename: entryName },
5832
+ mode
5833
+ );
5834
+ if (resolved.id === id) {
5215
5835
  return entryName;
5216
5836
  }
5217
5837
  }
5218
5838
  return void 0;
5219
5839
  }
5220
- async function findTaskLocation(fs4, rootPath, layout, list, id) {
5840
+ async function findTaskLocation(fs5, rootPath, layout, list, id, mode) {
5221
5841
  const listDirectoryPath = listPath(rootPath, layout, list);
5222
- await rejectSymbolicLinkComponents(fs4, listDirectoryPath);
5223
- const activeName = await findActiveTaskFilename(fs4, listDirectoryPath, id);
5842
+ await rejectSymbolicLinkComponents(fs5, listDirectoryPath);
5843
+ const activeName = await findActiveTaskFilename(fs5, listDirectoryPath, id, mode);
5224
5844
  if (activeName) {
5225
- const activePath = path7.join(listDirectoryPath, activeName);
5226
- await rejectSymbolicLinkComponents(fs4, activePath);
5227
- const activeStat = await statIfExists(fs4, activePath);
5845
+ const activePath = path8.join(listDirectoryPath, activeName);
5846
+ await rejectSymbolicLinkComponents(fs5, activePath);
5847
+ const activeStat = await statIfExists(fs5, activePath);
5228
5848
  if (activeStat?.isFile()) {
5229
5849
  return { archived: false, path: activePath };
5230
5850
  }
5231
5851
  }
5232
5852
  const archivedPath = archivedTaskPath(rootPath, layout, list, id);
5233
- await rejectSymbolicLinkComponents(fs4, archiveDirectoryPath(rootPath, layout, list));
5234
- await rejectSymbolicLinkComponents(fs4, archivedPath);
5235
- const archivedStat = await statIfExists(fs4, archivedPath);
5853
+ await rejectSymbolicLinkComponents(fs5, archiveDirectoryPath(rootPath, layout, list));
5854
+ await rejectSymbolicLinkComponents(fs5, archivedPath);
5855
+ const archivedStat = await statIfExists(fs5, archivedPath);
5236
5856
  if (archivedStat?.isFile()) {
5237
5857
  return { archived: true, path: archivedPath };
5238
5858
  }
5239
5859
  return void 0;
5240
5860
  }
5241
- async function readTaskAtLocation(fs4, rootPath, layout, list, id, validStates, initialState, mode) {
5242
- const location = await findTaskLocation(fs4, rootPath, layout, list, id);
5861
+ async function readTaskAtLocation(fs5, rootPath, layout, list, id, validStates, initialState, mode) {
5862
+ const location = await findTaskLocation(fs5, rootPath, layout, list, id, mode);
5243
5863
  if (!location) {
5244
5864
  throw new TaskNotFoundError(`Task "${list}/${id}" not found.`);
5245
5865
  }
5246
- return readTaskFile(fs4, list, id, location.path, validStates, initialState, mode);
5866
+ return readTaskFile(fs5, list, id, location.path, validStates, initialState, mode);
5247
5867
  }
5248
5868
  function createdFrontmatter(defaults2, input, initialState, mode) {
5249
5869
  const frontmatter = mode !== "passthrough" ? {
@@ -5259,12 +5879,12 @@ function createdFrontmatter(defaults2, input, initialState, mode) {
5259
5879
  const reservedKeys = reservedFrontmatterKeys(mode);
5260
5880
  for (const [key2, value] of Object.entries(defaults2.metadata)) {
5261
5881
  if (!reservedKeys.has(key2)) {
5262
- setOwnValue(frontmatter, key2, value);
5882
+ setOwnValue2(frontmatter, key2, value);
5263
5883
  }
5264
5884
  }
5265
5885
  for (const [key2, value] of Object.entries(input.metadata ?? {})) {
5266
5886
  if (!reservedKeys.has(key2)) {
5267
- setOwnValue(frontmatter, key2, value);
5887
+ setOwnValue2(frontmatter, key2, value);
5268
5888
  }
5269
5889
  }
5270
5890
  frontmatter.created = (/* @__PURE__ */ new Date()).toISOString();
@@ -5286,7 +5906,7 @@ function updatedFrontmatter(existingFrontmatter, task, patch, mode) {
5286
5906
  const reservedKeys = reservedFrontmatterKeys(mode);
5287
5907
  for (const [key2, value] of Object.entries(patch.metadata ?? {})) {
5288
5908
  if (!reservedKeys.has(key2)) {
5289
- setOwnValue(nextFrontmatter, key2, value);
5909
+ setOwnValue2(nextFrontmatter, key2, value);
5290
5910
  }
5291
5911
  }
5292
5912
  return nextFrontmatter;
@@ -5310,7 +5930,7 @@ function firedFrontmatter(existingFrontmatter, task, to, mode, metadataPatch) {
5310
5930
  const reservedKeys = reservedFrontmatterKeys(mode);
5311
5931
  for (const [key2, value] of Object.entries(metadataPatch ?? {})) {
5312
5932
  if (!reservedKeys.has(key2)) {
5313
- setOwnValue(nextFrontmatter, key2, value);
5933
+ setOwnValue2(nextFrontmatter, key2, value);
5314
5934
  }
5315
5935
  }
5316
5936
  return nextFrontmatter;
@@ -5344,11 +5964,19 @@ function createTasksView2(deps, layout, list) {
5344
5964
  if (isHiddenEntry(entryName)) continue;
5345
5965
  const parsed = parseActiveFilename(entryName);
5346
5966
  if (!parsed) continue;
5347
- const entryPath = path7.join(listDirectoryPath, entryName);
5967
+ const entryPath = path8.join(listDirectoryPath, entryName);
5348
5968
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
5349
5969
  const entryStat = await statIfExists(deps.fs, entryPath);
5350
5970
  if (!entryStat?.isFile()) continue;
5351
- result.push({ id: parsed.id, order: parsed.order, filename: entryName });
5971
+ result.push(
5972
+ await resolveActiveFilenameEntry(
5973
+ deps.fs,
5974
+ entryName,
5975
+ entryPath,
5976
+ { id: parsed.id, order: parsed.order, filename: entryName },
5977
+ deps.frontmatterMode
5978
+ )
5979
+ );
5352
5980
  }
5353
5981
  result.sort((left, right) => {
5354
5982
  const leftOrder = left.order ?? Number.POSITIVE_INFINITY;
@@ -5362,7 +5990,7 @@ function createTasksView2(deps, layout, list) {
5362
5990
  const entries = await readActiveEntries();
5363
5991
  const tasks = /* @__PURE__ */ new Map();
5364
5992
  for (const entry of entries) {
5365
- const filePath = path7.join(listDirectoryPath, entry.filename);
5993
+ const filePath = path8.join(listDirectoryPath, entry.filename);
5366
5994
  const file = await readTaskFile(
5367
5995
  deps.fs,
5368
5996
  list,
@@ -5383,7 +6011,7 @@ function createTasksView2(deps, layout, list) {
5383
6011
  const result = [];
5384
6012
  for (const entryName of entries) {
5385
6013
  if (isHiddenEntry(entryName) || !isMarkdownFile(entryName)) continue;
5386
- const entryPath = path7.join(archivePath, entryName);
6014
+ const entryPath = path8.join(archivePath, entryName);
5387
6015
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
5388
6016
  const entryStat = await statIfExists(deps.fs, entryPath);
5389
6017
  if (!entryStat?.isFile()) continue;
@@ -5413,15 +6041,20 @@ function createTasksView2(deps, layout, list) {
5413
6041
  if (desiredOrder === void 0) continue;
5414
6042
  const desiredFilename = activeTaskFilename(entry.id, desiredOrder, width);
5415
6043
  if (entry.filename !== desiredFilename) {
5416
- const fromPath = path7.join(listDirectoryPath, entry.filename);
5417
- const stagingPath = path7.join(
6044
+ const fromPath = path8.join(listDirectoryPath, entry.filename);
6045
+ const stagingPath = path8.join(
5418
6046
  listDirectoryPath,
5419
6047
  `${desiredFilename}.staging-${process.pid}-${index}`
5420
6048
  );
5421
- const targetPath = path7.join(listDirectoryPath, desiredFilename);
6049
+ const targetPath = path8.join(listDirectoryPath, desiredFilename);
5422
6050
  try {
5423
6051
  await deps.fs.rename(fromPath, stagingPath);
5424
- staged.push({ original: fromPath, staging: stagingPath, target: targetPath, finalized: false });
6052
+ staged.push({
6053
+ original: fromPath,
6054
+ staging: stagingPath,
6055
+ target: targetPath,
6056
+ finalized: false
6057
+ });
5425
6058
  } catch (error3) {
5426
6059
  for (const stagedEntry of staged.reverse()) {
5427
6060
  await deps.fs.rename(stagedEntry.staging, stagedEntry.original);
@@ -5556,8 +6189,7 @@ function createTasksView2(deps, layout, list) {
5556
6189
  if (filter?.state && entry.task.state !== filter.state) return false;
5557
6190
  return true;
5558
6191
  });
5559
- const orderedActiveTasks = applyOrder(orderedActive, filter?.order);
5560
- return [...orderedActiveTasks, ...filteredArchived.map((entry) => entry.task)];
6192
+ return applyOrder([...orderedActive, ...filteredArchived], filter?.order);
5561
6193
  },
5562
6194
  async get(id) {
5563
6195
  return (await getTaskFile(id)).task;
@@ -5566,9 +6198,17 @@ function createTasksView2(deps, layout, list) {
5566
6198
  assertCreateDoesNotSetState(input);
5567
6199
  assertCreateHasId(input);
5568
6200
  validateTaskId(input.id);
6201
+ validateTaskName(input.name);
5569
6202
  await rejectSymbolicLinkComponents(deps.fs, listDirectoryPath);
5570
- return withFileLock(deps.fs, path7.join(listDirectoryPath, ".transition.lock"), async () => {
5571
- const existing = await findTaskLocation(deps.fs, deps.path, layout, list, input.id);
6203
+ return withFileLock(deps.fs, path8.join(listDirectoryPath, ".transition.lock"), async () => {
6204
+ const existing = await findTaskLocation(
6205
+ deps.fs,
6206
+ deps.path,
6207
+ layout,
6208
+ list,
6209
+ input.id,
6210
+ deps.frontmatterMode
6211
+ );
5572
6212
  if (existing) {
5573
6213
  throw new TaskAlreadyExistsError(`Task "${list}/${input.id}" already exists.`);
5574
6214
  }
@@ -5580,7 +6220,7 @@ function createTasksView2(deps, layout, list) {
5580
6220
  const nextOrder = maxOrder + 1;
5581
6221
  const width = padWidthForCount(activeEntries.length + 1);
5582
6222
  const filename = activeTaskFilename(input.id, nextOrder, width);
5583
- const targetPath = path7.join(listDirectoryPath, filename);
6223
+ const targetPath = path8.join(listDirectoryPath, filename);
5584
6224
  const frontmatter = createdFrontmatter(
5585
6225
  deps.defaults,
5586
6226
  input,
@@ -5589,12 +6229,22 @@ function createTasksView2(deps, layout, list) {
5589
6229
  );
5590
6230
  const description = input.description ?? "";
5591
6231
  await writeAtomically(deps.fs, targetPath, serializeTaskDocument(frontmatter, description));
5592
- return createTask(list, input.id, frontmatter, description, deps.frontmatterMode, targetPath);
6232
+ return createTask(
6233
+ list,
6234
+ input.id,
6235
+ frontmatter,
6236
+ description,
6237
+ deps.frontmatterMode,
6238
+ targetPath
6239
+ );
5593
6240
  });
5594
6241
  },
5595
6242
  async update(id, patch) {
5596
6243
  assertUpdateDoesNotSetState(patch);
5597
6244
  validateTaskId(id);
6245
+ if (patch.name !== void 0) {
6246
+ validateTaskName(patch.name);
6247
+ }
5598
6248
  const existing = await getTaskFile(id);
5599
6249
  const nextFrontmatter = updatedFrontmatter(
5600
6250
  existing.frontmatter,
@@ -5680,7 +6330,14 @@ function createTasksView2(deps, layout, list) {
5680
6330
  };
5681
6331
  if (stateMachine.events[eventName]?.to === "archived") {
5682
6332
  validateTaskId(id);
5683
- const location = await findTaskLocation(deps.fs, deps.path, layout, list, id);
6333
+ const location = await findTaskLocation(
6334
+ deps.fs,
6335
+ deps.path,
6336
+ layout,
6337
+ list,
6338
+ id,
6339
+ deps.frontmatterMode
6340
+ );
5684
6341
  if (!location) {
5685
6342
  throw new TaskNotFoundError(`Task "${list}/${id}" not found.`);
5686
6343
  }
@@ -5688,7 +6345,7 @@ function createTasksView2(deps, layout, list) {
5688
6345
  validateTaskId(id);
5689
6346
  const { event, nextTask } = await withFileLock(
5690
6347
  deps.fs,
5691
- path7.join(listDirectoryPath, ".transition.lock"),
6348
+ path8.join(listDirectoryPath, ".transition.lock"),
5692
6349
  fireTask
5693
6350
  );
5694
6351
  await event.onEnter?.(nextTask);
@@ -5708,7 +6365,14 @@ function createTasksView2(deps, layout, list) {
5708
6365
  },
5709
6366
  async delete(id) {
5710
6367
  validateTaskId(id);
5711
- const location = await findTaskLocation(deps.fs, deps.path, layout, list, id);
6368
+ const location = await findTaskLocation(
6369
+ deps.fs,
6370
+ deps.path,
6371
+ layout,
6372
+ list,
6373
+ id,
6374
+ deps.frontmatterMode
6375
+ );
5712
6376
  if (!location) {
5713
6377
  throw new TaskNotFoundError(`Task "${list}/${id}" not found.`);
5714
6378
  }
@@ -5781,7 +6445,7 @@ async function markdownDirBackend(deps) {
5781
6445
  if (entryName === ARCHIVE_DIRECTORY_NAME || isHiddenEntry(entryName)) {
5782
6446
  continue;
5783
6447
  }
5784
- const entryPath = path7.join(deps.path, entryName);
6448
+ const entryPath = path8.join(deps.path, entryName);
5785
6449
  await rejectSymbolicLinkComponents(deps.fs, entryPath);
5786
6450
  const entryStat = await statIfExists(deps.fs, entryPath);
5787
6451
  if (entryStat?.isDirectory()) {
@@ -5823,12 +6487,26 @@ async function markdownDirBackend(deps) {
5823
6487
  }
5824
6488
  const targetListDir = listPath(deps.path, layout, targetListName);
5825
6489
  await rejectSymbolicLinkComponents(deps.fs, targetListDir);
5826
- return withFileLock(deps.fs, path7.join(targetListDir, ".transition.lock"), async () => {
5827
- const targetExisting = await findTaskLocation(deps.fs, deps.path, layout, targetListName, id);
6490
+ return withFileLock(deps.fs, path8.join(targetListDir, ".transition.lock"), async () => {
6491
+ const targetExisting = await findTaskLocation(
6492
+ deps.fs,
6493
+ deps.path,
6494
+ layout,
6495
+ targetListName,
6496
+ id,
6497
+ deps.frontmatterMode
6498
+ );
5828
6499
  if (targetExisting) {
5829
6500
  throw new TaskAlreadyExistsError(`Task "${targetListName}/${id}" already exists.`);
5830
6501
  }
5831
- const sourceLocation = await findTaskLocation(deps.fs, deps.path, layout, sourceListName, id);
6502
+ const sourceLocation = await findTaskLocation(
6503
+ deps.fs,
6504
+ deps.path,
6505
+ layout,
6506
+ sourceListName,
6507
+ id,
6508
+ deps.frontmatterMode
6509
+ );
5832
6510
  if (!sourceLocation) {
5833
6511
  throw new TaskNotFoundError(`Task "${sourceListName}/${id}" not found.`);
5834
6512
  }
@@ -5873,7 +6551,7 @@ async function markdownDirBackend(deps) {
5873
6551
  );
5874
6552
  const width = padWidthForCount(targetEntries.length + 1);
5875
6553
  const targetFilename = activeTaskFilename(id, maxOrder + 1, width);
5876
- const targetPath = path7.join(targetListDir, targetFilename);
6554
+ const targetPath = path8.join(targetListDir, targetFilename);
5877
6555
  await deps.fs.rename(sourceLocation.path, targetPath);
5878
6556
  return createTask(
5879
6557
  targetListName,
@@ -5895,7 +6573,7 @@ async function markdownDirBackend(deps) {
5895
6573
  }
5896
6574
 
5897
6575
  // ../task-list/src/backends/yaml-file.ts
5898
- import path8 from "node:path";
6576
+ import path9 from "node:path";
5899
6577
  import { isMap, parseDocument as parseDocument3 } from "yaml";
5900
6578
 
5901
6579
  // ../task-list/src/schema/store.schema.json
@@ -5955,7 +6633,7 @@ function malformedTask2(list, id, field) {
5955
6633
  return new MalformedTaskError(`Malformed task "${list}/${id}": invalid "${field}".`);
5956
6634
  }
5957
6635
  function validateListName2(name) {
5958
- if (name.length === 0 || name.startsWith(".") || name.includes("/") || name.includes("\\") || name.includes("..")) {
6636
+ if (!isTrimmedPrintableIdentifier(name) || name.startsWith(".") || name.includes("/") || name.includes("\\") || name.includes("..")) {
5959
6637
  throw new Error(`Invalid task list name "${name}".`);
5960
6638
  }
5961
6639
  return name;
@@ -5992,7 +6670,7 @@ function createTask2(list, id, taskRecord, sourcePath) {
5992
6670
  state: getOwnEntry(taskRecord, "state"),
5993
6671
  description: descriptionFromTaskRecord(taskRecord),
5994
6672
  metadata: metadataFromTaskRecord(taskRecord),
5995
- ...sourcePath !== void 0 && { sourcePath: path8.resolve(sourcePath) }
6673
+ ...sourcePath !== void 0 && { sourcePath: path9.resolve(sourcePath) }
5996
6674
  };
5997
6675
  }
5998
6676
  function matchesFilter(task, filter) {
@@ -6163,8 +6841,8 @@ function serializeDocument(document) {
6163
6841
  return serialized.endsWith("\n") ? serialized : `${serialized}
6164
6842
  `;
6165
6843
  }
6166
- async function readStore(fs4, filePath, validStates) {
6167
- const content = await fs4.readFile(filePath, "utf8");
6844
+ async function readStore(fs5, filePath, validStates) {
6845
+ const content = await fs5.readFile(filePath, "utf8");
6168
6846
  const document = parseStoreDocument(filePath, content);
6169
6847
  const store = document.toJS();
6170
6848
  assertValidStoreRecord(store, filePath);
@@ -6304,6 +6982,7 @@ function createTasksView3(deps, list) {
6304
6982
  assertCreateDoesNotSetState2(input);
6305
6983
  assertCreateHasId2(input);
6306
6984
  validateTaskId(input.id);
6985
+ validateTaskName(input.name);
6307
6986
  const { document, store } = await readStore(deps.fs, deps.path, validStates);
6308
6987
  if (getTaskRecord(store, list, input.id)) {
6309
6988
  throw new TaskAlreadyExistsError(`Task "${list}/${input.id}" already exists.`);
@@ -6316,6 +6995,9 @@ function createTasksView3(deps, list) {
6316
6995
  async update(id, patch) {
6317
6996
  assertUpdateDoesNotSetState2(patch);
6318
6997
  validateTaskId(id);
6998
+ if (patch.name !== void 0) {
6999
+ validateTaskName(patch.name);
7000
+ }
6319
7001
  const { document, store } = await readStore(deps.fs, deps.path, validStates);
6320
7002
  const existing = getTaskOrThrow(store, list, id);
6321
7003
  const nextTaskRecord = buildUpdatedTaskRecord(existing, patch);
@@ -6407,6 +7089,11 @@ function createTasksView3(deps, list) {
6407
7089
  insertIndex = anchor.position === "top" ? 0 : listNode.items.length;
6408
7090
  } else {
6409
7091
  const anchorId = "before" in anchor ? anchor.before : anchor.after;
7092
+ const activeIds = new Set(activeItemIds(listNode, validStates));
7093
+ if (!activeIds.has(anchorId)) {
7094
+ listNode.items.splice(fromIndex, 0, movedPair);
7095
+ throw new AnchorNotFoundError(anchorId);
7096
+ }
6410
7097
  const anchorIndex = findItemIndex(listNode, anchorId);
6411
7098
  if (anchorIndex < 0) {
6412
7099
  listNode.items.splice(fromIndex, 0, movedPair);
@@ -6591,7 +7278,7 @@ function isRecord4(value) {
6591
7278
 
6592
7279
  // ../task-list/src/move.ts
6593
7280
  import * as fsPromises2 from "node:fs/promises";
6594
- import path9 from "node:path";
7281
+ import path10 from "node:path";
6595
7282
 
6596
7283
  // ../toolcraft/src/human-in-loop/approval-tasks.ts
6597
7284
  import { randomBytes as randomBytes3 } from "node:crypto";
@@ -6778,7 +7465,7 @@ function areEqualStrings(left, right) {
6778
7465
  }
6779
7466
 
6780
7467
  // ../toolcraft/src/human-in-loop/runner.ts
6781
- import { access, lstat, readFile as readFile2, rename, unlink, writeFile as writeFile2 } from "node:fs/promises";
7468
+ import { access, lstat, readFile as readFile3, rename, unlink, writeFile as writeFile2 } from "node:fs/promises";
6782
7469
 
6783
7470
  // ../toolcraft/src/human-in-loop/default-provider.ts
6784
7471
  import process3 from "node:process";
@@ -6810,7 +7497,7 @@ on error number -128
6810
7497
  end try`;
6811
7498
  }
6812
7499
  function parseStdout(out) {
6813
- const value = out.endsWith("\r\n") ? out.slice(0, -2) : out.endsWith("\n") ? out.slice(0, -1) : out;
7500
+ const value = out.endsWith("\r\n") ? out.slice(0, -2) : out.endsWith("\n") ? out.slice(0, -1) : out.endsWith("\r") ? out.slice(0, -1) : out;
6814
7501
  switch (value) {
6815
7502
  case "Approve":
6816
7503
  case "APPROVED":
@@ -7090,13 +7777,13 @@ function formatAvailableApprovalCommandPaths(root) {
7090
7777
  }
7091
7778
  function enumerateApprovalCommandPaths(root) {
7092
7779
  const paths = [];
7093
- const visit = (node, path24) => {
7780
+ const visit = (node, path25) => {
7094
7781
  if (node.kind === "command") {
7095
- paths.push(path24.join("."));
7782
+ paths.push(path25.join("."));
7096
7783
  return;
7097
7784
  }
7098
7785
  for (const child of getVisibleCliChildren(node)) {
7099
- visit(child, [...path24, child.name]);
7786
+ visit(child, [...path25, child.name]);
7100
7787
  }
7101
7788
  };
7102
7789
  if (root.kind === "command") {
@@ -7131,21 +7818,21 @@ function createHandlerContext(command, params17) {
7131
7818
  }
7132
7819
  function createFs() {
7133
7820
  return {
7134
- readFile: async (path24, encoding = "utf8") => readFile2(path24, { encoding }),
7135
- writeFile: async (path24, contents, options) => {
7136
- await writeFile2(path24, contents, options);
7821
+ readFile: async (path25, encoding = "utf8") => readFile3(path25, { encoding }),
7822
+ writeFile: async (path25, contents, options) => {
7823
+ await writeFile2(path25, contents, options);
7137
7824
  },
7138
- exists: async (path24) => {
7825
+ exists: async (path25) => {
7139
7826
  try {
7140
- await access(path24);
7827
+ await access(path25);
7141
7828
  return true;
7142
7829
  } catch {
7143
7830
  return false;
7144
7831
  }
7145
7832
  },
7146
- lstat: async (path24) => lstat(path24),
7833
+ lstat: async (path25) => lstat(path25),
7147
7834
  rename: async (fromPath, toPath) => rename(fromPath, toPath),
7148
- unlink: async (path24) => unlink(path24)
7835
+ unlink: async (path25) => unlink(path25)
7149
7836
  };
7150
7837
  }
7151
7838
  function createEnv(values = process.env) {
@@ -7424,13 +8111,13 @@ function isMissingStateError(error3) {
7424
8111
  import { mkdir as mkdir2, realpath as realpath2, writeFile as writeFile4 } from "node:fs/promises";
7425
8112
  import { randomUUID as randomUUID5 } from "node:crypto";
7426
8113
  import os from "node:os";
7427
- import path13 from "node:path";
8114
+ import path14 from "node:path";
7428
8115
  import { CommanderError } from "commander";
7429
8116
 
7430
8117
  // ../toolcraft/src/mcp-proxy.ts
7431
8118
  import { existsSync as existsSync2 } from "node:fs";
7432
- import { lstat as lstat2, mkdir, readFile as readFile3, rename as rename2, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
7433
- import path12 from "node:path";
8119
+ import { lstat as lstat2, mkdir, readFile as readFile4, rename as rename2, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
8120
+ import path13 from "node:path";
7434
8121
  import { createHash as createHash3, randomUUID as randomUUID4 } from "node:crypto";
7435
8122
 
7436
8123
  // ../tiny-mcp-client/src/internal.ts
@@ -7439,13 +8126,13 @@ import { PassThrough as PassThrough2 } from "node:stream";
7439
8126
 
7440
8127
  // ../mcp-oauth/src/client/auth-store-session-store.ts
7441
8128
  import crypto from "node:crypto";
7442
- import path11 from "node:path";
8129
+ import path12 from "node:path";
7443
8130
 
7444
8131
  // ../auth-store/src/encrypted-file-store.ts
7445
8132
  import { createCipheriv, createDecipheriv, randomBytes as randomBytes4, randomUUID as randomUUID3, scrypt } from "node:crypto";
7446
8133
  import { promises as fs } from "node:fs";
7447
8134
  import { homedir, hostname, userInfo } from "node:os";
7448
- import path10 from "node:path";
8135
+ import path11 from "node:path";
7449
8136
 
7450
8137
  // ../auth-store/src/error-codes.ts
7451
8138
  function hasOwnErrorCode3(error3, code) {
@@ -7474,10 +8161,13 @@ var EncryptedFileStore = class {
7474
8161
  if (input.filePath === void 0) {
7475
8162
  const homeDirectory = (input.getHomeDirectory ?? homedir)();
7476
8163
  const defaultDirectory = input.defaultDirectory ?? ".auth-store";
7477
- this.filePath = path10.join(
8164
+ const defaultFileName = input.defaultFileName ?? "credentials.enc";
8165
+ assertSafeDefaultDirectory(defaultDirectory);
8166
+ assertSafeDefaultFileName(defaultFileName);
8167
+ this.filePath = path11.join(
7478
8168
  homeDirectory,
7479
8169
  defaultDirectory,
7480
- input.defaultFileName ?? "credentials.enc"
8170
+ defaultFileName
7481
8171
  );
7482
8172
  this.symbolicLinkCheckStartPath = resolveDefaultDirectoryCheckStart(
7483
8173
  homeDirectory,
@@ -7537,7 +8227,7 @@ var EncryptedFileStore = class {
7537
8227
  authTag: authTag.toString("base64"),
7538
8228
  ciphertext: ciphertext.toString("base64")
7539
8229
  };
7540
- await this.fs.mkdir(path10.dirname(this.filePath), { recursive: true });
8230
+ await this.fs.mkdir(path11.dirname(this.filePath), { recursive: true });
7541
8231
  await this.assertCredentialPathHasNoSymbolicLinks(this.filePath);
7542
8232
  const temporaryPath = `${this.filePath}.${process.pid}.${randomUUID3()}.tmp`;
7543
8233
  let temporaryCreated = false;
@@ -7569,7 +8259,7 @@ var EncryptedFileStore = class {
7569
8259
  }
7570
8260
  }
7571
8261
  async assertCredentialPathHasNoSymbolicLinks(targetPath) {
7572
- const resolvedPath = path10.resolve(targetPath);
8262
+ const resolvedPath = path11.resolve(targetPath);
7573
8263
  const protectedPaths = getProtectedCredentialPaths(
7574
8264
  resolvedPath,
7575
8265
  this.symbolicLinkCheckStartPath
@@ -7603,27 +8293,62 @@ var EncryptedFileStore = class {
7603
8293
  };
7604
8294
  function resolveDefaultDirectoryCheckStart(homeDirectory, defaultDirectory) {
7605
8295
  const [firstSegment] = defaultDirectory.split(/[\\/]+/).filter(Boolean);
7606
- return path10.resolve(homeDirectory, firstSegment ?? ".");
8296
+ return path11.resolve(homeDirectory, firstSegment ?? ".");
7607
8297
  }
7608
8298
  function getProtectedCredentialPaths(resolvedPath, symbolicLinkCheckStartPath) {
7609
8299
  if (symbolicLinkCheckStartPath === null) {
7610
- return [path10.dirname(resolvedPath), resolvedPath];
8300
+ return getExplicitProtectedCredentialPaths(resolvedPath);
7611
8301
  }
7612
- const resolvedStartPath = path10.resolve(symbolicLinkCheckStartPath);
8302
+ const resolvedStartPath = path11.resolve(symbolicLinkCheckStartPath);
7613
8303
  if (!isPathInsideOrEqual(resolvedPath, resolvedStartPath)) {
7614
- return [path10.dirname(resolvedPath), resolvedPath];
8304
+ return [path11.dirname(resolvedPath), resolvedPath];
7615
8305
  }
7616
8306
  const protectedPaths = [resolvedStartPath];
7617
8307
  let currentPath = resolvedStartPath;
7618
- for (const segment of path10.relative(resolvedStartPath, resolvedPath).split(path10.sep).filter(Boolean)) {
7619
- currentPath = path10.join(currentPath, segment);
8308
+ for (const segment of path11.relative(resolvedStartPath, resolvedPath).split(path11.sep).filter(Boolean)) {
8309
+ currentPath = path11.join(currentPath, segment);
8310
+ protectedPaths.push(currentPath);
8311
+ }
8312
+ return protectedPaths;
8313
+ }
8314
+ function assertSafeDefaultDirectory(defaultDirectory) {
8315
+ if (path11.isAbsolute(defaultDirectory) || path11.win32.isAbsolute(defaultDirectory)) {
8316
+ throw new Error("defaultDirectory must be a relative path inside the home directory");
8317
+ }
8318
+ for (const segment of splitPathSegments(defaultDirectory)) {
8319
+ if (segment === "..") {
8320
+ throw new Error("defaultDirectory must be a relative path inside the home directory");
8321
+ }
8322
+ }
8323
+ }
8324
+ function assertSafeDefaultFileName(defaultFileName) {
8325
+ if (defaultFileName.trim().length === 0 || defaultFileName === "." || defaultFileName === ".." || splitPathSegments(defaultFileName).length !== 1) {
8326
+ throw new Error("defaultFileName must be a file name without path separators");
8327
+ }
8328
+ }
8329
+ function splitPathSegments(value) {
8330
+ return value.split("/").flatMap((segment) => segment.split("\\")).filter((segment) => segment.length > 0);
8331
+ }
8332
+ function getExplicitProtectedCredentialPaths(resolvedPath) {
8333
+ const parsed = path11.parse(resolvedPath);
8334
+ const segments = resolvedPath.slice(parsed.root.length).split(path11.sep).filter((segment) => segment.length > 0);
8335
+ if (segments.length <= 1) {
8336
+ return [resolvedPath];
8337
+ }
8338
+ const protectedPaths = [];
8339
+ let currentPath = parsed.root;
8340
+ for (const [index, segment] of segments.entries()) {
8341
+ currentPath = path11.join(currentPath, segment);
8342
+ if (index === 0) {
8343
+ continue;
8344
+ }
7620
8345
  protectedPaths.push(currentPath);
7621
8346
  }
7622
8347
  return protectedPaths;
7623
8348
  }
7624
8349
  function isPathInsideOrEqual(childPath, parentPath) {
7625
- const relativePath = path10.relative(parentPath, childPath);
7626
- return relativePath === "" || !relativePath.startsWith("..") && !path10.isAbsolute(relativePath);
8350
+ const relativePath = path11.relative(parentPath, childPath);
8351
+ return relativePath === "" || !relativePath.startsWith("..") && !path11.isAbsolute(relativePath);
7627
8352
  }
7628
8353
  async function removeIfPresent(fileSystem, filePath) {
7629
8354
  try {
@@ -7714,8 +8439,14 @@ var KeychainStore = class {
7714
8439
  account;
7715
8440
  constructor(input) {
7716
8441
  this.runCommand = input.runCommand ?? runSecurityCommand;
7717
- this.service = input.service;
7718
- this.account = input.account;
8442
+ this.service = input.service.trim();
8443
+ this.account = input.account.trim();
8444
+ if (this.service.length === 0) {
8445
+ throw new Error("Keychain service must not be empty");
8446
+ }
8447
+ if (this.account.length === 0) {
8448
+ throw new Error("Keychain account must not be empty");
8449
+ }
7719
8450
  }
7720
8451
  async get() {
7721
8452
  const result = await this.executeSecurityCommand(
@@ -7742,10 +8473,10 @@ var KeychainStore = class {
7742
8473
  "-a",
7743
8474
  this.account,
7744
8475
  "-U",
7745
- "-w"
8476
+ "-w",
8477
+ value
7746
8478
  ],
7747
- "store secret in macOS Keychain",
7748
- { stdin: value }
8479
+ "store secret in macOS Keychain"
7749
8480
  );
7750
8481
  if (getCommandExitCode(result) !== 0) {
7751
8482
  throw createSecurityCliFailure("store secret in macOS Keychain", result);
@@ -7890,13 +8621,14 @@ function createSecretStore(input) {
7890
8621
  function resolveBackend(input) {
7891
8622
  const envVar = input.backendEnvVar ?? DEFAULT_BACKEND_ENV_VAR;
7892
8623
  const configuredBackend = input.backend ?? getOwnEnvValue(input.env, envVar) ?? getOwnEnvValue(process.env, envVar);
7893
- if (configuredBackend === "keychain") {
8624
+ const backend = configuredBackend?.trim();
8625
+ if (backend === "keychain") {
7894
8626
  return "keychain";
7895
8627
  }
7896
- if (configuredBackend === void 0 || configuredBackend === "file") {
8628
+ if (backend === void 0 || backend === "file") {
7897
8629
  return "file";
7898
8630
  }
7899
- throw new Error(`Unsupported auth store backend: ${configuredBackend}`);
8631
+ throw new Error(`Unsupported auth store backend: ${backend}`);
7900
8632
  }
7901
8633
  function getOwnEnvValue(env, key2) {
7902
8634
  return env !== void 0 && Object.prototype.hasOwnProperty.call(env, key2) ? env[key2] : void 0;
@@ -7921,6 +8653,7 @@ var DEFAULT_KEYCHAIN_SERVICE = "poe-code-mcp-oauth";
7921
8653
  var DEFAULT_CLIENT_FILE_SALT = "poe-code:mcp-oauth:clients:v1";
7922
8654
  var DEFAULT_CLIENT_FILE_DIRECTORY = ".poe-code/mcp-oauth/clients";
7923
8655
  var DEFAULT_CLIENT_KEYCHAIN_SERVICE = "poe-code-mcp-oauth-clients";
8656
+ var MAX_JS_DATE_MS = 864e13;
7924
8657
  function createAuthStoreSessionStore(options = {}) {
7925
8658
  return {
7926
8659
  async load(resource) {
@@ -7930,10 +8663,10 @@ function createAuthStoreSessionStore(options = {}) {
7930
8663
  return null;
7931
8664
  }
7932
8665
  const parsed = JSON.parse(value);
7933
- if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
8666
+ if (isStoredOAuthSession(parsed)) {
7934
8667
  return parsed;
7935
8668
  }
7936
- throw new Error("Stored OAuth session must be a JSON object");
8669
+ throw new Error("Stored OAuth session must match the expected shape");
7937
8670
  },
7938
8671
  async save(resource, session) {
7939
8672
  const store = createResourceSecretStore(resource, options);
@@ -7977,10 +8710,10 @@ function createAuthStoreClientStore(options) {
7977
8710
  function createNamedSecretStore(key2, options, defaults2) {
7978
8711
  const hash = crypto.createHash("sha256").update(key2).digest("hex");
7979
8712
  const configuredFilePath = options.fileStore?.filePath;
7980
- const parsedFilePath = configuredFilePath === void 0 ? null : path11.parse(configuredFilePath);
8713
+ const parsedFilePath = configuredFilePath === void 0 ? null : path12.parse(configuredFilePath);
7981
8714
  const fileStore = {
7982
8715
  ...options.fileStore,
7983
- filePath: parsedFilePath === null ? void 0 : path11.join(
8716
+ filePath: parsedFilePath === null ? void 0 : path12.join(
7984
8717
  parsedFilePath.dir,
7985
8718
  `${parsedFilePath.name}-${hash}${parsedFilePath.ext || ".enc"}`
7986
8719
  ),
@@ -7996,28 +8729,20 @@ function createNamedSecretStore(key2, options, defaults2) {
7996
8729
  return createSecretStore({ ...options, fileStore, keychainStore }).store;
7997
8730
  }
7998
8731
  function createResourceSecretStore(resource, options) {
7999
- return createNamedSecretStore(
8000
- canonicalizeResourceIndicator(resource),
8001
- options,
8002
- {
8003
- salt: DEFAULT_FILE_SALT,
8004
- directory: DEFAULT_FILE_DIRECTORY,
8005
- service: DEFAULT_KEYCHAIN_SERVICE,
8006
- accountPrefix: "provider"
8007
- }
8008
- );
8732
+ return createNamedSecretStore(canonicalizeResourceIndicator(resource), options, {
8733
+ salt: DEFAULT_FILE_SALT,
8734
+ directory: DEFAULT_FILE_DIRECTORY,
8735
+ service: DEFAULT_KEYCHAIN_SERVICE,
8736
+ accountPrefix: "provider"
8737
+ });
8009
8738
  }
8010
8739
  function createIssuerSecretStore(issuer, options) {
8011
- return createNamedSecretStore(
8012
- issuer,
8013
- options,
8014
- {
8015
- salt: DEFAULT_CLIENT_FILE_SALT,
8016
- directory: DEFAULT_CLIENT_FILE_DIRECTORY,
8017
- service: DEFAULT_CLIENT_KEYCHAIN_SERVICE,
8018
- accountPrefix: "issuer"
8019
- }
8020
- );
8740
+ return createNamedSecretStore(issuer, options, {
8741
+ salt: DEFAULT_CLIENT_FILE_SALT,
8742
+ directory: DEFAULT_CLIENT_FILE_DIRECTORY,
8743
+ service: DEFAULT_CLIENT_KEYCHAIN_SERVICE,
8744
+ accountPrefix: "issuer"
8745
+ });
8021
8746
  }
8022
8747
  function isObjectRecord(value) {
8023
8748
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -8029,6 +8754,50 @@ function getOwnString(record, key2) {
8029
8754
  const value = getOwnEntry4(record, key2);
8030
8755
  return typeof value === "string" ? value : void 0;
8031
8756
  }
8757
+ function isStoredOAuthSession(value) {
8758
+ if (!isObjectRecord(value)) {
8759
+ return false;
8760
+ }
8761
+ return isNonBlankOwnString(value, "resource") && isNonBlankOwnString(value, "authorizationServer") && isStoredOAuthClient(getOwnEntry4(value, "client")) && isStoredOAuthDiscovery(getOwnEntry4(value, "discovery")) && isStoredOAuthTokensOrMissing(getOwnEntry4(value, "tokens"));
8762
+ }
8763
+ function isStoredOAuthClient(value) {
8764
+ if (!isObjectRecord(value) || !isNonBlankOwnString(value, "clientId")) {
8765
+ return false;
8766
+ }
8767
+ const clientSecret = getOwnEntry4(value, "clientSecret");
8768
+ return clientSecret === void 0 || typeof clientSecret === "string" && clientSecret.trim().length > 0;
8769
+ }
8770
+ function isStoredOAuthDiscovery(value) {
8771
+ if (!isObjectRecord(value)) {
8772
+ return false;
8773
+ }
8774
+ return isNonBlankOwnString(value, "resourceMetadataUrl") && isObjectRecord(getOwnEntry4(value, "resourceMetadata")) && isObjectRecord(getOwnEntry4(value, "authorizationServerMetadata"));
8775
+ }
8776
+ function isStoredOAuthTokensOrMissing(value) {
8777
+ if (value === void 0) {
8778
+ return true;
8779
+ }
8780
+ if (!isObjectRecord(value)) {
8781
+ return false;
8782
+ }
8783
+ if (!isNonBlankOwnString(value, "accessToken") || getOwnString(value, "tokenType") !== "Bearer") {
8784
+ return false;
8785
+ }
8786
+ const expiresAt = getOwnEntry4(value, "expiresAt");
8787
+ if (expiresAt !== null && (typeof expiresAt !== "number" || !Number.isSafeInteger(expiresAt) || expiresAt > MAX_JS_DATE_MS || !Number.isFinite(new Date(expiresAt).getTime()))) {
8788
+ return false;
8789
+ }
8790
+ const refreshToken = getOwnEntry4(value, "refreshToken");
8791
+ if (refreshToken !== void 0 && (typeof refreshToken !== "string" || refreshToken.trim().length === 0)) {
8792
+ return false;
8793
+ }
8794
+ const scope = getOwnEntry4(value, "scope");
8795
+ return scope === void 0 || typeof scope === "string" && scope.trim().length > 0;
8796
+ }
8797
+ function isNonBlankOwnString(record, key2) {
8798
+ const value = getOwnString(record, key2);
8799
+ return value !== void 0 && value.trim().length > 0;
8800
+ }
8032
8801
 
8033
8802
  // ../mcp-oauth/src/client/default-oauth-client-provider.ts
8034
8803
  import { URL as URL2 } from "node:url";
@@ -8139,9 +8908,7 @@ function waitForAuthorizationCode(server, authorizationUrl, options, callbackPat
8139
8908
  } catch (error3) {
8140
8909
  res.writeHead(400);
8141
8910
  res.end(error3 instanceof Error ? error3.message : "Invalid OAuth callback");
8142
- if (callbackParameters.error === null) {
8143
- settle(() => reject(error3 instanceof Error ? error3 : new Error(String(error3))));
8144
- }
8911
+ settle(() => reject(error3 instanceof Error ? error3 : new Error(String(error3))));
8145
8912
  return;
8146
8913
  }
8147
8914
  const authorizationError = callbackParameters.error;
@@ -8153,7 +8920,10 @@ function waitForAuthorizationCode(server, authorizationUrl, options, callbackPat
8153
8920
  return;
8154
8921
  }
8155
8922
  try {
8156
- const code = validateAuthorizationCallbackParameters(callbackParameters, expectedAuthorization);
8923
+ const code = validateAuthorizationCallbackParameters(
8924
+ callbackParameters,
8925
+ expectedAuthorization
8926
+ );
8157
8927
  res.writeHead(200, { "Content-Type": "text/html" });
8158
8928
  res.end(buildSuccessPage(options.landingPage));
8159
8929
  settle(() => resolve(code));
@@ -8176,7 +8946,10 @@ function waitForAuthorizationCode(server, authorizationUrl, options, callbackPat
8176
8946
  const description = callbackParameters.errorDescription ?? callbackParameters.error;
8177
8947
  throw createAuthorizationError(callbackParameters.error, description);
8178
8948
  }
8179
- const code = validateAuthorizationCallbackParameters(callbackParameters, expectedAuthorization);
8949
+ const code = validateAuthorizationCallbackParameters(
8950
+ callbackParameters,
8951
+ expectedAuthorization
8952
+ );
8180
8953
  settle(() => resolve(code));
8181
8954
  } catch (error3) {
8182
8955
  settle(() => reject(error3 instanceof Error ? error3 : new Error(String(error3))));
@@ -8281,6 +9054,7 @@ function generateCodeChallenge(verifier) {
8281
9054
  }
8282
9055
 
8283
9056
  // ../mcp-oauth/src/client/token-endpoint.ts
9057
+ var MAX_JS_DATE_MS2 = 864e13;
8284
9058
  var OAuthError = class extends Error {
8285
9059
  error;
8286
9060
  errorDescription;
@@ -8358,22 +9132,32 @@ async function requestTokens(input) {
8358
9132
  if (typeof accessToken !== "string" || accessToken.trim().length === 0) {
8359
9133
  throw new Error("OAuth token response missing access_token");
8360
9134
  }
9135
+ const normalizedAccessToken = accessToken.trim();
8361
9136
  const tokenType = normalizeBearerTokenType(getOwnEntry6(payload, "token_type"));
8362
9137
  if (tokenType === null) {
8363
9138
  throw new Error("OAuth token response missing token_type=Bearer");
8364
9139
  }
8365
9140
  const expiresIn = getOwnEntry6(payload, "expires_in");
8366
- if (typeof expiresIn === "number" && Number.isFinite(expiresIn) && expiresIn < 0) {
8367
- throw new Error("OAuth token response has invalid expires_in");
9141
+ let expiresAt = null;
9142
+ if (expiresIn !== void 0) {
9143
+ if (typeof expiresIn !== "number" || !Number.isFinite(expiresIn) || !Number.isInteger(expiresIn) || expiresIn < 0) {
9144
+ throw new Error("OAuth token response has invalid expires_in");
9145
+ }
9146
+ expiresAt = input.now() + expiresIn * 1e3;
9147
+ if (!Number.isSafeInteger(expiresAt) || expiresAt > MAX_JS_DATE_MS2 || !Number.isFinite(new Date(expiresAt).getTime())) {
9148
+ throw new Error("OAuth token response has invalid expires_in");
9149
+ }
8368
9150
  }
8369
9151
  const refreshToken = getOwnEntry6(payload, "refresh_token");
8370
9152
  const scope = getOwnEntry6(payload, "scope");
9153
+ const normalizedRefreshToken = typeof refreshToken === "string" && refreshToken.trim().length > 0 ? refreshToken.trim() : void 0;
9154
+ const normalizedScope = typeof scope === "string" && scope.trim().length > 0 ? scope.trim() : void 0;
8371
9155
  return {
8372
- accessToken,
8373
- refreshToken: typeof refreshToken === "string" && refreshToken.length > 0 ? refreshToken : void 0,
9156
+ accessToken: normalizedAccessToken,
9157
+ refreshToken: normalizedRefreshToken === void 0 ? void 0 : normalizedRefreshToken,
8374
9158
  tokenType,
8375
- expiresAt: typeof expiresIn === "number" && Number.isFinite(expiresIn) ? input.now() + expiresIn * 1e3 : null,
8376
- scope: typeof scope === "string" && scope.length > 0 ? scope : void 0
9159
+ expiresAt,
9160
+ scope: normalizedScope === void 0 ? void 0 : normalizedScope
8377
9161
  };
8378
9162
  }
8379
9163
  async function readOAuthJsonObjectResponse(response) {
@@ -8424,6 +9208,7 @@ function normalizeBearerTokenType(value) {
8424
9208
  }
8425
9209
 
8426
9210
  // ../mcp-oauth/src/client/default-oauth-client-provider.ts
9211
+ var MAX_JS_DATE_MS3 = 864e13;
8427
9212
  function createOAuthClientProvider(options) {
8428
9213
  if (isProviderOptions(options)) {
8429
9214
  return options.provider;
@@ -8588,7 +9373,12 @@ function createDefaultOAuthClientProvider(options) {
8588
9373
  });
8589
9374
  let resolvedClient = null;
8590
9375
  try {
8591
- resolvedClient = await resolveClient(currentSession, discovery, loopback.redirectUri, fetch2);
9376
+ resolvedClient = await resolveClient(
9377
+ currentSession,
9378
+ discovery,
9379
+ loopback.redirectUri,
9380
+ fetch2
9381
+ );
8592
9382
  const sessionWithoutTokens = {
8593
9383
  resource,
8594
9384
  authorizationServer: discovery.authorizationServer,
@@ -8655,28 +9445,26 @@ function createDefaultOAuthClientProvider(options) {
8655
9445
  return finalPromise;
8656
9446
  }
8657
9447
  async function resolveClient(existingSession, discovery, redirectUri, fetch2) {
9448
+ const configuredClient = normalizeConfiguredClient(options.client);
8658
9449
  if (options.client.mode === "static") {
9450
+ if (configuredClient === null) {
9451
+ throw new Error("OAuth client_id must not be blank");
9452
+ }
8659
9453
  return {
8660
9454
  kind: "static",
8661
9455
  fromStoredRegistration: false,
8662
- client: {
8663
- clientId: options.client.clientId,
8664
- clientSecret: options.client.clientSecret
8665
- }
9456
+ client: configuredClient
8666
9457
  };
8667
9458
  }
8668
9459
  const registrationEndpoint = getOwnString2(
8669
9460
  discovery.authorizationServerMetadata,
8670
9461
  "registration_endpoint"
8671
9462
  );
8672
- if (registrationEndpoint === void 0 && options.client.clientId !== void 0) {
9463
+ if (registrationEndpoint === void 0 && configuredClient !== null) {
8673
9464
  return {
8674
9465
  kind: "static",
8675
9466
  fromStoredRegistration: false,
8676
- client: {
8677
- clientId: options.client.clientId,
8678
- clientSecret: options.client.clientSecret
8679
- }
9467
+ client: configuredClient
8680
9468
  };
8681
9469
  }
8682
9470
  const storedClient = await loadRegisteredClient(discovery.authorizationServer);
@@ -8698,7 +9486,7 @@ function createDefaultOAuthClientProvider(options) {
8698
9486
  throw new Error("Authorization server metadata is missing registration_endpoint");
8699
9487
  }
8700
9488
  if (existingSession !== null && existingSession.client.clientId.length > 0) {
8701
- const isConfiguredStaticFallback = options.client.clientId !== void 0 && existingSession.client.clientId === options.client.clientId && existingSession.client.clientSecret === options.client.clientSecret;
9489
+ const isConfiguredStaticFallback = configuredClient !== null && existingSession.client.clientId === configuredClient.clientId && existingSession.client.clientSecret === configuredClient.clientSecret;
8702
9490
  if (!isConfiguredStaticFallback) {
8703
9491
  await saveRegisteredClient(discovery.authorizationServer, existingSession.client);
8704
9492
  return {
@@ -8726,8 +9514,8 @@ function createDefaultOAuthClientProvider(options) {
8726
9514
  }
8727
9515
  const clientSecret = getOwnString2(payload, "client_secret");
8728
9516
  const registeredClient = {
8729
- clientId,
8730
- clientSecret: clientSecret !== void 0 && clientSecret.length > 0 ? clientSecret : void 0
9517
+ clientId: clientId.trim(),
9518
+ clientSecret: clientSecret !== void 0 && clientSecret.trim().length > 0 ? clientSecret.trim() : void 0
8731
9519
  };
8732
9520
  await saveRegisteredClient(discovery.authorizationServer, registeredClient);
8733
9521
  return {
@@ -8840,14 +9628,16 @@ function normalizeStoredClient(value) {
8840
9628
  if (clientId === void 0 || clientId.trim().length === 0) {
8841
9629
  return null;
8842
9630
  }
9631
+ const normalizedClientId = clientId.trim();
8843
9632
  const clientSecret = getOwnEntry7(value, "clientSecret");
8844
9633
  if (clientSecret === void 0) {
8845
- return { clientId };
9634
+ return { clientId: normalizedClientId };
8846
9635
  }
8847
9636
  if (typeof clientSecret !== "string" || clientSecret.trim().length === 0) {
8848
9637
  return null;
8849
9638
  }
8850
- return { clientId, clientSecret };
9639
+ const normalizedClientSecret = clientSecret.trim();
9640
+ return { clientId: normalizedClientId, clientSecret: normalizedClientSecret };
8851
9641
  }
8852
9642
  function normalizeStoredTokens(value) {
8853
9643
  if (value === void 0 || !isObjectRecord3(value)) {
@@ -8858,20 +9648,45 @@ function normalizeStoredTokens(value) {
8858
9648
  const expiresAt = getOwnEntry7(value, "expiresAt");
8859
9649
  const refreshToken = getOwnEntry7(value, "refreshToken");
8860
9650
  const scope = getOwnString2(value, "scope");
8861
- const normalizedRefreshToken = typeof refreshToken === "string" ? refreshToken : void 0;
8862
- if (accessToken === void 0 || accessToken.trim().length === 0 || tokenType !== "Bearer" || !(expiresAt === null || typeof expiresAt === "number" && Number.isFinite(expiresAt)) || refreshToken !== void 0 && (typeof refreshToken !== "string" || refreshToken.trim().length === 0)) {
9651
+ const normalizedAccessToken = accessToken?.trim();
9652
+ const normalizedRefreshToken = typeof refreshToken === "string" ? refreshToken.trim() : void 0;
9653
+ const normalizedScope = scope?.trim();
9654
+ if (accessToken === void 0 || normalizedAccessToken === void 0 || normalizedAccessToken.length === 0 || tokenType !== "Bearer" || !(expiresAt === null || typeof expiresAt === "number" && Number.isSafeInteger(expiresAt) && expiresAt <= MAX_JS_DATE_MS3 && Number.isFinite(new Date(expiresAt).getTime())) || refreshToken !== void 0 && (typeof refreshToken !== "string" || normalizedRefreshToken === void 0 || normalizedRefreshToken.length === 0)) {
8863
9655
  return void 0;
8864
9656
  }
8865
9657
  return {
8866
- accessToken,
9658
+ accessToken: normalizedAccessToken,
8867
9659
  tokenType,
8868
9660
  expiresAt,
8869
9661
  ...normalizedRefreshToken === void 0 ? {} : { refreshToken: normalizedRefreshToken },
8870
- ...scope === void 0 || scope.length === 0 ? {} : { scope }
9662
+ ...normalizedScope === void 0 || normalizedScope.length === 0 ? {} : { scope: normalizedScope }
9663
+ };
9664
+ }
9665
+ function getClientMetadata(client) {
9666
+ if (client.metadata === void 0) {
9667
+ return void 0;
9668
+ }
9669
+ return {
9670
+ clientName: normalizeOptionalOAuthString(client.metadata.clientName),
9671
+ scope: normalizeOptionalOAuthString(client.metadata.scope),
9672
+ softwareId: normalizeOptionalOAuthString(client.metadata.softwareId),
9673
+ softwareVersion: normalizeOptionalOAuthString(client.metadata.softwareVersion)
8871
9674
  };
8872
9675
  }
8873
- function getClientMetadata(client) {
8874
- return client.metadata;
9676
+ function normalizeConfiguredClient(client) {
9677
+ const clientId = normalizeOptionalOAuthString(client.clientId);
9678
+ if (clientId === void 0) {
9679
+ return null;
9680
+ }
9681
+ const clientSecret = normalizeOptionalOAuthString(client.clientSecret);
9682
+ return clientSecret === void 0 ? { clientId } : { clientId, clientSecret };
9683
+ }
9684
+ function normalizeOptionalOAuthString(value) {
9685
+ if (value === void 0) {
9686
+ return void 0;
9687
+ }
9688
+ const trimmed = value.trim();
9689
+ return trimmed.length === 0 ? void 0 : trimmed;
8875
9690
  }
8876
9691
  function getOwnEntry7(record, key2) {
8877
9692
  return Object.prototype.hasOwnProperty.call(record, key2) ? record[key2] : void 0;
@@ -8900,11 +9715,7 @@ function buildAuthorizationUrl(input) {
8900
9715
  "authorization_endpoint",
8901
9716
  "Authorization server metadata"
8902
9717
  );
8903
- const issuer = requireOwnString(
8904
- input.metadata,
8905
- "issuer",
8906
- "Authorization server metadata"
8907
- );
9718
+ const issuer = requireOwnString(input.metadata, "issuer", "Authorization server metadata");
8908
9719
  const url = new URL2(authorizationEndpoint);
8909
9720
  const resource = canonicalizeResourceIndicator(input.resource);
8910
9721
  const state = createAuthorizationState({
@@ -9512,7 +10323,7 @@ var McpClient = class {
9512
10323
  await onToolsChanged();
9513
10324
  });
9514
10325
  messageLayer.onNotification("notifications/resources/list_changed", async () => {
9515
- if (onResourcesChanged === void 0) {
10326
+ if (onResourcesChanged === void 0 || this.currentServerCapabilities?.resources?.listChanged !== true) {
9516
10327
  return;
9517
10328
  }
9518
10329
  await onResourcesChanged();
@@ -9531,7 +10342,7 @@ var McpClient = class {
9531
10342
  await onResourceUpdated(uri);
9532
10343
  });
9533
10344
  messageLayer.onNotification("notifications/prompts/list_changed", async () => {
9534
- if (onPromptsChanged === void 0) {
10345
+ if (onPromptsChanged === void 0 || this.currentServerCapabilities?.prompts?.listChanged !== true) {
9535
10346
  return;
9536
10347
  }
9537
10348
  await onPromptsChanged();
@@ -9762,7 +10573,11 @@ var McpClient = class {
9762
10573
  throw new Error("Server does not support resources");
9763
10574
  }
9764
10575
  const requestParams = params17.cursor === void 0 ? void 0 : { cursor: params17.cursor };
9765
- return await messageLayer.sendRequest("resources/list", requestParams);
10576
+ const result = await messageLayer.sendRequest("resources/list", requestParams);
10577
+ if (!isResourcesListResult(result)) {
10578
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid resources/list result");
10579
+ }
10580
+ return result;
9766
10581
  }
9767
10582
  async listResourceTemplates(params17 = {}) {
9768
10583
  const messageLayer = this.getMessageLayerOrThrow();
@@ -9771,7 +10586,11 @@ var McpClient = class {
9771
10586
  throw new Error("Server does not support resources");
9772
10587
  }
9773
10588
  const requestParams = params17.cursor === void 0 ? void 0 : { cursor: params17.cursor };
9774
- return await messageLayer.sendRequest("resources/templates/list", requestParams);
10589
+ const result = await messageLayer.sendRequest("resources/templates/list", requestParams);
10590
+ if (!isResourceTemplatesListResult(result)) {
10591
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid resources/templates/list result");
10592
+ }
10593
+ return result;
9775
10594
  }
9776
10595
  async readResource(params17) {
9777
10596
  const messageLayer = this.getMessageLayerOrThrow();
@@ -9779,7 +10598,11 @@ var McpClient = class {
9779
10598
  if (serverCapabilities.resources === void 0) {
9780
10599
  throw new Error("Server does not support resources");
9781
10600
  }
9782
- return await messageLayer.sendRequest("resources/read", params17);
10601
+ const result = await messageLayer.sendRequest("resources/read", params17);
10602
+ if (!isReadResourceResult(result)) {
10603
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid resources/read result");
10604
+ }
10605
+ return result;
9783
10606
  }
9784
10607
  async subscribe(uri) {
9785
10608
  const messageLayer = this.getMessageLayerOrThrow();
@@ -9814,7 +10637,11 @@ var McpClient = class {
9814
10637
  if (serverCapabilities.prompts === void 0) {
9815
10638
  throw new Error("Server does not support prompts");
9816
10639
  }
9817
- return await messageLayer.sendRequest("prompts/get", params17);
10640
+ const result = await messageLayer.sendRequest("prompts/get", params17);
10641
+ if (!isGetPromptResult(result)) {
10642
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid prompts/get result");
10643
+ }
10644
+ return result;
9818
10645
  }
9819
10646
  async complete(params17) {
9820
10647
  const messageLayer = this.getMessageLayerOrThrow();
@@ -9822,7 +10649,11 @@ var McpClient = class {
9822
10649
  if (serverCapabilities.completions === void 0) {
9823
10650
  throw new Error("Server does not support completions");
9824
10651
  }
9825
- return await messageLayer.sendRequest("completion/complete", params17);
10652
+ const result = await messageLayer.sendRequest("completion/complete", params17);
10653
+ if (!isCompleteResult(result)) {
10654
+ throw new McpError(ERROR_INVALID_REQUEST, "Invalid completion/complete result");
10655
+ }
10656
+ return result;
9826
10657
  }
9827
10658
  async setLogLevel(level) {
9828
10659
  const messageLayer = this.getMessageLayerOrThrow();
@@ -10813,6 +11644,44 @@ function isCallToolResult(value) {
10813
11644
  function isToolsListResult(value) {
10814
11645
  return isObjectRecord5(value) && Array.isArray(value.tools) && (value.nextCursor === void 0 || typeof value.nextCursor === "string");
10815
11646
  }
11647
+ function isResourcesListResult(value) {
11648
+ return isObjectRecord5(value) && Array.isArray(value.resources) && value.resources.every(isResource) && (value.nextCursor === void 0 || typeof value.nextCursor === "string");
11649
+ }
11650
+ function isResourceTemplatesListResult(value) {
11651
+ return isObjectRecord5(value) && Array.isArray(value.resourceTemplates) && value.resourceTemplates.every(isResourceTemplate) && (value.nextCursor === void 0 || typeof value.nextCursor === "string");
11652
+ }
11653
+ function isReadResourceResult(value) {
11654
+ return isObjectRecord5(value) && Array.isArray(value.contents) && value.contents.every(isResourceContents);
11655
+ }
11656
+ function isGetPromptResult(value) {
11657
+ return isObjectRecord5(value) && (value.description === void 0 || typeof value.description === "string") && Array.isArray(value.messages) && value.messages.every(isPromptMessage);
11658
+ }
11659
+ function isCompleteResult(value) {
11660
+ 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");
11661
+ }
11662
+ function isResource(value) {
11663
+ 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");
11664
+ }
11665
+ function isResourceTemplate(value) {
11666
+ 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");
11667
+ }
11668
+ function isResourceContents(value) {
11669
+ if (!isObjectRecord5(value) || typeof value.uri !== "string") {
11670
+ return false;
11671
+ }
11672
+ if (value.mimeType !== void 0 && typeof value.mimeType !== "string") {
11673
+ return false;
11674
+ }
11675
+ const hasText = value.text !== void 0;
11676
+ const hasBlob = value.blob !== void 0;
11677
+ if (!hasText && !hasBlob) {
11678
+ return false;
11679
+ }
11680
+ return (!hasText || typeof value.text === "string") && (!hasBlob || typeof value.blob === "string");
11681
+ }
11682
+ function isPromptMessage(value) {
11683
+ return isObjectRecord5(value) && (value.role === "user" || value.role === "assistant") && isContentItem(value.content);
11684
+ }
10816
11685
  function isContentItem(value) {
10817
11686
  if (!isObjectRecord5(value)) {
10818
11687
  return false;
@@ -10826,7 +11695,7 @@ function isContentItem(value) {
10826
11695
  if (value.type !== "resource" || !isObjectRecord5(value.resource)) {
10827
11696
  return false;
10828
11697
  }
10829
- return typeof value.resource.uri === "string" && (value.resource.mimeType === void 0 || typeof value.resource.mimeType === "string") && (typeof value.resource.text === "string" || typeof value.resource.blob === "string");
11698
+ return isResourceContents(value.resource);
10830
11699
  }
10831
11700
  function hasOwn(value, property) {
10832
11701
  return Object.prototype.hasOwnProperty.call(value, property);
@@ -10966,13 +11835,13 @@ function convertJsonSchema(schema) {
10966
11835
  }
10967
11836
  return convertSchema(schema, schema, []);
10968
11837
  }
10969
- function convertSchema(schema, root, path24) {
10970
- const resolvedSchema = resolveReferencedSchema(schema, root, path24);
11838
+ function convertSchema(schema, root, path25) {
11839
+ const resolvedSchema = resolveReferencedSchema(schema, root, path25);
10971
11840
  const normalizedSchema = normalizeNullability(resolvedSchema);
10972
11841
  const composition = getComposition(normalizedSchema.schema);
10973
11842
  if (Array.isArray(normalizedSchema.schema.type)) {
10974
11843
  throw new Error(
10975
- `JSON Schema "${formatJsonSchemaPath(path24)}" has an unsupported type "${formatJsonSchemaType(
11844
+ `JSON Schema "${formatJsonSchemaPath(path25)}" has an unsupported type "${formatJsonSchemaType(
10976
11845
  normalizedSchema.schema.type
10977
11846
  )}". Supported: string, number, integer, boolean, array, object.`
10978
11847
  );
@@ -10984,13 +11853,13 @@ function convertSchema(schema, root, path24) {
10984
11853
  return convertEnumSchema(resolvedSchema, normalizedSchema.nullable);
10985
11854
  }
10986
11855
  if (composition !== void 0) {
10987
- return convertCompositionSchema(normalizedSchema.schema, root, normalizedSchema.nullable, path24);
11856
+ return convertCompositionSchema(normalizedSchema.schema, root, normalizedSchema.nullable, path25);
10988
11857
  }
10989
11858
  if (isRecordSchema(normalizedSchema.schema)) {
10990
11859
  return applyMetadata(
10991
11860
  S.Record(
10992
11861
  convertSchema(normalizedSchema.schema.additionalProperties, root, [
10993
- ...path24,
11862
+ ...path25,
10994
11863
  "additionalProperties"
10995
11864
  ])
10996
11865
  ),
@@ -11039,12 +11908,12 @@ function convertSchema(schema, root, path24) {
11039
11908
  if (normalizedSchema.schema.items === void 0) {
11040
11909
  throw new Error(
11041
11910
  `JSON Schema "${formatJsonSchemaPath(
11042
- path24
11911
+ path25
11043
11912
  )}" is an array but is missing the "items" field. Add "items": { ... } to declare the element type.`
11044
11913
  );
11045
11914
  }
11046
11915
  return S.Array(
11047
- convertSchema(normalizedSchema.schema.items, root, [...path24, "items"]),
11916
+ convertSchema(normalizedSchema.schema.items, root, [...path25, "items"]),
11048
11917
  createCommonOptions(
11049
11918
  normalizedSchema.schema,
11050
11919
  normalizedSchema.nullable,
@@ -11054,7 +11923,7 @@ function convertSchema(schema, root, path24) {
11054
11923
  case "object":
11055
11924
  return convertObjectSchema(normalizedSchema.schema, root, {
11056
11925
  nullable: normalizedSchema.nullable,
11057
- path: path24
11926
+ path: path25
11058
11927
  });
11059
11928
  case "null":
11060
11929
  return applyMetadata(S.Json(), normalizedSchema.schema, {
@@ -11069,12 +11938,12 @@ function convertSchema(schema, root, path24) {
11069
11938
  }
11070
11939
  throw new Error(
11071
11940
  `JSON Schema "${formatJsonSchemaPath(
11072
- path24
11941
+ path25
11073
11942
  )}" must declare one of: "type", "enum", "const", "oneOf", "anyOf", or "allOf".`
11074
11943
  );
11075
11944
  }
11076
11945
  throw new Error(
11077
- `JSON Schema "${formatJsonSchemaPath(path24)}" has an unsupported type "${formatJsonSchemaType(
11946
+ `JSON Schema "${formatJsonSchemaPath(path25)}" has an unsupported type "${formatJsonSchemaType(
11078
11947
  normalizedSchema.schema.type
11079
11948
  )}". Supported: string, number, integer, boolean, array, object.`
11080
11949
  );
@@ -11118,21 +11987,21 @@ function convertEnumSchema(schema, nullable) {
11118
11987
  )
11119
11988
  });
11120
11989
  }
11121
- function convertCompositionSchema(schema, root, nullable, path24) {
11990
+ function convertCompositionSchema(schema, root, nullable, path25) {
11122
11991
  const composition = getComposition(schema);
11123
11992
  const branchSchemas = composition?.branches ?? [];
11124
11993
  const keyword = composition?.keyword ?? "oneOf";
11125
11994
  const branches = branchSchemas.map(
11126
- (branch, index) => resolveReferencedSchema(branch, root, [...path24, keyword, String(index)])
11995
+ (branch, index) => resolveReferencedSchema(branch, root, [...path25, keyword, String(index)])
11127
11996
  );
11128
- const discriminator = findDiscriminator(branches, root, path24);
11997
+ const discriminator = findDiscriminator(branches, root, path25);
11129
11998
  if (discriminator !== void 0) {
11130
11999
  const convertedBranches = Object.fromEntries(
11131
12000
  branches.map((branch, index) => [
11132
12001
  getDiscriminatorLiteral(branch, discriminator, root),
11133
12002
  convertObjectSchema(branch, root, {
11134
12003
  omitProperty: discriminator,
11135
- path: [...path24, keyword, String(index)]
12004
+ path: [...path25, keyword, String(index)]
11136
12005
  })
11137
12006
  ])
11138
12007
  );
@@ -11151,7 +12020,7 @@ function convertCompositionSchema(schema, root, nullable, path24) {
11151
12020
  S.Union(
11152
12021
  branches.map(
11153
12022
  (branch, index) => convertObjectSchema(branch, root, {
11154
- path: [...path24, keyword, String(index)]
12023
+ path: [...path25, keyword, String(index)]
11155
12024
  })
11156
12025
  )
11157
12026
  ),
@@ -11265,11 +12134,11 @@ function getComposition(schema) {
11265
12134
  }
11266
12135
  return void 0;
11267
12136
  }
11268
- function formatJsonSchemaPath(path24) {
11269
- if (path24.length === 0) {
12137
+ function formatJsonSchemaPath(path25) {
12138
+ if (path25.length === 0) {
11270
12139
  return "#";
11271
12140
  }
11272
- return `#/${path24.map(escapeJsonPointerSegment).join("/")}`;
12141
+ return `#/${path25.map(escapeJsonPointerSegment).join("/")}`;
11273
12142
  }
11274
12143
  function formatJsonSchemaType(type2) {
11275
12144
  return Array.isArray(type2) ? JSON.stringify(type2) : String(type2);
@@ -11285,11 +12154,11 @@ function isRecordSchema(schema) {
11285
12154
  const propertyKeys = Object.keys(schema.properties ?? {});
11286
12155
  return schema.type === "object" && propertyKeys.length === 0 && typeof schema.additionalProperties === "object" && schema.additionalProperties !== null;
11287
12156
  }
11288
- function findDiscriminator(branches, root, path24) {
12157
+ function findDiscriminator(branches, root, path25) {
11289
12158
  const [firstBranch] = branches;
11290
12159
  if (firstBranch === void 0) {
11291
12160
  throw new Error(
11292
- `JSON Schema "${formatJsonSchemaPath(path24)}" uses oneOf/anyOf/allOf but has no branches.`
12161
+ `JSON Schema "${formatJsonSchemaPath(path25)}" uses oneOf/anyOf/allOf but has no branches.`
11293
12162
  );
11294
12163
  }
11295
12164
  const candidateKeys = Object.keys(firstBranch.properties ?? {});
@@ -11329,19 +12198,19 @@ function getDiscriminatorLiteral(branch, key2, root) {
11329
12198
  }
11330
12199
  return void 0;
11331
12200
  }
11332
- function resolveReferencedSchema(schema, root, path24) {
12201
+ function resolveReferencedSchema(schema, root, path25) {
11333
12202
  if (schema.$ref === void 0) {
11334
12203
  return schema;
11335
12204
  }
11336
12205
  const resolvedTarget = resolveLocalRef(root, schema.$ref);
11337
12206
  if (resolvedTarget === void 0) {
11338
12207
  throw new Error(
11339
- `JSON Schema "${formatJsonSchemaPath(path24)}" uses "$ref": ${schema.$ref}. toolcraft only supports internal refs like "#/components/schemas/Foo".`
12208
+ `JSON Schema "${formatJsonSchemaPath(path25)}" uses "$ref": ${schema.$ref}. toolcraft only supports internal refs like "#/components/schemas/Foo".`
11340
12209
  );
11341
12210
  }
11342
12211
  const { $ref: ignoredRef, ...siblingKeywords } = schema;
11343
12212
  void ignoredRef;
11344
- const resolvedSchema = resolveReferencedSchema(resolvedTarget, root, path24);
12213
+ const resolvedSchema = resolveReferencedSchema(resolvedTarget, root, path25);
11345
12214
  if (Object.keys(siblingKeywords).length === 0) {
11346
12215
  return resolvedSchema;
11347
12216
  }
@@ -11365,9 +12234,9 @@ function mergeJsonSchemas(base, overlay) {
11365
12234
  ...mergedRequired === void 0 ? {} : { required: mergedRequired }
11366
12235
  };
11367
12236
  }
11368
- function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__PURE__ */ new Set()) {
12237
+ function hasSelfReferencingRef(schema, root, path25 = "#", activePaths = /* @__PURE__ */ new Set()) {
11369
12238
  const nextActivePaths = new Set(activePaths);
11370
- nextActivePaths.add(path24);
12239
+ nextActivePaths.add(path25);
11371
12240
  const localRefPath = getLocalRefPath(schema.$ref);
11372
12241
  if (localRefPath !== void 0) {
11373
12242
  if (nextActivePaths.has(localRefPath)) {
@@ -11378,13 +12247,13 @@ function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__P
11378
12247
  return true;
11379
12248
  }
11380
12249
  }
11381
- if (schema.items !== void 0 && hasSelfReferencingRef(schema.items, root, `${path24}/items`, nextActivePaths)) {
12250
+ if (schema.items !== void 0 && hasSelfReferencingRef(schema.items, root, `${path25}/items`, nextActivePaths)) {
11382
12251
  return true;
11383
12252
  }
11384
12253
  if (typeof schema.additionalProperties === "object" && schema.additionalProperties !== null && hasSelfReferencingRef(
11385
12254
  schema.additionalProperties,
11386
12255
  root,
11387
- `${path24}/additionalProperties`,
12256
+ `${path25}/additionalProperties`,
11388
12257
  nextActivePaths
11389
12258
  )) {
11390
12259
  return true;
@@ -11393,7 +12262,7 @@ function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__P
11393
12262
  if (hasSelfReferencingRef(
11394
12263
  childSchema,
11395
12264
  root,
11396
- `${path24}/properties/${escapeJsonPointerSegment(key2)}`,
12265
+ `${path25}/properties/${escapeJsonPointerSegment(key2)}`,
11397
12266
  nextActivePaths
11398
12267
  )) {
11399
12268
  return true;
@@ -11403,24 +12272,24 @@ function hasSelfReferencingRef(schema, root, path24 = "#", activePaths = /* @__P
11403
12272
  if (hasSelfReferencingRef(
11404
12273
  childSchema,
11405
12274
  root,
11406
- `${path24}/$defs/${escapeJsonPointerSegment(key2)}`,
12275
+ `${path25}/$defs/${escapeJsonPointerSegment(key2)}`,
11407
12276
  nextActivePaths
11408
12277
  )) {
11409
12278
  return true;
11410
12279
  }
11411
12280
  }
11412
12281
  for (const [index, childSchema] of (schema.oneOf ?? []).entries()) {
11413
- if (hasSelfReferencingRef(childSchema, root, `${path24}/oneOf/${index}`, nextActivePaths)) {
12282
+ if (hasSelfReferencingRef(childSchema, root, `${path25}/oneOf/${index}`, nextActivePaths)) {
11414
12283
  return true;
11415
12284
  }
11416
12285
  }
11417
12286
  for (const [index, childSchema] of (schema.anyOf ?? []).entries()) {
11418
- if (hasSelfReferencingRef(childSchema, root, `${path24}/anyOf/${index}`, nextActivePaths)) {
12287
+ if (hasSelfReferencingRef(childSchema, root, `${path25}/anyOf/${index}`, nextActivePaths)) {
11419
12288
  return true;
11420
12289
  }
11421
12290
  }
11422
12291
  for (const [index, childSchema] of (schema.allOf ?? []).entries()) {
11423
- if (hasSelfReferencingRef(childSchema, root, `${path24}/allOf/${index}`, nextActivePaths)) {
12292
+ if (hasSelfReferencingRef(childSchema, root, `${path25}/allOf/${index}`, nextActivePaths)) {
11424
12293
  return true;
11425
12294
  }
11426
12295
  }
@@ -11436,14 +12305,14 @@ function getLocalRefPath(ref) {
11436
12305
  return ref.startsWith("#/") ? ref : void 0;
11437
12306
  }
11438
12307
  function resolveLocalRef(root, ref) {
11439
- const path24 = getLocalRefPath(ref);
11440
- if (path24 === void 0) {
12308
+ const path25 = getLocalRefPath(ref);
12309
+ if (path25 === void 0) {
11441
12310
  return void 0;
11442
12311
  }
11443
- if (path24 === "#") {
12312
+ if (path25 === "#") {
11444
12313
  return root;
11445
12314
  }
11446
- const segments = path24.slice(2).split("/").map(unescapeJsonPointerSegment);
12315
+ const segments = path25.slice(2).split("/").map(unescapeJsonPointerSegment);
11447
12316
  let current = root;
11448
12317
  for (const segment of segments) {
11449
12318
  if (Array.isArray(current)) {
@@ -11489,15 +12358,15 @@ function getBooleanDefault(value) {
11489
12358
  return typeof value === "boolean" ? value : void 0;
11490
12359
  }
11491
12360
  function getArrayDefault(value) {
11492
- return Array.isArray(value) && value.every((item) => isJsonValue(item)) ? value : void 0;
12361
+ return Array.isArray(value) && value.every((item) => isJsonValue2(item)) ? value : void 0;
11493
12362
  }
11494
12363
  function getPrimitiveEnumDefault(value, candidates) {
11495
12364
  return isPrimitiveEnumValue(value) && candidates.includes(value) ? value : void 0;
11496
12365
  }
11497
12366
  function getJsonDefault(value) {
11498
- return isJsonValue(value) ? value : void 0;
12367
+ return isJsonValue2(value) ? value : void 0;
11499
12368
  }
11500
- function isJsonValue(value) {
12369
+ function isJsonValue2(value) {
11501
12370
  if (value === null) {
11502
12371
  return true;
11503
12372
  }
@@ -11505,12 +12374,12 @@ function isJsonValue(value) {
11505
12374
  return true;
11506
12375
  }
11507
12376
  if (Array.isArray(value)) {
11508
- return value.every((item) => isJsonValue(item));
12377
+ return value.every((item) => isJsonValue2(item));
11509
12378
  }
11510
12379
  if (!isPlainObject(value)) {
11511
12380
  return false;
11512
12381
  }
11513
- return Object.values(value).every((item) => isJsonValue(item));
12382
+ return Object.values(value).every((item) => isJsonValue2(item));
11514
12383
  }
11515
12384
  function isPlainObject(value) {
11516
12385
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -11605,6 +12474,7 @@ function createProxyCommand(parent, tool, commandName, connection) {
11605
12474
  kind: "command",
11606
12475
  name: commandName,
11607
12476
  description: tool.description,
12477
+ hidden: false,
11608
12478
  examples: [],
11609
12479
  aliases: [],
11610
12480
  positional: [],
@@ -11700,7 +12570,7 @@ async function ensureConnected(connection) {
11700
12570
  async function readCache(cachePath) {
11701
12571
  try {
11702
12572
  await assertCachePathHasNoSymlinks(cachePath);
11703
- const raw = await readFile3(cachePath, "utf8");
12573
+ const raw = await readFile4(cachePath, "utf8");
11704
12574
  const parsed = JSON.parse(raw);
11705
12575
  if (parsed === null || typeof parsed !== "object" || !Array.isArray(parsed.tools) || parsed.upstream === void 0 || typeof parsed.upstream.name !== "string" || typeof parsed.upstream.version !== "string") {
11706
12576
  return void 0;
@@ -11721,7 +12591,7 @@ async function readCache(cachePath) {
11721
12591
  }
11722
12592
  }
11723
12593
  async function writeCache(cachePath, cache) {
11724
- const directory = path12.dirname(cachePath);
12594
+ const directory = path13.dirname(cachePath);
11725
12595
  const tempPath = `${cachePath}.tmp-${randomUUID4()}`;
11726
12596
  let tempCreated = false;
11727
12597
  await assertCachePathHasNoSymlinks(cachePath);
@@ -11918,13 +12788,13 @@ function collectProxyGroups(root) {
11918
12788
  function findProjectRoot(from = process.cwd()) {
11919
12789
  let current = process.cwd();
11920
12790
  if (from !== current) {
11921
- current = path12.resolve(from);
12791
+ current = path13.resolve(from);
11922
12792
  }
11923
12793
  while (true) {
11924
- if (existsSync2(path12.join(current, "package.json"))) {
12794
+ if (existsSync2(path13.join(current, "package.json"))) {
11925
12795
  return current;
11926
12796
  }
11927
- const parent = path12.dirname(current);
12797
+ const parent = path13.dirname(current);
11928
12798
  if (parent === current) {
11929
12799
  return void 0;
11930
12800
  }
@@ -11941,7 +12811,7 @@ function resolveCachePath(name, projectRoot) {
11941
12811
  if (name.length === 0 || name === "." || name === ".." || name.includes("/") || name.includes("\\")) {
11942
12812
  throw new Error(`MCP proxy group name must be a file-safe name: "${name}".`);
11943
12813
  }
11944
- return path12.join(resolvedProjectRoot, ".toolcraft", "mcp", `${name}.json`);
12814
+ return path13.join(resolvedProjectRoot, ".toolcraft", "mcp", `${name}.json`);
11945
12815
  }
11946
12816
  async function assertCachePathHasNoSymlinks(filePath) {
11947
12817
  let currentPath = filePath;
@@ -11955,10 +12825,10 @@ async function assertCachePathHasNoSymlinks(filePath) {
11955
12825
  throw error3;
11956
12826
  }
11957
12827
  }
11958
- if (path12.basename(currentPath) === ".toolcraft") {
12828
+ if (path13.basename(currentPath) === ".toolcraft") {
11959
12829
  return;
11960
12830
  }
11961
- const parentPath = path12.dirname(currentPath);
12831
+ const parentPath = path13.dirname(currentPath);
11962
12832
  if (parentPath === currentPath) {
11963
12833
  return;
11964
12834
  }
@@ -12104,20 +12974,20 @@ function reportsEnabled(option, env) {
12104
12974
  function resolveReportDir(option, projectRoot) {
12105
12975
  const configuredDir = typeof option === "object" ? option.dir : void 0;
12106
12976
  if (configuredDir === void 0 || configuredDir.length === 0) {
12107
- return path13.join(projectRoot, ".toolcraft", "errors");
12977
+ return path14.join(projectRoot, ".toolcraft", "errors");
12108
12978
  }
12109
- return path13.isAbsolute(configuredDir) ? configuredDir : path13.join(projectRoot, configuredDir);
12979
+ return path14.isAbsolute(configuredDir) ? configuredDir : path14.join(projectRoot, configuredDir);
12110
12980
  }
12111
12981
  function reportDirMustStayWithinProject(option) {
12112
12982
  const configuredDir = typeof option === "object" ? option.dir : void 0;
12113
- return configuredDir === void 0 || configuredDir.length === 0 || !path13.isAbsolute(configuredDir);
12983
+ return configuredDir === void 0 || configuredDir.length === 0 || !path14.isAbsolute(configuredDir);
12114
12984
  }
12115
12985
  function isWithinDirectory(parent, child) {
12116
- const relative = path13.relative(parent, child);
12117
- return relative === "" || !path13.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path13.sep}`);
12986
+ const relative = path14.relative(parent, child);
12987
+ return relative === "" || !path14.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path14.sep}`);
12118
12988
  }
12119
12989
  async function assertReportDirWithinProject(projectRoot, reportDir) {
12120
- if (!isWithinDirectory(path13.resolve(projectRoot), path13.resolve(reportDir))) {
12990
+ if (!isWithinDirectory(path14.resolve(projectRoot), path14.resolve(reportDir))) {
12121
12991
  throw new Error("Error report directory resolves outside project root.");
12122
12992
  }
12123
12993
  const [canonicalProjectRoot, canonicalReportDir] = await Promise.all([
@@ -12168,7 +13038,7 @@ function slugifyCommandPath(commandPath) {
12168
13038
  return output.length === 0 ? "root" : output;
12169
13039
  }
12170
13040
  function relativeDisplayPath(projectRoot, absolutePath) {
12171
- const relative = path13.relative(projectRoot, absolutePath);
13041
+ const relative = path14.relative(projectRoot, absolutePath);
12172
13042
  return relative.length === 0 || relative.startsWith("..") ? absolutePath : relative;
12173
13043
  }
12174
13044
  function redactValue(value) {
@@ -12488,7 +13358,7 @@ async function writeErrorReport(context) {
12488
13358
  const projectRoot = resolveProjectRoot(context.projectRoot);
12489
13359
  const reportDir = resolveReportDir(context.errorReports, projectRoot);
12490
13360
  const fileName = `${formatTimestamp(/* @__PURE__ */ new Date())}-${slugifyCommandPath(context.commandPath)}-${randomUUID5()}.log`;
12491
- const absolutePath = path13.join(reportDir, fileName);
13361
+ const absolutePath = path14.join(reportDir, fileName);
12492
13362
  await mkdir2(reportDir, { recursive: true });
12493
13363
  if (reportDirMustStayWithinProject(context.errorReports)) {
12494
13364
  await assertReportDirWithinProject(projectRoot, reportDir);
@@ -12958,7 +13828,7 @@ function inferProgramName(argv) {
12958
13828
  if (typeof entrypoint !== "string" || entrypoint.length === 0) {
12959
13829
  return "toolcraft";
12960
13830
  }
12961
- const parsed = path14.parse(entrypoint);
13831
+ const parsed = path15.parse(entrypoint);
12962
13832
  return parsed.name.length > 0 ? parsed.name : "toolcraft";
12963
13833
  }
12964
13834
  function normalizeRoots(roots, argv) {
@@ -13016,11 +13886,11 @@ function formatSegment(segment, casing) {
13016
13886
  const separator = casing === "snake" ? "_" : "-";
13017
13887
  return splitWords3(segment).join(separator);
13018
13888
  }
13019
- function toOptionFlag(path24, casing) {
13020
- return `--${path24.map((segment) => formatSegment(segment, casing)).join(".")}`;
13889
+ function toOptionFlag(path25, casing) {
13890
+ return `--${path25.map((segment) => formatSegment(segment, casing)).join(".")}`;
13021
13891
  }
13022
- function toOptionAttribute(path24, casing) {
13023
- return path24.map((segment) => {
13892
+ function toOptionAttribute(path25, casing) {
13893
+ return path25.map((segment) => {
13024
13894
  const formatted = formatSegment(segment, casing);
13025
13895
  if (casing === "snake") {
13026
13896
  return formatted;
@@ -13031,23 +13901,23 @@ function toOptionAttribute(path24, casing) {
13031
13901
  ).join("");
13032
13902
  }).join(".");
13033
13903
  }
13034
- function toDisplayPath(path24) {
13035
- return path24.join(".");
13904
+ function toDisplayPath(path25) {
13905
+ return path25.join(".");
13036
13906
  }
13037
- function toUnionKindControlPath(path24) {
13038
- if (path24.length === 0) {
13907
+ function toUnionKindControlPath(path25) {
13908
+ if (path25.length === 0) {
13039
13909
  return ["kind"];
13040
13910
  }
13041
- const head = path24.slice(0, -1);
13042
- const tail = path24[path24.length - 1] ?? "";
13911
+ const head = path25.slice(0, -1);
13912
+ const tail = path25[path25.length - 1] ?? "";
13043
13913
  return [...head, `${tail}Kind`];
13044
13914
  }
13045
- function toUnionKindDisplayPath(path24) {
13046
- if (path24.length === 0) {
13915
+ function toUnionKindDisplayPath(path25) {
13916
+ if (path25.length === 0) {
13047
13917
  return "kind";
13048
13918
  }
13049
- const head = path24.slice(0, -1);
13050
- const tail = path24[path24.length - 1] ?? "";
13919
+ const head = path25.slice(0, -1);
13920
+ const tail = path25[path25.length - 1] ?? "";
13051
13921
  return [...head, `${tail}-kind`].join(".");
13052
13922
  }
13053
13923
  function createSyntheticEnumSchema(values) {
@@ -13063,14 +13933,14 @@ function getRequiredBranchFingerprint(branch, casing) {
13063
13933
  const requiredKeys = Object.entries(branch.shape).filter(([, schema]) => schema.kind !== "optional").map(([key2]) => formatSegment(key2, casing)).sort();
13064
13934
  return requiredKeys.join("+");
13065
13935
  }
13066
- function collectFields(schema, casing, globalLongOptionFlags, path24 = [], inheritedOptional = false, variantContext) {
13936
+ function collectFields(schema, casing, globalLongOptionFlags, path25 = [], inheritedOptional = false, variantContext) {
13067
13937
  const collected = {
13068
13938
  dynamicFields: [],
13069
13939
  fields: [],
13070
13940
  variants: []
13071
13941
  };
13072
13942
  for (const [key2, rawChildSchema] of Object.entries(schema.shape)) {
13073
- const nextPath = [...path24, key2];
13943
+ const nextPath = [...path25, key2];
13074
13944
  const runtimeOptional = inheritedOptional || rawChildSchema.kind === "optional";
13075
13945
  const childSchema = unwrapOptional2(rawChildSchema);
13076
13946
  const requiredWhenActive = rawChildSchema.kind !== "optional" && childSchema.default === void 0;
@@ -13256,9 +14126,9 @@ function collectFields(schema, casing, globalLongOptionFlags, path24 = [], inher
13256
14126
  }
13257
14127
  return collected;
13258
14128
  }
13259
- function toCommanderOptionAttribute(path24, casing, globalLongOptionFlags) {
13260
- const optionAttribute = toOptionAttribute(path24, casing);
13261
- const optionFlag = toOptionFlag(path24, casing);
14129
+ function toCommanderOptionAttribute(path25, casing, globalLongOptionFlags) {
14130
+ const optionAttribute = toOptionAttribute(path25, casing);
14131
+ const optionFlag = toOptionFlag(path25, casing);
13262
14132
  if (!globalLongOptionFlags.has(optionFlag)) {
13263
14133
  return optionAttribute;
13264
14134
  }
@@ -13531,6 +14401,20 @@ function parseArrayValue(value, schema, label) {
13531
14401
  (item) => parseScalarValue(item, itemSchema, label)
13532
14402
  );
13533
14403
  }
14404
+ function isNegativeNumericArrayToken(token, schema) {
14405
+ if (!token.startsWith("-") || token.startsWith("--")) {
14406
+ return false;
14407
+ }
14408
+ const itemSchema = unwrapOptional2(schema.item);
14409
+ if (itemSchema.kind !== "number") {
14410
+ return false;
14411
+ }
14412
+ const items = splitArrayInput(token);
14413
+ return items.length > 0 && items.every((item) => isValidNumberSchemaValue(Number(item), itemSchema));
14414
+ }
14415
+ function isNextArrayOptionToken(token, schema) {
14416
+ return token.startsWith("-") && !isNegativeNumericArrayToken(token, schema);
14417
+ }
13534
14418
  function validateArrayBounds(value, schema, label) {
13535
14419
  if (schema.minItems !== void 0 && value.length < schema.minItems) {
13536
14420
  throw new UserError(
@@ -13670,6 +14554,14 @@ function isNodeVisibleInScope(node, scope) {
13670
14554
  function getVisibleChildren(group, scope) {
13671
14555
  return group.children.filter((child) => isNodeVisibleInScope(child, scope));
13672
14556
  }
14557
+ function getHelpChildren(group, scope) {
14558
+ return getVisibleChildren(group, scope).filter((child) => {
14559
+ if (child.kind === "command") {
14560
+ return child.hidden !== true;
14561
+ }
14562
+ return true;
14563
+ });
14564
+ }
13673
14565
  function findVisibleChild(group, token, scope) {
13674
14566
  return getVisibleChildren(group, scope).find(
13675
14567
  (child) => child.name === token || child.aliases.includes(token)
@@ -13816,6 +14708,26 @@ function describeHelpValueToken(schema, field) {
13816
14708
  }
13817
14709
  return describeFieldNameValueToken(field.displayPath, field.optionFlag) ?? "value";
13818
14710
  }
14711
+ function formatCompactEnumSignatureToken(schema) {
14712
+ if (schema.kind !== "enum" || schema.values.length < 2 || schema.values.length > 3) {
14713
+ return void 0;
14714
+ }
14715
+ const tokens = schema.values.map((value) => String(value));
14716
+ const compact = tokens.every(
14717
+ (token) => token.length > 0 && token.length <= 24 && token.trim() === token && !token.includes("|") && !token.includes(" ") && !token.includes("\n") && !token.includes("\r") && !token.includes(" ")
14718
+ );
14719
+ return compact ? tokens.join("|") : void 0;
14720
+ }
14721
+ function formatCommandParameterFieldFlags(field, globalLongOptionFlags) {
14722
+ if (field.positionalIndex !== void 0 || field.schema.kind === "boolean") {
14723
+ return formatHelpFieldFlags(field, globalLongOptionFlags);
14724
+ }
14725
+ const enumToken = formatCompactEnumSignatureToken(field.schema);
14726
+ if (enumToken !== void 0) {
14727
+ return `${formatOptionFlags(field, globalLongOptionFlags)} ${enumToken}`;
14728
+ }
14729
+ return formatHelpFieldFlags(field, globalLongOptionFlags);
14730
+ }
13819
14731
  function describeDynamicFieldType(field) {
13820
14732
  if (field.schema.kind === "record") {
13821
14733
  const valueSchema = unwrapOptional2(field.schema.value);
@@ -13983,7 +14895,7 @@ function formatCommandParameterTokens(command, casing, globalLongOptionFlags) {
13983
14895
  const fields = assignPositionals(collected.fields, command.positional);
13984
14896
  return fields.filter((field) => field.global !== true).map(
13985
14897
  (field) => wrapOptionalCommandParameterToken(
13986
- formatHelpFieldFlags(field, globalLongOptionFlags),
14898
+ formatCommandParameterFieldFlags(field, globalLongOptionFlags),
13987
14899
  field.positionalIndex === void 0 && (field.optional || field.hasDefault)
13988
14900
  )
13989
14901
  ).concat(
@@ -13997,7 +14909,7 @@ function formatCommandRowName(node, casing, globalLongOptionFlags) {
13997
14909
  return name;
13998
14910
  }
13999
14911
  function formatCommandRows(group, scope, casing, globalLongOptionFlags) {
14000
- return getVisibleChildren(group, scope).map((child) => ({
14912
+ return getHelpChildren(group, scope).map((child) => ({
14001
14913
  name: formatCommandRowName(child, casing, globalLongOptionFlags),
14002
14914
  description: child.description ?? ""
14003
14915
  }));
@@ -14041,7 +14953,7 @@ function collectSchemaGlobalFieldRows(group, scope, casing, globalLongOptionFlag
14041
14953
  }
14042
14954
  return;
14043
14955
  }
14044
- for (const child of getVisibleChildren(node, scope)) {
14956
+ for (const child of getHelpChildren(node, scope)) {
14045
14957
  visit(child);
14046
14958
  }
14047
14959
  };
@@ -14064,6 +14976,17 @@ function buildUsageLine(breadcrumb, rootUsageName, suffix) {
14064
14976
  const tokens = [rootUsageName, subPath, suffix].filter((segment) => segment.length > 0);
14065
14977
  return tokens.join(" ");
14066
14978
  }
14979
+ function formatGroupUsageSuffix(group, scope, casing, globalLongOptionFlags) {
14980
+ if (group.default !== void 0 && group.default.hidden === true && group.default.scope.includes(scope)) {
14981
+ const parameterTokens = formatCommandParameterTokens(
14982
+ group.default,
14983
+ casing,
14984
+ globalLongOptionFlags
14985
+ );
14986
+ return ["[command]", "[OPTIONS]", ...parameterTokens].join(" ");
14987
+ }
14988
+ return "[command] [OPTIONS]";
14989
+ }
14067
14990
  function renderGroupHelp(group, breadcrumb, scope, casing, globalOptions, rootUsageName, isRoot) {
14068
14991
  const sections = [];
14069
14992
  const globalLongOptionFlags = getGlobalLongOptionFlags(
@@ -14097,7 +15020,11 @@ ${builtInLine}`
14097
15020
  return renderHelpDocument({
14098
15021
  breadcrumb,
14099
15022
  rootUsageName,
14100
- usageLine: buildUsageLine(breadcrumb, rootUsageName, "[command] [OPTIONS]"),
15023
+ usageLine: buildUsageLine(
15024
+ breadcrumb,
15025
+ rootUsageName,
15026
+ formatGroupUsageSuffix(group, scope, casing, globalLongOptionFlags)
15027
+ ),
14101
15028
  description: group.description,
14102
15029
  requiresAuth: group.requires?.auth === true,
14103
15030
  sections
@@ -14206,6 +15133,8 @@ function createNodeCommand(node, casing, globalLongOptionFlags, execute, presets
14206
15133
  return null;
14207
15134
  }
14208
15135
  const command = new CommanderCommand(node.name);
15136
+ Reflect.set(command, "_toolcraftHidden", node.hidden);
15137
+ Reflect.set(command, "_toolcraftOriginalName", node.name);
14209
15138
  const collected = collectFields(node.params, casing, globalLongOptionFlags);
14210
15139
  const fields = assignPositionals(collected.fields, node.positional);
14211
15140
  validateUniqueOptionFlags(fields, globalLongOptionFlags);
@@ -14249,6 +15178,7 @@ function createNodeCommand(node, casing, globalLongOptionFlags, execute, presets
14249
15178
  if (!isNodeVisibleInScope(node, "cli")) {
14250
15179
  return null;
14251
15180
  }
15181
+ const reservedChildNames = node.children.filter((child) => !isNodeVisibleInScope(child, "cli")).flatMap((child) => getNodeCommandNames(child));
14252
15182
  const visibleChildren = node.children.map(
14253
15183
  (child) => createNodeCommand(
14254
15184
  child,
@@ -14261,6 +15191,7 @@ function createNodeCommand(node, casing, globalLongOptionFlags, execute, presets
14261
15191
  )
14262
15192
  ).filter((child) => child !== null);
14263
15193
  const group = new CommanderCommand(node.name);
15194
+ Reflect.set(group, "_toolcraftReservedChildNames", reservedChildNames);
14264
15195
  if (node.description !== void 0) {
14265
15196
  group.description(node.description);
14266
15197
  }
@@ -14275,7 +15206,7 @@ function createNodeCommand(node, casing, globalLongOptionFlags, execute, presets
14275
15206
  return group;
14276
15207
  }
14277
15208
  function addCommanderChild(parent, child, isDefault, siblingNames) {
14278
- if (isDefault && child.name().length === 0) {
15209
+ if (isDefault && (child.name().length === 0 || isToolcraftHiddenCommander(child))) {
14279
15210
  let internalName = "__toolcraft_default__";
14280
15211
  let suffix = 2;
14281
15212
  while (siblingNames.has(internalName)) {
@@ -14283,10 +15214,37 @@ function addCommanderChild(parent, child, isDefault, siblingNames) {
14283
15214
  suffix += 1;
14284
15215
  }
14285
15216
  child.name(internalName);
15217
+ Reflect.set(
15218
+ parent,
15219
+ "_toolcraftHiddenDefaultNames",
15220
+ getToolcraftHiddenDefaultNames(parent).concat([
15221
+ ...new Set([Reflect.get(child, "_toolcraftOriginalName"), ...child.aliases()].filter(
15222
+ (name) => typeof name === "string" && name.length > 0
15223
+ ))
15224
+ ])
15225
+ );
14286
15226
  parent.addCommand(child, { hidden: true, isDefault: true });
14287
15227
  return;
14288
15228
  }
14289
- parent.addCommand(child, isDefault ? { isDefault: true } : void 0);
15229
+ const options = {
15230
+ ...isDefault ? { isDefault: true } : {},
15231
+ ...isToolcraftHiddenCommander(child) ? { hidden: true } : {}
15232
+ };
15233
+ parent.addCommand(child, Object.keys(options).length > 0 ? options : void 0);
15234
+ }
15235
+ function isToolcraftHiddenCommander(command) {
15236
+ return Reflect.get(command, "_toolcraftHidden") === true;
15237
+ }
15238
+ function getToolcraftHiddenDefaultNames(command) {
15239
+ const value = Reflect.get(command, "_toolcraftHiddenDefaultNames");
15240
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
15241
+ }
15242
+ function getToolcraftReservedChildNames(command) {
15243
+ const value = Reflect.get(command, "_toolcraftReservedChildNames");
15244
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
15245
+ }
15246
+ function getNodeCommandNames(node) {
15247
+ return [node.name, ...node.aliases].filter((name) => name.length > 0);
14290
15248
  }
14291
15249
  function addGlobalOptions(command, presetsEnabled, controls) {
14292
15250
  const options = [];
@@ -14338,10 +15296,10 @@ function parseDebugStackMode(value) {
14338
15296
  formatInvalidEnumMessage("--debug", String(value), ["raw"], { candidates: ["raw"] })
14339
15297
  );
14340
15298
  }
14341
- function setNestedValue(target, path24, value) {
15299
+ function setNestedValue(target, path25, value) {
14342
15300
  let cursor2 = target;
14343
- for (let index = 0; index < path24.length - 1; index += 1) {
14344
- const segment = path24[index] ?? "";
15301
+ for (let index = 0; index < path25.length - 1; index += 1) {
15302
+ const segment = path25[index] ?? "";
14345
15303
  const existing = Object.prototype.hasOwnProperty.call(cursor2, segment) ? cursor2[segment] : void 0;
14346
15304
  if (typeof existing === "object" && existing !== null) {
14347
15305
  cursor2 = existing;
@@ -14356,7 +15314,7 @@ function setNestedValue(target, path24, value) {
14356
15314
  });
14357
15315
  cursor2 = next;
14358
15316
  }
14359
- const leaf = path24[path24.length - 1];
15317
+ const leaf = path25[path25.length - 1];
14360
15318
  if (leaf !== void 0) {
14361
15319
  Object.defineProperty(cursor2, leaf, {
14362
15320
  value,
@@ -14448,6 +15406,37 @@ function resolveOutput(resolvedFlags) {
14448
15406
  }
14449
15407
  return "rich";
14450
15408
  }
15409
+ function resolveOutputFromArgv(argv) {
15410
+ for (let index = 0; index < argv.length; index += 1) {
15411
+ const token = argv[index] ?? "";
15412
+ if (token === "--json") {
15413
+ return "json";
15414
+ }
15415
+ if (token === "--md" || token === "--markdown") {
15416
+ return "md";
15417
+ }
15418
+ if (token === "--output") {
15419
+ const value = argv[index + 1];
15420
+ if (value === "rich" || value === "md" || value === "json") {
15421
+ return value;
15422
+ }
15423
+ if (value === "markdown") {
15424
+ return "md";
15425
+ }
15426
+ continue;
15427
+ }
15428
+ if (token.startsWith("--output=")) {
15429
+ const value = token.slice("--output=".length);
15430
+ if (value === "rich" || value === "md" || value === "json") {
15431
+ return value;
15432
+ }
15433
+ if (value === "markdown") {
15434
+ return "md";
15435
+ }
15436
+ }
15437
+ }
15438
+ return "rich";
15439
+ }
14451
15440
  var DESIGN_SYSTEM_OUTPUT_BY_MODE = {
14452
15441
  rich: "terminal",
14453
15442
  md: "markdown",
@@ -14473,21 +15462,21 @@ async function withOutputFormat2(output, fn) {
14473
15462
  }
14474
15463
  function createFs2() {
14475
15464
  return {
14476
- readFile: async (path24, encoding = "utf8") => readFile4(path24, { encoding }),
14477
- writeFile: async (path24, contents, options) => {
14478
- await writeFile5(path24, contents, options);
15465
+ readFile: async (path25, encoding = "utf8") => readFile5(path25, { encoding }),
15466
+ writeFile: async (path25, contents, options) => {
15467
+ await writeFile5(path25, contents, options);
14479
15468
  },
14480
- exists: async (path24) => {
15469
+ exists: async (path25) => {
14481
15470
  try {
14482
- await access2(path24);
15471
+ await access2(path25);
14483
15472
  return true;
14484
15473
  } catch {
14485
15474
  return false;
14486
15475
  }
14487
15476
  },
14488
- lstat: async (path24) => lstat3(path24),
15477
+ lstat: async (path25) => lstat3(path25),
14489
15478
  rename: async (fromPath, toPath) => rename3(fromPath, toPath),
14490
- unlink: async (path24) => unlink3(path24)
15479
+ unlink: async (path25) => unlink3(path25)
14491
15480
  };
14492
15481
  }
14493
15482
  function createEnv2(values = process.env) {
@@ -14503,9 +15492,9 @@ function isPlainObject4(value) {
14503
15492
  function hasFieldValue(value) {
14504
15493
  return value !== void 0;
14505
15494
  }
14506
- function hasNestedField(fields, path24) {
15495
+ function hasNestedField(fields, path25) {
14507
15496
  return fields.some(
14508
- (field) => path24.length < field.path.length && path24.every((segment, index) => field.path[index] === segment)
15497
+ (field) => path25.length < field.path.length && path25.every((segment, index) => field.path[index] === segment)
14509
15498
  );
14510
15499
  }
14511
15500
  function describeExpectedPresetValue(schema) {
@@ -14608,7 +15597,7 @@ function validatePresetFieldValue(value, field, presetPath) {
14608
15597
  async function loadPresetValues(fields, presetPath) {
14609
15598
  let rawPreset;
14610
15599
  try {
14611
- rawPreset = await readFile4(presetPath, {
15600
+ rawPreset = await readFile5(presetPath, {
14612
15601
  encoding: "utf8"
14613
15602
  });
14614
15603
  } catch (error3) {
@@ -14634,9 +15623,9 @@ async function loadPresetValues(fields, presetPath) {
14634
15623
  }
14635
15624
  const fieldByPath = new Map(fields.map((field) => [field.displayPath, field]));
14636
15625
  const presetValues = {};
14637
- function visitObject(current, path24) {
15626
+ function visitObject(current, path25) {
14638
15627
  for (const [key2, value] of Object.entries(current)) {
14639
- const nextPath = [...path24, key2];
15628
+ const nextPath = [...path25, key2];
14640
15629
  const displayPath = toDisplayPath(nextPath);
14641
15630
  const field = fieldByPath.get(displayPath);
14642
15631
  if (field !== void 0) {
@@ -14843,8 +15832,8 @@ function createFixtureService(definition) {
14843
15832
  );
14844
15833
  }
14845
15834
  function resolveFixturePath(commandPath) {
14846
- const parsed = path14.parse(commandPath);
14847
- return path14.join(parsed.dir, `${parsed.name}.fixture.json`);
15835
+ const parsed = path15.parse(commandPath);
15836
+ return path15.join(parsed.dir, `${parsed.name}.fixture.json`);
14848
15837
  }
14849
15838
  function selectFixtureScenario(scenarios, selector, fixturePath) {
14850
15839
  if (isNumericFixtureSelector(selector)) {
@@ -14875,7 +15864,7 @@ async function loadFixtureScenario(command, selector) {
14875
15864
  const fixturePath = resolveFixturePath(commandPath);
14876
15865
  let rawFixture;
14877
15866
  try {
14878
- rawFixture = await readFile4(fixturePath, {
15867
+ rawFixture = await readFile5(fixturePath, {
14879
15868
  encoding: "utf8"
14880
15869
  });
14881
15870
  } catch {
@@ -14969,6 +15958,44 @@ function renderApprovalDeclined(error3) {
14969
15958
  logger2.error(error3.message);
14970
15959
  process.exitCode = 1;
14971
15960
  }
15961
+ function renderCliErrorPattern(pattern) {
15962
+ const logger2 = createLogger();
15963
+ if (pattern.kind === "usage") {
15964
+ logger2.error(
15965
+ appendUsagePointer(pattern.message, {
15966
+ rootUsageName: pattern.rootUsageName,
15967
+ commandPath: pattern.commandPath
15968
+ })
15969
+ );
15970
+ process.exitCode = 1;
15971
+ return;
15972
+ }
15973
+ if (pattern.kind === "runtime-user") {
15974
+ logger2.error(pattern.message);
15975
+ process.exitCode = 1;
15976
+ return;
15977
+ }
15978
+ if (pattern.kind === "toolcraft-bug") {
15979
+ logger2.error(
15980
+ `toolcraft hit an internal invariant: ${pattern.error.message}
15981
+ This is a bug in toolcraft or in the command definition; it cannot be worked around by changing argv. Re-run with --debug for a stack trace and file an issue.`
15982
+ );
15983
+ if (pattern.debugStackMode !== void 0 && pattern.error.stack) {
15984
+ process.stderr.write(`${formatDebugStack(pattern.error.stack, pattern.debugStackMode)}
15985
+ `);
15986
+ }
15987
+ process.exitCode = 1;
15988
+ return;
15989
+ }
15990
+ logger2.error(
15991
+ pattern.debugStackMode !== void 0 ? pattern.message : `${pattern.message} Use --debug for a stack trace.`
15992
+ );
15993
+ if (pattern.debugStackMode !== void 0 && pattern.stack !== void 0) {
15994
+ process.stderr.write(`${formatDebugStack(pattern.stack, pattern.debugStackMode)}
15995
+ `);
15996
+ }
15997
+ process.exitCode = 1;
15998
+ }
14972
15999
  function validateServices(services) {
14973
16000
  for (const name of Object.keys(services)) {
14974
16001
  if (RESERVED_SERVICE_NAMES.has(name)) {
@@ -14978,8 +16005,8 @@ function validateServices(services) {
14978
16005
  }
14979
16006
  }
14980
16007
  }
14981
- function getNestedValue(target, path24) {
14982
- return path24.reduce(
16008
+ function getNestedValue(target, path25) {
16009
+ return path25.reduce(
14983
16010
  (current, segment) => current !== null && typeof current === "object" ? current[segment] : void 0,
14984
16011
  target
14985
16012
  );
@@ -15064,7 +16091,7 @@ function consumeFieldValue(args, index, schema, label, inlineValue) {
15064
16091
  let cursor2 = index + 1;
15065
16092
  while (cursor2 < args.length) {
15066
16093
  const token = args[cursor2] ?? "";
15067
- if (token.startsWith("-")) {
16094
+ if (isNextArrayOptionToken(token, schema)) {
15068
16095
  break;
15069
16096
  }
15070
16097
  const parsed = parseArrayValue(token, schema, label);
@@ -15889,73 +16916,82 @@ function renderHttpError(error3, options) {
15889
16916
  `);
15890
16917
  }
15891
16918
  }
15892
- function handleRunError(error3, options) {
16919
+ async function handleRunError(error3, options) {
15893
16920
  const logger2 = createLogger();
15894
- if (error3 instanceof UserError) {
15895
- logger2.error(
15896
- appendUsagePointer(error3.message, {
15897
- rootUsageName: options.rootUsageName,
15898
- commandPath: options.commandPath
15899
- })
15900
- );
15901
- process.exitCode = 1;
15902
- return;
15903
- }
15904
- if (error3 instanceof Error && error3.name === "ToolcraftBugError") {
15905
- logger2.error(
15906
- `toolcraft hit an internal invariant: ${error3.message}
15907
- This is a bug in toolcraft or in the command definition; it cannot be worked around by changing argv. Re-run with --debug for a stack trace and file an issue.`
15908
- );
15909
- if (options.debugStackMode !== void 0 && error3.stack) {
15910
- process.stderr.write(`${formatDebugStack(error3.stack, options.debugStackMode)}
15911
- `);
15912
- }
15913
- process.exitCode = 1;
15914
- return;
15915
- }
15916
- if (error3 instanceof CommanderError2) {
15917
- process.exitCode = error3.exitCode;
15918
- if (error3.code === "commander.helpDisplayed" || error3.code === "commander.version") {
16921
+ await withOutputFormat2(options.output, async () => {
16922
+ if (error3 instanceof UserError) {
16923
+ renderCliErrorPattern(
16924
+ options.userErrorPattern === "usage" ? {
16925
+ kind: "usage",
16926
+ message: error3.message,
16927
+ rootUsageName: options.rootUsageName,
16928
+ commandPath: options.commandPath
16929
+ } : {
16930
+ kind: "runtime-user",
16931
+ message: error3.message
16932
+ }
16933
+ );
15919
16934
  return;
15920
16935
  }
15921
- if (error3.code === "commander.unknownCommand") {
15922
- logger2.error(
15923
- appendUsagePointer(
15924
- formatUnknownCommandError(error3, options.program, options.argv ?? process.argv),
15925
- {
15926
- rootUsageName: options.rootUsageName,
15927
- commandPath: options.commandPath
15928
- }
15929
- )
15930
- );
16936
+ if (error3 instanceof Error && error3.name === "ToolcraftBugError") {
16937
+ renderCliErrorPattern({
16938
+ kind: "toolcraft-bug",
16939
+ error: error3,
16940
+ debugStackMode: options.debugStackMode
16941
+ });
15931
16942
  return;
15932
16943
  }
15933
- if (error3.code === "commander.unknownOption") {
15934
- const argv = options.argv ?? process.argv;
16944
+ if (error3 instanceof CommanderError2) {
16945
+ process.exitCode = error3.exitCode;
16946
+ if (error3.code === "commander.helpDisplayed" || error3.code === "commander.version") {
16947
+ return;
16948
+ }
16949
+ if (error3.code === "commander.unknownCommand") {
16950
+ logger2.error(
16951
+ appendUsagePointer(
16952
+ formatUnknownCommandError(error3, options.program, options.argv ?? process.argv),
16953
+ {
16954
+ rootUsageName: options.rootUsageName,
16955
+ commandPath: options.commandPath
16956
+ }
16957
+ )
16958
+ );
16959
+ return;
16960
+ }
16961
+ if (error3.code === "commander.unknownOption") {
16962
+ const argv = options.argv ?? process.argv;
16963
+ logger2.error(
16964
+ appendUsagePointer(formatUnknownOptionError(error3, options.program, argv), {
16965
+ rootUsageName: options.rootUsageName,
16966
+ commandPath: options.commandPath.length > 0 ? options.commandPath : findCurrentCommanderCommandPath(options.program, argv)
16967
+ })
16968
+ );
16969
+ return;
16970
+ }
15935
16971
  logger2.error(
15936
- appendUsagePointer(formatUnknownOptionError(error3, options.program, argv), {
16972
+ appendUsagePointer(formatCommanderErrorMessage(error3), {
15937
16973
  rootUsageName: options.rootUsageName,
15938
- commandPath: options.commandPath.length > 0 ? options.commandPath : findCurrentCommanderCommandPath(options.program, argv)
16974
+ commandPath: options.commandPath.length > 0 ? options.commandPath : findCurrentCommanderCommandPath(options.program, options.argv ?? process.argv)
15939
16975
  })
15940
16976
  );
15941
16977
  return;
15942
16978
  }
15943
- return;
15944
- }
15945
- if (isHttpErrorLike(error3)) {
15946
- renderHttpError(error3, options);
15947
- process.exitCode = 1;
15948
- return;
15949
- }
15950
- const message2 = error3 instanceof Error ? error3.message : String(error3);
15951
- logger2.error(
15952
- options.debugStackMode !== void 0 ? message2 : `${message2} Use --debug for a stack trace.`
15953
- );
15954
- if (options.debugStackMode !== void 0 && error3 instanceof Error && error3.stack) {
15955
- process.stderr.write(`${formatDebugStack(error3.stack, options.debugStackMode)}
15956
- `);
15957
- }
15958
- process.exitCode = 1;
16979
+ if (isHttpErrorLike(error3)) {
16980
+ renderHttpError(error3, options);
16981
+ process.exitCode = 1;
16982
+ return;
16983
+ }
16984
+ const message2 = error3 instanceof Error ? error3.message : String(error3);
16985
+ renderCliErrorPattern({
16986
+ kind: "unexpected",
16987
+ message: message2,
16988
+ stack: error3 instanceof Error ? error3.stack : void 0,
16989
+ debugStackMode: options.debugStackMode
16990
+ });
16991
+ });
16992
+ }
16993
+ function formatCommanderErrorMessage(error3) {
16994
+ return error3.message.startsWith("error:") ? error3.message : `error: ${error3.message}`;
15959
16995
  }
15960
16996
  function formatInvalidEnumMessage(label, value, values, opts = {}) {
15961
16997
  const suggestions = suggest(
@@ -16116,6 +17152,13 @@ function findUnknownCommanderCommand(program, argv) {
16116
17152
  }
16117
17153
  continue;
16118
17154
  }
17155
+ if (getToolcraftHiddenDefaultNames(current).includes(token) || getToolcraftReservedChildNames(current).includes(token)) {
17156
+ return {
17157
+ input: token,
17158
+ currentCommand: current,
17159
+ commandPath: pathSegments.join(" ")
17160
+ };
17161
+ }
16119
17162
  if (current.commands.length === 0 || getDefaultCommanderCommandName(current) !== void 0) {
16120
17163
  return void 0;
16121
17164
  }
@@ -16190,6 +17233,11 @@ async function runCLI(roots, options = {}) {
16190
17233
  if (version !== void 0) {
16191
17234
  program.version(version, "--version");
16192
17235
  }
17236
+ Reflect.set(
17237
+ program,
17238
+ "_toolcraftReservedChildNames",
17239
+ root.children.filter((child) => !isNodeVisibleInScope(child, "cli")).flatMap((child) => getNodeCommandNames(child))
17240
+ );
16193
17241
  let lastActionCommand;
16194
17242
  let resolvedCommandPath = "";
16195
17243
  let errorReportContext;
@@ -16264,13 +17312,15 @@ async function runCLI(roots, options = {}) {
16264
17312
  process.stderr.write(`Saved error report to ${report.displayPath}
16265
17313
  `);
16266
17314
  }
16267
- handleRunError(error3, {
17315
+ await handleRunError(error3, {
16268
17316
  debugStackMode: resolvedFlags !== void 0 ? resolveDebugStackMode(resolvedFlags.debug) : getDebugStackModeFromArgv(process.argv),
17317
+ output: resolvedFlags !== void 0 ? resolveOutput(resolvedFlags) : resolveOutputFromArgv(process.argv),
16269
17318
  verbose: resolvedFlags ? Boolean(resolvedFlags.verbose) : process.argv.includes("--verbose"),
16270
17319
  program,
16271
17320
  argv: process.argv,
16272
17321
  rootUsageName,
16273
- commandPath: resolvedCommandPath
17322
+ commandPath: resolvedCommandPath,
17323
+ userErrorPattern: errorReportContext?.params === void 0 ? "usage" : "runtime-user"
16274
17324
  });
16275
17325
  }
16276
17326
  }
@@ -16281,7 +17331,7 @@ import { randomUUID as randomUUID6 } from "node:crypto";
16281
17331
  // src/terminal-session.ts
16282
17332
  import { EventEmitter as EventEmitter2 } from "node:events";
16283
17333
  import { accessSync, chmodSync, constants } from "node:fs";
16284
- import { createRequire } from "node:module";
17334
+ import { createRequire as createRequire2 } from "node:module";
16285
17335
  import { dirname, join } from "node:path";
16286
17336
  import * as nodePty from "node-pty";
16287
17337
 
@@ -17493,8 +18543,8 @@ var spawnHelperChecked = false;
17493
18543
  function ensureSpawnHelperExecutable() {
17494
18544
  if (spawnHelperChecked) return;
17495
18545
  spawnHelperChecked = true;
17496
- const require3 = createRequire(import.meta.url);
17497
- const nodePtyDir = dirname(require3.resolve("node-pty"));
18546
+ const require4 = createRequire2(import.meta.url);
18547
+ const nodePtyDir = dirname(require4.resolve("node-pty"));
17498
18548
  const helper = join(nodePtyDir, "..", "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper");
17499
18549
  try {
17500
18550
  accessSync(helper, constants.X_OK);
@@ -17907,7 +18957,7 @@ var getSession = defineCommand({
17907
18957
 
17908
18958
  // ../agent-skill-config/src/configs.ts
17909
18959
  import os2 from "node:os";
17910
- import path15 from "node:path";
18960
+ import path16 from "node:path";
17911
18961
 
17912
18962
  // ../agent-defs/src/agents/claude-code.ts
17913
18963
  var claudeCodeAgent = {
@@ -18271,7 +19321,7 @@ var templateMutation = {
18271
19321
 
18272
19322
  // ../config-mutations/src/execution/apply-mutation.ts
18273
19323
  import { randomUUID as randomUUID7 } from "node:crypto";
18274
- import path17 from "node:path";
19324
+ import path18 from "node:path";
18275
19325
 
18276
19326
  // ../config-mutations/src/formats/json.ts
18277
19327
  import * as jsonc from "jsonc-parser";
@@ -18394,22 +19444,22 @@ function prune(obj, shape) {
18394
19444
  }
18395
19445
  return { changed, result };
18396
19446
  }
18397
- function modifyAtPath(content, path24, value) {
19447
+ function modifyAtPath(content, path25, value) {
18398
19448
  const indent = detectIndent(content);
18399
19449
  const formattingOptions = {
18400
19450
  tabSize: indent === " " ? 1 : indent.length,
18401
19451
  insertSpaces: indent !== " ",
18402
19452
  eol: "\n"
18403
19453
  };
18404
- const edits = jsonc.modify(content, path24, value, { formattingOptions });
19454
+ const edits = jsonc.modify(content, path25, value, { formattingOptions });
18405
19455
  let result = jsonc.applyEdits(content, edits);
18406
19456
  if (!result.endsWith("\n")) {
18407
19457
  result += "\n";
18408
19458
  }
18409
19459
  return result;
18410
19460
  }
18411
- function removeAtPath(content, path24) {
18412
- return modifyAtPath(content, path24, void 0);
19461
+ function removeAtPath(content, path25) {
19462
+ return modifyAtPath(content, path25, void 0);
18413
19463
  }
18414
19464
  function serializeUpdate(content, current, next) {
18415
19465
  let result = content || "{}";
@@ -18419,15 +19469,15 @@ function serializeUpdate(content, current, next) {
18419
19469
  }
18420
19470
  return result;
18421
19471
  }
18422
- function applyObjectUpdate(content, path24, current, next) {
19472
+ function applyObjectUpdate(content, path25, current, next) {
18423
19473
  let result = content;
18424
19474
  for (const key2 of Object.keys(current)) {
18425
19475
  if (!hasConfigEntry(next, key2)) {
18426
- result = removeAtPath(result, [...path24, key2]);
19476
+ result = removeAtPath(result, [...path25, key2]);
18427
19477
  }
18428
19478
  }
18429
19479
  for (const [key2, nextValue] of Object.entries(next)) {
18430
- const nextPath = [...path24, key2];
19480
+ const nextPath = [...path25, key2];
18431
19481
  const hasCurrent = hasConfigEntry(current, key2);
18432
19482
  const currentValue = hasCurrent ? current[key2] : void 0;
18433
19483
  if (hasCurrent && isConfigObject(currentValue) && isConfigObject(nextValue)) {
@@ -18627,20 +19677,20 @@ function getConfigFormat(pathOrFormat) {
18627
19677
  }
18628
19678
  return formatRegistry[formatName];
18629
19679
  }
18630
- function detectFormat(path24) {
18631
- const ext = getExtension(path24);
19680
+ function detectFormat(path25) {
19681
+ const ext = getExtension(path25);
18632
19682
  return extensionMap[ext];
18633
19683
  }
18634
- function getExtension(path24) {
18635
- const lastDot = path24.lastIndexOf(".");
19684
+ function getExtension(path25) {
19685
+ const lastDot = path25.lastIndexOf(".");
18636
19686
  if (lastDot === -1) {
18637
19687
  return "";
18638
19688
  }
18639
- return path24.slice(lastDot).toLowerCase();
19689
+ return path25.slice(lastDot).toLowerCase();
18640
19690
  }
18641
19691
 
18642
19692
  // ../config-mutations/src/execution/path-utils.ts
18643
- import path16 from "node:path";
19693
+ import path17 from "node:path";
18644
19694
  function expandHome(targetPath, homeDir) {
18645
19695
  if (!targetPath?.startsWith("~")) {
18646
19696
  return targetPath;
@@ -18657,7 +19707,7 @@ function expandHome(targetPath, homeDir) {
18657
19707
  remainder = remainder.slice(1);
18658
19708
  }
18659
19709
  }
18660
- return remainder.length === 0 ? homeDir : path16.join(homeDir, remainder);
19710
+ return remainder.length === 0 ? homeDir : path17.join(homeDir, remainder);
18661
19711
  }
18662
19712
  function validateHomePath(targetPath) {
18663
19713
  if (typeof targetPath !== "string" || targetPath.length === 0) {
@@ -18672,21 +19722,21 @@ function validateHomePath(targetPath) {
18672
19722
  function resolvePath(rawPath, homeDir, pathMapper) {
18673
19723
  validateHomePath(rawPath);
18674
19724
  const expanded = expandHome(rawPath, homeDir);
18675
- const canonicalHome = path16.resolve(homeDir);
18676
- const canonicalExpanded = path16.resolve(expanded);
18677
- const relative = path16.relative(canonicalHome, canonicalExpanded);
18678
- if (relative === ".." || relative.startsWith(`..${path16.sep}`) || path16.isAbsolute(relative)) {
19725
+ const canonicalHome = path17.resolve(homeDir);
19726
+ const canonicalExpanded = path17.resolve(expanded);
19727
+ const relative = path17.relative(canonicalHome, canonicalExpanded);
19728
+ if (relative === ".." || relative.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative)) {
18679
19729
  throw new Error(`Target path resolves outside home directory: "${rawPath}"`);
18680
19730
  }
18681
19731
  if (!pathMapper) {
18682
19732
  return canonicalExpanded;
18683
19733
  }
18684
- const rawDirectory = path16.dirname(expanded);
19734
+ const rawDirectory = path17.dirname(expanded);
18685
19735
  const mappedDirectory = pathMapper.mapTargetDirectory({
18686
19736
  targetDirectory: rawDirectory
18687
19737
  });
18688
- const filename = path16.basename(expanded);
18689
- return filename.length === 0 ? mappedDirectory : path16.join(mappedDirectory, filename);
19738
+ const filename = path17.basename(expanded);
19739
+ return filename.length === 0 ? mappedDirectory : path17.join(mappedDirectory, filename);
18690
19740
  }
18691
19741
 
18692
19742
  // ../config-mutations/src/error-codes.ts
@@ -18698,9 +19748,9 @@ function hasOwnErrorCode5(error3, code) {
18698
19748
  function isNotFound(error3) {
18699
19749
  return hasOwnErrorCode5(error3, "ENOENT");
18700
19750
  }
18701
- async function readFileIfExists(fs4, target) {
19751
+ async function readFileIfExists(fs5, target) {
18702
19752
  try {
18703
- return await fs4.readFile(target, "utf8");
19753
+ return await fs5.readFile(target, "utf8");
18704
19754
  } catch (error3) {
18705
19755
  if (isNotFound(error3)) {
18706
19756
  return null;
@@ -18708,9 +19758,9 @@ async function readFileIfExists(fs4, target) {
18708
19758
  throw error3;
18709
19759
  }
18710
19760
  }
18711
- async function pathExists(fs4, target) {
19761
+ async function pathExists(fs5, target) {
18712
19762
  try {
18713
- await fs4.stat(target);
19763
+ await fs5.stat(target);
18714
19764
  return true;
18715
19765
  } catch (error3) {
18716
19766
  if (isNotFound(error3)) {
@@ -18756,8 +19806,8 @@ function isAlreadyExists(error3) {
18756
19806
  return hasOwnErrorCode5(error3, "EEXIST");
18757
19807
  }
18758
19808
  async function assertRegularWriteTarget(context, targetPath) {
18759
- const boundary = path17.dirname(path17.resolve(context.homeDir));
18760
- let currentPath = path17.resolve(targetPath);
19809
+ const boundary = path18.dirname(path18.resolve(context.homeDir));
19810
+ let currentPath = path18.resolve(targetPath);
18761
19811
  while (currentPath !== boundary) {
18762
19812
  try {
18763
19813
  if ((await context.fs.lstat(currentPath)).isSymbolicLink()) {
@@ -18768,7 +19818,7 @@ async function assertRegularWriteTarget(context, targetPath) {
18768
19818
  throw error3;
18769
19819
  }
18770
19820
  }
18771
- const parentPath = path17.dirname(currentPath);
19821
+ const parentPath = path18.dirname(currentPath);
18772
19822
  if (parentPath === currentPath) {
18773
19823
  return;
18774
19824
  }
@@ -18833,6 +19883,56 @@ function describeMutation(kind, targetPath) {
18833
19883
  return "Operation";
18834
19884
  }
18835
19885
  }
19886
+ function mutationTargetPath(mutation, options) {
19887
+ switch (mutation.kind) {
19888
+ case "ensureDirectory":
19889
+ case "removeDirectory":
19890
+ return resolveValue(mutation.path, options);
19891
+ case "removeFile":
19892
+ case "chmod":
19893
+ case "backup":
19894
+ case "restoreBackup":
19895
+ case "configMerge":
19896
+ case "configPrune":
19897
+ case "configTransform":
19898
+ case "templateWrite":
19899
+ case "templateMergeToml":
19900
+ case "templateMergeJson":
19901
+ return resolveValue(mutation.target, options);
19902
+ default:
19903
+ return void 0;
19904
+ }
19905
+ }
19906
+ function resolveMutationDetails(mutation, context, options) {
19907
+ try {
19908
+ const rawTarget = mutationTargetPath(mutation, options);
19909
+ if (rawTarget === void 0) {
19910
+ return {
19911
+ kind: mutation.kind,
19912
+ label: mutation.label ?? mutation.kind
19913
+ };
19914
+ }
19915
+ try {
19916
+ const targetPath = resolvePath(rawTarget, context.homeDir, context.pathMapper);
19917
+ return {
19918
+ kind: mutation.kind,
19919
+ label: mutation.label ?? describeMutation(mutation.kind, targetPath),
19920
+ targetPath
19921
+ };
19922
+ } catch {
19923
+ return {
19924
+ kind: mutation.kind,
19925
+ label: mutation.label ?? describeMutation(mutation.kind, rawTarget),
19926
+ targetPath: void 0
19927
+ };
19928
+ }
19929
+ } catch {
19930
+ return {
19931
+ kind: mutation.kind,
19932
+ label: mutation.label ?? mutation.kind
19933
+ };
19934
+ }
19935
+ }
18836
19936
  function pruneKeysByPrefix(table, prefix) {
18837
19937
  const result = {};
18838
19938
  for (const [key2, value] of Object.entries(table)) {
@@ -18923,6 +20023,7 @@ async function applyEnsureDirectory(mutation, context, options) {
18923
20023
  label: mutation.label ?? describeMutation(mutation.kind, targetPath),
18924
20024
  targetPath
18925
20025
  };
20026
+ await assertRegularWriteTarget(context, targetPath);
18926
20027
  const existed = await pathExists(context.fs, targetPath);
18927
20028
  if (!context.dryRun) {
18928
20029
  await context.fs.mkdir(targetPath, { recursive: true });
@@ -19039,6 +20140,7 @@ async function applyChmod(mutation, context, options) {
19039
20140
  };
19040
20141
  }
19041
20142
  try {
20143
+ await assertRegularWriteTarget(context, targetPath);
19042
20144
  const stat2 = await context.fs.stat(targetPath);
19043
20145
  const currentMode = typeof stat2.mode === "number" ? stat2.mode & 511 : null;
19044
20146
  if (currentMode === mutation.mode) {
@@ -19072,6 +20174,7 @@ async function applyBackup(mutation, context, options) {
19072
20174
  label: mutation.label ?? describeMutation(mutation.kind, targetPath),
19073
20175
  targetPath
19074
20176
  };
20177
+ await assertRegularWriteTarget(context, targetPath);
19075
20178
  if (mutation.once && await findLatestGeneratedBackup(context.fs, targetPath) !== null) {
19076
20179
  return {
19077
20180
  outcome: { changed: false, effect: "none", detail: "noop" },
@@ -19138,13 +20241,13 @@ async function applyRestoreBackup(mutation, context, options) {
19138
20241
  }
19139
20242
  return { outcome: { changed: true, effect: "copy", detail: "restore" }, details };
19140
20243
  }
19141
- async function findLatestGeneratedBackup(fs4, targetPath) {
20244
+ async function findLatestGeneratedBackup(fs5, targetPath) {
19142
20245
  const separatorIndex = targetPath.lastIndexOf("/");
19143
20246
  const directoryPath = separatorIndex <= 0 ? "/" : targetPath.slice(0, separatorIndex);
19144
20247
  const targetName = targetPath.slice(separatorIndex + 1);
19145
20248
  let entries;
19146
20249
  try {
19147
- entries = await fs4.readdir(directoryPath);
20250
+ entries = await fs5.readdir(directoryPath);
19148
20251
  } catch (error3) {
19149
20252
  if (isNotFound(error3)) {
19150
20253
  return null;
@@ -19208,6 +20311,9 @@ async function applyConfigMerge(mutation, context, options) {
19208
20311
  preserveContent = null;
19209
20312
  }
19210
20313
  const value = resolveValue(mutation.value, options);
20314
+ if (!isConfigObject4(value)) {
20315
+ throw new Error(`configMerge value must be an object for "${rawPath}".`);
20316
+ }
19211
20317
  let merged;
19212
20318
  if (mutation.pruneByPrefix) {
19213
20319
  merged = mergeWithPruneByPrefix(current, value, mutation.pruneByPrefix);
@@ -19341,6 +20447,13 @@ async function applyConfigTransform(mutation, context, options) {
19341
20447
  };
19342
20448
  }
19343
20449
  const serialized = serializeConfigUpdate(format, preserveContent, current, transformed);
20450
+ const serializedChanged = serialized !== rawContent;
20451
+ if (!serializedChanged) {
20452
+ return {
20453
+ outcome: { changed: false, effect: "none", detail: "noop" },
20454
+ details
20455
+ };
20456
+ }
19344
20457
  if (!context.dryRun) {
19345
20458
  await writeAtomically2(context, targetPath, serialized);
19346
20459
  }
@@ -19457,25 +20570,14 @@ async function runMutations(mutations, context, options) {
19457
20570
  };
19458
20571
  }
19459
20572
  async function executeMutation(mutation, context, options) {
19460
- context.observers?.onStart?.({
19461
- kind: mutation.kind,
19462
- label: mutation.label ?? mutation.kind,
19463
- targetPath: void 0
19464
- // Will be resolved during apply
19465
- });
20573
+ const pendingDetails = resolveMutationDetails(mutation, context, options);
20574
+ context.observers?.onStart?.(pendingDetails);
19466
20575
  try {
19467
20576
  const { outcome, details } = await applyMutation(mutation, context, options);
19468
20577
  context.observers?.onComplete?.(details, outcome);
19469
20578
  return { outcome, details };
19470
20579
  } catch (error3) {
19471
- context.observers?.onError?.(
19472
- {
19473
- kind: mutation.kind,
19474
- label: mutation.label ?? mutation.kind,
19475
- targetPath: void 0
19476
- },
19477
- error3
19478
- );
20580
+ context.observers?.onError?.(pendingDetails, error3);
19479
20581
  throw error3;
19480
20582
  }
19481
20583
  }
@@ -19486,8 +20588,8 @@ function hasOwnErrorCode6(error3, code) {
19486
20588
  }
19487
20589
 
19488
20590
  // ../agent-skill-config/src/templates.ts
19489
- import { readFile as readFile5, stat } from "node:fs/promises";
19490
- import path18 from "node:path";
20591
+ import { readFile as readFile6, stat } from "node:fs/promises";
20592
+ import path19 from "node:path";
19491
20593
  import { fileURLToPath as fileURLToPath3 } from "node:url";
19492
20594
 
19493
20595
  // ../agent-skill-config/src/apply.ts
@@ -19504,9 +20606,9 @@ function toHomeRelative(localSkillDir) {
19504
20606
  const normalized = localSkillDir.startsWith("./") ? localSkillDir.slice(2) : localSkillDir;
19505
20607
  return `~/${normalized}`;
19506
20608
  }
19507
- async function pathExists2(fs4, targetPath) {
20609
+ async function pathExists2(fs5, targetPath) {
19508
20610
  try {
19509
- await fs4.stat(targetPath);
20611
+ await fs5.stat(targetPath);
19510
20612
  return true;
19511
20613
  } catch (error3) {
19512
20614
  if (hasOwnErrorCode6(error3, "ENOENT")) {
@@ -19523,7 +20625,7 @@ async function installSkill(agentId, skill, options) {
19523
20625
  }
19524
20626
  const scope = options.scope ?? "local";
19525
20627
  const config2 = support.config;
19526
- if (skill.name.length === 0 || skill.name === "." || skill.name === ".." || skill.name.includes("/") || skill.name.includes("\\") || skill.name.includes("\n") || skill.name.includes("\r")) {
20628
+ if (skill.name.length === 0 || skill.name !== skill.name.trim() || skill.name === "." || skill.name === ".." || skill.name.includes("/") || skill.name.includes("\\") || skill.name.includes("\n") || skill.name.includes("\r")) {
19527
20629
  throw new Error(`Invalid skill name: ${skill.name}`);
19528
20630
  }
19529
20631
  const skillDir = scope === "global" ? config2.globalSkillDir : toHomeRelative(config2.localSkillDir);
@@ -19559,29 +20661,29 @@ async function installSkill(agentId, skill, options) {
19559
20661
  }
19560
20662
  }
19561
20663
  );
19562
- return { skillPath: skillFilePath, displayPath };
20664
+ return { skillPath: absoluteSkillPath, displayPath };
19563
20665
  }
19564
20666
 
19565
20667
  // ../agent-skill-config/src/resolve-skill-reference.ts
19566
- import { statSync as statSync2 } from "node:fs";
19567
- import path19 from "node:path";
20668
+ import * as fs2 from "node:fs";
20669
+ import path20 from "node:path";
19568
20670
 
19569
20671
  // ../agent-skill-config/src/git-exclude.ts
19570
20672
  import { execFileSync } from "node:child_process";
19571
20673
  import { randomUUID as randomUUID8 } from "node:crypto";
19572
- import * as fs2 from "node:fs";
19573
- import path20 from "node:path";
20674
+ import * as fs3 from "node:fs";
20675
+ import path21 from "node:path";
19574
20676
 
19575
20677
  // ../agent-skill-config/src/bridge-active-skills.ts
19576
- import * as fs3 from "node:fs";
20678
+ import * as fs4 from "node:fs";
19577
20679
  import { createHash as createHash4, randomUUID as randomUUID9 } from "node:crypto";
19578
- import path21 from "node:path";
20680
+ import path22 from "node:path";
19579
20681
 
19580
20682
  // src/commands/installer.ts
19581
20683
  import os3 from "node:os";
19582
- import path22 from "node:path";
20684
+ import path23 from "node:path";
19583
20685
  import * as nodeFs2 from "node:fs/promises";
19584
- import { readFile as readFile6 } from "node:fs/promises";
20686
+ import { readFile as readFile7 } from "node:fs/promises";
19585
20687
  var DEFAULT_INSTALL_AGENT = "claude-code";
19586
20688
  var DEFAULT_INSTALL_SCOPE = "local";
19587
20689
  var TERMINAL_PILOT_SKILL_NAME = "terminal-pilot";
@@ -19631,7 +20733,7 @@ async function loadTerminalPilotTemplate() {
19631
20733
  ];
19632
20734
  for (const candidate of candidates) {
19633
20735
  try {
19634
- terminalPilotTemplateCache = await readFile6(candidate, "utf8");
20736
+ terminalPilotTemplateCache = await readFile7(candidate, "utf8");
19635
20737
  return terminalPilotTemplateCache;
19636
20738
  } catch (error3) {
19637
20739
  if (!isNotFoundError2(error3)) {
@@ -19646,7 +20748,7 @@ function resolveHomeRelativePath(targetPath, homeDir) {
19646
20748
  return homeDir;
19647
20749
  }
19648
20750
  if (targetPath.startsWith("~/")) {
19649
- return path22.join(homeDir, targetPath.slice(2));
20751
+ return path23.join(homeDir, targetPath.slice(2));
19650
20752
  }
19651
20753
  return targetPath;
19652
20754
  }
@@ -19656,22 +20758,22 @@ function getSkillFolderWithHome(agent, scope, cwd, homeDir) {
19656
20758
  throwUnsupportedAgent(agent);
19657
20759
  }
19658
20760
  return {
19659
- displayPath: path22.join(
20761
+ displayPath: path23.join(
19660
20762
  scope === "global" ? config2.globalSkillDir : config2.localSkillDir,
19661
20763
  TERMINAL_PILOT_SKILL_NAME
19662
20764
  ),
19663
- fullPath: path22.join(
19664
- scope === "global" ? resolveHomeRelativePath(config2.globalSkillDir, homeDir) : path22.resolve(cwd, config2.localSkillDir),
20765
+ fullPath: path23.join(
20766
+ scope === "global" ? resolveHomeRelativePath(config2.globalSkillDir, homeDir) : path23.resolve(cwd, config2.localSkillDir),
19665
20767
  TERMINAL_PILOT_SKILL_NAME
19666
20768
  )
19667
20769
  };
19668
20770
  }
19669
- async function assertNoSymbolicLinkPath(fs4, targetPath) {
19670
- const rootPath = path22.parse(targetPath).root;
20771
+ async function assertNoSymbolicLinkPath(fs5, targetPath) {
20772
+ const rootPath = path23.parse(targetPath).root;
19671
20773
  let currentPath = targetPath;
19672
20774
  while (currentPath !== rootPath) {
19673
20775
  try {
19674
- if ((await fs4.lstat(currentPath)).isSymbolicLink()) {
20776
+ if ((await fs5.lstat(currentPath)).isSymbolicLink()) {
19675
20777
  throw new UserError(`Refusing terminal-pilot skill operation through symbolic link: ${currentPath}`);
19676
20778
  }
19677
20779
  } catch (error3) {
@@ -19679,7 +20781,7 @@ async function assertNoSymbolicLinkPath(fs4, targetPath) {
19679
20781
  throw error3;
19680
20782
  }
19681
20783
  }
19682
- currentPath = path22.dirname(currentPath);
20784
+ currentPath = path23.dirname(currentPath);
19683
20785
  }
19684
20786
  }
19685
20787
 
@@ -20378,11 +21480,11 @@ import { Resvg } from "@resvg/resvg-js";
20378
21480
 
20379
21481
  // ../terminal-png/src/font.ts
20380
21482
  import { readFileSync as readFileSync4 } from "node:fs";
20381
- import { createRequire as createRequire2 } from "node:module";
21483
+ import { createRequire as createRequire3 } from "node:module";
20382
21484
  import { dirname as dirname2, join as join2 } from "node:path";
20383
21485
  import { fileURLToPath as fileURLToPath4 } from "node:url";
20384
- var require2 = createRequire2(import.meta.url);
20385
- var fontPackageRoot = dirname2(require2.resolve("jetbrains-mono/package.json"));
21486
+ var require3 = createRequire3(import.meta.url);
21487
+ var fontPackageRoot = dirname2(require3.resolve("jetbrains-mono/package.json"));
20386
21488
  var webfontRoot = join2(fontPackageRoot, "fonts/webfonts");
20387
21489
  function readWebfontBase64(filename) {
20388
21490
  return readFileSync4(join2(webfontRoot, filename)).toString("base64");
@@ -21092,9 +22194,9 @@ var uninstall = defineCommand({
21092
22194
  };
21093
22195
  }
21094
22196
  });
21095
- async function folderExists(fs4, folderPath) {
22197
+ async function folderExists(fs5, folderPath) {
21096
22198
  try {
21097
- await fs4.stat(folderPath);
22199
+ await fs5.stat(folderPath);
21098
22200
  return true;
21099
22201
  } catch (error3) {
21100
22202
  if (hasOwnErrorCode4(error3, "ENOENT")) {
@@ -21239,7 +22341,7 @@ async function isDirectExecution(argv) {
21239
22341
  try {
21240
22342
  const modulePath = fileURLToPath5(import.meta.url);
21241
22343
  const [resolvedEntryPoint, resolvedModulePath] = await Promise.all([
21242
- realpath3(path23.resolve(entryPoint)),
22344
+ realpath3(path24.resolve(entryPoint)),
21243
22345
  realpath3(modulePath)
21244
22346
  ]);
21245
22347
  return resolvedEntryPoint === resolvedModulePath;