outfitter 0.2.7 → 0.3.3

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 (312) hide show
  1. package/README.md +34 -7
  2. package/dist/actions/add.d.ts +18 -0
  3. package/dist/actions/add.js +14 -0
  4. package/dist/actions/check-automation.d.ts +20 -0
  5. package/dist/actions/check-automation.js +27 -0
  6. package/dist/actions/check.d.ts +34 -0
  7. package/dist/actions/check.js +19 -0
  8. package/dist/actions/demo.d.ts +12 -0
  9. package/dist/actions/demo.js +11 -0
  10. package/dist/actions/docs-output-mode.d.ts +4 -0
  11. package/dist/actions/docs-output-mode.js +8 -0
  12. package/dist/actions/docs.d.ts +25 -0
  13. package/dist/actions/docs.js +31 -0
  14. package/dist/actions/doctor.d.ts +10 -0
  15. package/dist/actions/doctor.js +15 -0
  16. package/dist/actions/init.d.ts +28 -0
  17. package/dist/actions/init.js +31 -0
  18. package/dist/actions/scaffold.d.ts +19 -0
  19. package/dist/actions/scaffold.js +21 -0
  20. package/dist/actions/shared.d.ts +61 -0
  21. package/dist/actions/shared.js +30 -0
  22. package/dist/actions/upgrade.d.ts +17 -0
  23. package/dist/actions/upgrade.js +21 -0
  24. package/dist/actions.d.ts +1 -1
  25. package/dist/actions.js +53 -22
  26. package/dist/cli.js +66 -4
  27. package/dist/commands/add.js +3 -3
  28. package/dist/commands/check-action-ceremony.d.ts +55 -0
  29. package/dist/commands/check-action-ceremony.js +15 -0
  30. package/dist/commands/check-docs-sentinel.d.ts +27 -0
  31. package/dist/commands/check-docs-sentinel.js +18 -0
  32. package/dist/commands/check-orchestrator.d.ts +2 -0
  33. package/dist/commands/check-orchestrator.js +17 -0
  34. package/dist/commands/check-preset-versions.d.ts +20 -0
  35. package/dist/commands/check-preset-versions.js +15 -0
  36. package/dist/commands/check-publish-guardrails.d.ts +38 -0
  37. package/dist/commands/check-publish-guardrails.js +19 -0
  38. package/dist/commands/check-surface-map-format.d.ts +29 -0
  39. package/dist/commands/check-surface-map-format.js +19 -0
  40. package/dist/commands/check-surface-map.d.ts +20 -0
  41. package/dist/commands/check-surface-map.js +15 -0
  42. package/dist/commands/check-tsdoc.d.ts +2 -21
  43. package/dist/commands/check-tsdoc.js +3 -2
  44. package/dist/commands/check.d.ts +2 -0
  45. package/dist/commands/check.js +3 -3
  46. package/dist/commands/demo.js +1 -1
  47. package/dist/commands/docs-api.d.ts +4 -0
  48. package/dist/commands/docs-api.js +13 -0
  49. package/dist/commands/docs-export.d.ts +4 -0
  50. package/dist/commands/docs-export.js +12 -0
  51. package/dist/commands/docs-list.d.ts +3 -0
  52. package/dist/commands/docs-list.js +13 -0
  53. package/dist/commands/docs-module-loader.d.ts +2 -2
  54. package/dist/commands/docs-module-loader.js +2 -2
  55. package/dist/commands/docs-search.d.ts +3 -0
  56. package/dist/commands/docs-search.js +13 -0
  57. package/dist/commands/docs-show.d.ts +3 -0
  58. package/dist/commands/docs-show.js +13 -0
  59. package/dist/commands/docs-types.d.ts +21 -0
  60. package/dist/commands/doctor.js +4 -12
  61. package/dist/commands/init-execution.d.ts +8 -0
  62. package/dist/commands/init-execution.js +11 -0
  63. package/dist/commands/init-option-resolution.d.ts +5 -0
  64. package/dist/commands/init-option-resolution.js +14 -0
  65. package/dist/commands/init-output.d.ts +9 -0
  66. package/dist/commands/init-output.js +11 -0
  67. package/dist/commands/init.d.ts +7 -5
  68. package/dist/commands/init.js +10 -18
  69. package/dist/commands/jq-utils.d.ts +17 -0
  70. package/dist/commands/jq-utils.js +8 -0
  71. package/dist/commands/repo.d.ts +3 -3
  72. package/dist/commands/repo.js +8 -4
  73. package/dist/commands/scaffold-output.d.ts +4 -0
  74. package/dist/commands/scaffold-output.js +11 -0
  75. package/dist/commands/scaffold-planning.d.ts +65 -0
  76. package/dist/commands/scaffold-planning.js +20 -0
  77. package/dist/commands/scaffold.d.ts +3 -3
  78. package/dist/commands/scaffold.js +10 -16
  79. package/dist/commands/shared-deps.d.ts +5 -4
  80. package/dist/commands/shared-deps.js +3 -3
  81. package/dist/commands/upgrade-apply.d.ts +14 -0
  82. package/dist/commands/upgrade-apply.js +8 -0
  83. package/dist/commands/upgrade-codemods.d.ts +5 -0
  84. package/dist/commands/upgrade-codemods.js +4 -5
  85. package/dist/commands/upgrade-latest-version.d.ts +8 -0
  86. package/dist/commands/upgrade-latest-version.js +8 -0
  87. package/dist/commands/upgrade-migration-docs.d.ts +3 -0
  88. package/dist/commands/upgrade-migration-docs.js +15 -0
  89. package/dist/commands/upgrade-migration-frontmatter.d.ts +2 -0
  90. package/dist/commands/upgrade-migration-frontmatter.js +10 -0
  91. package/dist/commands/upgrade-migration-guides.d.ts +5 -0
  92. package/dist/commands/upgrade-migration-guides.js +10 -0
  93. package/dist/commands/upgrade-output.d.ts +5 -0
  94. package/dist/commands/upgrade-output.js +11 -0
  95. package/dist/commands/upgrade-planner.js +1 -1
  96. package/dist/commands/upgrade-report.d.ts +5 -0
  97. package/dist/commands/upgrade-report.js +8 -0
  98. package/dist/commands/upgrade-workspace.js +2 -2
  99. package/dist/commands/upgrade.d.ts +4 -220
  100. package/dist/commands/upgrade.js +21 -9
  101. package/dist/create/index.d.ts +3 -3
  102. package/dist/create/index.js +2 -30
  103. package/dist/create/planner.d.ts +2 -2
  104. package/dist/create/planner.js +80 -17
  105. package/dist/create/presets.d.ts +2 -2
  106. package/dist/create/presets.js +2 -2
  107. package/dist/create/types.d.ts +1 -1
  108. package/dist/engine/blocks.d.ts +2 -2
  109. package/dist/engine/blocks.js +5 -5
  110. package/dist/engine/collector.d.ts +1 -1
  111. package/dist/engine/collector.js +1 -1
  112. package/dist/engine/config.d.ts +2 -2
  113. package/dist/engine/config.js +4 -4
  114. package/dist/engine/dependency-versions.d.ts +13 -8
  115. package/dist/engine/dependency-versions.js +4 -4
  116. package/dist/engine/executor.d.ts +2 -2
  117. package/dist/engine/executor.js +149 -12
  118. package/dist/engine/index.d.ts +9 -7
  119. package/dist/engine/index.js +17 -31
  120. package/dist/engine/names.js +1 -1
  121. package/dist/engine/post-scaffold.d.ts +2 -2
  122. package/dist/engine/post-scaffold.js +1 -1
  123. package/dist/engine/preset.d.ts +3 -0
  124. package/dist/engine/preset.js +17 -0
  125. package/dist/engine/render-plan.d.ts +1 -1
  126. package/dist/engine/render-plan.js +1 -1
  127. package/dist/engine/template.d.ts +3 -2
  128. package/dist/engine/template.js +24 -7
  129. package/dist/engine/types.d.ts +1 -1
  130. package/dist/engine/types.js +1 -1
  131. package/dist/engine/workspace.d.ts +2 -2
  132. package/dist/engine/workspace.js +1 -1
  133. package/dist/index.d.ts +17 -398
  134. package/dist/index.js +7 -164
  135. package/dist/manifest.js +2 -2
  136. package/dist/output-mode.js +1 -1
  137. package/dist/shared/{outfitter-6fgk6adm.d.ts → outfitter-1tfa9hke.d.ts} +16 -1
  138. package/dist/shared/{outfitter-6bkqjk86.d.ts → outfitter-2nx0k4b3.d.ts} +1 -0
  139. package/dist/shared/outfitter-2ysjerp6.d.ts +44 -0
  140. package/dist/shared/outfitter-2z61gp5w.js +29 -0
  141. package/dist/shared/outfitter-34vg353f.d.ts +82 -0
  142. package/dist/shared/{outfitter-5yjr404v.d.ts → outfitter-3dq4r10s.d.ts} +5 -3
  143. package/dist/shared/outfitter-3rcrvva8.js +103 -0
  144. package/dist/shared/{outfitter-79vfxt6y.js → outfitter-3tx3adgj.js} +12 -3
  145. package/dist/shared/{outfitter-63gse8fv.js → outfitter-507ra35w.js} +33 -64
  146. package/dist/shared/outfitter-56jq0rh2.d.ts +42 -0
  147. package/dist/shared/{outfitter-r419zfgs.d.ts → outfitter-58rn1sj1.d.ts} +1 -1
  148. package/dist/shared/outfitter-5d9wbzhh.d.ts +19 -0
  149. package/dist/shared/outfitter-5j7zee11.d.ts +180 -0
  150. package/dist/shared/{outfitter-s7jetkge.d.ts → outfitter-5r6q2749.d.ts} +1 -1
  151. package/dist/shared/outfitter-5vx1bp7h.js +41 -0
  152. package/dist/shared/outfitter-6ddf91vh.js +190 -0
  153. package/dist/shared/{outfitter-mt7d1ek2.js → outfitter-6mpkh3zn.js} +39 -305
  154. package/dist/shared/{outfitter-ybbazsxq.d.ts → outfitter-6rtcemk7.d.ts} +8 -4
  155. package/dist/shared/{outfitter-9x1brcmq.js → outfitter-6t7xeyg1.js} +13 -38
  156. package/dist/shared/outfitter-738z4c37.js +262 -0
  157. package/dist/shared/{outfitter-yvksv5qb.js → outfitter-76k25svs.js} +4 -4
  158. package/dist/shared/outfitter-7n7vsz95.js +101 -0
  159. package/dist/shared/outfitter-7q9fnbwa.js +60 -0
  160. package/dist/shared/outfitter-84chvazx.js +480 -0
  161. package/dist/shared/outfitter-8ggmja91.js +301 -0
  162. package/dist/shared/{outfitter-qakwgrrh.d.ts → outfitter-8kmak0wc.d.ts} +1 -1
  163. package/dist/shared/outfitter-940h0x7b.js +71 -0
  164. package/dist/shared/{outfitter-fn20r49x.d.ts → outfitter-954y4mzx.d.ts} +1 -1
  165. package/dist/shared/outfitter-b9cpnr7e.js +110 -0
  166. package/dist/shared/outfitter-c7sbs7es.js +92 -0
  167. package/dist/shared/outfitter-cyhzstz0.js +93 -0
  168. package/dist/shared/{outfitter-n9g1zk4x.d.ts → outfitter-cyvr4r8d.d.ts} +3 -2
  169. package/dist/shared/outfitter-d0kqashd.d.ts +98 -0
  170. package/dist/shared/outfitter-dx4hn4ta.js +325 -0
  171. package/dist/shared/{outfitter-bn9c8p2e.js → outfitter-e84cr97g.js} +37 -9
  172. package/dist/shared/outfitter-ec83h4v2.js +17 -0
  173. package/dist/shared/{outfitter-vh4xgb93.js → outfitter-ekb6t1zz.js} +4 -4
  174. package/dist/shared/outfitter-ex8gn945.js +51 -0
  175. package/dist/shared/outfitter-f3a70135.js +75 -0
  176. package/dist/shared/outfitter-fbvfd5zq.d.ts +13 -0
  177. package/dist/shared/outfitter-fj2v5ffz.js +165 -0
  178. package/dist/shared/outfitter-fx1m251y.js +122 -0
  179. package/dist/shared/outfitter-fxry5n58.js +254 -0
  180. package/dist/shared/outfitter-g3hvjshg.js +1 -0
  181. package/dist/shared/{outfitter-f9znfhkn.d.ts → outfitter-gdc7b7de.d.ts} +1 -1
  182. package/dist/shared/outfitter-gyayfx5r.js +156 -0
  183. package/dist/shared/outfitter-h0wmtxw8.d.ts +23 -0
  184. package/dist/shared/{outfitter-z5sx06qe.d.ts → outfitter-hcexcvxe.d.ts} +1 -1
  185. package/dist/shared/outfitter-hf5bj2gq.js +117 -0
  186. package/dist/shared/{outfitter-e9rrfekb.d.ts → outfitter-htx4asgr.d.ts} +4 -3
  187. package/dist/shared/outfitter-jkct38dh.js +53 -0
  188. package/dist/shared/outfitter-jwxggvz4.js +42 -0
  189. package/dist/shared/outfitter-k6zyvg2n.js +306 -0
  190. package/dist/shared/outfitter-mstr60zz.js +215 -0
  191. package/dist/shared/outfitter-n0ed012k.js +101 -0
  192. package/dist/shared/outfitter-n13pqaft.js +19 -0
  193. package/dist/shared/outfitter-nxvjxrmw.d.ts +48 -0
  194. package/dist/shared/outfitter-p2wn07b7.js +160 -0
  195. package/dist/shared/{outfitter-5y646xzk.js → outfitter-px5sv5gn.js} +29 -9
  196. package/dist/shared/outfitter-q1g58t85.js +8 -0
  197. package/dist/shared/{outfitter-pj9vp00r.js → outfitter-qsd5638j.js} +26 -249
  198. package/dist/shared/outfitter-qsrx7m4w.js +72 -0
  199. package/dist/shared/outfitter-r2awqszh.d.ts +52 -0
  200. package/dist/shared/outfitter-rdpw2sbp.d.ts +77 -0
  201. package/dist/shared/outfitter-rp89dafm.js +109 -0
  202. package/dist/shared/outfitter-s1c0whzj.js +121 -0
  203. package/dist/shared/{outfitter-w1j80j1r.js → outfitter-ssrtakh3.js} +21 -5
  204. package/dist/shared/outfitter-ssynegbs.js +167 -0
  205. package/dist/shared/{outfitter-zwyvewr1.js → outfitter-svts4wk2.js} +1 -1
  206. package/dist/shared/outfitter-tavatb5p.js +166 -0
  207. package/dist/shared/outfitter-tqznjgbm.js +44 -0
  208. package/dist/shared/{outfitter-yraebrmw.d.ts → outfitter-wcrp7d7m.d.ts} +1 -1
  209. package/dist/shared/outfitter-wkt0a0ra.js +67 -0
  210. package/dist/shared/{outfitter-ha89qf8q.js → outfitter-wrcqq29p.js} +4 -4
  211. package/dist/shared/outfitter-wyg1tpp5.d.ts +43 -0
  212. package/dist/shared/outfitter-x0vpb7tj.js +126 -0
  213. package/dist/shared/{outfitter-m44n0qzw.js → outfitter-x39awx8g.js} +11 -26
  214. package/dist/shared/outfitter-x4cc5xsq.js +168 -0
  215. package/dist/shared/outfitter-x8w5sjnd.d.ts +39 -0
  216. package/dist/shared/{outfitter-amc4jbs1.d.ts → outfitter-xr6g13nz.d.ts} +2 -2
  217. package/dist/shared/outfitter-xs94pkfe.js +106 -0
  218. package/dist/shared/outfitter-y37yfehn.d.ts +37 -0
  219. package/dist/shared/{outfitter-fhnjpjwc.d.ts → outfitter-y6ee0k45.d.ts} +1 -1
  220. package/dist/shared/{outfitter-j833sxws.js → outfitter-ydw7x6bh.js} +1 -1
  221. package/dist/shared/outfitter-yhb23pjc.js +89 -0
  222. package/dist/shared/{outfitter-mtbpabf3.js → outfitter-ypcvwg1s.js} +1 -1
  223. package/dist/shared/outfitter-znbqe5zy.d.ts +45 -0
  224. package/dist/shared/{outfitter-dpj9erew.d.ts → outfitter-zng6w0t9.d.ts} +1 -1
  225. package/dist/targets/index.d.ts +2 -2
  226. package/dist/targets/index.js +2 -3
  227. package/dist/targets/registry.d.ts +2 -2
  228. package/dist/targets/registry.js +207 -14
  229. package/dist/targets/types.d.ts +1 -1
  230. package/package.json +203 -40
  231. package/dist/shared/chunk-x6644tk8.js +0 -6491
  232. package/dist/shared/outfitter-20f6a2n4.js +0 -35
  233. package/dist/shared/outfitter-5akzvppx.js +0 -125
  234. package/dist/shared/outfitter-7ch26yq8.js +0 -885
  235. package/dist/shared/outfitter-ehp18x1n.js +0 -1
  236. package/dist/shared/outfitter-h3q6ae6d.d.ts +0 -48
  237. package/dist/shared/outfitter-hvsaxgcp.js +0 -1
  238. package/dist/shared/outfitter-p71qb0f0.js +0 -82
  239. package/dist/shared/outfitter-pcj9gg2g.js +0 -909
  240. package/dist/shared/outfitter-xe5mzgdc.js +0 -208
  241. package/dist/shared/outfitter-z0we32cp.d.ts +0 -63
  242. package/template-versions.json +0 -22
  243. package/templates/.gitkeep +0 -0
  244. package/templates/basic/.gitignore.template +0 -30
  245. package/templates/basic/.lefthook.yml.template +0 -26
  246. package/templates/basic/package.json.template +0 -46
  247. package/templates/basic/src/index.ts.template +0 -26
  248. package/templates/basic/tsconfig.json.template +0 -34
  249. package/templates/cli/.gitignore.template +0 -4
  250. package/templates/cli/.lefthook.yml.template +0 -26
  251. package/templates/cli/README.md.template +0 -35
  252. package/templates/cli/biome.json.template +0 -4
  253. package/templates/cli/package.json.template +0 -53
  254. package/templates/cli/src/cli.ts.template +0 -8
  255. package/templates/cli/src/index.ts.template +0 -7
  256. package/templates/cli/src/program.ts.template +0 -31
  257. package/templates/cli/tsconfig.json.template +0 -34
  258. package/templates/daemon/.gitignore.template +0 -4
  259. package/templates/daemon/.lefthook.yml.template +0 -26
  260. package/templates/daemon/README.md.template +0 -67
  261. package/templates/daemon/biome.json.template +0 -4
  262. package/templates/daemon/package.json.template +0 -56
  263. package/templates/daemon/src/cli.ts.template +0 -96
  264. package/templates/daemon/src/daemon-main.ts.template +0 -79
  265. package/templates/daemon/src/daemon.ts.template +0 -11
  266. package/templates/daemon/src/index.ts.template +0 -7
  267. package/templates/daemon/tsconfig.json.template +0 -23
  268. package/templates/full-stack/.gitignore.template +0 -30
  269. package/templates/full-stack/README.md.template +0 -30
  270. package/templates/full-stack/apps/cli/package.json.template +0 -39
  271. package/templates/full-stack/apps/cli/src/cli.ts.template +0 -24
  272. package/templates/full-stack/apps/cli/src/index.test.ts.template +0 -18
  273. package/templates/full-stack/apps/cli/src/index.ts.template +0 -5
  274. package/templates/full-stack/apps/cli/tsconfig.json.template +0 -37
  275. package/templates/full-stack/apps/mcp/package.json.template +0 -40
  276. package/templates/full-stack/apps/mcp/src/index.test.ts.template +0 -18
  277. package/templates/full-stack/apps/mcp/src/index.ts.template +0 -6
  278. package/templates/full-stack/apps/mcp/src/mcp.ts.template +0 -22
  279. package/templates/full-stack/apps/mcp/src/server.ts.template +0 -10
  280. package/templates/full-stack/apps/mcp/tsconfig.json.template +0 -37
  281. package/templates/full-stack/package.json.template +0 -16
  282. package/templates/full-stack/packages/core/package.json.template +0 -36
  283. package/templates/full-stack/packages/core/src/handlers.ts.template +0 -31
  284. package/templates/full-stack/packages/core/src/index.test.ts.template +0 -30
  285. package/templates/full-stack/packages/core/src/index.ts.template +0 -8
  286. package/templates/full-stack/packages/core/src/types.ts.template +0 -13
  287. package/templates/full-stack/packages/core/tsconfig.json.template +0 -34
  288. package/templates/library/.gitignore.template +0 -30
  289. package/templates/library/README.md.template +0 -29
  290. package/templates/library/bunup.config.ts.template +0 -20
  291. package/templates/library/package.json.template +0 -55
  292. package/templates/library/src/handlers.ts.template +0 -31
  293. package/templates/library/src/index.test.ts.template +0 -35
  294. package/templates/library/src/index.ts.template +0 -8
  295. package/templates/library/src/types.ts.template +0 -13
  296. package/templates/library/tsconfig.json.template +0 -34
  297. package/templates/mcp/.gitignore.template +0 -4
  298. package/templates/mcp/.lefthook.yml.template +0 -26
  299. package/templates/mcp/README.md.template +0 -54
  300. package/templates/mcp/biome.json.template +0 -4
  301. package/templates/mcp/package.json.template +0 -53
  302. package/templates/mcp/src/index.ts.template +0 -7
  303. package/templates/mcp/src/mcp.ts.template +0 -33
  304. package/templates/mcp/src/server.ts.template +0 -8
  305. package/templates/mcp/tsconfig.json.template +0 -23
  306. package/templates/minimal/.gitignore.template +0 -30
  307. package/templates/minimal/.lefthook.yml.template +0 -26
  308. package/templates/minimal/package.json.template +0 -53
  309. package/templates/minimal/src/index.ts.template +0 -26
  310. package/templates/minimal/tsconfig.json.template +0 -34
  311. /package/dist/{shared/outfitter-344t1r38.js → commands/docs-types.js} +0 -0
  312. /package/dist/shared/{outfitter-mdt37hqm.js → outfitter-eepj7rf7.js} +0 -0
