@shrkcrft/cli 0.1.0-alpha.2

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 (450) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +15 -0
  3. package/dist/asset-preview/apply-action-hint-stub.d.ts +28 -0
  4. package/dist/asset-preview/apply-action-hint-stub.d.ts.map +1 -0
  5. package/dist/asset-preview/apply-action-hint-stub.js +170 -0
  6. package/dist/asset-preview/apply-asset-preview.d.ts +31 -0
  7. package/dist/asset-preview/apply-asset-preview.d.ts.map +1 -0
  8. package/dist/asset-preview/apply-asset-preview.js +210 -0
  9. package/dist/asset-preview/apply-knowledge-stale-fix.d.ts +37 -0
  10. package/dist/asset-preview/apply-knowledge-stale-fix.d.ts.map +1 -0
  11. package/dist/asset-preview/apply-knowledge-stale-fix.js +344 -0
  12. package/dist/asset-preview/apply-missing-barrel.d.ts +15 -0
  13. package/dist/asset-preview/apply-missing-barrel.d.ts.map +1 -0
  14. package/dist/asset-preview/apply-missing-barrel.js +65 -0
  15. package/dist/asset-preview/apply-template-drift-fix.d.ts +21 -0
  16. package/dist/asset-preview/apply-template-drift-fix.d.ts.map +1 -0
  17. package/dist/asset-preview/apply-template-drift-fix.js +125 -0
  18. package/dist/asset-preview/apply-template-update.d.ts +43 -0
  19. package/dist/asset-preview/apply-template-update.d.ts.map +1 -0
  20. package/dist/asset-preview/apply-template-update.js +257 -0
  21. package/dist/asset-preview/entry-mutator.d.ts +106 -0
  22. package/dist/asset-preview/entry-mutator.d.ts.map +1 -0
  23. package/dist/asset-preview/entry-mutator.js +428 -0
  24. package/dist/authoring/authoring-kit.d.ts +36 -0
  25. package/dist/authoring/authoring-kit.d.ts.map +1 -0
  26. package/dist/authoring/authoring-kit.js +106 -0
  27. package/dist/command-registry.d.ts +158 -0
  28. package/dist/command-registry.d.ts.map +1 -0
  29. package/dist/command-registry.js +348 -0
  30. package/dist/commands/apply.command.d.ts +3 -0
  31. package/dist/commands/apply.command.d.ts.map +1 -0
  32. package/dist/commands/apply.command.js +879 -0
  33. package/dist/commands/architecture.command.d.ts +5 -0
  34. package/dist/commands/architecture.command.d.ts.map +1 -0
  35. package/dist/commands/architecture.command.js +141 -0
  36. package/dist/commands/ask.command.d.ts +3 -0
  37. package/dist/commands/ask.command.d.ts.map +1 -0
  38. package/dist/commands/ask.command.js +58 -0
  39. package/dist/commands/audit.command.d.ts +3 -0
  40. package/dist/commands/audit.command.d.ts.map +1 -0
  41. package/dist/commands/audit.command.js +141 -0
  42. package/dist/commands/biome.command.d.ts +7 -0
  43. package/dist/commands/biome.command.d.ts.map +1 -0
  44. package/dist/commands/biome.command.js +350 -0
  45. package/dist/commands/boundaries.command.d.ts +9 -0
  46. package/dist/commands/boundaries.command.d.ts.map +1 -0
  47. package/dist/commands/boundaries.command.js +314 -0
  48. package/dist/commands/brief.command.d.ts +3 -0
  49. package/dist/commands/brief.command.d.ts.map +1 -0
  50. package/dist/commands/brief.command.js +206 -0
  51. package/dist/commands/bundle.command.d.ts +3 -0
  52. package/dist/commands/bundle.command.d.ts.map +1 -0
  53. package/dist/commands/bundle.command.js +1183 -0
  54. package/dist/commands/changes.command.d.ts +3 -0
  55. package/dist/commands/changes.command.d.ts.map +1 -0
  56. package/dist/commands/changes.command.js +155 -0
  57. package/dist/commands/check.command.d.ts +3 -0
  58. package/dist/commands/check.command.d.ts.map +1 -0
  59. package/dist/commands/check.command.js +553 -0
  60. package/dist/commands/checks.command.d.ts +29 -0
  61. package/dist/commands/checks.command.d.ts.map +1 -0
  62. package/dist/commands/checks.command.js +521 -0
  63. package/dist/commands/ci.command.d.ts +3 -0
  64. package/dist/commands/ci.command.d.ts.map +1 -0
  65. package/dist/commands/ci.command.js +680 -0
  66. package/dist/commands/codemod.command.d.ts +3 -0
  67. package/dist/commands/codemod.command.d.ts.map +1 -0
  68. package/dist/commands/codemod.command.js +130 -0
  69. package/dist/commands/command-catalog.d.ts +265 -0
  70. package/dist/commands/command-catalog.d.ts.map +1 -0
  71. package/dist/commands/command-catalog.js +3242 -0
  72. package/dist/commands/commands.command.d.ts +92 -0
  73. package/dist/commands/commands.command.d.ts.map +1 -0
  74. package/dist/commands/commands.command.js +1208 -0
  75. package/dist/commands/constructs.command.d.ts +15 -0
  76. package/dist/commands/constructs.command.d.ts.map +1 -0
  77. package/dist/commands/constructs.command.js +669 -0
  78. package/dist/commands/context.command.d.ts +3 -0
  79. package/dist/commands/context.command.d.ts.map +1 -0
  80. package/dist/commands/context.command.js +120 -0
  81. package/dist/commands/contract-gate.command.d.ts +5 -0
  82. package/dist/commands/contract-gate.command.d.ts.map +1 -0
  83. package/dist/commands/contract-gate.command.js +208 -0
  84. package/dist/commands/contract-templates.command.d.ts +8 -0
  85. package/dist/commands/contract-templates.command.d.ts.map +1 -0
  86. package/dist/commands/contract-templates.command.js +151 -0
  87. package/dist/commands/contract.command.d.ts +3 -0
  88. package/dist/commands/contract.command.d.ts.map +1 -0
  89. package/dist/commands/contract.command.js +105 -0
  90. package/dist/commands/conventions.command.d.ts +8 -0
  91. package/dist/commands/conventions.command.d.ts.map +1 -0
  92. package/dist/commands/conventions.command.js +169 -0
  93. package/dist/commands/coverage.command.d.ts +3 -0
  94. package/dist/commands/coverage.command.d.ts.map +1 -0
  95. package/dist/commands/coverage.command.js +56 -0
  96. package/dist/commands/daily.commands.d.ts +5 -0
  97. package/dist/commands/daily.commands.d.ts.map +1 -0
  98. package/dist/commands/daily.commands.js +224 -0
  99. package/dist/commands/dashboard-export.command.d.ts +4 -0
  100. package/dist/commands/dashboard-export.command.d.ts.map +1 -0
  101. package/dist/commands/dashboard-export.command.js +86 -0
  102. package/dist/commands/dashboard.command.d.ts +3 -0
  103. package/dist/commands/dashboard.command.d.ts.map +1 -0
  104. package/dist/commands/dashboard.command.js +106 -0
  105. package/dist/commands/dev.command.d.ts +3 -0
  106. package/dist/commands/dev.command.d.ts.map +1 -0
  107. package/dist/commands/dev.command.js +1392 -0
  108. package/dist/commands/diagnostics.command.d.ts +5 -0
  109. package/dist/commands/diagnostics.command.d.ts.map +1 -0
  110. package/dist/commands/diagnostics.command.js +97 -0
  111. package/dist/commands/docs.command.d.ts +4 -0
  112. package/dist/commands/docs.command.d.ts.map +1 -0
  113. package/dist/commands/docs.command.js +34 -0
  114. package/dist/commands/doctor.command.d.ts +7 -0
  115. package/dist/commands/doctor.command.d.ts.map +1 -0
  116. package/dist/commands/doctor.command.js +681 -0
  117. package/dist/commands/drift.command.d.ts +3 -0
  118. package/dist/commands/drift.command.d.ts.map +1 -0
  119. package/dist/commands/drift.command.js +124 -0
  120. package/dist/commands/eslint.command.d.ts +7 -0
  121. package/dist/commands/eslint.command.d.ts.map +1 -0
  122. package/dist/commands/eslint.command.js +423 -0
  123. package/dist/commands/explore.command.d.ts +3 -0
  124. package/dist/commands/explore.command.d.ts.map +1 -0
  125. package/dist/commands/explore.command.js +65 -0
  126. package/dist/commands/export-bundle.command.d.ts +6 -0
  127. package/dist/commands/export-bundle.command.d.ts.map +1 -0
  128. package/dist/commands/export-bundle.command.js +96 -0
  129. package/dist/commands/export.command.d.ts +3 -0
  130. package/dist/commands/export.command.d.ts.map +1 -0
  131. package/dist/commands/export.command.js +83 -0
  132. package/dist/commands/feedback-dispatch.command.d.ts +12 -0
  133. package/dist/commands/feedback-dispatch.command.d.ts.map +1 -0
  134. package/dist/commands/feedback-dispatch.command.js +63 -0
  135. package/dist/commands/feedback.command.d.ts +11 -0
  136. package/dist/commands/feedback.command.d.ts.map +1 -0
  137. package/dist/commands/feedback.command.js +336 -0
  138. package/dist/commands/fix.command.d.ts +3 -0
  139. package/dist/commands/fix.command.d.ts.map +1 -0
  140. package/dist/commands/fix.command.js +776 -0
  141. package/dist/commands/gen.command.d.ts +3 -0
  142. package/dist/commands/gen.command.d.ts.map +1 -0
  143. package/dist/commands/gen.command.js +136 -0
  144. package/dist/commands/git.command.d.ts +6 -0
  145. package/dist/commands/git.command.d.ts.map +1 -0
  146. package/dist/commands/git.command.js +81 -0
  147. package/dist/commands/graph.command.d.ts +3 -0
  148. package/dist/commands/graph.command.d.ts.map +1 -0
  149. package/dist/commands/graph.command.js +287 -0
  150. package/dist/commands/grounding.command.d.ts +7 -0
  151. package/dist/commands/grounding.command.d.ts.map +1 -0
  152. package/dist/commands/grounding.command.js +54 -0
  153. package/dist/commands/help.command.d.ts +20 -0
  154. package/dist/commands/help.command.d.ts.map +1 -0
  155. package/dist/commands/help.command.js +127 -0
  156. package/dist/commands/helper.command.d.ts +6 -0
  157. package/dist/commands/helper.command.d.ts.map +1 -0
  158. package/dist/commands/helper.command.js +170 -0
  159. package/dist/commands/ide.command.d.ts +6 -0
  160. package/dist/commands/ide.command.d.ts.map +1 -0
  161. package/dist/commands/ide.command.js +340 -0
  162. package/dist/commands/impact.command.d.ts +3 -0
  163. package/dist/commands/impact.command.d.ts.map +1 -0
  164. package/dist/commands/impact.command.js +819 -0
  165. package/dist/commands/import.command.d.ts +3 -0
  166. package/dist/commands/import.command.d.ts.map +1 -0
  167. package/dist/commands/import.command.js +115 -0
  168. package/dist/commands/infer.command.d.ts +3 -0
  169. package/dist/commands/infer.command.d.ts.map +1 -0
  170. package/dist/commands/infer.command.js +227 -0
  171. package/dist/commands/ingest.command.d.ts +6 -0
  172. package/dist/commands/ingest.command.d.ts.map +1 -0
  173. package/dist/commands/ingest.command.js +532 -0
  174. package/dist/commands/init.command.d.ts +3 -0
  175. package/dist/commands/init.command.d.ts.map +1 -0
  176. package/dist/commands/init.command.js +301 -0
  177. package/dist/commands/inspect.command.d.ts +3 -0
  178. package/dist/commands/inspect.command.d.ts.map +1 -0
  179. package/dist/commands/inspect.command.js +122 -0
  180. package/dist/commands/knowledge-author.command.d.ts +22 -0
  181. package/dist/commands/knowledge-author.command.d.ts.map +1 -0
  182. package/dist/commands/knowledge-author.command.js +366 -0
  183. package/dist/commands/knowledge-propose.command.d.ts +3 -0
  184. package/dist/commands/knowledge-propose.command.d.ts.map +1 -0
  185. package/dist/commands/knowledge-propose.command.js +125 -0
  186. package/dist/commands/knowledge.command.d.ts +18 -0
  187. package/dist/commands/knowledge.command.d.ts.map +1 -0
  188. package/dist/commands/knowledge.command.js +538 -0
  189. package/dist/commands/languages.command.d.ts +3 -0
  190. package/dist/commands/languages.command.d.ts.map +1 -0
  191. package/dist/commands/languages.command.js +300 -0
  192. package/dist/commands/lint.command.d.ts +15 -0
  193. package/dist/commands/lint.command.d.ts.map +1 -0
  194. package/dist/commands/lint.command.js +194 -0
  195. package/dist/commands/mcp.command.d.ts +3 -0
  196. package/dist/commands/mcp.command.d.ts.map +1 -0
  197. package/dist/commands/mcp.command.js +74 -0
  198. package/dist/commands/memory.command.d.ts +11 -0
  199. package/dist/commands/memory.command.d.ts.map +1 -0
  200. package/dist/commands/memory.command.js +264 -0
  201. package/dist/commands/onboard.command.d.ts +3 -0
  202. package/dist/commands/onboard.command.d.ts.map +1 -0
  203. package/dist/commands/onboard.command.js +650 -0
  204. package/dist/commands/orchestrate.command.d.ts +3 -0
  205. package/dist/commands/orchestrate.command.d.ts.map +1 -0
  206. package/dist/commands/orchestrate.command.js +49 -0
  207. package/dist/commands/owners.command.d.ts +5 -0
  208. package/dist/commands/owners.command.d.ts.map +1 -0
  209. package/dist/commands/owners.command.js +113 -0
  210. package/dist/commands/ownership.command.d.ts +5 -0
  211. package/dist/commands/ownership.command.d.ts.map +1 -0
  212. package/dist/commands/ownership.command.js +117 -0
  213. package/dist/commands/pack-author.command.d.ts +30 -0
  214. package/dist/commands/pack-author.command.d.ts.map +1 -0
  215. package/dist/commands/pack-author.command.js +242 -0
  216. package/dist/commands/packs-new.d.ts +27 -0
  217. package/dist/commands/packs-new.d.ts.map +1 -0
  218. package/dist/commands/packs-new.js +805 -0
  219. package/dist/commands/packs.command.d.ts +15 -0
  220. package/dist/commands/packs.command.d.ts.map +1 -0
  221. package/dist/commands/packs.command.js +958 -0
  222. package/dist/commands/paths.command.d.ts +6 -0
  223. package/dist/commands/paths.command.d.ts.map +1 -0
  224. package/dist/commands/paths.command.js +97 -0
  225. package/dist/commands/pipelines.command.d.ts +9 -0
  226. package/dist/commands/pipelines.command.d.ts.map +1 -0
  227. package/dist/commands/pipelines.command.js +308 -0
  228. package/dist/commands/plan-check.command.d.ts +27 -0
  229. package/dist/commands/plan-check.command.d.ts.map +1 -0
  230. package/dist/commands/plan-check.command.js +150 -0
  231. package/dist/commands/plan-simulate.command.d.ts +3 -0
  232. package/dist/commands/plan-simulate.command.d.ts.map +1 -0
  233. package/dist/commands/plan-simulate.command.js +60 -0
  234. package/dist/commands/plan.command.d.ts +8 -0
  235. package/dist/commands/plan.command.d.ts.map +1 -0
  236. package/dist/commands/plan.command.js +139 -0
  237. package/dist/commands/playbooks.command.d.ts +10 -0
  238. package/dist/commands/playbooks.command.d.ts.map +1 -0
  239. package/dist/commands/playbooks.command.js +296 -0
  240. package/dist/commands/plugin.command.d.ts +11 -0
  241. package/dist/commands/plugin.command.d.ts.map +1 -0
  242. package/dist/commands/plugin.command.js +394 -0
  243. package/dist/commands/policy.command.d.ts +8 -0
  244. package/dist/commands/policy.command.d.ts.map +1 -0
  245. package/dist/commands/policy.command.js +451 -0
  246. package/dist/commands/pr.command.d.ts +3 -0
  247. package/dist/commands/pr.command.d.ts.map +1 -0
  248. package/dist/commands/pr.command.js +132 -0
  249. package/dist/commands/preflight.command.d.ts +3 -0
  250. package/dist/commands/preflight.command.d.ts.map +1 -0
  251. package/dist/commands/preflight.command.js +102 -0
  252. package/dist/commands/presets.command.d.ts +17 -0
  253. package/dist/commands/presets.command.d.ts.map +1 -0
  254. package/dist/commands/presets.command.js +647 -0
  255. package/dist/commands/profiles.command.d.ts +7 -0
  256. package/dist/commands/profiles.command.d.ts.map +1 -0
  257. package/dist/commands/profiles.command.js +151 -0
  258. package/dist/commands/provenance.command.d.ts +26 -0
  259. package/dist/commands/provenance.command.d.ts.map +1 -0
  260. package/dist/commands/provenance.command.js +237 -0
  261. package/dist/commands/quality.command.d.ts +5 -0
  262. package/dist/commands/quality.command.d.ts.map +1 -0
  263. package/dist/commands/quality.command.js +69 -0
  264. package/dist/commands/recommend.command.d.ts +4 -0
  265. package/dist/commands/recommend.command.d.ts.map +1 -0
  266. package/dist/commands/recommend.command.js +270 -0
  267. package/dist/commands/registrations.command.d.ts +3 -0
  268. package/dist/commands/registrations.command.d.ts.map +1 -0
  269. package/dist/commands/registrations.command.js +300 -0
  270. package/dist/commands/registry.command.d.ts +4 -0
  271. package/dist/commands/registry.command.d.ts.map +1 -0
  272. package/dist/commands/registry.command.js +37 -0
  273. package/dist/commands/release.command.d.ts +4 -0
  274. package/dist/commands/release.command.d.ts.map +1 -0
  275. package/dist/commands/release.command.js +639 -0
  276. package/dist/commands/repo.command.d.ts +3 -0
  277. package/dist/commands/repo.command.d.ts.map +1 -0
  278. package/dist/commands/repo.command.js +24 -0
  279. package/dist/commands/report.command.d.ts +3 -0
  280. package/dist/commands/report.command.d.ts.map +1 -0
  281. package/dist/commands/report.command.js +511 -0
  282. package/dist/commands/reposet.command.d.ts +6 -0
  283. package/dist/commands/reposet.command.d.ts.map +1 -0
  284. package/dist/commands/reposet.command.js +120 -0
  285. package/dist/commands/review.command.d.ts +3 -0
  286. package/dist/commands/review.command.d.ts.map +1 -0
  287. package/dist/commands/review.command.js +354 -0
  288. package/dist/commands/risk.command.d.ts +3 -0
  289. package/dist/commands/risk.command.d.ts.map +1 -0
  290. package/dist/commands/risk.command.js +56 -0
  291. package/dist/commands/rounds.command.d.ts +8 -0
  292. package/dist/commands/rounds.command.d.ts.map +1 -0
  293. package/dist/commands/rounds.command.js +180 -0
  294. package/dist/commands/rules.command.d.ts +49 -0
  295. package/dist/commands/rules.command.d.ts.map +1 -0
  296. package/dist/commands/rules.command.js +435 -0
  297. package/dist/commands/runtime.command.d.ts +3 -0
  298. package/dist/commands/runtime.command.d.ts.map +1 -0
  299. package/dist/commands/runtime.command.js +56 -0
  300. package/dist/commands/safety.command.d.ts +3 -0
  301. package/dist/commands/safety.command.d.ts.map +1 -0
  302. package/dist/commands/safety.command.js +117 -0
  303. package/dist/commands/scaffolds.command.d.ts +5 -0
  304. package/dist/commands/scaffolds.command.d.ts.map +1 -0
  305. package/dist/commands/scaffolds.command.js +122 -0
  306. package/dist/commands/schemas.command.d.ts +21 -0
  307. package/dist/commands/schemas.command.d.ts.map +1 -0
  308. package/dist/commands/schemas.command.js +296 -0
  309. package/dist/commands/search.command.d.ts +12 -0
  310. package/dist/commands/search.command.d.ts.map +1 -0
  311. package/dist/commands/search.command.js +275 -0
  312. package/dist/commands/self-config.command.d.ts +7 -0
  313. package/dist/commands/self-config.command.d.ts.map +1 -0
  314. package/dist/commands/self-config.command.js +156 -0
  315. package/dist/commands/self.command.d.ts +3 -0
  316. package/dist/commands/self.command.d.ts.map +1 -0
  317. package/dist/commands/self.command.js +117 -0
  318. package/dist/commands/simulate.command.d.ts +3 -0
  319. package/dist/commands/simulate.command.d.ts.map +1 -0
  320. package/dist/commands/simulate.command.js +54 -0
  321. package/dist/commands/spec.command.d.ts +29 -0
  322. package/dist/commands/spec.command.d.ts.map +1 -0
  323. package/dist/commands/spec.command.js +985 -0
  324. package/dist/commands/start-here.command.d.ts +3 -0
  325. package/dist/commands/start-here.command.d.ts.map +1 -0
  326. package/dist/commands/start-here.command.js +35 -0
  327. package/dist/commands/stats.command.d.ts +3 -0
  328. package/dist/commands/stats.command.d.ts.map +1 -0
  329. package/dist/commands/stats.command.js +88 -0
  330. package/dist/commands/surface.command.d.ts +15 -0
  331. package/dist/commands/surface.command.d.ts.map +1 -0
  332. package/dist/commands/surface.command.js +328 -0
  333. package/dist/commands/task-context.command.d.ts +7 -0
  334. package/dist/commands/task-context.command.d.ts.map +1 -0
  335. package/dist/commands/task-context.command.js +646 -0
  336. package/dist/commands/task.command.d.ts +3 -0
  337. package/dist/commands/task.command.d.ts.map +1 -0
  338. package/dist/commands/task.command.js +301 -0
  339. package/dist/commands/template-quality.command.d.ts +5 -0
  340. package/dist/commands/template-quality.command.d.ts.map +1 -0
  341. package/dist/commands/template-quality.command.js +128 -0
  342. package/dist/commands/templates.command.d.ts +26 -0
  343. package/dist/commands/templates.command.d.ts.map +1 -0
  344. package/dist/commands/templates.command.js +964 -0
  345. package/dist/commands/test.command.d.ts +3 -0
  346. package/dist/commands/test.command.d.ts.map +1 -0
  347. package/dist/commands/test.command.js +262 -0
  348. package/dist/commands/tests.command.d.ts +5 -0
  349. package/dist/commands/tests.command.d.ts.map +1 -0
  350. package/dist/commands/tests.command.js +97 -0
  351. package/dist/commands/trace.command.d.ts +3 -0
  352. package/dist/commands/trace.command.d.ts.map +1 -0
  353. package/dist/commands/trace.command.js +121 -0
  354. package/dist/commands/upgrade.command.d.ts +4 -0
  355. package/dist/commands/upgrade.command.d.ts.map +1 -0
  356. package/dist/commands/upgrade.command.js +43 -0
  357. package/dist/commands/version.command.d.ts +3 -0
  358. package/dist/commands/version.command.d.ts.map +1 -0
  359. package/dist/commands/version.command.js +10 -0
  360. package/dist/commands/why.command.d.ts +24 -0
  361. package/dist/commands/why.command.d.ts.map +1 -0
  362. package/dist/commands/why.command.js +119 -0
  363. package/dist/dashboard/dashboard-api-server.d.ts +21 -0
  364. package/dist/dashboard/dashboard-api-server.d.ts.map +1 -0
  365. package/dist/dashboard/dashboard-api-server.js +410 -0
  366. package/dist/dashboard/live-session-server.d.ts +18 -0
  367. package/dist/dashboard/live-session-server.d.ts.map +1 -0
  368. package/dist/dashboard/live-session-server.js +133 -0
  369. package/dist/diff/collect-changed-paths.d.ts +27 -0
  370. package/dist/diff/collect-changed-paths.d.ts.map +1 -0
  371. package/dist/diff/collect-changed-paths.js +68 -0
  372. package/dist/doctor/doctor-tags.d.ts +63 -0
  373. package/dist/doctor/doctor-tags.d.ts.map +1 -0
  374. package/dist/doctor/doctor-tags.js +146 -0
  375. package/dist/export/export-formats.d.ts +22 -0
  376. package/dist/export/export-formats.d.ts.map +1 -0
  377. package/dist/export/export-formats.js +135 -0
  378. package/dist/index.d.ts +22 -0
  379. package/dist/index.d.ts.map +1 -0
  380. package/dist/index.js +21 -0
  381. package/dist/init/detected-block.d.ts +57 -0
  382. package/dist/init/detected-block.d.ts.map +1 -0
  383. package/dist/init/detected-block.js +197 -0
  384. package/dist/init/gitignore.d.ts +30 -0
  385. package/dist/init/gitignore.d.ts.map +1 -0
  386. package/dist/init/gitignore.js +110 -0
  387. package/dist/init/init-templates.d.ts +6 -0
  388. package/dist/init/init-templates.d.ts.map +1 -0
  389. package/dist/init/init-templates.js +413 -0
  390. package/dist/main.d.ts +18 -0
  391. package/dist/main.d.ts.map +1 -0
  392. package/dist/main.js +699 -0
  393. package/dist/output/failure-hints.d.ts +55 -0
  394. package/dist/output/failure-hints.d.ts.map +1 -0
  395. package/dist/output/failure-hints.js +159 -0
  396. package/dist/output/format-output.d.ts +9 -0
  397. package/dist/output/format-output.d.ts.map +1 -0
  398. package/dist/output/format-output.js +26 -0
  399. package/dist/output/print-error.d.ts +3 -0
  400. package/dist/output/print-error.d.ts.map +1 -0
  401. package/dist/output/print-error.js +14 -0
  402. package/dist/output/watch-loop.d.ts +37 -0
  403. package/dist/output/watch-loop.d.ts.map +1 -0
  404. package/dist/output/watch-loop.js +115 -0
  405. package/dist/schemas/json-schemas.d.ts +1630 -0
  406. package/dist/schemas/json-schemas.d.ts.map +1 -0
  407. package/dist/schemas/json-schemas.js +811 -0
  408. package/dist/surface/about.d.ts +10 -0
  409. package/dist/surface/about.d.ts.map +1 -0
  410. package/dist/surface/about.js +53 -0
  411. package/dist/surface/load-surface-context.d.ts +34 -0
  412. package/dist/surface/load-surface-context.d.ts.map +1 -0
  413. package/dist/surface/load-surface-context.js +100 -0
  414. package/dist/surface/no-args-landing.d.ts +7 -0
  415. package/dist/surface/no-args-landing.d.ts.map +1 -0
  416. package/dist/surface/no-args-landing.js +36 -0
  417. package/dist/surface/not-enabled-error.d.ts +24 -0
  418. package/dist/surface/not-enabled-error.d.ts.map +1 -0
  419. package/dist/surface/not-enabled-error.js +36 -0
  420. package/dist/surface/profiles.d.ts +37 -0
  421. package/dist/surface/profiles.d.ts.map +1 -0
  422. package/dist/surface/profiles.js +151 -0
  423. package/dist/surface/shape-defaults.d.ts +21 -0
  424. package/dist/surface/shape-defaults.d.ts.map +1 -0
  425. package/dist/surface/shape-defaults.js +50 -0
  426. package/dist/surface/spine-extractor.d.ts +38 -0
  427. package/dist/surface/spine-extractor.d.ts.map +1 -0
  428. package/dist/surface/spine-extractor.js +100 -0
  429. package/dist/surface/surface-config-writer.d.ts +59 -0
  430. package/dist/surface/surface-config-writer.d.ts.map +1 -0
  431. package/dist/surface/surface-config-writer.js +135 -0
  432. package/dist/surface/surface-summary.d.ts +66 -0
  433. package/dist/surface/surface-summary.d.ts.map +1 -0
  434. package/dist/surface/surface-summary.js +162 -0
  435. package/dist/surface/tier.d.ts +100 -0
  436. package/dist/surface/tier.d.ts.map +1 -0
  437. package/dist/surface/tier.js +172 -0
  438. package/dist/task-next/apply-batch-runner.d.ts +42 -0
  439. package/dist/task-next/apply-batch-runner.d.ts.map +1 -0
  440. package/dist/task-next/apply-batch-runner.js +192 -0
  441. package/dist/task-next/task-next-ranker.d.ts +75 -0
  442. package/dist/task-next/task-next-ranker.d.ts.map +1 -0
  443. package/dist/task-next/task-next-ranker.js +179 -0
  444. package/dist/usage/usage-log.d.ts +54 -0
  445. package/dist/usage/usage-log.d.ts.map +1 -0
  446. package/dist/usage/usage-log.js +105 -0
  447. package/dist/validation/run-validation-loop.d.ts +38 -0
  448. package/dist/validation/run-validation-loop.d.ts.map +1 -0
  449. package/dist/validation/run-validation-loop.js +100 -0
  450. package/package.json +73 -0
