godpowers 0.15.0

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 (444) hide show
  1. package/AGENTS.md +37 -0
  2. package/CHANGELOG.md +639 -0
  3. package/INSPIRATION.md +52 -0
  4. package/LICENSE +21 -0
  5. package/README.md +232 -0
  6. package/SKILL.md +500 -0
  7. package/agents/god-archaeologist.md +139 -0
  8. package/agents/god-architect.md +92 -0
  9. package/agents/god-auditor.md +150 -0
  10. package/agents/god-browser-tester.md +144 -0
  11. package/agents/god-context-writer.md +137 -0
  12. package/agents/god-coordinator.md +138 -0
  13. package/agents/god-debt-assessor.md +132 -0
  14. package/agents/god-debugger.md +77 -0
  15. package/agents/god-deploy-engineer.md +87 -0
  16. package/agents/god-deps-auditor.md +111 -0
  17. package/agents/god-design-reviewer.md +137 -0
  18. package/agents/god-designer.md +171 -0
  19. package/agents/god-docs-writer.md +102 -0
  20. package/agents/god-executor.md +76 -0
  21. package/agents/god-explorer.md +110 -0
  22. package/agents/god-harden-auditor.md +163 -0
  23. package/agents/god-incident-investigator.md +144 -0
  24. package/agents/god-launch-strategist.md +103 -0
  25. package/agents/god-migration-strategist.md +126 -0
  26. package/agents/god-observability-engineer.md +76 -0
  27. package/agents/god-orchestrator.md +728 -0
  28. package/agents/god-org-context-loader.md +124 -0
  29. package/agents/god-planner.md +73 -0
  30. package/agents/god-pm.md +105 -0
  31. package/agents/god-quality-reviewer.md +74 -0
  32. package/agents/god-reconciler.md +230 -0
  33. package/agents/god-reconstructor.md +124 -0
  34. package/agents/god-repo-scaffolder.md +60 -0
  35. package/agents/god-retrospective.md +109 -0
  36. package/agents/god-roadmap-reconciler.md +123 -0
  37. package/agents/god-roadmap-updater.md +89 -0
  38. package/agents/god-roadmapper.md +82 -0
  39. package/agents/god-spec-reviewer.md +70 -0
  40. package/agents/god-spike-runner.md +119 -0
  41. package/agents/god-stack-selector.md +93 -0
  42. package/agents/god-standards-check.md +132 -0
  43. package/agents/god-storyteller.md +116 -0
  44. package/agents/god-updater.md +174 -0
  45. package/bin/install.js +514 -0
  46. package/extensions/data-pack/README.md +33 -0
  47. package/extensions/data-pack/agents/god-dashboard-builder.md +66 -0
  48. package/extensions/data-pack/agents/god-etl-engineer.md +64 -0
  49. package/extensions/data-pack/agents/god-ml-feature-engineer.md +66 -0
  50. package/extensions/data-pack/manifest.yaml +39 -0
  51. package/extensions/data-pack/package.json +42 -0
  52. package/extensions/data-pack/skills/god-dashboard.md +28 -0
  53. package/extensions/data-pack/skills/god-etl.md +28 -0
  54. package/extensions/data-pack/skills/god-ml-feature.md +28 -0
  55. package/extensions/data-pack/workflows/dashboard-arc.yaml +13 -0
  56. package/extensions/data-pack/workflows/etl-arc.yaml +13 -0
  57. package/extensions/data-pack/workflows/ml-feature-arc.yaml +13 -0
  58. package/extensions/launch-pack/README.md +36 -0
  59. package/extensions/launch-pack/agents/god-indie-hackers-strategist.md +128 -0
  60. package/extensions/launch-pack/agents/god-oss-release-strategist.md +125 -0
  61. package/extensions/launch-pack/agents/god-product-hunt-strategist.md +118 -0
  62. package/extensions/launch-pack/agents/god-show-hn-strategist.md +113 -0
  63. package/extensions/launch-pack/manifest.yaml +45 -0
  64. package/extensions/launch-pack/package.json +41 -0
  65. package/extensions/launch-pack/skills/god-indie-hackers.md +39 -0
  66. package/extensions/launch-pack/skills/god-oss-release.md +43 -0
  67. package/extensions/launch-pack/skills/god-product-hunt.md +41 -0
  68. package/extensions/launch-pack/skills/god-show-hn.md +40 -0
  69. package/extensions/launch-pack/workflows/indie-hackers.yaml +13 -0
  70. package/extensions/launch-pack/workflows/oss-release.yaml +13 -0
  71. package/extensions/launch-pack/workflows/product-hunt.yaml +13 -0
  72. package/extensions/launch-pack/workflows/show-hn.yaml +13 -0
  73. package/extensions/security-pack/README.md +48 -0
  74. package/extensions/security-pack/agents/god-hipaa-auditor.md +117 -0
  75. package/extensions/security-pack/agents/god-pci-auditor.md +100 -0
  76. package/extensions/security-pack/agents/god-soc2-auditor.md +107 -0
  77. package/extensions/security-pack/manifest.yaml +39 -0
  78. package/extensions/security-pack/package.json +42 -0
  79. package/extensions/security-pack/skills/god-hipaa-audit.md +41 -0
  80. package/extensions/security-pack/skills/god-pci-audit.md +40 -0
  81. package/extensions/security-pack/skills/god-soc2-audit.md +42 -0
  82. package/extensions/security-pack/workflows/hipaa-arc.yaml +15 -0
  83. package/extensions/security-pack/workflows/pci-arc.yaml +15 -0
  84. package/extensions/security-pack/workflows/soc2-arc.yaml +15 -0
  85. package/hooks/pre-tool-use.sh +40 -0
  86. package/hooks/session-start.sh +74 -0
  87. package/lib/README.md +28 -0
  88. package/lib/agent-browser-driver.js +215 -0
  89. package/lib/agent-cache.js +194 -0
  90. package/lib/agent-validator.js +275 -0
  91. package/lib/artifact-diff.js +168 -0
  92. package/lib/artifact-linter.js +142 -0
  93. package/lib/awesome-design.js +312 -0
  94. package/lib/browser-bridge.js +209 -0
  95. package/lib/budget.js +215 -0
  96. package/lib/checkpoint.js +390 -0
  97. package/lib/code-scanner.js +262 -0
  98. package/lib/context-budget.js +170 -0
  99. package/lib/context-writer.js +348 -0
  100. package/lib/cost-tracker.js +325 -0
  101. package/lib/cross-artifact-impact.js +162 -0
  102. package/lib/cross-repo-linkage.js +150 -0
  103. package/lib/design-detector.js +167 -0
  104. package/lib/design-spec.js +348 -0
  105. package/lib/drift-detector.js +212 -0
  106. package/lib/event-reader.js +174 -0
  107. package/lib/events.js +183 -0
  108. package/lib/extensions.js +257 -0
  109. package/lib/have-nots-validator.js +647 -0
  110. package/lib/impact.js +314 -0
  111. package/lib/impeccable-bridge.js +139 -0
  112. package/lib/intent.js +177 -0
  113. package/lib/linkage.js +232 -0
  114. package/lib/meta-linter.js +263 -0
  115. package/lib/multi-repo-detector.js +182 -0
  116. package/lib/otel-exporter.js +308 -0
  117. package/lib/recipes.js +186 -0
  118. package/lib/reverse-sync.js +332 -0
  119. package/lib/review-required.js +224 -0
  120. package/lib/router.js +278 -0
  121. package/lib/runtime-audit.js +455 -0
  122. package/lib/runtime-test.js +309 -0
  123. package/lib/skillui-bridge.js +216 -0
  124. package/lib/state-lock.js +201 -0
  125. package/lib/state.js +142 -0
  126. package/lib/story-validator.js +301 -0
  127. package/lib/suite-state.js +220 -0
  128. package/lib/workflow-parser.js +109 -0
  129. package/lib/workflow-runner.js +221 -0
  130. package/package.json +63 -0
  131. package/references/HAVE-NOTS.md +573 -0
  132. package/references/building/BUILD-ANTIPATTERNS.md +102 -0
  133. package/references/building/BUILD-VERTICAL-SLICES.md +75 -0
  134. package/references/building/BUILD-WAVES.md +61 -0
  135. package/references/building/README.md +17 -0
  136. package/references/design/COLOR.md +122 -0
  137. package/references/design/DESIGN-ANATOMY.md +121 -0
  138. package/references/design/DESIGN-ANTIPATTERNS.md +108 -0
  139. package/references/design/INTERACTION.md +148 -0
  140. package/references/design/MOTION.md +120 -0
  141. package/references/design/RESPONSIVE.md +157 -0
  142. package/references/design/SPATIAL.md +109 -0
  143. package/references/design/TYPOGRAPHY.md +121 -0
  144. package/references/design/UX-WRITING.md +135 -0
  145. package/references/orchestration/MODE-DETECTION.md +74 -0
  146. package/references/orchestration/README.md +18 -0
  147. package/references/orchestration/SCALE-DETECTION.md +81 -0
  148. package/references/planning/ARCH-ANATOMY.md +143 -0
  149. package/references/planning/ARCH-ANTIPATTERNS.md +52 -0
  150. package/references/planning/PRD-ANATOMY.md +117 -0
  151. package/references/planning/PRD-ANTIPATTERNS.md +138 -0
  152. package/references/planning/README.md +16 -0
  153. package/references/planning/ROADMAP-ANATOMY.md +43 -0
  154. package/references/planning/ROADMAP-ANTIPATTERNS.md +94 -0
  155. package/references/planning/STACK-ANATOMY.md +60 -0
  156. package/references/planning/STACK-ANTIPATTERNS.md +95 -0
  157. package/references/shared/GLOSSARY.md +80 -0
  158. package/references/shared/ORCHESTRATORS.md +76 -0
  159. package/references/shared/README.md +14 -0
  160. package/references/shipping/DEPLOY-ANTIPATTERNS.md +64 -0
  161. package/references/shipping/DEPLOY-PATTERNS.md +110 -0
  162. package/references/shipping/HARDEN-ANTIPATTERNS.md +66 -0
  163. package/references/shipping/HARDEN-OWASP-WORKSHEETS.md +89 -0
  164. package/references/shipping/LAUNCH-ANTIPATTERNS.md +68 -0
  165. package/references/shipping/OBSERVE-ANTIPATTERNS.md +62 -0
  166. package/references/shipping/OBSERVE-SLO-EXAMPLES.md +107 -0
  167. package/references/shipping/README.md +18 -0
  168. package/routing/god-add-backlog.yaml +24 -0
  169. package/routing/god-add-tests.yaml +27 -0
  170. package/routing/god-add-todo.yaml +24 -0
  171. package/routing/god-agent-audit.yaml +24 -0
  172. package/routing/god-arch.yaml +46 -0
  173. package/routing/god-archaeology.yaml +28 -0
  174. package/routing/god-audit.yaml +32 -0
  175. package/routing/god-budget.yaml +24 -0
  176. package/routing/god-build-agent.yaml +24 -0
  177. package/routing/god-build.yaml +46 -0
  178. package/routing/god-cache-clear.yaml +24 -0
  179. package/routing/god-check-todos.yaml +24 -0
  180. package/routing/god-context-scan.yaml +24 -0
  181. package/routing/god-context.yaml +44 -0
  182. package/routing/god-cost.yaml +24 -0
  183. package/routing/god-debug.yaml +28 -0
  184. package/routing/god-deploy.yaml +34 -0
  185. package/routing/god-design-impact.yaml +25 -0
  186. package/routing/god-design.yaml +67 -0
  187. package/routing/god-discuss.yaml +27 -0
  188. package/routing/god-docs.yaml +33 -0
  189. package/routing/god-doctor.yaml +27 -0
  190. package/routing/god-explore.yaml +27 -0
  191. package/routing/god-extension-add.yaml +24 -0
  192. package/routing/god-extension-info.yaml +24 -0
  193. package/routing/god-extension-list.yaml +24 -0
  194. package/routing/god-extension-remove.yaml +24 -0
  195. package/routing/god-extract-learnings.yaml +24 -0
  196. package/routing/god-fast.yaml +27 -0
  197. package/routing/god-feature.yaml +34 -0
  198. package/routing/god-graph.yaml +24 -0
  199. package/routing/god-harden.yaml +41 -0
  200. package/routing/god-help.yaml +27 -0
  201. package/routing/god-hotfix.yaml +34 -0
  202. package/routing/god-hygiene.yaml +28 -0
  203. package/routing/god-init.yaml +37 -0
  204. package/routing/god-intel.yaml +24 -0
  205. package/routing/god-launch.yaml +41 -0
  206. package/routing/god-lifecycle.yaml +27 -0
  207. package/routing/god-link.yaml +24 -0
  208. package/routing/god-lint.yaml +24 -0
  209. package/routing/god-list-assumptions.yaml +27 -0
  210. package/routing/god-locate.yaml +24 -0
  211. package/routing/god-logs.yaml +24 -0
  212. package/routing/god-map-codebase.yaml +24 -0
  213. package/routing/god-metrics.yaml +24 -0
  214. package/routing/god-mode.yaml +31 -0
  215. package/routing/god-next.yaml +27 -0
  216. package/routing/god-note.yaml +24 -0
  217. package/routing/god-observe.yaml +34 -0
  218. package/routing/god-org-context.yaml +28 -0
  219. package/routing/god-party.yaml +24 -0
  220. package/routing/god-pause-work.yaml +27 -0
  221. package/routing/god-plant-seed.yaml +24 -0
  222. package/routing/god-postmortem.yaml +34 -0
  223. package/routing/god-pr-branch.yaml +25 -0
  224. package/routing/god-prd.yaml +49 -0
  225. package/routing/god-quick.yaml +28 -0
  226. package/routing/god-reconcile.yaml +48 -0
  227. package/routing/god-reconstruct.yaml +36 -0
  228. package/routing/god-redo.yaml +27 -0
  229. package/routing/god-refactor.yaml +36 -0
  230. package/routing/god-repair.yaml +27 -0
  231. package/routing/god-repo.yaml +35 -0
  232. package/routing/god-restore.yaml +27 -0
  233. package/routing/god-resume-work.yaml +27 -0
  234. package/routing/god-review-changes.yaml +25 -0
  235. package/routing/god-review.yaml +28 -0
  236. package/routing/god-roadmap-check.yaml +39 -0
  237. package/routing/god-roadmap-update.yaml +37 -0
  238. package/routing/god-roadmap.yaml +42 -0
  239. package/routing/god-rollback.yaml +27 -0
  240. package/routing/god-scan.yaml +24 -0
  241. package/routing/god-set-profile.yaml +24 -0
  242. package/routing/god-settings.yaml +24 -0
  243. package/routing/god-skip.yaml +27 -0
  244. package/routing/god-smite.yaml +29 -0
  245. package/routing/god-spike.yaml +35 -0
  246. package/routing/god-sprint.yaml +25 -0
  247. package/routing/god-stack.yaml +41 -0
  248. package/routing/god-standards.yaml +24 -0
  249. package/routing/god-status.yaml +27 -0
  250. package/routing/god-stories.yaml +24 -0
  251. package/routing/god-story-build.yaml +25 -0
  252. package/routing/god-story-close.yaml +25 -0
  253. package/routing/god-story-verify.yaml +25 -0
  254. package/routing/god-story.yaml +24 -0
  255. package/routing/god-suite-init.yaml +24 -0
  256. package/routing/god-suite-patch.yaml +25 -0
  257. package/routing/god-suite-release.yaml +25 -0
  258. package/routing/god-suite-status.yaml +25 -0
  259. package/routing/god-suite-sync.yaml +25 -0
  260. package/routing/god-sync.yaml +33 -0
  261. package/routing/god-tech-debt.yaml +32 -0
  262. package/routing/god-test-extension.yaml +24 -0
  263. package/routing/god-test-runtime.yaml +25 -0
  264. package/routing/god-thread.yaml +24 -0
  265. package/routing/god-trace.yaml +24 -0
  266. package/routing/god-undo.yaml +27 -0
  267. package/routing/god-update-deps.yaml +39 -0
  268. package/routing/god-upgrade.yaml +33 -0
  269. package/routing/god-version.yaml +24 -0
  270. package/routing/god-workstream.yaml +24 -0
  271. package/routing/god.yaml +24 -0
  272. package/routing/recipes/add-feature-defer-current-milestone.yaml +21 -0
  273. package/routing/recipes/add-feature-future-conditional.yaml +21 -0
  274. package/routing/recipes/add-feature-mid-arc-pause.yaml +33 -0
  275. package/routing/recipes/add-feature-next-milestone.yaml +23 -0
  276. package/routing/recipes/add-feature-parallel.yaml +29 -0
  277. package/routing/recipes/add-feature-prd-update.yaml +21 -0
  278. package/routing/recipes/add-feature-small.yaml +24 -0
  279. package/routing/recipes/add-feature-tiny.yaml +24 -0
  280. package/routing/recipes/bluefield-org-aware.yaml +27 -0
  281. package/routing/recipes/broken-install.yaml +22 -0
  282. package/routing/recipes/brownfield-onboarding.yaml +32 -0
  283. package/routing/recipes/bug-no-urgency.yaml +21 -0
  284. package/routing/recipes/capture-idea.yaml +22 -0
  285. package/routing/recipes/capture-todo.yaml +21 -0
  286. package/routing/recipes/clean-pr.yaml +21 -0
  287. package/routing/recipes/code-cleanup.yaml +23 -0
  288. package/routing/recipes/docs-drift.yaml +21 -0
  289. package/routing/recipes/existing-codebase-onboarding.yaml +32 -0
  290. package/routing/recipes/extract-learnings.yaml +22 -0
  291. package/routing/recipes/greenfield-fast.yaml +25 -0
  292. package/routing/recipes/greenfield-manual.yaml +32 -0
  293. package/routing/recipes/greenfield-with-ideation.yaml +29 -0
  294. package/routing/recipes/incident-postmortem.yaml +24 -0
  295. package/routing/recipes/major-framework-upgrade.yaml +23 -0
  296. package/routing/recipes/monthly-deps.yaml +22 -0
  297. package/routing/recipes/multi-repo-suite.yaml +56 -0
  298. package/routing/recipes/parallel-engineers.yaml +26 -0
  299. package/routing/recipes/pause-handoff.yaml +21 -0
  300. package/routing/recipes/production-broken.yaml +26 -0
  301. package/routing/recipes/rerun-tier.yaml +21 -0
  302. package/routing/recipes/returning-after-break.yaml +31 -0
  303. package/routing/recipes/state-drift.yaml +21 -0
  304. package/routing/recipes/undo-last.yaml +21 -0
  305. package/routing/recipes/weekly-health-check.yaml +24 -0
  306. package/routing/recipes/whats-next.yaml +22 -0
  307. package/routing/recipes/where-am-i.yaml +21 -0
  308. package/schema/events.v1.json +63 -0
  309. package/schema/extension-manifest.v1.json +84 -0
  310. package/schema/intent.v1.yaml.json +116 -0
  311. package/schema/recipe.v1.json +120 -0
  312. package/schema/routing.v1.json +163 -0
  313. package/schema/state.v1.json +146 -0
  314. package/schema/workflow.v1.json +96 -0
  315. package/skills/god-add-backlog.md +40 -0
  316. package/skills/god-add-tests.md +53 -0
  317. package/skills/god-add-todo.md +32 -0
  318. package/skills/god-agent-audit.md +87 -0
  319. package/skills/god-arch.md +81 -0
  320. package/skills/god-archaeology.md +48 -0
  321. package/skills/god-audit.md +65 -0
  322. package/skills/god-budget.md +103 -0
  323. package/skills/god-build-agent.md +91 -0
  324. package/skills/god-build.md +90 -0
  325. package/skills/god-cache-clear.md +75 -0
  326. package/skills/god-check-todos.md +42 -0
  327. package/skills/god-context-scan.md +125 -0
  328. package/skills/god-context.md +147 -0
  329. package/skills/god-cost.md +118 -0
  330. package/skills/god-debug.md +30 -0
  331. package/skills/god-deploy.md +76 -0
  332. package/skills/god-design-impact.md +86 -0
  333. package/skills/god-design.md +275 -0
  334. package/skills/god-discuss.md +46 -0
  335. package/skills/god-docs.md +81 -0
  336. package/skills/god-doctor.md +94 -0
  337. package/skills/god-explore.md +50 -0
  338. package/skills/god-export-otel.md +87 -0
  339. package/skills/god-extension-add.md +79 -0
  340. package/skills/god-extension-info.md +75 -0
  341. package/skills/god-extension-list.md +55 -0
  342. package/skills/god-extension-remove.md +66 -0
  343. package/skills/god-extract-learnings.md +60 -0
  344. package/skills/god-fast.md +47 -0
  345. package/skills/god-feature.md +114 -0
  346. package/skills/god-graph.md +56 -0
  347. package/skills/god-harden.md +106 -0
  348. package/skills/god-help.md +66 -0
  349. package/skills/god-hotfix.md +139 -0
  350. package/skills/god-hygiene.md +104 -0
  351. package/skills/god-init.md +161 -0
  352. package/skills/god-intel.md +36 -0
  353. package/skills/god-launch.md +86 -0
  354. package/skills/god-lifecycle.md +119 -0
  355. package/skills/god-link.md +90 -0
  356. package/skills/god-lint.md +128 -0
  357. package/skills/god-list-assumptions.md +56 -0
  358. package/skills/god-locate.md +97 -0
  359. package/skills/god-logs.md +57 -0
  360. package/skills/god-map-codebase.md +45 -0
  361. package/skills/god-metrics.md +51 -0
  362. package/skills/god-mode.md +159 -0
  363. package/skills/god-next.md +257 -0
  364. package/skills/god-note.md +39 -0
  365. package/skills/god-observe.md +76 -0
  366. package/skills/god-org-context.md +81 -0
  367. package/skills/god-party.md +87 -0
  368. package/skills/god-pause-work.md +64 -0
  369. package/skills/god-plant-seed.md +59 -0
  370. package/skills/god-postmortem.md +103 -0
  371. package/skills/god-pr-branch.md +50 -0
  372. package/skills/god-prd.md +90 -0
  373. package/skills/god-quick.md +50 -0
  374. package/skills/god-reconcile.md +90 -0
  375. package/skills/god-reconstruct.md +72 -0
  376. package/skills/god-redo.md +73 -0
  377. package/skills/god-refactor.md +137 -0
  378. package/skills/god-repair.md +82 -0
  379. package/skills/god-repo.md +49 -0
  380. package/skills/god-restore.md +91 -0
  381. package/skills/god-resume-work.md +42 -0
  382. package/skills/god-review-changes.md +93 -0
  383. package/skills/god-review.md +52 -0
  384. package/skills/god-roadmap-check.md +66 -0
  385. package/skills/god-roadmap-update.md +64 -0
  386. package/skills/god-roadmap.md +77 -0
  387. package/skills/god-rollback.md +88 -0
  388. package/skills/god-scan.md +106 -0
  389. package/skills/god-set-profile.md +58 -0
  390. package/skills/god-settings.md +44 -0
  391. package/skills/god-skip.md +78 -0
  392. package/skills/god-smite.md +86 -0
  393. package/skills/god-spike.md +120 -0
  394. package/skills/god-sprint.md +77 -0
  395. package/skills/god-stack.md +74 -0
  396. package/skills/god-standards.md +62 -0
  397. package/skills/god-status.md +99 -0
  398. package/skills/god-stories.md +60 -0
  399. package/skills/god-story-build.md +76 -0
  400. package/skills/god-story-close.md +82 -0
  401. package/skills/god-story-verify.md +71 -0
  402. package/skills/god-story.md +55 -0
  403. package/skills/god-suite-init.md +75 -0
  404. package/skills/god-suite-patch.md +64 -0
  405. package/skills/god-suite-release.md +58 -0
  406. package/skills/god-suite-status.md +63 -0
  407. package/skills/god-suite-sync.md +49 -0
  408. package/skills/god-sync.md +102 -0
  409. package/skills/god-tech-debt.md +56 -0
  410. package/skills/god-test-extension.md +87 -0
  411. package/skills/god-test-runtime.md +144 -0
  412. package/skills/god-thread.md +39 -0
  413. package/skills/god-trace.md +50 -0
  414. package/skills/god-undo.md +68 -0
  415. package/skills/god-update-deps.md +134 -0
  416. package/skills/god-upgrade.md +139 -0
  417. package/skills/god-version.md +37 -0
  418. package/skills/god-workstream.md +61 -0
  419. package/skills/god.md +207 -0
  420. package/templates/ARCH.md +99 -0
  421. package/templates/DEPS-AUDIT.md +66 -0
  422. package/templates/DESIGN.md +71 -0
  423. package/templates/DOCS-UPDATE-LOG.md +64 -0
  424. package/templates/HARDEN-FINDINGS.md +69 -0
  425. package/templates/MIGRATION.md +86 -0
  426. package/templates/POSTMORTEM.md +88 -0
  427. package/templates/PRD.md +80 -0
  428. package/templates/PROGRESS.md +49 -0
  429. package/templates/ROADMAP.md +47 -0
  430. package/templates/SPIKE.md +72 -0
  431. package/templates/STACK-DECISION.md +61 -0
  432. package/workflows/audit-only.yaml +22 -0
  433. package/workflows/bluefield-arc.yaml +87 -0
  434. package/workflows/brownfield-arc.yaml +44 -0
  435. package/workflows/deps-audit.yaml +56 -0
  436. package/workflows/docs-arc.yaml +22 -0
  437. package/workflows/feature-arc.yaml +59 -0
  438. package/workflows/full-arc.yaml +84 -0
  439. package/workflows/hotfix-arc.yaml +59 -0
  440. package/workflows/hygiene.yaml +43 -0
  441. package/workflows/migration-arc.yaml +73 -0
  442. package/workflows/postmortem.yaml +31 -0
  443. package/workflows/refactor-arc.yaml +59 -0
  444. package/workflows/spike.yaml +23 -0