@@ -0,0 +1,160 @@
1
+ // @bun
2
+ import {
3
+ resolveStructuredOutputMode
4
+ } from "./outfitter-7r12fj7f.js";
5
+
6
+ // apps/outfitter/src/commands/check-action-ceremony.ts
7
+ import { readdirSync } from "fs";
8
+ import { resolve } from "path";
9
+ import { Result } from "@outfitter/contracts";
10
+ var ACTIONS_RELATIVE_DIR = "apps/outfitter/src/actions";
11
+ var CEREMONY_BUDGETS = [
12
+ {
13
+ id: "direct-defineAction-generics",
14
+ description: "Direct defineAction<T> invocations should stay constrained (prefer export-level typing)",
15
+ maxCount: 1,
16
+ pattern: /(?<!typeof\s)defineAction</g
17
+ },
18
+ {
19
+ id: "schema-zodtype-casts",
20
+ description: "Action-local schema casts should not expand without justification",
21
+ maxCount: 6,
22
+ pattern: /as z\.ZodType</g
23
+ },
24
+ {
25
+ id: "direct-internalerror-construction",
26
+ description: "Direct InternalError creation in action handlers should stay minimal (use shared adapter)",
27
+ maxCount: 1,
28
+ pattern: /new InternalError\(/g
29
+ }
30
+ ];
31
+
32
+ class CheckActionCeremonyError extends Error {
33
+ _tag = "CheckActionCeremonyError";
34
+ constructor(message) {
35
+ super(message);
36
+ this.name = "CheckActionCeremonyError";
37
+ }
38
+ }
39
+ function countMatches(content, pattern) {
40
+ const matches = content.match(pattern);
41
+ return matches ? matches.length : 0;
42
+ }
43
+ function readActionSources(actionsDir) {
44
+ return readdirSync(actionsDir).filter((entry) => entry.endsWith(".ts")).map((entry) => resolve(actionsDir, entry));
45
+ }
46
+ async function runCheckActionCeremony(options) {
47
+ try {
48
+ const cwd = resolve(options.cwd);
49
+ const actionsDir = resolve(cwd, ACTIONS_RELATIVE_DIR);
50
+ const actionFiles = readActionSources(actionsDir);
51
+ const counts = Object.fromEntries(CEREMONY_BUDGETS.map((budget) => [budget.id, 0]));
52
+ for (const filePath of actionFiles) {
53
+ const file = Bun.file(filePath);
54
+ const content = await file.text();
55
+ for (const budget of CEREMONY_BUDGETS) {
56
+ if (budget.id === "direct-internalerror-construction" && filePath.endsWith("shared.ts")) {
57
+ continue;
58
+ }
59
+ counts[budget.id] = (counts[budget.id] ?? 0) + countMatches(content, budget.pattern);
60
+ }
61
+ }
62
+ const budgets = CEREMONY_BUDGETS.map((budget) => {
63
+ const count = counts[budget.id] ?? 0;
64
+ return {
65
+ id: budget.id,
66
+ description: budget.description,
67
+ count,
68
+ maxCount: budget.maxCount,
69
+ ok: count <= budget.maxCount
70
+ };
71
+ });
72
+ return Result.ok({
73
+ actionsDir,
74
+ budgets,
75
+ ok: budgets.every((budget) => budget.ok)
76
+ });
77
+ } catch (error) {
78
+ const message = error instanceof Error ? error.message : "Failed to check action ceremony";
79
+ return Result.err(new CheckActionCeremonyError(message));
80
+ }
81
+ }
82
+ async function printCheckActionCeremonyResult(result, options) {
83
+ const structuredMode = resolveStructuredOutputMode(options?.mode);
84
+ if (structuredMode) {
85
+ const serialized = structuredMode === "json" ? JSON.stringify(result, null, 2) : JSON.stringify(result);
86
+ process.stdout.write(`${serialized}
87
+ `);
88
+ return;
89
+ }
90
+ process.stdout.write(`[action-ceremony] checked ${result.budgets.length} guardrails in ${result.actionsDir}
91
+ `);
92
+ const failed = result.budgets.filter((budget) => !budget.ok);
93
+ if (failed.length === 0) {
94
+ process.stdout.write(`[action-ceremony] all ceremony guardrails are within budget
95
+ `);
96
+ return;
97
+ }
98
+ process.stderr.write(`[action-ceremony] ceremony budget exceeded:
99
+ `);
100
+ for (const budget of failed) {
101
+ process.stderr.write(` - ${budget.id}: ${budget.count}/${budget.maxCount} (${budget.description})
102
+ `);
103
+ }
104
+ }
105
+ function parseCliArgs(argv) {
106
+ let cwd = process.cwd();
107
+ let outputMode = "human";
108
+ for (let index = 0;index < argv.length; index++) {
109
+ const arg = argv[index];
110
+ if (arg === "--cwd") {
111
+ const value = argv[index + 1];
112
+ if (!value) {
113
+ throw new CheckActionCeremonyError("Missing value for --cwd");
114
+ }
115
+ cwd = value;
116
+ index += 1;
117
+ continue;
118
+ }
119
+ if (arg === "--json") {
120
+ outputMode = "json";
121
+ continue;
122
+ }
123
+ if (arg === "--jsonl") {
124
+ outputMode = "jsonl";
125
+ continue;
126
+ }
127
+ }
128
+ return {
129
+ cwd: resolve(cwd),
130
+ outputMode
131
+ };
132
+ }
133
+ async function runCheckActionCeremonyFromArgv(argv) {
134
+ let parsed;
135
+ try {
136
+ parsed = parseCliArgs(argv);
137
+ } catch (error) {
138
+ const message = error instanceof Error ? error.message : "Invalid command arguments";
139
+ process.stderr.write(`${message}
140
+ `);
141
+ return 1;
142
+ }
143
+ const result = await runCheckActionCeremony({ cwd: parsed.cwd });
144
+ if (result.isErr()) {
145
+ process.stderr.write(`${result.error.message}
146
+ `);
147
+ return 1;
148
+ }
149
+ await printCheckActionCeremonyResult(result.value, {
150
+ mode: parsed.outputMode
151
+ });
152
+ return result.value.ok ? 0 : 1;
153
+ }
154
+ if (import.meta.main) {
155
+ runCheckActionCeremonyFromArgv(process.argv.slice(2)).then((exitCode) => {
156
+ process.exit(exitCode);
157
+ });
158
+ }
159
+
160
+ export { CheckActionCeremonyError, runCheckActionCeremony, printCheckActionCeremonyResult, runCheckActionCeremonyFromArgv };
@@ -1,14 +1,14 @@
1
1
  // @bun
2
- import {
3
- getWorkspacePatterns,
4
- hasWorkspacesField
5
- } from "./outfitter-1fy7byz5.js";
6
2
  import {
7
3
  validatePackageName
8
- } from "./outfitter-4q1zfmvc.js";
4
+ } from "./outfitter-q1g58t85.js";
9
5
  import {
10
6
  resolveStructuredOutputMode
11
7
  } from "./outfitter-7r12fj7f.js";