@@ -0,0 +1,1183 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import * as nodePath from 'node:path';
3
+ import { buildBundleDiffFromIds, buildPlanDependencyGraph, buildTaskPacket, createFeatureBundleState, decomposeTask, inspectSharkcraft, listFeatureBundles, markBundlePlanApplied, readFeatureBundle, recomputeBundleStatus, recordBundleReport, recordBundleValidation, renderBundleDiff, renderBundleValidationHtml, renderGraphDot, renderGraphMermaid, renderGraphText, renderBundleReplayWorkflow, replayAllBundles, replayBundle, renderBundleReplayBatchHtml, setBundleDependencies, setBundleNextAction, upsertBundlePlan, writeFeatureBundle, getBundleDir, BundleReplayStatus, } from '@shrkcrft/inspector';
4
+ import { buildSavedPlan, generate, OverwriteStrategy, savePlanToFile, } from '@shrkcrft/generator';
5
+ import { flagBool, flagString, flagVars, resolveCwd, } from "../command-registry.js";
6
+ import { asJson, header, kv } from "../output/format-output.js";
7
+ const SUBCOMMANDS = new Set([
8
+ 'create',
9
+ 'list',
10
+ 'show',
11
+ 'status',
12
+ 'next',
13
+ 'report',
14
+ 'review',
15
+ 'commands',
16
+ 'plan',
17
+ 'graph',
18
+ 'apply-plan',
19
+ 'apply-assist',
20
+ 'validate',
21
+ 'decompose',
22
+ 'record-apply',
23
+ 'replay',
24
+ 'diff',
25
+ ]);
26
+ function slugify(s) {
27
+ return s.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 40);
28
+ }
29
+ function nowSlug() {
30
+ return new Date().toISOString().replace(/[:.]/g, '-');
31
+ }
32
+ async function bundleCreate(args) {
33
+ const task = args.positional.join(' ').trim();
34
+ if (!task) {
35
+ process.stderr.write('Usage: shrk bundle create "<task>"\n');
36
+ return 2;
37
+ }
38
+ const cwd = resolveCwd(args);
39
+ const inspection = await inspectSharkcraft({ cwd });
40
+ const packet = buildTaskPacket(inspection, task, { maxTokens: 3500 });
41
+ const decomposition = decomposeTask(inspection, task);
42
+ const id = `${nowSlug()}-${slugify(task)}`;
43
+ const sessionId = flagString(args, 'session');
44
+ const state = createFeatureBundleState({
45
+ id,
46
+ task,
47
+ projectRoot: cwd,
48
+ packet,
49
+ decomposition,
50
+ ...(sessionId ? { sessionId } : {}),
51
+ });
52
+ const final = writeFeatureBundle(cwd, state);
53
+ // Write companion files
54
+ const dir = getBundleDir(cwd, id);
55
+ writeFileSync(nodePath.join(dir, 'task.md'), `# ${task}\n`, 'utf8');
56
+ writeFileSync(nodePath.join(dir, 'decomposition.json'), JSON.stringify(decomposition, null, 2) + '\n', 'utf8');
57
+ writeFileSync(nodePath.join(dir, 'task-packet.json'), JSON.stringify(packet, null, 2) + '\n', 'utf8');
58
+ writeFileSync(nodePath.join(dir, 'commands.sh'), [
59
+ '#!/usr/bin/env bash',
60
+ '# Suggested commands. Review before running.',
61
+ ...packet.recommendedCliCommands,
62
+ ].join('\n') + '\n', 'utf8');
63
+ if (flagBool(args, 'json')) {
64
+ process.stdout.write(asJson({ id, dir, task, status: final.status, nextAction: final.nextAction }) + '\n');
65
+ return 0;
66
+ }
67
+ process.stdout.write(header(`Bundle created: ${id}`));
68
+ process.stdout.write(kv('task', task) + '\n');
69
+ process.stdout.write(kv('dir', dir) + '\n');
70
+ process.stdout.write(kv('risk', final.riskLevel) + '\n');
71
+ process.stdout.write(`Next: ${final.nextAction}\n`);
72
+ return 0;
73
+ }
74
+ async function bundleList(args) {
75
+ const cwd = resolveCwd(args);
76
+ const all = listFeatureBundles(cwd);
77
+ if (flagBool(args, 'json')) {
78
+ process.stdout.write(asJson(all.map((b) => ({
79
+ id: b.id,
80
+ task: b.task,
81
+ status: b.status,
82
+ risk: b.riskLevel,
83
+ plans: b.plans.length,
84
+ }))) + '\n');
85
+ return 0;
86
+ }
87
+ for (const b of all) {
88
+ process.stdout.write(`${b.id} [${b.status}] ${b.plans.length} plans ${b.task}\n`);
89
+ }
90
+ return 0;
91
+ }
92
+ function loadOrFail(cwd, id) {
93
+ if (!id) {
94
+ process.stderr.write('Usage: shrk bundle <subcommand> <bundleId>\n');
95
+ return 2;
96
+ }
97
+ const b = readFeatureBundle(cwd, id);
98
+ if (!b) {
99
+ process.stderr.write(`No bundle "${id}".\n`);
100
+ return 1;
101
+ }
102
+ return b;
103
+ }
104
+ async function bundleShow(args) {
105
+ const cwd = resolveCwd(args);
106
+ const bundle = loadOrFail(cwd, args.positional[0]);
107
+ if (typeof bundle === 'number')
108
+ return bundle;
109
+ if (flagBool(args, 'json')) {
110
+ process.stdout.write(asJson(bundle) + '\n');
111
+ return 0;
112
+ }
113
+ process.stdout.write(header(`Bundle: ${bundle.id}`));
114
+ process.stdout.write(kv('task', bundle.task) + '\n');
115
+ process.stdout.write(kv('status', bundle.status) + '\n');
116
+ process.stdout.write(kv('risk', bundle.riskLevel) + '\n');
117
+ process.stdout.write(kv('plans', String(bundle.plans.length)) + '\n');
118
+ process.stdout.write(kv('validations', String(bundle.validations.length)) + '\n');
119
+ process.stdout.write(`Next: ${bundle.nextAction ?? '(none)'}\n`);
120
+ return 0;
121
+ }
122
+ async function bundleStatus(args) {
123
+ const cwd = resolveCwd(args);
124
+ const bundle = loadOrFail(cwd, args.positional[0]);
125
+ if (typeof bundle === 'number')
126
+ return bundle;
127
+ const summary = computeBundleStatusSummary(cwd, bundle);
128
+ if (flagBool(args, 'json')) {
129
+ process.stdout.write(asJson(summary) + '\n');
130
+ return 0;
131
+ }
132
+ process.stdout.write(header(`Bundle status: ${bundle.id}`));
133
+ process.stdout.write(kv('task', bundle.task) + '\n');
134
+ process.stdout.write(kv('status', summary.status) + '\n');
135
+ process.stdout.write(kv('risk', bundle.riskLevel) + '\n');
136
+ process.stdout.write(kv('plans applied', `${summary.appliedPlans}/${summary.totalPlans}`) + '\n');
137
+ process.stdout.write(kv('plans unapplied', String(summary.unappliedPlans.length)) + '\n');
138
+ process.stdout.write(kv('intents', String(summary.intentPlans.length)) + '\n');
139
+ process.stdout.write(kv('validations', `${summary.validationsPassed}/${summary.validationsTotal}`) + '\n');
140
+ process.stdout.write(kv('audit entries', String(summary.auditEntries)) + '\n');
141
+ process.stdout.write(`\nPlan groups (${summary.planGroups.length}):\n`);
142
+ for (const g of summary.planGroups) {
143
+ process.stdout.write(` ${g.id}: ${g.planNames.join(', ')}\n`);
144
+ }
145
+ if (summary.dependencies.length > 0) {
146
+ process.stdout.write('\nDependencies:\n');
147
+ for (const d of summary.dependencies.slice(0, 10)) {
148
+ process.stdout.write(` ${d.from} → ${d.to} (${d.reason})\n`);
149
+ }
150
+ }
151
+ process.stdout.write(`\nNext: ${summary.nextSafeAction}\n`);
152
+ return 0;
153
+ }
154
+ function computeBundleStatusSummary(cwd, bundle) {
155
+ const applied = bundle.plans.filter((p) => p.status === 'applied').map((p) => p.name);
156
+ const intents = bundle.plans.filter((p) => p.status === 'intent').map((p) => p.name);
157
+ const unapplied = bundle.plans
158
+ .filter((p) => p.status !== 'applied' && p.status !== 'intent')
159
+ .map((p) => p.name);
160
+ // Audit log line count, if present.
161
+ let auditEntries = 0;
162
+ try {
163
+ const auditFile = nodePath.join(getBundleDir(cwd, bundle.id), 'reports', 'apply-audit.log');
164
+ if (existsSync(auditFile)) {
165
+ auditEntries = readFileSync(auditFile, 'utf8').split('\n').filter((l) => l.length > 0).length;
166
+ }
167
+ }
168
+ catch {
169
+ /* ignore */
170
+ }
171
+ const validationsPassed = bundle.validations.filter((v) => v.passed).length;
172
+ const nextSafeAction = computeNextSafeAction(bundle, applied, intents, unapplied);
173
+ return {
174
+ id: bundle.id,
175
+ task: bundle.task,
176
+ status: bundle.status,
177
+ riskLevel: bundle.riskLevel,
178
+ totalPlans: bundle.plans.length,
179
+ appliedPlans: applied.length,
180
+ unappliedPlans: unapplied,
181
+ intentPlans: intents,
182
+ planGroups: bundle.planGroups,
183
+ dependencies: bundle.dependencies,
184
+ validationsTotal: bundle.validations.length,
185
+ validationsPassed,
186
+ auditEntries,
187
+ nextSafeAction,
188
+ };
189
+ }
190
+ function computeNextSafeAction(bundle, applied, intents, unapplied) {
191
+ if (bundle.plans.length === 0) {
192
+ return `shrk bundle plan ${bundle.id} --all-suggested`;
193
+ }
194
+ if (intents.length > 0) {
195
+ return `shrk bundle plan ${bundle.id} --template <id> --var k=v # fill missing vars`;
196
+ }
197
+ if (unapplied.length === 0) {
198
+ if (bundle.validations.length === 0) {
199
+ return `shrk bundle validate ${bundle.id} --all-verifications --report`;
200
+ }
201
+ return `shrk bundle report ${bundle.id}`;
202
+ }
203
+ // Find the next-unblocked plan: a plan whose dependencies are all applied.
204
+ const appliedSet = new Set(applied);
205
+ const blockedBy = new Map();
206
+ for (const e of bundle.dependencies) {
207
+ const s = blockedBy.get(e.to) ?? new Set();
208
+ s.add(e.from);
209
+ blockedBy.set(e.to, s);
210
+ }
211
+ for (const name of unapplied) {
212
+ const deps = blockedBy.get(name);
213
+ if (!deps || [...deps].every((d) => appliedSet.has(d))) {
214
+ const plan = bundle.plans.find((p) => p.name === name);
215
+ if (!plan)
216
+ continue;
217
+ return `shrk apply .sharkcraft/bundles/${bundle.id}/plans/${plan.file} --verify-signature && shrk bundle record-apply ${bundle.id} ${name}`;
218
+ }
219
+ }
220
+ return `shrk bundle apply-assist ${bundle.id} # some plans blocked by deps`;
221
+ }
222
+ async function bundleReport(args) {
223
+ const cwd = resolveCwd(args);
224
+ const bundle = loadOrFail(cwd, args.positional[0]);
225
+ if (typeof bundle === 'number')
226
+ return bundle;
227
+ const summary = computeBundleStatusSummary(cwd, bundle);
228
+ const lines = [];
229
+ lines.push(`# Bundle final report: ${bundle.id}`);
230
+ lines.push('');
231
+ lines.push(`**Task:** ${bundle.task}`);
232
+ lines.push(`**Status:** ${bundle.status}`);
233
+ lines.push(`**Risk:** ${bundle.riskLevel}`);
234
+ lines.push(`**Created:** ${bundle.createdAt}`);
235
+ lines.push(`**Updated:** ${bundle.updatedAt}`);
236
+ lines.push('');
237
+ lines.push(`## Plan groups (${bundle.planGroups.length})`);
238
+ for (const g of bundle.planGroups) {
239
+ lines.push(`- \`${g.id}\`: ${g.planNames.join(', ')}`);
240
+ }
241
+ if (bundle.dependencies.length > 0) {
242
+ lines.push('');
243
+ lines.push(`## Dependencies (${bundle.dependencies.length})`);
244
+ for (const d of bundle.dependencies)
245
+ lines.push(`- \`${d.from}\` → \`${d.to}\` _(${d.reason})_`);
246
+ }
247
+ lines.push('');
248
+ lines.push(`## Plans (${bundle.plans.length})`);
249
+ for (const p of bundle.plans) {
250
+ lines.push(`- \`${p.name}\` (${p.templateId}) — **${p.status}**`);
251
+ if (p.expectedTargets.length > 0) {
252
+ for (const t of p.expectedTargets.slice(0, 5))
253
+ lines.push(` - target: \`${t}\``);
254
+ }
255
+ }
256
+ if (bundle.validations.length > 0) {
257
+ lines.push('');
258
+ lines.push(`## Validations (${bundle.validations.length})`);
259
+ for (const v of bundle.validations) {
260
+ lines.push(`- ${v.startedAt}: **${v.passed ? 'passed' : 'failed'}** — ${v.boundaryViolations} violations, ${v.warnings} warnings`);
261
+ for (const c of v.commandsRun) {
262
+ lines.push(` - ${c.passed ? 'OK' : 'FAIL'} ${c.command}: ${c.note ?? ''}`);
263
+ }
264
+ }
265
+ }
266
+ lines.push('');
267
+ lines.push(`## Audit`);
268
+ lines.push(`- Plans applied: ${summary.appliedPlans}/${summary.totalPlans}`);
269
+ lines.push(`- Apply audit entries: ${summary.auditEntries}`);
270
+ lines.push('');
271
+ lines.push(`## Next safe action`);
272
+ lines.push('```');
273
+ lines.push(summary.nextSafeAction);
274
+ lines.push('```');
275
+ const out = lines.join('\n') + '\n';
276
+ const file = nodePath.join(getBundleDir(cwd, bundle.id), 'reports', 'final-report.md');
277
+ mkdirSync(nodePath.dirname(file), { recursive: true });
278
+ writeFileSync(file, out, 'utf8');
279
+ const updated = recordBundleReport(bundle, 'reports/final-report.md');
280
+ writeFeatureBundle(cwd, updated);
281
+ if (flagBool(args, 'json')) {
282
+ process.stdout.write(asJson({ id: bundle.id, file, summary }) + '\n');
283
+ return 0;
284
+ }
285
+ process.stdout.write(out);
286
+ return 0;
287
+ }
288
+ async function bundleCommands(args) {
289
+ const cwd = resolveCwd(args);
290
+ const bundle = loadOrFail(cwd, args.positional[0]);
291
+ if (typeof bundle === 'number')
292
+ return bundle;
293
+ for (const c of bundle.commandHints)
294
+ process.stdout.write(`${c}\n`);
295
+ return 0;
296
+ }
297
+ async function bundlePlan(args) {
298
+ const cwd = resolveCwd(args);
299
+ const bundle = loadOrFail(cwd, args.positional[0]);
300
+ if (typeof bundle === 'number')
301
+ return bundle;
302
+ const inspection = await inspectSharkcraft({ cwd });
303
+ const explicitTemplate = flagString(args, 'template');
304
+ const explicitName = flagString(args, 'name');
305
+ const variables = flagVars(args);
306
+ const allSuggested = flagBool(args, 'all-suggested');
307
+ const fromPipeline = flagBool(args, 'from-pipeline');
308
+ const targets = [];
309
+ // Determine targets.
310
+ if (explicitTemplate) {
311
+ const planName = explicitName ?? explicitTemplate.replace(/[^a-z0-9]+/gi, '-');
312
+ const t = { templateId: explicitTemplate, planName, variables: { ...variables } };
313
+ if (explicitName)
314
+ t.userName = explicitName;
315
+ targets.push(t);
316
+ }
317
+ else if (allSuggested || fromPipeline) {
318
+ const packetFile = nodePath.join(getBundleDir(cwd, bundle.id), 'task-packet.json');
319
+ let candidateIds = [];
320
+ if (existsSync(packetFile)) {
321
+ try {
322
+ const packet = JSON.parse(readFileSync(packetFile, 'utf8'));
323
+ candidateIds = (packet.relevantTemplates ?? []).map((t) => t.id);
324
+ }
325
+ catch {
326
+ /* ignore */
327
+ }
328
+ }
329
+ for (const id of candidateIds.slice(0, 4)) {
330
+ targets.push({
331
+ templateId: id,
332
+ planName: id.replace(/[^a-z0-9]+/gi, '-'),
333
+ variables: {},
334
+ });
335
+ }
336
+ }
337
+ if (targets.length === 0) {
338
+ process.stderr.write(`No templates targeted. Use --template <id> or --all-suggested.\n`);
339
+ return 1;
340
+ }
341
+ const dir = getBundleDir(cwd, bundle.id);
342
+ const plansDir = nodePath.join(dir, 'plans');
343
+ const reviewsDir = nodePath.join(dir, 'reviews');
344
+ mkdirSync(plansDir, { recursive: true });
345
+ mkdirSync(reviewsDir, { recursive: true });
346
+ const results = [];
347
+ let updated = bundle;
348
+ for (const target of targets) {
349
+ const template = inspection.templateRegistry.get(target.templateId);
350
+ if (!template) {
351
+ results.push({ templateId: target.templateId, status: 'unknown-template' });
352
+ continue;
353
+ }
354
+ const r = generate(template, {
355
+ templateId: template.id,
356
+ ...(target.userName ? { name: target.userName } : {}),
357
+ variables: target.variables,
358
+ projectRoot: cwd,
359
+ overwriteStrategy: OverwriteStrategy.Never,
360
+ write: false,
361
+ });
362
+ if (!r.ok) {
363
+ results.push({ templateId: target.templateId, status: 'gen-error', message: r.error.message });
364
+ continue;
365
+ }
366
+ const plan = r.value.plan;
367
+ const missing = plan.warnings
368
+ .map((w) => /Variable\s+'(\w+)'/.exec(w)?.[1])
369
+ .filter((m) => Boolean(m));
370
+ if (missing.length > 0 || plan.changes.length === 0) {
371
+ const intentFile = `${target.planName}.intent.md`;
372
+ writeFileSync(nodePath.join(plansDir, intentFile), `# Plan intent for ${target.templateId}\n\nMissing variables: ${missing.join(', ')}\n`, 'utf8');
373
+ const entry = {
374
+ name: target.planName,
375
+ templateId: target.templateId,
376
+ generatedName: target.planName,
377
+ variables: target.variables,
378
+ missingVariables: missing,
379
+ file: intentFile,
380
+ status: 'intent',
381
+ expectedTargets: [],
382
+ };
383
+ updated = upsertBundlePlan(updated, entry);
384
+ results.push({ templateId: target.templateId, status: 'intent', file: `plans/${intentFile}` });
385
+ continue;
386
+ }
387
+ const saved = buildSavedPlan({
388
+ templateId: template.id,
389
+ name: target.planName,
390
+ variables: target.variables,
391
+ projectRoot: cwd,
392
+ plan,
393
+ });
394
+ const planFile = `${target.planName}.json`;
395
+ const planFullPath = nodePath.join(plansDir, planFile);
396
+ const sr = savePlanToFile(saved, planFullPath);
397
+ if (!sr.ok) {
398
+ results.push({ templateId: target.templateId, status: 'save-error', message: sr.error.message });
399
+ continue;
400
+ }
401
+ const expectedTargets = plan.changes.map((c) => c.relativePath);
402
+ const entry = {
403
+ name: target.planName,
404
+ templateId: target.templateId,
405
+ generatedName: target.planName,
406
+ variables: target.variables,
407
+ missingVariables: [],
408
+ file: planFile,
409
+ status: 'reviewed',
410
+ expectedTargets,
411
+ };
412
+ updated = upsertBundlePlan(updated, entry);
413
+ results.push({ templateId: target.templateId, status: 'saved', file: `plans/${planFile}` });
414
+ }
415
+ updated = recomputeBundleStatus(updated);
416
+ // Persist graph-derived dependencies so MCP / read-only consumers see the
417
+ // order without rebuilding the graph from the registries.
418
+ const graph = buildPlanDependencyGraph(inspection, updated);
419
+ updated = setBundleDependencies(updated, graph.edges.map((e) => ({ from: e.from, to: e.to, reason: e.reason })), graph.order);
420
+ const nextAction = updated.plans.length > 0
421
+ ? `shrk bundle apply-assist ${bundle.id}`
422
+ : `shrk bundle plan ${bundle.id}`;
423
+ updated = setBundleNextAction(updated, nextAction);
424
+ writeFeatureBundle(cwd, updated);
425
+ if (flagBool(args, 'json')) {
426
+ process.stdout.write(asJson({ id: bundle.id, plans: results }) + '\n');
427
+ return 0;
428
+ }
429
+ process.stdout.write(header(`Bundle plan: ${bundle.id}`));
430
+ for (const r of results) {
431
+ process.stdout.write(` ${String(r.status).padEnd(14)} ${r.file ?? r.templateId}\n`);
432
+ }
433
+ return 0;
434
+ }
435
+ async function bundleGraph(args) {
436
+ const cwd = resolveCwd(args);
437
+ const bundle = loadOrFail(cwd, args.positional[0]);
438
+ if (typeof bundle === 'number')
439
+ return bundle;
440
+ const inspection = await inspectSharkcraft({ cwd });
441
+ const graph = buildPlanDependencyGraph(inspection, bundle);
442
+ const fmt = flagString(args, 'format') ?? (flagBool(args, 'json') ? 'json' : 'text');
443
+ if (fmt === 'json') {
444
+ process.stdout.write(asJson(graph) + '\n');
445
+ }
446
+ else if (fmt === 'dot') {
447
+ process.stdout.write(renderGraphDot(graph));
448
+ }
449
+ else if (fmt === 'mermaid') {
450
+ process.stdout.write(renderGraphMermaid(graph));
451
+ }
452
+ else {
453
+ process.stdout.write(renderGraphText(graph));
454
+ }
455
+ return 0;
456
+ }
457
+ async function bundleApplyAssist(args) {
458
+ const cwd = resolveCwd(args);
459
+ const bundle = loadOrFail(cwd, args.positional[0]);
460
+ if (typeof bundle === 'number')
461
+ return bundle;
462
+ const inspection = await inspectSharkcraft({ cwd });
463
+ const graph = buildPlanDependencyGraph(inspection, bundle);
464
+ const ordered = graph.order;
465
+ const resume = flagBool(args, 'resume');
466
+ // Group plans into waves using bundle.planGroups when present, else the
467
+ // topological order is a single group.
468
+ const groups = bundle.planGroups.length > 0
469
+ ? [...bundle.planGroups]
470
+ : [{ id: 'group-1', planNames: ordered }];
471
+ const appliedSet = new Set(bundle.plans.filter((p) => p.status === 'applied').map((p) => p.name));
472
+ const skipped = [];
473
+ const commands = [];
474
+ for (const planName of ordered) {
475
+ const p = bundle.plans.find((x) => x.name === planName);
476
+ if (!p)
477
+ continue;
478
+ if (p.status === 'intent')
479
+ continue;
480
+ if (resume && appliedSet.has(planName)) {
481
+ skipped.push(planName);
482
+ continue;
483
+ }
484
+ commands.push(`shrk apply .sharkcraft/bundles/${bundle.id}/plans/${p.file} --verify-signature`);
485
+ }
486
+ const validateAfterGroup = flagBool(args, 'validate-after-group');
487
+ const validateFinal = flagBool(args, 'validate-final');
488
+ const outputFlag = flagString(args, 'output');
489
+ const fmt = flagString(args, 'format') ?? (flagBool(args, 'json') ? 'json' : 'markdown');
490
+ if (fmt === 'json') {
491
+ process.stdout.write(asJson({
492
+ id: bundle.id,
493
+ order: ordered,
494
+ commands,
495
+ planGroups: groups,
496
+ validateAfterGroup,
497
+ validateFinal,
498
+ resume,
499
+ skipped,
500
+ }) + '\n');
501
+ return 0;
502
+ }
503
+ if (fmt === 'shell' || flagBool(args, 'write-script') || outputFlag) {
504
+ const out = buildApplyAssistScript(bundle, groups, ordered, {
505
+ validateAfterGroup,
506
+ validateFinal,
507
+ resume,
508
+ });
509
+ const destPath = outputFlag
510
+ ? (nodePath.isAbsolute(outputFlag) ? outputFlag : nodePath.join(cwd, outputFlag))
511
+ : nodePath.join(getBundleDir(cwd, bundle.id), 'reports', 'apply-assist.sh');
512
+ if (flagBool(args, 'write-script') || outputFlag) {
513
+ mkdirSync(nodePath.dirname(destPath), { recursive: true });
514
+ writeFileSync(destPath, out, { mode: 0o755 });
515
+ const rel = nodePath.relative(getBundleDir(cwd, bundle.id), destPath);
516
+ if (!rel.startsWith('..')) {
517
+ const updated = recordBundleReport(bundle, rel);
518
+ writeFeatureBundle(cwd, updated);
519
+ }
520
+ process.stdout.write(`Wrote ${destPath}\n`);
521
+ return 0;
522
+ }
523
+ process.stdout.write(out);
524
+ return 0;
525
+ }
526
+ // Markdown (default).
527
+ process.stdout.write(`# Apply-assist for ${bundle.id}\n\n`);
528
+ if (resume) {
529
+ process.stdout.write(`Resume mode: ${skipped.length} plan(s) already applied — skipping.\n`);
530
+ if (skipped.length > 0)
531
+ process.stdout.write(` Skipped: ${skipped.join(', ')}\n`);
532
+ process.stdout.write('\n');
533
+ }
534
+ process.stdout.write(`Order:\n`);
535
+ for (const g of groups) {
536
+ process.stdout.write(`- ${g.id}: ${g.planNames.join(', ')}\n`);
537
+ }
538
+ process.stdout.write(`\nCommands (run yourself — no auto-apply):\n\n`);
539
+ for (const c of commands)
540
+ process.stdout.write(`\`\`\`\n${c}\n\`\`\`\n\n`);
541
+ if (commands.length === 0 && resume) {
542
+ process.stdout.write('All plans already applied — nothing to resume.\n');
543
+ }
544
+ process.stdout.write(`After each plan, run:\n\`\`\`\nshrk check boundaries\nbun test\n\`\`\`\n`);
545
+ return 0;
546
+ }
547
+ function buildApplyAssistScript(bundle, groups, topoOrder, opts) {
548
+ const lines = [];
549
+ lines.push('#!/usr/bin/env bash');
550
+ lines.push(`# apply-assist v2 — bundle ${bundle.id}`);
551
+ lines.push('# - applies plans in dependency order, respecting plan groups');
552
+ lines.push('# - stops on the first failure (set -euo pipefail)');
553
+ lines.push('# - calls `shrk bundle record-apply` after each successful apply');
554
+ if (opts.resume)
555
+ lines.push('# - resume mode: skips plans already marked applied');
556
+ if (opts.validateAfterGroup)
557
+ lines.push('# - runs `shrk bundle validate --boundaries` after each group');
558
+ if (opts.validateFinal)
559
+ lines.push('# - runs `shrk bundle validate --all-verifications --report` at the end');
560
+ lines.push('# - logs every command + outcome to reports/apply-assist.log');
561
+ lines.push('set -euo pipefail');
562
+ lines.push(`BUNDLE_ID=${shellEscape(bundle.id)}`);
563
+ lines.push(`BUNDLE_DIR=".sharkcraft/bundles/$BUNDLE_ID"`);
564
+ lines.push('LOG_FILE="$BUNDLE_DIR/reports/apply-assist.log"');
565
+ lines.push('mkdir -p "$BUNDLE_DIR/reports"');
566
+ lines.push('log() { echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) $*" | tee -a "$LOG_FILE"; }');
567
+ lines.push('phase() { echo; echo "=== $* ==="; log "PHASE $*"; }');
568
+ // Helper to find the plan file for a given plan name.
569
+ const planFileByName = new Map();
570
+ for (const p of bundle.plans)
571
+ planFileByName.set(p.name, p.file);
572
+ const isApplied = (name) => bundle.plans.find((x) => x.name === name)?.status === 'applied';
573
+ const isIntent = (name) => bundle.plans.find((x) => x.name === name)?.status === 'intent';
574
+ let groupIndex = 0;
575
+ for (const g of groups) {
576
+ groupIndex += 1;
577
+ const applicable = g.planNames.filter((n) => !isIntent(n) && !isApplied(n) && planFileByName.has(n));
578
+ // Re-order applicable using the topological sort within the group.
579
+ applicable.sort((a, b) => topoOrder.indexOf(a) - topoOrder.indexOf(b));
580
+ if (applicable.length === 0) {
581
+ lines.push('');
582
+ lines.push(`phase "Group ${groupIndex} (${g.id}) — nothing to do"`);
583
+ continue;
584
+ }
585
+ lines.push('');
586
+ lines.push(`phase "Group ${groupIndex} (${g.id}) — ${applicable.length} plan(s)"`);
587
+ for (const name of applicable) {
588
+ const planFile = planFileByName.get(name);
589
+ const cmd = `shrk apply $BUNDLE_DIR/plans/${shellEscape(planFile)} --verify-signature`;
590
+ lines.push(`log "About to apply: ${shellEscape(name)} ($cmd)"`);
591
+ lines.push(`echo "About to apply plan: ${shellEscape(name)}"`);
592
+ lines.push(`echo "Command: ${cmd}"`);
593
+ lines.push('read -p "Continue? (yes/no) " ans');
594
+ lines.push('if [ "$ans" != "yes" ]; then log "SKIPPED ${name}"; echo "Skipped."; exit 1; fi');
595
+ lines.push(`echo "+ ${cmd}"`);
596
+ lines.push(`${cmd} 2>&1 | tee -a "$LOG_FILE"`);
597
+ lines.push(`shrk bundle record-apply $BUNDLE_ID ${shellEscape(name)} --note "via apply-assist.sh"`);
598
+ lines.push(`log "APPLIED ${shellEscape(name)}"`);
599
+ }
600
+ if (opts.validateAfterGroup) {
601
+ lines.push('');
602
+ lines.push(`phase "Validate after group ${groupIndex}"`);
603
+ lines.push(`shrk bundle validate $BUNDLE_ID --boundaries 2>&1 | tee -a "$LOG_FILE"`);
604
+ }
605
+ }
606
+ if (opts.validateFinal) {
607
+ lines.push('');
608
+ lines.push('phase "Final validation"');
609
+ lines.push(`shrk bundle validate $BUNDLE_ID --all-verifications --report 2>&1 | tee -a "$LOG_FILE"`);
610
+ }
611
+ lines.push('');
612
+ lines.push('log "Apply-assist completed cleanly."');
613
+ lines.push('echo "Done."');
614
+ return lines.join('\n') + '\n';
615
+ }
616
+ function shellEscape(s) {
617
+ // Conservative: wrap in single quotes and escape embedded single quotes.
618
+ return `'${s.replace(/'/g, `'\\''`)}'`;
619
+ }
620
+ async function bundleValidate(args) {
621
+ const cwd = resolveCwd(args);
622
+ const bundle = loadOrFail(cwd, args.positional[0]);
623
+ if (typeof bundle === 'number')
624
+ return bundle;
625
+ const inspection = await inspectSharkcraft({ cwd });
626
+ const all = flagBool(args, 'all-verifications');
627
+ const strict = flagBool(args, 'strict');
628
+ const runBoundaries = flagBool(args, 'boundaries') || all;
629
+ const runDrift = flagBool(args, 'drift') || all;
630
+ const runCoverage = flagBool(args, 'coverage') || all;
631
+ const runAgent = flagBool(args, 'agent-tests') || all;
632
+ const runContext = flagBool(args, 'context-tests') || all;
633
+ const runTestImpact = flagBool(args, 'test-impact') || all;
634
+ const verificationId = flagString(args, 'verification');
635
+ const startedAt = new Date().toISOString();
636
+ const commandsRun = [];
637
+ let boundaryViolations = 0;
638
+ let warnings = 0;
639
+ if (runBoundaries) {
640
+ try {
641
+ const { evaluateBoundaries, loadTsconfigPaths, scanImports } = await import('@shrkcrft/boundaries');
642
+ const scan = scanImports({ projectRoot: cwd });
643
+ const tsconfigPaths = loadTsconfigPaths(cwd);
644
+ const evalResult = evaluateBoundaries(scan, inspection.boundaryRegistry.list(), {
645
+ ...(tsconfigPaths.aliases.size > 0 ? { tsconfigPaths } : {}),
646
+ });
647
+ boundaryViolations = evalResult.violations.length;
648
+ const fail = strict ? boundaryViolations > 0 : evalResult.counts.error > 0;
649
+ commandsRun.push({
650
+ command: 'boundaries',
651
+ passed: !fail,
652
+ note: `${boundaryViolations} violations (${evalResult.counts.error}err / ${evalResult.counts.warning}warn)`,
653
+ });
654
+ warnings += evalResult.counts.warning;
655
+ }
656
+ catch (e) {
657
+ commandsRun.push({ command: 'boundaries', passed: false, note: e.message });
658
+ }
659
+ }
660
+ if (runDrift) {
661
+ try {
662
+ const { buildDriftReport } = await import('@shrkcrft/inspector');
663
+ const drift = buildDriftReport(inspection);
664
+ const fail = drift.counts.error > 0 || (strict && drift.counts.warning > 0);
665
+ commandsRun.push({
666
+ command: 'drift',
667
+ passed: !fail,
668
+ note: `${drift.counts.error}err / ${drift.counts.warning}warn / ${drift.counts.info}info`,
669
+ });
670
+ warnings += drift.counts.warning;
671
+ }
672
+ catch (e) {
673
+ commandsRun.push({ command: 'drift', passed: false, note: e.message });
674
+ }
675
+ }
676
+ if (runCoverage) {
677
+ try {
678
+ const { buildCoverageReport } = await import('@shrkcrft/inspector');
679
+ const cov = buildCoverageReport(inspection);
680
+ const gaps = cov.categories.filter((c) => c.score < 80).length;
681
+ const fail = strict && gaps > 0;
682
+ commandsRun.push({
683
+ command: 'coverage',
684
+ passed: !fail,
685
+ note: `overall=${cov.overall} gaps<80%=${gaps}`,
686
+ });
687
+ }
688
+ catch (e) {
689
+ commandsRun.push({ command: 'coverage', passed: false, note: e.message });
690
+ }
691
+ }
692
+ if (runAgent) {
693
+ try {
694
+ const { loadAgentContractTests, runAgentContractTest } = await import('@shrkcrft/inspector');
695
+ const tests = await loadAgentContractTests(inspection);
696
+ const results = tests.map((t) => runAgentContractTest(inspection, t));
697
+ const failed = results.filter((r) => !r.passed).length;
698
+ commandsRun.push({
699
+ command: 'agent-tests',
700
+ passed: failed === 0,
701
+ note: `${results.length - failed}/${results.length} passed`,
702
+ });
703
+ }
704
+ catch (e) {
705
+ commandsRun.push({ command: 'agent-tests', passed: false, note: e.message });
706
+ }
707
+ }
708
+ if (runContext) {
709
+ try {
710
+ const { loadContextTests, runContextTest } = await import('@shrkcrft/inspector');
711
+ const tests = await loadContextTests(inspection);
712
+ const results = tests.map((t) => runContextTest(inspection, t));
713
+ const failed = results.filter((r) => !r.passed).length;
714
+ commandsRun.push({
715
+ command: 'context-tests',
716
+ passed: failed === 0,
717
+ note: `${results.length - failed}/${results.length} passed`,
718
+ });
719
+ }
720
+ catch (e) {
721
+ commandsRun.push({ command: 'context-tests', passed: false, note: e.message });
722
+ }
723
+ }
724
+ if (runTestImpact) {
725
+ try {
726
+ const { analyzeTestImpact } = await import('@shrkcrft/inspector');
727
+ const files = bundle.plans.flatMap((p) => p.expectedTargets);
728
+ const ti = analyzeTestImpact(inspection, { files });
729
+ // Only fail under --strict when there are missing tests.
730
+ const fail = strict && ti.missingTestFiles.length > 0;
731
+ commandsRun.push({
732
+ command: 'test-impact',
733
+ passed: !fail,
734
+ note: `likely=${ti.likelyTestFiles.length} missing=${ti.missingTestFiles.length} confidence=${ti.confidence}%`,
735
+ });
736
+ }
737
+ catch (e) {
738
+ commandsRun.push({ command: 'test-impact', passed: false, note: e.message });
739
+ }
740
+ }
741
+ // Optional explicit verification command from sharkcraft.config (cli-only allow-list).
742
+ if (verificationId) {
743
+ const cfg = inspection.config;
744
+ const entry = cfg?.verificationCommands?.find((v) => v.id === verificationId);
745
+ if (!entry) {
746
+ commandsRun.push({
747
+ command: `verification:${verificationId}`,
748
+ passed: false,
749
+ note: 'not present in sharkcraft.config.ts verificationCommands[]',
750
+ });
751
+ }
752
+ else {
753
+ commandsRun.push({
754
+ command: `verification:${verificationId}`,
755
+ passed: true,
756
+ note: 'documented (human must run)',
757
+ });
758
+ }
759
+ }
760
+ const finishedAt = new Date().toISOString();
761
+ const passed = commandsRun.every((c) => c.passed);
762
+ const reportFile = `reports/validate-${nowSlug()}.json`;
763
+ const fullPath = nodePath.join(getBundleDir(cwd, bundle.id), reportFile);
764
+ mkdirSync(nodePath.dirname(fullPath), { recursive: true });
765
+ const validation = {
766
+ startedAt,
767
+ finishedAt,
768
+ passed,
769
+ warnings,
770
+ commandsRun,
771
+ boundaryViolations,
772
+ reportFile,
773
+ };
774
+ writeFileSync(fullPath, JSON.stringify(validation, null, 2) + '\n', 'utf8');
775
+ let updated = recordBundleValidation(bundle, validation);
776
+ updated = recomputeBundleStatus(updated);
777
+ // --report: write Markdown + JSON summary into reports/, plus optional HTML.
778
+ const wantReport = flagBool(args, 'report');
779
+ const wantHtml = flagBool(args, 'html');
780
+ if (wantReport || wantHtml) {
781
+ const slug = nowSlug();
782
+ if (wantReport) {
783
+ const md = [
784
+ `# Bundle validation report: ${bundle.id}`,
785
+ '',
786
+ `**Task:** ${bundle.task}`,
787
+ `**Status:** ${updated.status}`,
788
+ `**Started:** ${startedAt}`,
789
+ `**Finished:** ${finishedAt}`,
790
+ `**Passed:** ${passed}`,
791
+ `**Warnings:** ${warnings}`,
792
+ '',
793
+ `## Gate matrix`,
794
+ '| Gate | Result | Note |',
795
+ '| --- | --- | --- |',
796
+ ...commandsRun.map((c) => `| \`${c.command}\` | ${c.passed ? '✅ OK' : '❌ FAIL'} | ${c.note ?? ''} |`),
797
+ '',
798
+ `## Plans (${updated.plans.length})`,
799
+ ...updated.plans.map((p) => `- \`${p.name}\` (${p.templateId}) — **${p.status}**`),
800
+ '',
801
+ `## Affected files`,
802
+ ...(updated.affectedFiles.length === 0
803
+ ? ['(none tracked)']
804
+ : updated.affectedFiles.map((f) => `- \`${f}\``)),
805
+ ].join('\n') + '\n';
806
+ const mdFile = `reports/validate-${slug}.md`;
807
+ writeFileSync(nodePath.join(getBundleDir(cwd, bundle.id), mdFile), md, 'utf8');
808
+ updated = recordBundleReport(updated, mdFile);
809
+ const jsonFile = `reports/validate-${slug}.json`;
810
+ writeFileSync(nodePath.join(getBundleDir(cwd, bundle.id), jsonFile), JSON.stringify({ bundle: { id: updated.id, task: updated.task, status: updated.status }, validation }, null, 2) + '\n', 'utf8');
811
+ updated = recordBundleReport(updated, jsonFile);
812
+ }
813
+ if (wantHtml) {
814
+ const html = renderBundleValidationHtml(updated, validation);
815
+ const htmlFile = `reports/validate-${slug}.html`;
816
+ writeFileSync(nodePath.join(getBundleDir(cwd, bundle.id), htmlFile), html, 'utf8');
817
+ updated = recordBundleReport(updated, htmlFile);
818
+ }
819
+ }
820
+ writeFeatureBundle(cwd, updated);
821
+ if (flagBool(args, 'json')) {
822
+ process.stdout.write(asJson(validation) + '\n');
823
+ return passed ? 0 : 1;
824
+ }
825
+ process.stdout.write(`validation ${passed ? 'passed' : 'failed'} (${commandsRun.length} command(s))\n`);
826
+ for (const c of commandsRun) {
827
+ process.stdout.write(` ${c.passed ? 'OK ' : 'FAIL'} ${c.command.padEnd(16)} ${c.note ?? ''}\n`);
828
+ }
829
+ return passed ? 0 : 1;
830
+ }
831
+ async function bundleDecompose(args) {
832
+ const cwd = resolveCwd(args);
833
+ const bundle = loadOrFail(cwd, args.positional[0]);
834
+ if (typeof bundle === 'number')
835
+ return bundle;
836
+ const inspection = await inspectSharkcraft({ cwd });
837
+ const d = decomposeTask(inspection, bundle.task);
838
+ if (flagBool(args, 'json')) {
839
+ process.stdout.write(asJson(d) + '\n');
840
+ return 0;
841
+ }
842
+ process.stdout.write(`task: ${d.task}\nverb: ${d.verb}\nsubtasks:\n`);
843
+ for (const s of d.subtasks)
844
+ process.stdout.write(` - ${s.id} (${s.riskLevel}): ${s.title}\n`);
845
+ return 0;
846
+ }
847
+ export const bundleCommand = {
848
+ name: 'bundle',
849
+ description: 'Feature workflow bundles (multi-plan, dep graph, apply assist, validate).',
850
+ usage: 'shrk bundle create|list|show|status|report|commands|plan|graph|apply-assist|validate|replay|decompose|record-apply|next|review [...args]',
851
+ async run(args) {
852
+ const sub = args.positional[0];
853
+ const rest = args.positional.slice(1);
854
+ if (!sub || !SUBCOMMANDS.has(sub)) {
855
+ process.stderr.write(`Usage: ${this.usage}\n`);
856
+ return 2;
857
+ }
858
+ const subArgs = { ...args, positional: rest };
859
+ switch (sub) {
860
+ case 'create': return bundleCreate(subArgs);
861
+ case 'list': return bundleList(subArgs);
862
+ case 'show': return bundleShow(subArgs);
863
+ case 'status': return bundleStatus(subArgs);
864
+ case 'report': return bundleReport(subArgs);
865
+ case 'commands': return bundleCommands(subArgs);
866
+ case 'plan': return bundlePlan(subArgs);
867
+ case 'graph': return bundleGraph(subArgs);
868
+ case 'apply-plan':
869
+ case 'apply-assist': return bundleApplyAssist(subArgs);
870
+ case 'validate': return bundleValidate(subArgs);
871
+ case 'decompose': return bundleDecompose(subArgs);
872
+ case 'record-apply': return bundleRecordApply(subArgs);
873
+ case 'replay': return bundleReplay(subArgs);
874
+ case 'next': return bundleNext(subArgs);
875
+ case 'review': return bundleReview(subArgs);
876
+ case 'diff': return bundleDiffCommand(subArgs);
877
+ default: return 2;
878
+ }
879
+ },
880
+ };
881
+ async function bundleNext(args) {
882
+ const cwd = resolveCwd(args);
883
+ const bundle = loadOrFail(cwd, args.positional[0]);
884
+ if (typeof bundle === 'number')
885
+ return bundle;
886
+ const summary = computeBundleStatusSummary(cwd, bundle);
887
+ if (flagBool(args, 'json')) {
888
+ process.stdout.write(asJson({
889
+ id: bundle.id,
890
+ status: summary.status,
891
+ nextSafeAction: summary.nextSafeAction,
892
+ blockedPlans: blockedPlans(bundle, summary),
893
+ }) + '\n');
894
+ return 0;
895
+ }
896
+ process.stdout.write(`${summary.nextSafeAction}\n`);
897
+ return 0;
898
+ }
899
+ function blockedPlans(bundle, _summary) {
900
+ const applied = new Set(bundle.plans.filter((p) => p.status === 'applied').map((p) => p.name));
901
+ const out = [];
902
+ const blockedBy = new Map();
903
+ for (const e of bundle.dependencies) {
904
+ const list = blockedBy.get(e.to) ?? [];
905
+ if (!applied.has(e.from))
906
+ list.push(e.from);
907
+ blockedBy.set(e.to, list);
908
+ }
909
+ for (const p of bundle.plans) {
910
+ if (applied.has(p.name))
911
+ continue;
912
+ const deps = blockedBy.get(p.name) ?? [];
913
+ if (deps.length > 0)
914
+ out.push({ name: p.name, blockedBy: deps });
915
+ }
916
+ return out;
917
+ }
918
+ async function bundleReview(args) {
919
+ const cwd = resolveCwd(args);
920
+ const bundle = loadOrFail(cwd, args.positional[0]);
921
+ if (typeof bundle === 'number')
922
+ return bundle;
923
+ const inspection = await inspectSharkcraft({ cwd });
924
+ // Pull boundary suggestions for files the bundle plans expect to touch.
925
+ const expected = bundle.plans.flatMap((p) => p.expectedTargets);
926
+ const review = {
927
+ bundleId: bundle.id,
928
+ task: bundle.task,
929
+ status: bundle.status,
930
+ plans: bundle.plans.map((p) => ({
931
+ name: p.name,
932
+ templateId: p.templateId,
933
+ status: p.status,
934
+ expectedTargets: p.expectedTargets,
935
+ })),
936
+ dependencyOrder: buildPlanDependencyGraph(inspection, bundle).order,
937
+ introducedBoundaryRisks: expected
938
+ .filter((f) => f.includes('/internal/') || f.includes('/private/'))
939
+ .map((f) => ({ file: f, reason: 'targets a path commonly under boundary rules' })),
940
+ missingValidations: bundle.validations.length === 0,
941
+ humanApprovalGates: bundle.plans
942
+ .filter((p) => p.status !== 'applied' && p.status !== 'intent')
943
+ .map((p) => `shrk apply .sharkcraft/bundles/${bundle.id}/plans/${p.file} --verify-signature`),
944
+ };
945
+ if (flagBool(args, 'json')) {
946
+ process.stdout.write(asJson(review) + '\n');
947
+ return 0;
948
+ }
949
+ process.stdout.write(header(`Bundle review: ${bundle.id}`));
950
+ process.stdout.write(kv('task', bundle.task) + '\n');
951
+ process.stdout.write(kv('status', bundle.status) + '\n');
952
+ process.stdout.write(`\nDependency order: ${review.dependencyOrder.join(' → ') || '(empty)'}\n`);
953
+ process.stdout.write(`Plans:\n`);
954
+ for (const p of review.plans) {
955
+ process.stdout.write(` ${p.status.padEnd(10)} ${p.name} (${p.templateId})\n`);
956
+ }
957
+ if (review.introducedBoundaryRisks.length > 0) {
958
+ process.stdout.write('\nIntroduced boundary risks:\n');
959
+ for (const r of review.introducedBoundaryRisks)
960
+ process.stdout.write(` - ${r.file}: ${r.reason}\n`);
961
+ }
962
+ if (review.missingValidations) {
963
+ process.stdout.write('\n! No validations have been run yet. Run:\n');
964
+ process.stdout.write(` shrk bundle validate ${bundle.id} --all-verifications --report\n`);
965
+ }
966
+ if (review.humanApprovalGates.length > 0) {
967
+ process.stdout.write('\nHuman approval gates:\n');
968
+ for (const c of review.humanApprovalGates)
969
+ process.stdout.write(` $ ${c}\n`);
970
+ }
971
+ return 0;
972
+ }
973
+ async function bundleReplay(args) {
974
+ const cwd = resolveCwd(args);
975
+ // Sub-form: `shrk bundle replay scaffold github-actions [...]`
976
+ if (args.positional[0] === 'scaffold') {
977
+ return bundleReplayScaffold({ ...args, positional: args.positional.slice(1) });
978
+ }
979
+ const all = flagBool(args, 'all') || args.positional[0] === '--all';
980
+ const strict = flagBool(args, 'strict');
981
+ if (all) {
982
+ const sinceMatch = flagString(args, 'since');
983
+ const batch = replayAllBundles(cwd, {
984
+ strict,
985
+ ...(sinceMatch ? { match: sinceMatch } : {}),
986
+ });
987
+ if (flagBool(args, 'html')) {
988
+ const out = flagString(args, 'output') ?? nodePath.join(cwd, '.sharkcraft', 'reports', 'bundle-replay-all.html');
989
+ const abs = nodePath.isAbsolute(out) ? out : nodePath.resolve(cwd, out);
990
+ mkdirSync(nodePath.dirname(abs), { recursive: true });
991
+ writeFileSync(abs, renderBundleReplayBatchHtml(batch), 'utf8');
992
+ if (!flagBool(args, 'json'))
993
+ process.stdout.write(`Wrote ${abs}\n`);
994
+ }
995
+ if (flagBool(args, 'json')) {
996
+ process.stdout.write(asJson(batch) + '\n');
997
+ return batch.tamperedCount + batch.missingCount === 0 ? 0 : 1;
998
+ }
999
+ if (flagBool(args, 'report')) {
1000
+ const reportPath = nodePath.join(cwd, '.sharkcraft', 'reports', 'bundle-replay-all.md');
1001
+ mkdirSync(nodePath.dirname(reportPath), { recursive: true });
1002
+ const lines = [];
1003
+ lines.push('# Bundle replay (all)');
1004
+ lines.push('');
1005
+ lines.push(`Total: ${batch.total} · Clean: ${batch.cleanCount} · Warnings: ${batch.warningsCount} · Tampered: ${batch.tamperedCount} · Missing: ${batch.missingCount}`);
1006
+ lines.push('');
1007
+ lines.push('| Bundle | Status | Audit | Issues |');
1008
+ lines.push('| --- | --- | ---: | ---: |');
1009
+ for (const r of batch.reports) {
1010
+ const issuesCount = r.planEntries.reduce((acc, p) => acc + p.issues.length, 0) + r.warnings.length;
1011
+ lines.push(`| \`${r.bundleId}\` | ${r.status} | ${r.auditEntries} | ${issuesCount} |`);
1012
+ }
1013
+ if (batch.topIssues.length > 0) {
1014
+ lines.push('');
1015
+ lines.push('## Top issues');
1016
+ for (const i of batch.topIssues) {
1017
+ lines.push(`- \`${i.bundleId}\`${i.planName ? ` / \`${i.planName}\`` : ''} — **${i.code}** ${i.message}`);
1018
+ }
1019
+ }
1020
+ writeFileSync(reportPath, lines.join('\n') + '\n', 'utf8');
1021
+ process.stdout.write(`Wrote ${reportPath}\n`);
1022
+ }
1023
+ process.stdout.write(header(`Bundle replay (${batch.total})`));
1024
+ process.stdout.write(`clean=${batch.cleanCount} warnings=${batch.warningsCount} tampered=${batch.tamperedCount} missing=${batch.missingCount}\n`);
1025
+ for (const r of batch.reports) {
1026
+ process.stdout.write(` ${r.status.padEnd(10)} ${r.bundleId}\n`);
1027
+ }
1028
+ if (batch.topIssues.length > 0) {
1029
+ process.stdout.write('\nTop issues:\n');
1030
+ for (const i of batch.topIssues) {
1031
+ process.stdout.write(` ${i.bundleId}${i.planName ? `/${i.planName}` : ''}: ${i.code} — ${i.message}\n`);
1032
+ }
1033
+ }
1034
+ return batch.tamperedCount + batch.missingCount === 0 ? 0 : 1;
1035
+ }
1036
+ const id = args.positional[0];
1037
+ if (!id) {
1038
+ process.stderr.write('Usage: shrk bundle replay <id> [--strict] [--json] | shrk bundle replay --all\n');
1039
+ return 2;
1040
+ }
1041
+ const result = replayBundle(cwd, id, { strict });
1042
+ if (flagBool(args, 'json')) {
1043
+ process.stdout.write(asJson(result) + '\n');
1044
+ return result.status === BundleReplayStatus.Clean || result.status === BundleReplayStatus.Warnings ? 0 : 1;
1045
+ }
1046
+ process.stdout.write(header(`Bundle replay: ${id}`));
1047
+ process.stdout.write(`status: ${result.status}\n`);
1048
+ process.stdout.write(`audit entries: ${result.auditEntries}\n`);
1049
+ for (const p of result.planEntries) {
1050
+ const label = p.applied ? 'applied' : 'unapplied';
1051
+ process.stdout.write(` ${p.planName.padEnd(28)} ${label.padEnd(10)} ${p.currentHash ?? '(no-hash)'}\n`);
1052
+ for (const issue of p.issues)
1053
+ process.stdout.write(` ! ${issue}\n`);
1054
+ }
1055
+ if (result.warnings.length > 0) {
1056
+ process.stdout.write('Warnings:\n');
1057
+ for (const w of result.warnings)
1058
+ process.stdout.write(` - ${w.code}: ${w.message}\n`);
1059
+ }
1060
+ if (result.recommendedFix) {
1061
+ process.stdout.write(`\nFix: ${result.recommendedFix}\n`);
1062
+ }
1063
+ return result.status === BundleReplayStatus.Clean || result.status === BundleReplayStatus.Warnings ? 0 : 1;
1064
+ }
1065
+ async function bundleReplayScaffold(args) {
1066
+ const cwd = resolveCwd(args);
1067
+ const target = args.positional[0];
1068
+ if (target !== 'github-actions') {
1069
+ process.stderr.write('Usage: shrk bundle replay scaffold github-actions [--schedule weekly|daily|manual] [--with-report-site] [--output <path>] [--write] [--force]\n');
1070
+ return 2;
1071
+ }
1072
+ const scheduleRaw = flagString(args, 'schedule') ?? 'weekly';
1073
+ const validSchedules = new Set(['weekly', 'daily', 'manual']);
1074
+ if (!validSchedules.has(scheduleRaw)) {
1075
+ process.stderr.write(`Unknown --schedule "${scheduleRaw}". Use weekly|daily|manual.\n`);
1076
+ return 2;
1077
+ }
1078
+ const schedule = scheduleRaw;
1079
+ const body = renderBundleReplayWorkflow({
1080
+ schedule,
1081
+ ...(flagBool(args, 'with-report-site') ? { withReportSite: true } : {}),
1082
+ });
1083
+ const outputRel = flagString(args, 'output') ?? '.github/workflows/sharkcraft-bundle-replay.yml';
1084
+ const outputAbs = nodePath.isAbsolute(outputRel) ? outputRel : nodePath.resolve(cwd, outputRel);
1085
+ const wantWrite = flagBool(args, 'write');
1086
+ const force = flagBool(args, 'force');
1087
+ if (!wantWrite) {
1088
+ if (flagBool(args, 'json')) {
1089
+ process.stdout.write(asJson({ mode: 'dry-run', output: outputAbs, bytes: body.length, body }) + '\n');
1090
+ return 0;
1091
+ }
1092
+ process.stdout.write(header(`Bundle-replay CI scaffold (dry-run)`));
1093
+ process.stdout.write(`output: ${outputAbs}\n\n${body}`);
1094
+ return 0;
1095
+ }
1096
+ if (existsSync(outputAbs) && !force) {
1097
+ process.stderr.write(`Refusing to overwrite ${outputAbs}. Pass --force.\n`);
1098
+ return 1;
1099
+ }
1100
+ mkdirSync(nodePath.dirname(outputAbs), { recursive: true });
1101
+ writeFileSync(outputAbs, body, 'utf8');
1102
+ if (flagBool(args, 'json'))
1103
+ process.stdout.write(asJson({ mode: 'write', output: outputAbs, bytes: body.length }) + '\n');
1104
+ else
1105
+ process.stdout.write(`Wrote ${outputAbs}\n`);
1106
+ return 0;
1107
+ }
1108
+ async function bundleRecordApply(args) {
1109
+ const id = args.positional[0];
1110
+ const planName = args.positional[1];
1111
+ if (!id || !planName) {
1112
+ process.stderr.write('Usage: shrk bundle record-apply <id> <planName> [--note "<note>"]\n');
1113
+ return 2;
1114
+ }
1115
+ const cwd = resolveCwd(args);
1116
+ const bundle = readFeatureBundle(cwd, id);
1117
+ if (!bundle) {
1118
+ process.stderr.write(`No bundle "${id}".\n`);
1119
+ return 1;
1120
+ }
1121
+ if (!bundle.plans.some((p) => p.name === planName)) {
1122
+ process.stderr.write(`No plan "${planName}" in bundle ${id}.\n`);
1123
+ return 1;
1124
+ }
1125
+ const note = flagString(args, 'note');
1126
+ let updated = markBundlePlanApplied(bundle, planName, note);
1127
+ // Append to the audit log under reports/apply-audit.log
1128
+ const auditFile = nodePath.join(getBundleDir(cwd, id), 'reports', 'apply-audit.log');
1129
+ mkdirSync(nodePath.dirname(auditFile), { recursive: true });
1130
+ const line = `${new Date().toISOString()} applied ${planName}${note ? ' ' + note : ''}\n`;
1131
+ try {
1132
+ const existing = existsSync(auditFile) ? readFileSync(auditFile, 'utf8') : '';
1133
+ writeFileSync(auditFile, existing + line, 'utf8');
1134
+ }
1135
+ catch {
1136
+ writeFileSync(auditFile, line, 'utf8');
1137
+ }
1138
+ updated = recordBundleReport(updated, 'reports/apply-audit.log');
1139
+ updated = recomputeBundleStatus(updated);
1140
+ writeFeatureBundle(cwd, updated);
1141
+ if (flagBool(args, 'json')) {
1142
+ process.stdout.write(asJson({ id, planName, status: 'applied' }) + '\n');
1143
+ return 0;
1144
+ }
1145
+ process.stdout.write(`Recorded apply of ${planName} (bundle ${id}). Status: ${updated.status}\n`);
1146
+ return 0;
1147
+ }
1148
+ async function bundleDiffCommand(args) {
1149
+ const cwd = resolveCwd(args);
1150
+ const aId = args.positional[0];
1151
+ const bId = args.positional[1];
1152
+ if (!aId || !bId) {
1153
+ process.stderr.write('Usage: shrk bundle diff <bundleA> <bundleB> [--format text|markdown|html|json] [--output <path>]\n');
1154
+ return 2;
1155
+ }
1156
+ const formatRaw = (flagString(args, 'format') ?? 'text');
1157
+ const valid = new Set(['text', 'markdown', 'html', 'json']);
1158
+ if (!valid.has(formatRaw)) {
1159
+ process.stderr.write(`Unknown --format "${formatRaw}". Use text|markdown|html|json.\n`);
1160
+ return 2;
1161
+ }
1162
+ const diff = buildBundleDiffFromIds(cwd, aId, bId);
1163
+ if ('error' in diff) {
1164
+ process.stderr.write(diff.error + '\n');
1165
+ return 1;
1166
+ }
1167
+ const body = renderBundleDiff(diff, formatRaw);
1168
+ const output = flagString(args, 'output');
1169
+ if (output) {
1170
+ const abs = nodePath.isAbsolute(output) ? output : nodePath.resolve(cwd, output);
1171
+ mkdirSync(nodePath.dirname(abs), { recursive: true });
1172
+ writeFileSync(abs, body, 'utf8');
1173
+ process.stdout.write(`Wrote ${abs}\n`);
1174
+ return 0;
1175
+ }
1176
+ if (flagBool(args, 'json')) {
1177
+ // honour --json as a shortcut for --format json
1178
+ process.stdout.write(renderBundleDiff(diff, 'json'));
1179
+ return 0;
1180
+ }
1181
+ process.stdout.write(body);
1182
+ return 0;
1183
+ }