@@ -0,0 +1,325 @@
1
+ /**
2
+ * Cost Tracker - token + dollar accounting for godpowers runs.
3
+ *
4
+ * The model.call event already exists in the vocabulary. This module
5
+ * adds a typed recorder, per-tier / per-agent / per-model aggregation,
6
+ * and a savings counter (cache hits = tokens that would have been
7
+ * spent but weren't).
8
+ *
9
+ * Token costs surface in two places:
10
+ * 1. Real spend: every LLM call records tokens_in / tokens_out / cost_usd
11
+ * 2. Avoided spend: cache.hit events record savings_tokens / savings_usd
12
+ *
13
+ * Public API:
14
+ * recordCost(handle, attrs) - emit a cost.recorded event
15
+ * recordCacheHit(handle, attrs) - emit a cache.hit event with savings
16
+ * recordCacheMiss(handle, attrs) - emit a cache.miss event
17
+ * aggregate(projectRoot, runIds?) -> { perTier, perAgent, perModel, totals }
18
+ * priceTokens({model, in, out}) -> usd estimate
19
+ *
20
+ * Pricing table is approximate, in USD per 1M tokens, May 2026 ballpark.
21
+ * Overridable via opts.pricing in aggregate().
22
+ */
23
+
24
+ const events = require('./events');
25
+
26
+ const DEFAULT_PRICING = {
27
+ // Per 1M tokens (input, output). Keep approximate; user can override.
28
+ 'claude-3-5-sonnet': { in: 3.00, out: 15.00 },
29
+ 'claude-3-5-haiku': { in: 0.80, out: 4.00 },
30
+ 'claude-3-opus': { in: 15.00, out: 75.00 },
31
+ 'claude-4': { in: 5.00, out: 25.00 }, // estimate
32
+ 'gpt-4o': { in: 2.50, out: 10.00 },
33
+ 'gpt-4o-mini': { in: 0.15, out: 0.60 },
34
+ 'gpt-4-turbo': { in: 10.00, out: 30.00 },
35
+ 'gpt-5': { in: 5.00, out: 20.00 }, // estimate
36
+ 'gemini-1.5-pro': { in: 3.50, out: 10.50 },
37
+ 'gemini-1.5-flash': { in: 0.075, out: 0.30 },
38
+ 'o1': { in: 15.00, out: 60.00 },
39
+ 'o3-mini': { in: 3.00, out: 12.00 },
40
+ // Fallback bucket
41
+ '_unknown': { in: 5.00, out: 15.00 }
42
+ };
43
+
44
+ /**
45
+ * Compute USD cost from token counts.
46
+ */
47
+ function priceTokens({ model, in: inTok, out: outTok, pricing }) {
48
+ const table = pricing || DEFAULT_PRICING;
49
+ const p = table[model] || table[normalizeModel(model)] || table._unknown;
50
+ const inCost = (inTok || 0) * p.in / 1_000_000;
51
+ const outCost = (outTok || 0) * p.out / 1_000_000;
52
+ return Number((inCost + outCost).toFixed(6));
53
+ }
54
+
55
+ function normalizeModel(m) {
56
+ if (!m) return '_unknown';
57
+ const s = String(m).toLowerCase();
58
+ // Order matters: "gemini" contains "mini" as a substring, and "claude" can
59
+ // contain "o" etc. Check the most specific tokens first.
60
+ if (s.includes('haiku')) return 'claude-3-5-haiku';
61
+ if (s.includes('sonnet')) return 'claude-3-5-sonnet';
62
+ if (s.includes('opus')) return 'claude-3-opus';
63
+ if (s.includes('flash')) return 'gemini-1.5-flash';
64
+ if (s.includes('gemini')) return 'gemini-1.5-pro';
65
+ if (s.includes('claude')) return 'claude-4';
66
+ if (s.includes('4o-mini') || s.endsWith('-mini')) return 'gpt-4o-mini';
67
+ if (s.includes('4o')) return 'gpt-4o';
68
+ if (s.includes('gpt-5') || s === 'gpt5') return 'gpt-5';
69
+ if (s.includes('gpt-4') || s === 'gpt4') return 'gpt-4-turbo';
70
+ if (s.includes('o3')) return 'o3-mini';
71
+ if (s.includes('o1')) return 'o1';
72
+ return '_unknown';
73
+ }
74
+
75
+ /**
76
+ * Record a real cost (spend that happened). The caller has a handle
77
+ * from events.startRun.
78
+ *
79
+ * attrs: {
80
+ * model, tokens_in, tokens_out,
81
+ * agent?, tier?,
82
+ * cost_usd? (optional explicit override),
83
+ * source? ('live' | 'estimated', default 'estimated')
84
+ * }
85
+ *
86
+ * The `source` field distinguishes real per-call token counts reported
87
+ * by the AI tool ('live') from heuristic byte-based estimates the
88
+ * orchestrator computes itself ('estimated'). `/god-cost --strict`
89
+ * uses this to fail loudly when any record is estimated.
90
+ */
91
+ function recordCost(handle, attrs) {
92
+ const source = attrs.source === 'live' ? 'live' : 'estimated';
93
+ const cost_usd = attrs.cost_usd != null
94
+ ? attrs.cost_usd
95
+ : priceTokens({ model: attrs.model, in: attrs.tokens_in, out: attrs.tokens_out, pricing: attrs.pricing });
96
+ handle.emit({
97
+ span_id: attrs.span_id || handle.rootSpanId,
98
+ name: 'cost.recorded',
99
+ attrs: {
100
+ model: attrs.model,
101
+ tokens_in: attrs.tokens_in || 0,
102
+ tokens_out: attrs.tokens_out || 0,
103
+ cost_usd,
104
+ agent: attrs.agent,
105
+ tier: attrs.tier,
106
+ source
107
+ }
108
+ });
109
+ return cost_usd;
110
+ }
111
+
112
+ /**
113
+ * Canonical entry point for AI tools that have actual per-call token
114
+ * counts from the provider's API response. Records a 'live' cost.
115
+ *
116
+ * attrs: { model, tokens_in, tokens_out, agent?, tier?, cost_usd? }
117
+ *
118
+ * Use this rather than recordCost() directly when you have real
119
+ * usage numbers; the `source: 'live'` tag is what lets /god-cost
120
+ * --strict trust the totals.
121
+ */
122
+ function recordModelCall(handle, attrs) {
123
+ return recordCost(handle, { ...attrs, source: 'live' });
124
+ }
125
+
126
+ /**
127
+ * Record a cache hit. Estimates the savings as what the spend would
128
+ * have been if the agent had been spawned.
129
+ */
130
+ function recordCacheHit(handle, attrs) {
131
+ const savings_usd = attrs.savings_usd != null
132
+ ? attrs.savings_usd
133
+ : priceTokens({
134
+ model: attrs.model,
135
+ in: attrs.would_have_spent_in || 0,
136
+ out: attrs.would_have_spent_out || 0,
137
+ pricing: attrs.pricing
138
+ });
139
+ handle.emit({
140
+ span_id: attrs.span_id || handle.rootSpanId,
141
+ name: 'cache.hit',
142
+ attrs: {
143
+ cache_key: attrs.cache_key,
144
+ agent: attrs.agent,
145
+ tier: attrs.tier,
146
+ model: attrs.model,
147
+ savings_tokens: (attrs.would_have_spent_in || 0) + (attrs.would_have_spent_out || 0),
148
+ savings_usd
149
+ }
150
+ });
151
+ return savings_usd;
152
+ }
153
+
154
+ function recordCacheMiss(handle, attrs) {
155
+ handle.emit({
156
+ span_id: attrs.span_id || handle.rootSpanId,
157
+ name: 'cache.miss',
158
+ attrs: {
159
+ cache_key: attrs.cache_key,
160
+ agent: attrs.agent,
161
+ tier: attrs.tier,
162
+ reason: attrs.reason || 'no-entry'
163
+ }
164
+ });
165
+ }
166
+
167
+ /**
168
+ * Aggregate cost events across one or all runs.
169
+ *
170
+ * Returns:
171
+ * {
172
+ * totals: {
173
+ * spent_usd, spent_tokens, saved_usd, saved_tokens,
174
+ * cache_hits, cache_misses, hit_rate, calls
175
+ * },
176
+ * perTier: { 'tier-1': {spent_usd, spent_tokens, calls, ...}, ... },
177
+ * perAgent: { 'god-pm': {...}, ... },
178
+ * perModel: { 'claude-3-5-sonnet': {...}, ... }
179
+ * }
180
+ */
181
+ function aggregate(projectRoot, runIds) {
182
+ if (!runIds) runIds = events.listRuns(projectRoot);
183
+ if (!Array.isArray(runIds)) runIds = [runIds];
184
+
185
+ const totals = {
186
+ spent_usd: 0, spent_tokens: 0,
187
+ saved_usd: 0, saved_tokens: 0,
188
+ cache_hits: 0, cache_misses: 0, hit_rate: 0,
189
+ calls: 0,
190
+ // Split by data source. live = AI tool reported real token counts;
191
+ // estimated = orchestrator's heuristic byte-based estimate.
192
+ live_calls: 0, live_usd: 0, live_tokens: 0,
193
+ estimated_calls: 0, estimated_usd: 0, estimated_tokens: 0
194
+ };
195
+ const perTier = {};
196
+ const perAgent = {};
197
+ const perModel = {};
198
+
199
+ function bump(bucket, key, fields) {
200
+ if (!bucket[key]) {
201
+ bucket[key] = { spent_usd: 0, spent_tokens: 0, saved_usd: 0,
202
+ saved_tokens: 0, calls: 0, cache_hits: 0 };
203
+ }
204
+ for (const [k, v] of Object.entries(fields)) {
205
+ bucket[key][k] = (bucket[key][k] || 0) + v;
206
+ }
207
+ }
208
+
209
+ for (const runId of runIds) {
210
+ for (const e of events.readRun(projectRoot, runId)) {
211
+ if (e.name === 'cost.recorded') {
212
+ const a = e.attrs || {};
213
+ const usd = a.cost_usd || 0;
214
+ const tok = (a.tokens_in || 0) + (a.tokens_out || 0);
215
+ const source = a.source === 'live' ? 'live' : 'estimated';
216
+ totals.spent_usd += usd;
217
+ totals.spent_tokens += tok;
218
+ totals.calls += 1;
219
+ if (source === 'live') {
220
+ totals.live_calls += 1;
221
+ totals.live_usd += usd;
222
+ totals.live_tokens += tok;
223
+ } else {
224
+ totals.estimated_calls += 1;
225
+ totals.estimated_usd += usd;
226
+ totals.estimated_tokens += tok;
227
+ }
228
+ if (a.tier) bump(perTier, a.tier, { spent_usd: usd, spent_tokens: tok, calls: 1 });
229
+ if (a.agent) bump(perAgent, a.agent, { spent_usd: usd, spent_tokens: tok, calls: 1 });
230
+ if (a.model) bump(perModel, a.model, { spent_usd: usd, spent_tokens: tok, calls: 1 });
231
+ } else if (e.name === 'cache.hit') {
232
+ const a = e.attrs || {};
233
+ const usd = a.savings_usd || 0;
234
+ const tok = a.savings_tokens || 0;
235
+ totals.saved_usd += usd;
236
+ totals.saved_tokens += tok;
237
+ totals.cache_hits += 1;
238
+ if (a.tier) bump(perTier, a.tier, { saved_usd: usd, saved_tokens: tok, cache_hits: 1 });
239
+ if (a.agent) bump(perAgent, a.agent, { saved_usd: usd, saved_tokens: tok, cache_hits: 1 });
240
+ } else if (e.name === 'cache.miss') {
241
+ totals.cache_misses += 1;
242
+ }
243
+ }
244
+ }
245
+
246
+ const attempts = totals.cache_hits + totals.cache_misses;
247
+ totals.hit_rate = attempts > 0 ? totals.cache_hits / attempts : 0;
248
+ for (const m of ['spent_usd', 'saved_usd', 'live_usd', 'estimated_usd']) {
249
+ totals[m] = Number(totals[m].toFixed(6));
250
+ }
251
+
252
+ return { totals, perTier, perAgent, perModel };
253
+ }
254
+
255
+ /**
256
+ * Check whether every cost.recorded event has source: 'live'.
257
+ *
258
+ * Returns { strict: bool, live_calls, estimated_calls, total_calls }.
259
+ * Used by /god-cost --strict to fail when any record is estimated.
260
+ */
261
+ function isStrictLive(projectRoot, runIds) {
262
+ const agg = aggregate(projectRoot, runIds);
263
+ const t = agg.totals;
264
+ return {
265
+ strict: t.calls > 0 && t.estimated_calls === 0,
266
+ live_calls: t.live_calls,
267
+ estimated_calls: t.estimated_calls,
268
+ total_calls: t.calls
269
+ };
270
+ }
271
+
272
+ /**
273
+ * Format an aggregate as a readable report.
274
+ */
275
+ function formatReport(agg) {
276
+ const t = agg.totals;
277
+ const lines = [];
278
+ lines.push('GODPOWERS COST REPORT');
279
+ lines.push('');
280
+ lines.push(`Spent: $${t.spent_usd.toFixed(4)} across ${t.calls} model calls (${t.spent_tokens} tokens)`);
281
+ if (t.live_calls > 0 || t.estimated_calls > 0) {
282
+ lines.push(` Live: $${t.live_usd.toFixed(4)} (${t.live_calls} calls, ${t.live_tokens} tokens)`);
283
+ lines.push(` Estimated: $${t.estimated_usd.toFixed(4)} (${t.estimated_calls} calls, ${t.estimated_tokens} tokens)`);
284
+ }
285
+ lines.push(`Saved: $${t.saved_usd.toFixed(4)} via ${t.cache_hits} cache hits (${t.saved_tokens} tokens)`);
286
+ lines.push(`Cache hit rate: ${(t.hit_rate * 100).toFixed(1)}% (${t.cache_hits}/${t.cache_hits + t.cache_misses})`);
287
+ lines.push('');
288
+ if (Object.keys(agg.perTier).length > 0) {
289
+ lines.push('Per tier:');
290
+ for (const [k, v] of Object.entries(agg.perTier).sort()) {
291
+ lines.push(` ${k}: $${v.spent_usd.toFixed(4)} (${v.calls} calls, ${v.cache_hits} hits, $${v.saved_usd.toFixed(4)} saved)`);
292
+ }
293
+ lines.push('');
294
+ }
295
+ if (Object.keys(agg.perAgent).length > 0) {
296
+ lines.push('Per agent (top 10 by spend):');
297
+ const sorted = Object.entries(agg.perAgent)
298
+ .sort((a, b) => b[1].spent_usd - a[1].spent_usd)
299
+ .slice(0, 10);
300
+ for (const [k, v] of sorted) {
301
+ lines.push(` ${k}: $${v.spent_usd.toFixed(4)} (${v.calls} calls)`);
302
+ }
303
+ lines.push('');
304
+ }
305
+ if (Object.keys(agg.perModel).length > 0) {
306
+ lines.push('Per model:');
307
+ for (const [k, v] of Object.entries(agg.perModel).sort()) {
308
+ lines.push(` ${k}: $${v.spent_usd.toFixed(4)} (${v.calls} calls)`);
309
+ }
310
+ }
311
+ return lines.join('\n');
312
+ }
313
+
314
+ module.exports = {
315
+ recordCost,
316
+ recordModelCall,
317
+ recordCacheHit,
318
+ recordCacheMiss,
319
+ aggregate,
320
+ isStrictLive,
321
+ formatReport,
322
+ priceTokens,
323
+ normalizeModel,
324
+ DEFAULT_PRICING
325
+ };
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Cross-Artifact Impact
3
+ *
4
+ * Generalizes the per-pair impact pattern (DESIGN -> code) to
5
+ * artifact-to-artifact relationships:
6
+ * PRD -> ARCH (requirement removal may leave containers over-spec'd)
7
+ * ARCH -> DESIGN (container split may need DESIGN component re-binding)
8
+ * ARCH -> ROADMAP (container removal may invalidate milestones)
9
+ * STACK -> ARCH (dep change may force ADR flip-point review)
10
+ * STACK -> DESIGN (UI lib change may force token review)
11
+ * PRD -> ROADMAP (requirement change may invalidate milestone gates)
12
+ *
13
+ * Public API:
14
+ * forArtifactPair(projectRoot, sourceType, oldContent, newContent, targetType, targetContent)
15
+ * -> { impacts, severity }
16
+ * suggestArtifactReviews(projectRoot, sourceType, oldContent, newContent)
17
+ * -> [{ targetType, reason, severity }]
18
+ */
19
+
20
+ const impact = require('./impact');
21
+
22
+ /**
23
+ * Define which target artifacts may be impacted by a source artifact change.
24
+ */
25
+ const IMPACT_RULES = {
26
+ prd: [
27
+ {
28
+ target: 'arch',
29
+ check: (idDiff) => idDiff.removed.length > 0,
30
+ reason: (idDiff) => `${idDiff.removed.length} PRD requirement(s) removed; ARCH containers may be over-spec'd`,
31
+ severity: 'warning'
32
+ },
33
+ {
34
+ target: 'roadmap',
35
+ check: (idDiff) => idDiff.removed.length > 0 || idDiff.added.length > 0,
36
+ reason: (idDiff) => `PRD requirements changed; ROADMAP milestone gates may need updating`,
37
+ severity: 'warning'
38
+ },
39
+ {
40
+ target: 'design',
41
+ check: (idDiff, sectionChanges) => sectionChanges.some(c => c.section && c.section.match(/Target Users|Brand|Register/i)),
42
+ reason: () => `PRD target users / register changed; DESIGN PRODUCT.md may need re-aligning`,
43
+ severity: 'info'
44
+ }
45
+ ],
46
+ arch: [
47
+ {
48
+ target: 'design',
49
+ check: (idDiff) => idDiff.removed.some(id => id.startsWith('C-')),
50
+ reason: (idDiff) => `ARCH container removed; DESIGN components bound to it may need re-binding`,
51
+ severity: 'warning'
52
+ },
53
+ {
54
+ target: 'roadmap',
55
+ check: (idDiff) => idDiff.removed.length > 0,
56
+ reason: () => `ARCH structure changed; ROADMAP milestone gates may reference removed elements`,
57
+ severity: 'info'
58
+ }
59
+ ],
60
+ stack: [
61
+ {
62
+ target: 'arch',
63
+ check: (idDiff) => idDiff.removed.length > 0 || idDiff.added.length > 0,
64
+ reason: () => `STACK changes; ADR flip-points may need review`,
65
+ severity: 'warning'
66
+ },
67
+ {
68
+ target: 'design',
69
+ check: (idDiff, sectionChanges, oldContent, newContent) => {
70
+ // Check if a UI framework changed
71
+ const oldUi = /react|vue|svelte|next|nuxt|angular|solid|qwik|astro|tailwind|shadcn|mui|chakra/i;
72
+ const newUi = oldUi;
73
+ const hadUi = oldContent && oldUi.test(oldContent);
74
+ const hasUi = newContent && newUi.test(newContent);
75
+ return hadUi !== hasUi || (hadUi && hasUi && oldContent !== newContent);
76
+ },
77
+ reason: () => `STACK UI library may have changed; DESIGN tokens may need recomputation`,
78
+ severity: 'info'
79
+ }
80
+ ],
81
+ design: [
82
+ {
83
+ target: 'arch',
84
+ check: (idDiff) => idDiff.added.some(id => id.startsWith('D-')) || idDiff.removed.some(id => id.startsWith('D-')),
85
+ reason: () => `DESIGN components changed; ARCH UI surface descriptions may need updating`,
86
+ severity: 'info'
87
+ }
88
+ ],
89
+ roadmap: [
90
+ // Roadmap changes are usually informational; rarely break upstream
91
+ ]
92
+ };
93
+
94
+ /**
95
+ * For a given source artifact change, suggest which downstream artifacts
96
+ * to review.
97
+ *
98
+ * Returns: [{ targetType, reason, severity }]
99
+ */
100
+ function suggestArtifactReviews(projectRoot, sourceType, oldContent, newContent) {
101
+ const rules = IMPACT_RULES[sourceType] || [];
102
+ const idDiff = impact.diffIds(sourceType, oldContent, newContent);
103
+ const results = [];
104
+
105
+ // Compute section diff for prose-driven rules
106
+ const artifactDiff = require('./artifact-diff');
107
+ const sectionDiffResult = artifactDiff.diffArtifacts(oldContent || '', newContent || '');
108
+ const sectionChanges = sectionDiffResult.changes || [];
109
+
110
+ for (const rule of rules) {
111
+ let triggered;
112
+ try {
113
+ triggered = rule.check(idDiff, sectionChanges, oldContent, newContent);
114
+ } catch (e) {
115
+ triggered = false;
116
+ }
117
+ if (triggered) {
118
+ results.push({
119
+ targetType: rule.target,
120
+ reason: rule.reason(idDiff, sectionChanges),
121
+ severity: rule.severity
122
+ });
123
+ }
124
+ }
125
+ return results;
126
+ }
127
+
128
+ /**
129
+ * Specific pairwise impact: given a source change AND a target artifact
130
+ * content, report what specifically might need to change in the target.
131
+ */
132
+ function forArtifactPair(projectRoot, sourceType, oldContent, newContent, targetType, targetContent) {
133
+ const suggestions = suggestArtifactReviews(projectRoot, sourceType, oldContent, newContent);
134
+ const matched = suggestions.find(s => s.targetType === targetType);
135
+ if (!matched) {
136
+ return { impacts: [], severity: 'info' };
137
+ }
138
+
139
+ // Extract IDs from both source and target
140
+ const sourceDiff = impact.diffIds(sourceType, oldContent, newContent);
141
+ const targetIds = impact.extractIds(targetType, targetContent || '');
142
+
143
+ // Find target IDs that mention removed source IDs
144
+ const impacts = [];
145
+ for (const removed of sourceDiff.removed) {
146
+ if (targetContent && targetContent.includes(removed)) {
147
+ impacts.push({
148
+ kind: 'cross-reference',
149
+ sourceId: removed,
150
+ targetReference: 'mentioned in target',
151
+ message: `Source ${removed} was removed; target ${targetType} still mentions it.`
152
+ });
153
+ }
154
+ }
155
+ return { impacts, severity: matched.severity, summary: matched.reason };
156
+ }
157
+
158
+ module.exports = {
159
+ IMPACT_RULES,
160
+ suggestArtifactReviews,
161
+ forArtifactPair
162
+ };
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Cross-Repo Linkage
3
+ *
4
+ * Extends the per-repo linkage map (lib/linkage.js) to span multiple
5
+ * repos in a Mode D suite. IDs are repo-qualified to prevent collisions:
6
+ * <repo-name>:<id> e.g., shared-libs:C-auth-service
7
+ *
8
+ * Public API:
9
+ * qualifyId(repoName, id) -> string
10
+ * parseQualifiedId(qid) -> { repo, id } | null
11
+ * readForwardSuite(hubPath) -> { 'qualified-id': [files] }
12
+ * crossRepoOrphans(hubPath, knownIds) -> [...]
13
+ * crossRepoImpact(hubPath, qualifiedId) -> [{ repo, files }]
14
+ * collectAllIds(hubPath) -> { id, repo, declared, implemented }[]
15
+ */
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+
20
+ const linkage = require('./linkage');
21
+ const detector = require('./multi-repo-detector');
22
+
23
+ /**
24
+ * Qualify a stable ID with its repo name.
25
+ */
26
+ function qualifyId(repoName, id) {
27
+ return `${repoName}:${id}`;
28
+ }
29
+
30
+ /**
31
+ * Parse a qualified ID. Returns null if not qualified.
32
+ */
33
+ function parseQualifiedId(qid) {
34
+ if (!qid || typeof qid !== 'string') return null;
35
+ const idx = qid.indexOf(':');
36
+ if (idx === -1) return null;
37
+ return {
38
+ repo: qid.slice(0, idx),
39
+ id: qid.slice(idx + 1)
40
+ };
41
+ }
42
+
43
+ /**
44
+ * Read each sibling's forward map and build a qualified map for the suite.
45
+ */
46
+ function readForwardSuite(hubPath) {
47
+ const config = detector.readSuiteConfig(hubPath);
48
+ if (!config) return {};
49
+ const out = {};
50
+ const siblings = (config.siblings || []).map(sib => {
51
+ if (typeof sib === 'string') return { name: sib, path: path.resolve(hubPath, sib) };
52
+ return { name: sib.name, path: path.resolve(hubPath, sib.path || sib.name) };
53
+ });
54
+ for (const sib of siblings) {
55
+ if (!fs.existsSync(sib.path)) continue;
56
+ const fwd = linkage.readForward(sib.path);
57
+ for (const [id, files] of Object.entries(fwd)) {
58
+ const qid = qualifyId(sib.name, id);
59
+ out[qid] = files.map(f => `${sib.name}/${f}`);
60
+ }
61
+ }
62
+ return out;
63
+ }
64
+
65
+ /**
66
+ * Find IDs that are declared but have no implementing file across all
67
+ * repos.
68
+ *
69
+ * `knownIds` is a list of qualified IDs (e.g., ['shared:C-auth', 'app:P-MUST-01']).
70
+ */
71
+ function crossRepoOrphans(hubPath, knownIds) {
72
+ const fwd = readForwardSuite(hubPath);
73
+ return knownIds.filter(qid => !fwd[qid] || fwd[qid].length === 0);
74
+ }
75
+
76
+ /**
77
+ * Given a qualified ID, find files across the suite that depend on it.
78
+ * Useful when removing a token from one repo: scans all sibling repos
79
+ * for usage of the qualified token reference.
80
+ */
81
+ function crossRepoImpact(hubPath, qualifiedId) {
82
+ const config = detector.readSuiteConfig(hubPath);
83
+ if (!config) return [];
84
+ const parsed = parseQualifiedId(qualifiedId);
85
+ if (!parsed) return [];
86
+
87
+ const siblings = (config.siblings || []).map(sib => {
88
+ if (typeof sib === 'string') return { name: sib, path: path.resolve(hubPath, sib) };
89
+ return { name: sib.name, path: path.resolve(hubPath, sib.path || sib.name) };
90
+ });
91
+
92
+ const result = [];
93
+ for (const sib of siblings) {
94
+ if (!fs.existsSync(sib.path)) continue;
95
+ const reverse = linkage.readReverse(sib.path);
96
+ const matches = [];
97
+ for (const [file, ids] of Object.entries(reverse)) {
98
+ if (ids.includes(qualifiedId) || ids.includes(parsed.id)) {
99
+ matches.push(file);
100
+ }
101
+ }
102
+ if (matches.length > 0) {
103
+ result.push({ repo: sib.name, files: matches });
104
+ }
105
+ }
106
+ return result;
107
+ }
108
+
109
+ /**
110
+ * Walk all repos and collect every linked ID with its repo origin.
111
+ * Returns deduplicated list:
112
+ * [{ qualifiedId, repo, id, fileCount }, ...]
113
+ */
114
+ function collectAllIds(hubPath) {
115
+ const fwd = readForwardSuite(hubPath);
116
+ const result = [];
117
+ for (const [qid, files] of Object.entries(fwd)) {
118
+ const parsed = parseQualifiedId(qid);
119
+ if (parsed) {
120
+ result.push({
121
+ qualifiedId: qid,
122
+ repo: parsed.repo,
123
+ id: parsed.id,
124
+ fileCount: files.length
125
+ });
126
+ }
127
+ }
128
+ return result.sort((a, b) => a.qualifiedId.localeCompare(b.qualifiedId));
129
+ }
130
+
131
+ /**
132
+ * Compute coverage across the suite: percent of declared IDs that are
133
+ * implemented in at least one repo.
134
+ */
135
+ function suiteCoverage(hubPath, knownIds) {
136
+ if (knownIds.length === 0) return 1;
137
+ const fwd = readForwardSuite(hubPath);
138
+ const linked = knownIds.filter(qid => fwd[qid] && fwd[qid].length > 0).length;
139
+ return linked / knownIds.length;
140
+ }
141
+
142
+ module.exports = {
143
+ qualifyId,
144
+ parseQualifiedId,
145
+ readForwardSuite,
146
+ crossRepoOrphans,
147
+ crossRepoImpact,
148
+ collectAllIds,
149
+ suiteCoverage
150
+ };