8
+ import {
9
+ getWorkspacePatterns,
10
+ hasWorkspacesField
11
+ } from "./outfitter-1fy7byz5.js";
12
12
 
13
13
  // apps/outfitter/src/commands/doctor.ts
14
14
  import { existsSync, readFileSync } from "fs";
@@ -16,9 +16,29 @@ import { join, resolve } from "path";
16
16
  import { output } from "@outfitter/cli";
17
17
  import { createTheme } from "@outfitter/tui/render";
18
18
  var MIN_BUN_VERSION = "1.3.6";
19
- function checkBunVersion() {
20
- const required = MIN_BUN_VERSION;
19
+ function readPinnedBunVersion(projectRoot) {
20
+ const versionFile = join(projectRoot, ".bun-version");
21
+ if (!existsSync(versionFile)) {
22
+ return;
23
+ }
24
+ const pinned = readFileSync(versionFile, "utf-8").trim();
25
+ return pinned.length > 0 ? pinned : undefined;
26
+ }
27
+ function checkBunVersion(cwd, rootCwd) {
21
28
  const current = Bun.version;
29
+ const pinned = readPinnedBunVersion(rootCwd ?? cwd);
30
+ if (pinned) {
31
+ const passed2 = current === pinned;
32
+ return {
33
+ passed: passed2,
34
+ version: current,
35
+ required: pinned,
36
+ ...passed2 ? {} : {
37
+ error: `Bun version ${current} does not match pinned ${pinned}`
38
+ }
39
+ };
40
+ }
41
+ const required = MIN_BUN_VERSION;
22
42
  const passed = Bun.semver.satisfies(current, `>=${required}`);
23
43
  return {
24
44
  passed,
@@ -172,7 +192,7 @@ function discoverWorkspaceMemberPaths(cwd, packageJson) {
172
192
  }
173
193
  }
174
194
  }
175
- return [...memberPaths].sort();
195
+ return [...memberPaths].toSorted();
176
196
  }
177
197
  function isWorkspaceRoot(packageJson) {
178
198
  return packageJson ? hasWorkspacesField(packageJson) : false;
@@ -180,7 +200,7 @@ function isWorkspaceRoot(packageJson) {
180
200
  function runDoctorForCwd(cwd, options) {
181
201
  const packageJsonRead = readPackageJson(cwd);
182
202
  const wsRoot = isWorkspaceRoot(packageJsonRead.parsed);
183
- const bunVersion = checkBunVersion();
203
+ const bunVersion = checkBunVersion(cwd, options.rootCwd);
184
204
  const packageJson = checkPackageJson(packageJsonRead);
185
205
  const dependencies = checkDependencies(cwd, packageJsonRead, options.rootCwd);
186
206
  const configFiles = checkConfigFiles(cwd);
@@ -0,0 +1,8 @@
1
+ export { addBlocks } from "./blocks.js";
2
+ export { injectSharedConfig, rewriteLocalDependencies } from "./config.js";
3
+ export { executePlan } from "./executor.js";
4
+ export { deriveBinName, deriveProjectName, isPathWithin, resolveAuthor, resolvePackageName, resolveYear, sanitizePackageName, validatePackageName, validateProjectDirectoryName } from "./names.js";
5
+ export { copyPresetFiles, getOutputFilename, getPresetsBaseDir, isBinaryFile, replacePlaceholders } from "./preset.js";
6
+ export { copyTemplateFiles, getTemplatesDir } from "./template.js";
7
+ export { ScaffoldError } from "./types.js";
8
+ export { buildWorkspaceRootPackageJson, detectWorkspaceRoot, scaffoldWorkspaceRoot } from "./workspace.js";
@@ -1,25 +1,6 @@
1
1
  // @bun
2
- import {
3
- runPostScaffold
4
- } from "./outfitter-4s9meh3j.js";
5
- import {
6
- getScaffoldTarget
7
- } from "./outfitter-xe5mzgdc.js";
8
- import {
9
- OperationCollector
10
- } from "./outfitter-1h7k8xxt.js";
11
- import {
12
- renderOperationPlan
13
- } from "./outfitter-ttjr95y9.js";
14
- import {
15
- executePlan
16
- } from "./outfitter-5akzvppx.js";
17
2
  import {
18
3
  buildWorkspaceRootPackageJson,
19
- detectWorkspaceRoot,
20
- scaffoldWorkspaceRoot
21
- } from "./outfitter-1fy7byz5.js";
22
- import {
23
4
  deriveBinName,
24
5
  deriveProjectName,
25
6
  isPathWithin,
@@ -28,12 +9,12 @@ import {
28
9
  sanitizePackageName,
29
10
  validatePackageName,
30
11
  validateProjectDirectoryName
31
- } from "./outfitter-4q1zfmvc.js";
12
+ } from "./outfitter-q1g58t85.js";
32
13
  import {
33
- resolveStructuredOutputMode
34
- } from "./outfitter-7r12fj7f.js";
14
+ detectWorkspaceRoot
15
+ } from "./outfitter-1fy7byz5.js";
35
16
 
36
- // apps/outfitter/src/commands/scaffold.ts
17
+ // apps/outfitter/src/commands/scaffold-planning.ts
37
18
  import {
38
19
  cpSync,
39
20
  existsSync,
@@ -46,15 +27,7 @@ import {
46
27
  writeFileSync
47
28
  } from "fs";
48
29
  import { basename, dirname, join, resolve } from "path";
49
- import { exitWithError, output } from "@outfitter/cli";
50
30
  import { Result } from "@outfitter/contracts";
51
- class ScaffoldCommandError extends Error {
52
- _tag = "ScaffoldCommandError";
53
- constructor(message) {
54
- super(message);
55
- this.name = "ScaffoldCommandError";
56
- }
57
- }
58
31
  function readPackageJson(path) {
59
32
  if (!existsSync(path)) {
60
33
  return null;
@@ -103,7 +76,7 @@ function detectProjectStructure(cwd) {
103
76
  }
104
77
  const wsResult2 = detectWorkspaceRoot(resolvedCwd);
105
78
  if (wsResult2.isErr()) {
106
- return Result.err(new ScaffoldCommandError(wsResult2.error.message));
79
+ return Result.err(wsResult2.error.message);
107
80
  }
108
81
  if (wsResult2.value) {
109
82
  const rootPkg = readPackageJson(join(wsResult2.value, "package.json"));
@@ -123,7 +96,7 @@ function detectProjectStructure(cwd) {
123
96
  }
124
97
  const wsResult = detectWorkspaceRoot(resolvedCwd);
125
98
  if (wsResult.isErr()) {
126
- return Result.err(new ScaffoldCommandError(wsResult.error.message));
99
+ return Result.err(wsResult.error.message);
127
100
  }
128
101
  if (wsResult.value) {
129
102
  const rootPkg = readPackageJson(join(wsResult.value, "package.json"));
@@ -138,7 +111,7 @@ function detectProjectStructure(cwd) {
138
111
  return Result.ok({ kind: "none", rootDir: resolvedCwd });
139
112
  }
140
113
  function detectExistingCategory(pkg) {
141
- const metadata = readTemplateMetadata(pkg);
114
+ const metadata = readPresetMetadata(pkg);
142
115
  if (metadata?.kind) {
143
116
  return metadata.kind;
144
117
  }
@@ -160,15 +133,15 @@ function detectExistingCategory(pkg) {
160
133
  }
161
134
  }
162
135
  const deps = {
163
- ...pkg.dependencies ?? {},
164
- ...pkg.devDependencies ?? {}
136
+ ...pkg.dependencies,
137
+ ...pkg.devDependencies
165
138
  };
166
139
  if (deps["@modelcontextprotocol/sdk"] || deps["@outfitter/mcp"]) {
167
140
  return "runnable";
168
141
  }
169
142
  return "library";
170
143
  }
171
- function readTemplateMetadata(pkg) {
144
+ function readPresetMetadata(pkg) {
172
145
  const outfitter = pkg.outfitter;
173
146
  if (!outfitter || typeof outfitter !== "object" || Array.isArray(outfitter)) {
174
147
  return null;
@@ -180,7 +153,7 @@ function readTemplateMetadata(pkg) {
180
153
  const templateRecord = template;
181
154
  const kind = templateRecord["kind"] === "runnable" || templateRecord["kind"] === "library" ? templateRecord["kind"] : undefined;
182
155
  const placement = templateRecord["placement"] === "apps" || templateRecord["placement"] === "packages" ? templateRecord["placement"] : undefined;
183
- const surfaces = parseTemplateSurfaces(templateRecord["surfaces"]);
156
+ const surfaces = parsePresetSurfaces(templateRecord["surfaces"]);
184
157
  const hasMetadata = kind !== undefined || placement !== undefined || surfaces !== undefined && surfaces.length > 0;
185
158
  if (!hasMetadata) {
186
159
  return null;
@@ -191,7 +164,7 @@ function readTemplateMetadata(pkg) {
191
164
  ...surfaces ? { surfaces } : {}
192
165
  };
193
166
  }
194
- function parseTemplateSurfaces(value) {
167
+ function parsePresetSurfaces(value) {
195
168
  if (!Array.isArray(value)) {
196
169
  return;
197
170
  }
@@ -210,7 +183,7 @@ function ensureWorkspacePattern(rootDir, placement, dryRun, collector) {
210
183
  });
211
184
  return Result.ok(true);
212
185
  }
213
- return Result.err(new ScaffoldCommandError("Failed to read workspace package.json"));
186
+ return Result.err("Failed to read workspace package.json");
214
187
  }
215
188
  const pattern = `${placement}/*`;
216
189
  const patterns = [...extractWorkspacePatterns(pkg)];
@@ -257,22 +230,22 @@ function movePath(source, destination) {
257
230
  function convertToWorkspace(rootDir, existingPkg, dryRun, collector) {
258
231
  const parentWorkspace = detectWorkspaceRoot(dirname(rootDir));
259
232
  if (parentWorkspace.isErr()) {
260
- return Result.err(new ScaffoldCommandError(parentWorkspace.error.message));
233
+ return Result.err(parentWorkspace.error.message);
261
234
  }
262
235
  if (parentWorkspace.value && parentWorkspace.value !== rootDir) {
263
- return Result.err(new ScaffoldCommandError(`Cannot convert to workspace: already inside workspace at '${parentWorkspace.value}'`));
236
+ return Result.err(`Cannot convert to workspace: already inside workspace at '${parentWorkspace.value}'`);
264
237
  }
265
238
  const category = detectExistingCategory(existingPkg);
266
239
  const placement = category === "runnable" ? "apps" : "packages";
267
240
  const existingName = deriveProjectName(existingPkg.name ?? basename(rootDir));
268
241
  const invalidExistingName = validateProjectDirectoryName(existingName);
269
242
  if (invalidExistingName) {
270
- return Result.err(new ScaffoldCommandError(`Invalid existing project name '${existingName}': ${invalidExistingName}`));
243
+ return Result.err(`Invalid existing project name '${existingName}': ${invalidExistingName}`);
271
244
  }
272
245
  const destinationBaseDir = resolve(rootDir, placement);
273
246
  const destinationDir = resolve(destinationBaseDir, existingName);
274
247
  if (!isPathWithin(destinationBaseDir, destinationDir)) {
275
- return Result.err(new ScaffoldCommandError(`Invalid existing project name '${existingName}': path escapes '${destinationBaseDir}'`));
248
+ return Result.err(`Invalid existing project name '${existingName}': path escapes '${destinationBaseDir}'`);
276
249
  }
277
250
  const entries = readdirSync(rootDir);
278
251
  const preserve = new Set([".git", "node_modules", ".outfitter", "bun.lock"]);
@@ -341,7 +314,7 @@ function convertToWorkspace(rootDir, existingPkg, dryRun, collector) {
341
314
  rmSync(stagingDir, { recursive: true, force: true });
342
315
  }
343
316
  } catch {}
344
- return Result.err(new ScaffoldCommandError(`Workspace conversion failed: ${error instanceof Error ? error.message : "Unknown error"}`));
317
+ return Result.err(`Workspace conversion failed: ${error instanceof Error ? error.message : "Unknown error"}`);
345
318
  }
346
319
  return Result.ok({
347
320
  movedExisting: {
@@ -376,9 +349,10 @@ function buildScaffoldPlan(target, rootDir, targetName, options) {
376
349
  },
377
350
  changes: [
378
351
  {
379
- type: "copy-template",
380
- template: target.templateDir,
352
+ type: "copy-preset",
353
+ preset: target.presetDir,
381
354
  targetDir,
355
+ includeTooling: !options.noTooling,
382
356
  overlayBaseTemplate: true
383
357
  },
384
358
  { type: "inject-shared-config" },
@@ -387,215 +361,18 @@ function buildScaffoldPlan(target, rootDir, targetName, options) {
387
361
  ]
388
362
  };
389
363
  }
390
- async function runScaffold(options) {
391
- const targetResult = getScaffoldTarget(options.target);
392
- if (targetResult.isErr()) {
393
- return Result.err(new ScaffoldCommandError(targetResult.error.message));
394
- }
395
- const target = targetResult.value;
396
- const targetName = deriveProjectName(options.name ?? target.id);
364
+ function validateScaffoldTargetName(targetName) {
397
365
  const invalidTargetName = validateProjectDirectoryName(targetName);
398
366
  if (invalidTargetName) {
399
- return Result.err(new ScaffoldCommandError(`Invalid target name '${targetName}': ${invalidTargetName}`));
367
+ return Result.err(`Invalid target name '${targetName}': ${invalidTargetName}`);
400
368
  }
401
369
  const invalidPackageName = validatePackageName(targetName);
402
370
  if (invalidPackageName) {
403
371
  const suggested = sanitizePackageName(targetName);
404
372
  const suggestion = suggested.length > 0 && suggested !== targetName ? ` Try '${suggested}'.` : "";
405
- return Result.err(new ScaffoldCommandError(`Invalid package name '${targetName}': ${invalidPackageName}.${suggestion}`));
406
- }
407
- const structureResult = detectProjectStructure(options.cwd);
408
- if (structureResult.isErr()) {
409
- return structureResult;
410
- }
411
- const dryRun = options.dryRun;
412
- const collector = dryRun ? new OperationCollector : undefined;
413
- let rootDir = resolve(options.cwd);
414
- let converted = false;
415
- let movedExisting;
416
- let workspacePatternsUpdated = false;
417
- if (structureResult.value.kind === "workspace") {
418
- rootDir = structureResult.value.rootDir;
419
- const patternResult = ensureWorkspacePattern(rootDir, target.placement, dryRun, collector);
420
- if (patternResult.isErr()) {
421
- return patternResult;
422
- }
423
- workspacePatternsUpdated = patternResult.value;
424
- } else if (structureResult.value.kind === "single-package") {
425
- const conversionResult = convertToWorkspace(structureResult.value.rootDir, structureResult.value.packageJson, dryRun, collector);
426
- if (conversionResult.isErr()) {
427
- return conversionResult;
428
- }
429
- rootDir = structureResult.value.rootDir;
430
- converted = true;
431
- movedExisting = conversionResult.value.movedExisting;
432
- } else {
433
- const workspaceName = `${basename(rootDir)}-workspace`;
434
- if (dryRun) {
435
- const packageJsonPath = join(rootDir, "package.json");
436
- if (existsSync(packageJsonPath) && !options.force) {
437
- return Result.err(new ScaffoldCommandError(`Directory '${rootDir}' already has a package.json. Use --force to overwrite.`));
438
- }
439
- collector?.add({
440
- type: "dir-create",
441
- path: join(rootDir, "apps")
442
- });
443
- collector?.add({
444
- type: "dir-create",
445
- path: join(rootDir, "packages")
446
- });
447
- collector?.add(existsSync(packageJsonPath) ? {
448
- type: "file-overwrite",
449
- path: packageJsonPath,
450
- source: "generated"
451
- } : {
452
- type: "file-create",
453
- path: packageJsonPath,
454
- source: "generated"
455
- });
456
- const gitignorePath = join(rootDir, ".gitignore");
457
- if (options.force || !existsSync(gitignorePath)) {
458
- collector?.add(existsSync(gitignorePath) ? {
459
- type: "file-overwrite",
460
- path: gitignorePath,
461
- source: "generated"
462
- } : {
463
- type: "file-create",
464
- path: gitignorePath,
465
- source: "generated"
466
- });
467
- }
468
- } else {
469
- const workspaceResult = scaffoldWorkspaceRoot(rootDir, workspaceName, options.force);
470
- if (workspaceResult.isErr()) {
471
- return Result.err(new ScaffoldCommandError(workspaceResult.error.message));
472
- }
473
- }
474
- converted = true;
475
- }
476
- const targetBaseDir = resolve(rootDir, target.placement);
477
- const targetDir = resolve(targetBaseDir, targetName);
478
- if (!isPathWithin(targetBaseDir, targetDir)) {
479
- return Result.err(new ScaffoldCommandError(`Invalid target name '${targetName}': path escapes '${targetBaseDir}'`));
480
- }
481
- if (existsSync(targetDir) && !options.force && !dryRun) {
482
- return Result.err(new ScaffoldCommandError(`'${target.placement}/${targetName}/' already exists. Use --force to overwrite.`));
373
+ return Result.err(`Invalid package name '${targetName}': ${invalidPackageName}.${suggestion}`);
483
374
  }
484
- const plan = buildScaffoldPlan(target, rootDir, targetName, options);
485
- const executeResult = await executePlan(plan, {
486
- force: options.force,
487
- ...collector ? { collector } : {}
488
- });
489
- if (executeResult.isErr()) {
490
- return Result.err(new ScaffoldCommandError(executeResult.error.message));
491
- }
492
- const postScaffoldResult = await runPostScaffold({
493
- rootDir,
494
- projectDir: targetDir,
495
- origin: "scaffold",
496
- target: target.id,
497
- structure: "workspace",
498
- skipInstall: options.skipInstall,
499
- skipGit: true,
500
- skipCommit: true,
501
- dryRun,
502
- installTimeoutMs: options.installTimeout ?? 60000
503
- }, collector);
504
- if (postScaffoldResult.isErr()) {
505
- return Result.err(new ScaffoldCommandError("Post-scaffold step failed"));
506
- }
507
- return Result.ok({
508
- target: target.id,
509
- rootDir,
510
- targetDir,
511
- converted,
512
- movedExisting,
513
- workspacePatternsUpdated,
514
- blocksAdded: executeResult.value.blocksAdded,
515
- postScaffold: postScaffoldResult.value,
516
- ...collector ? { dryRunPlan: collector.toJSON() } : {}
517
- });
518
- }
519
- async function printScaffoldResults(result, options) {
520
- const structuredMode = resolveStructuredOutputMode(options?.mode);
521
- if (result.dryRunPlan) {
522
- if (structuredMode) {
523
- await output({
524
- target: result.target,
525
- rootDir: result.rootDir,
526
- targetDir: result.targetDir,
527
- converted: result.converted,
528
- movedExisting: result.movedExisting ?? null,
529
- ...result.dryRunPlan
530
- }, { mode: structuredMode });
531
- return;
532
- }
533
- const collector = new OperationCollector;
534
- for (const op of result.dryRunPlan.operations) {
535
- collector.add(op);
536
- }
537
- await renderOperationPlan(collector, { rootDir: result.rootDir });
538
- return;
539
- }
540
- if (structuredMode) {
541
- await output({
542
- target: result.target,
543
- rootDir: result.rootDir,
544
- targetDir: result.targetDir,
545
- converted: result.converted,
546
- movedExisting: result.movedExisting ?? null,
547
- workspacePatternsUpdated: result.workspacePatternsUpdated,
548
- blocksAdded: result.blocksAdded ?? null,
549
- postScaffold: result.postScaffold,
550
- nextSteps: result.postScaffold.nextSteps
551
- }, { mode: structuredMode });
552
- return;
553
- }
554
- const lines = [];
555
- if (result.converted) {
556
- lines.push("Converted to workspace structure:");
557
- if (result.movedExisting) {
558
- lines.push(` Moved existing package -> ${result.movedExisting.to}`);
559
- }
560
- lines.push(" Created workspace root package.json");
561
- lines.push("");
562
- }
563
- lines.push(`Scaffolded ${result.targetDir}`);
564
- if (result.blocksAdded && result.blocksAdded.created.length > 0) {
565
- lines.push(`Added ${result.blocksAdded.created.length} tooling file(s):`);
566
- for (const created of result.blocksAdded.created) {
567
- lines.push(` + ${created}`);
568
- }
569
- }
570
- lines.push("", "Next steps:");
571
- for (const step of result.postScaffold.nextSteps) {
572
- lines.push(` ${step}`);
573
- }
574
- await output(lines, { mode: "human" });
575
- }
576
- function scaffoldCommand(program) {
577
- program.command("scaffold <target> [name]").description("Add a capability to an existing project").option("-f, --force", "Overwrite existing files", false).option("--skip-install", "Skip bun install", false).option("--dry-run", "Preview changes without executing", false).option("--with <blocks>", "Comma-separated tooling blocks to add").option("--no-tooling", "Skip default tooling blocks").option("--local", "Use workspace:* for @outfitter dependencies").option("--install-timeout <ms>", "bun install timeout in ms").action(async (target, name, _flags, command) => {
578
- const resolvedFlags = command.optsWithGlobals();
579
- const mode = resolvedFlags.json ? "json" : undefined;
580
- const outputOptions = mode ? { mode } : undefined;
581
- const result = await runScaffold({
582
- target,
583
- name,
584
- force: Boolean(resolvedFlags.force),
585
- skipInstall: Boolean(resolvedFlags.skipInstall),
586
- dryRun: Boolean(resolvedFlags.dryRun),
587
- with: resolvedFlags.with,
588
- noTooling: resolvedFlags.noTooling,
589
- local: resolvedFlags.local,
590
- cwd: process.cwd(),
591
- ...resolvedFlags.installTimeout !== undefined ? { installTimeout: resolvedFlags.installTimeout } : {}
592
- });
593
- if (result.isErr()) {
594
- exitWithError(result.error, outputOptions);
595
- return;
596
- }
597
- await printScaffoldResults(result.value, outputOptions);
598
- });
375
+ return Result.ok(undefined);
599
376
  }
600
377
 
601
- export { ScaffoldCommandError, runScaffold, printScaffoldResults, scaffoldCommand };
378
+ export { detectProjectStructure, ensureWorkspacePattern, convertToWorkspace, buildScaffoldPlan, validateScaffoldTargetName };