@geraldmaron/construct 1.1.1 → 1.2.1

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 (426) hide show
  1. package/README.md +30 -19
  2. package/bin/construct +487 -87
  3. package/bin/construct-postinstall.mjs +30 -2
  4. package/examples/distribution/README.md +42 -0
  5. package/examples/distribution/manifest.json +53 -0
  6. package/examples/distribution/sources/adr.md +84 -0
  7. package/examples/distribution/sources/deck-one-pager.md +65 -0
  8. package/examples/distribution/sources/prd-platform.md +161 -0
  9. package/examples/distribution/sources/research-brief.md +80 -0
  10. package/examples/distribution/sources/rfc-platform.md +82 -0
  11. package/examples/distribution/sources/runbook.md +103 -0
  12. package/examples/distribution/sources/strategy.md +88 -0
  13. package/lib/adapters-sync.mjs +67 -0
  14. package/lib/artifact-gate-notice.mjs +38 -0
  15. package/lib/artifact-manifest.mjs +258 -0
  16. package/lib/artifact-release-gate.mjs +171 -0
  17. package/lib/artifact-reviewers.mjs +68 -0
  18. package/lib/artifact-type-from-path.mjs +79 -0
  19. package/lib/artifact-workflow.mjs +252 -0
  20. package/lib/audit-skills.mjs +4 -0
  21. package/lib/audit-specialists.mjs +285 -0
  22. package/lib/audit-trail.mjs +1 -1
  23. package/lib/auto-docs.mjs +90 -19
  24. package/lib/beads/drift.mjs +27 -6
  25. package/lib/beads-client.mjs +49 -121
  26. package/lib/beads-optimistic.mjs +5 -12
  27. package/lib/brand-fonts.mjs +93 -0
  28. package/lib/brand-prose.mjs +214 -0
  29. package/lib/brand-tokens.mjs +92 -0
  30. package/lib/bridges/copilot-proxy.mjs +13 -26
  31. package/lib/capability-ledger.mjs +156 -0
  32. package/lib/certification/artifact-fixtures.mjs +132 -0
  33. package/lib/certification/artifact-gates.mjs +63 -0
  34. package/lib/certification/artifact-provenance.mjs +97 -0
  35. package/lib/certification/canonical-scenarios.mjs +78 -0
  36. package/lib/certification/cli.mjs +191 -0
  37. package/lib/certification/dashboard-api.mjs +71 -0
  38. package/lib/certification/demo-parity.mjs +116 -0
  39. package/lib/certification/document-io-fixtures.mjs +246 -0
  40. package/lib/certification/document-workflow.mjs +97 -0
  41. package/lib/certification/eval-bridge.mjs +77 -0
  42. package/lib/certification/model-routing.mjs +149 -0
  43. package/lib/certification/prompt-budget.mjs +119 -0
  44. package/lib/certification/rc-gate.mjs +206 -0
  45. package/lib/certification/real-llm-scenarios.mjs +303 -0
  46. package/lib/certification/role-cards.mjs +113 -0
  47. package/lib/certification/role-overlays.mjs +117 -0
  48. package/lib/certification/run.mjs +122 -0
  49. package/lib/certification/runner.mjs +323 -0
  50. package/lib/certification/scenarios.mjs +51 -0
  51. package/lib/certification/skill-inventory.mjs +289 -0
  52. package/lib/certification/skill-scenarios.mjs +147 -0
  53. package/lib/certification/specialist-contracts.mjs +85 -0
  54. package/lib/certification/specialist-scenarios.mjs +175 -0
  55. package/lib/certification/stale-impact.mjs +146 -0
  56. package/lib/certification/status.mjs +252 -0
  57. package/lib/certification/store.mjs +77 -0
  58. package/lib/chat/cli.mjs +333 -0
  59. package/lib/chat/command-suggest.mjs +161 -0
  60. package/lib/chat/commands.mjs +215 -0
  61. package/lib/chat/config.mjs +142 -0
  62. package/lib/chat/context-compactor.mjs +250 -0
  63. package/lib/chat/context-continuation.mjs +253 -0
  64. package/lib/chat/continuation-source.mjs +58 -0
  65. package/lib/chat/demo-guide.mjs +61 -0
  66. package/lib/chat/design-tokens.mjs +91 -0
  67. package/lib/chat/desktop-binary.mjs +79 -0
  68. package/lib/chat/desktop-build.mjs +130 -0
  69. package/lib/chat/desktop-launcher.mjs +133 -0
  70. package/lib/chat/evidence.mjs +145 -0
  71. package/lib/chat/export.mjs +74 -0
  72. package/lib/chat/harness/driver.mjs +91 -0
  73. package/lib/chat/list-picker.mjs +112 -0
  74. package/lib/chat/model-picker.mjs +356 -0
  75. package/lib/chat/openrouter-fallback.mjs +151 -0
  76. package/lib/chat/permission-prompt.mjs +33 -0
  77. package/lib/chat/picker-catalog.mjs +45 -0
  78. package/lib/chat/policy-telemetry.mjs +34 -0
  79. package/lib/chat/present.mjs +246 -0
  80. package/lib/chat/session-context.mjs +39 -0
  81. package/lib/chat/session-persist.mjs +73 -0
  82. package/lib/chat/session-restore.mjs +71 -0
  83. package/lib/chat/session-settings.mjs +53 -0
  84. package/lib/chat/system-prompt.mjs +52 -0
  85. package/lib/chat/transparency.mjs +93 -0
  86. package/lib/chat/tui/color-scheme.mjs +42 -0
  87. package/lib/chat/tui/markdown.mjs +123 -0
  88. package/lib/chat/tui/presentation.mjs +100 -0
  89. package/lib/chat/tui/render.mjs +500 -0
  90. package/lib/chat/tui/turn-block.mjs +284 -0
  91. package/lib/chat/tui/turn-present.mjs +18 -0
  92. package/lib/chat/tui/turn-state.mjs +88 -0
  93. package/lib/chat/tui/usage.mjs +122 -0
  94. package/lib/chat/web-commands.mjs +146 -0
  95. package/lib/chat/web-launcher.mjs +63 -0
  96. package/lib/chat/web-picker-keys.mjs +46 -0
  97. package/lib/chat/web-session.mjs +159 -0
  98. package/lib/cli-commands.mjs +146 -15
  99. package/lib/cli-service-inventory.mjs +42 -0
  100. package/lib/comment-lint.mjs +6 -4
  101. package/lib/config/intake-policy.mjs +209 -0
  102. package/lib/config/project-config.mjs +11 -2
  103. package/lib/config/schema.mjs +86 -6
  104. package/lib/config/source-targets.mjs +311 -0
  105. package/lib/contract-schemas/decision.json +50 -0
  106. package/lib/contract-schemas/implementation.json +51 -0
  107. package/lib/contract-schemas/review-report.json +32 -0
  108. package/lib/contract-schemas/test-report.json +43 -0
  109. package/lib/contracts/construct-handoff.mjs +60 -0
  110. package/lib/contracts/validate.mjs +32 -3
  111. package/lib/contracts/violation-log.mjs +58 -5
  112. package/lib/dashboard-demo.mjs +71 -0
  113. package/lib/dashboard-static.mjs +19 -5
  114. package/lib/decisions/registry.mjs +5 -3
  115. package/lib/deck-export-pptx.mjs +1152 -0
  116. package/lib/demo-recording.mjs +142 -0
  117. package/lib/demo-script.mjs +114 -0
  118. package/lib/demo-surface.mjs +249 -0
  119. package/lib/demo.mjs +598 -140
  120. package/lib/diagram-export.mjs +192 -0
  121. package/lib/diagram.mjs +13 -11
  122. package/lib/docs-verify.mjs +25 -7
  123. package/lib/doctor/index.mjs +3 -1
  124. package/lib/doctor/project-adapters.mjs +44 -0
  125. package/lib/doctor/source-checkout.mjs +16 -0
  126. package/lib/doctor/watchers/cx-budget.mjs +98 -0
  127. package/lib/doctor/watchers/graph-staleness.mjs +52 -0
  128. package/lib/doctor/watchers/process-pressure.mjs +4 -3
  129. package/lib/document-export.mjs +384 -38
  130. package/lib/document-extract.mjs +44 -4
  131. package/lib/document-ingest.mjs +29 -20
  132. package/lib/embed/auto-sources.mjs +44 -0
  133. package/lib/embed/cli.mjs +4 -3
  134. package/lib/embed/daemon.mjs +18 -46
  135. package/lib/embed/demand-fetch.mjs +50 -19
  136. package/lib/embed/inbox.mjs +6 -10
  137. package/lib/embed/worker.mjs +4 -3
  138. package/lib/embedded-contract/index.mjs +11 -0
  139. package/lib/embedded-contract/model-resolve.mjs +10 -9
  140. package/lib/env-config.mjs +26 -0
  141. package/lib/evals/dataset.mjs +137 -0
  142. package/lib/evals/gates.mjs +175 -0
  143. package/lib/export-branding.mjs +32 -0
  144. package/lib/graph/build-co-change.mjs +54 -0
  145. package/lib/graph/build-from-registry.mjs +136 -0
  146. package/lib/graph/build-import-graph.mjs +153 -0
  147. package/lib/graph/cli.mjs +110 -0
  148. package/lib/graph/impact-cli.mjs +89 -0
  149. package/lib/graph/impact.mjs +108 -0
  150. package/lib/graph/staleness.mjs +44 -0
  151. package/lib/graph/store.mjs +172 -0
  152. package/lib/health-check.mjs +90 -76
  153. package/lib/hooks/artifact-release-gate.mjs +43 -0
  154. package/lib/hooks/brand-prose-lint.mjs +38 -0
  155. package/lib/hooks/graph-impact-advisory.mjs +62 -0
  156. package/lib/hooks/session-optimize.mjs +84 -207
  157. package/lib/hooks/session-start.mjs +18 -16
  158. package/lib/host-disposition.mjs +7 -0
  159. package/lib/improvement/cli.mjs +189 -0
  160. package/lib/improvement/controller.mjs +137 -0
  161. package/lib/improvement/proposal.mjs +120 -0
  162. package/lib/improvement/specialist-loop.mjs +192 -0
  163. package/lib/improvement/store.mjs +89 -0
  164. package/lib/improvement/surface.mjs +219 -0
  165. package/lib/ingest-tooling.mjs +97 -0
  166. package/lib/init/doc-lanes.mjs +165 -0
  167. package/lib/init-docs.mjs +31 -178
  168. package/lib/init-unified.mjs +50 -119
  169. package/lib/init-update-guide.mjs +102 -0
  170. package/lib/init-update.mjs +32 -1
  171. package/lib/init.mjs +8 -0
  172. package/lib/install/desktop-binary-download.mjs +85 -0
  173. package/lib/install/legacy-global-cleanup.mjs +189 -0
  174. package/lib/intake/constants.mjs +29 -0
  175. package/lib/intake/daemon.mjs +2 -0
  176. package/lib/intake/git-queue.mjs +9 -8
  177. package/lib/intake/intake-config.mjs +52 -105
  178. package/lib/intake/legacy-paths.mjs +5 -0
  179. package/lib/intake/queue.mjs +2 -1
  180. package/lib/intake/session-prelude.mjs +90 -1
  181. package/lib/libreoffice-export.mjs +97 -0
  182. package/lib/logging/rotate.mjs +9 -0
  183. package/lib/maintenance/docker-reclaim.mjs +206 -0
  184. package/lib/mcp/external-schema-cost.mjs +74 -0
  185. package/lib/mcp/server.mjs +103 -10
  186. package/lib/mcp/stdio-mcp-probe.mjs +188 -0
  187. package/lib/mcp/tool-budget.mjs +55 -4
  188. package/lib/mcp/tools/document.mjs +18 -4
  189. package/lib/mcp/tools/embedded-contract.mjs +14 -0
  190. package/lib/mcp/tools/skills.mjs +32 -3
  191. package/lib/mcp/tools/workflow.mjs +13 -1
  192. package/lib/model-free-selector.mjs +18 -0
  193. package/lib/model-registry.mjs +13 -229
  194. package/lib/model-router.mjs +373 -92
  195. package/lib/models/behavior-matrix.mjs +289 -0
  196. package/lib/models/catalog.mjs +209 -0
  197. package/lib/models/execution-capability-profile.mjs +196 -0
  198. package/lib/models/execution-policy.mjs +307 -0
  199. package/lib/models/provider-poll.mjs +383 -0
  200. package/lib/npm-spawn-env.mjs +17 -0
  201. package/lib/ollama/installed-models.mjs +129 -0
  202. package/lib/oracle/actions.mjs +187 -0
  203. package/lib/oracle/artifact-gate.mjs +99 -0
  204. package/lib/oracle/cli.mjs +204 -0
  205. package/lib/oracle/daemon-entry.mjs +14 -0
  206. package/lib/oracle/dispatch.mjs +81 -0
  207. package/lib/oracle/execute.mjs +143 -0
  208. package/lib/oracle/gaps.mjs +76 -0
  209. package/lib/oracle/index.mjs +84 -0
  210. package/lib/oracle/issues.mjs +164 -0
  211. package/lib/oracle/org-graph.mjs +170 -0
  212. package/lib/oracle/policy.mjs +80 -0
  213. package/lib/oracle/read-model.mjs +398 -0
  214. package/lib/oracle/reconcile.mjs +191 -0
  215. package/lib/oracle/routing.mjs +89 -0
  216. package/lib/oracle/synthesize.mjs +384 -0
  217. package/lib/oracle/verdicts.mjs +51 -0
  218. package/lib/orchestration/worker.mjs +88 -27
  219. package/lib/orchestration-policy.mjs +50 -0
  220. package/lib/parity.mjs +96 -2
  221. package/lib/playwright-demo.mjs +254 -0
  222. package/lib/project-init-shared.mjs +4 -1
  223. package/lib/prompt-composer.js +7 -3
  224. package/lib/prompt-validation-contract.mjs +24 -0
  225. package/lib/provider-capabilities.js +57 -11
  226. package/lib/providers/contract/adapters/confluence/index.mjs +181 -0
  227. package/lib/providers/contract/adapters/git/index.mjs +115 -0
  228. package/lib/providers/contract/adapters/github/index.mjs +166 -0
  229. package/lib/providers/contract/adapters/jira/index.mjs +187 -0
  230. package/lib/providers/contract/adapters/slack/index.mjs +175 -0
  231. package/lib/providers/contract/contract-tests.mjs +57 -0
  232. package/lib/providers/contract/errors.mjs +48 -0
  233. package/lib/providers/contract/interface.mjs +50 -0
  234. package/lib/providers/contract/registry.mjs +102 -0
  235. package/lib/providers/copilot-auth.mjs +297 -0
  236. package/lib/providers/credential-bootstrap.mjs +178 -0
  237. package/lib/providers/credential-catalog.mjs +46 -0
  238. package/lib/providers/credential-sources.mjs +63 -0
  239. package/lib/providers/creds.mjs +5 -2
  240. package/lib/providers/op-run.mjs +59 -0
  241. package/lib/providers/secret-resolver.mjs +159 -0
  242. package/lib/publish-template.mjs +163 -0
  243. package/lib/publish-tooling.mjs +119 -0
  244. package/lib/publish.mjs +305 -0
  245. package/lib/registry/cli.mjs +82 -0
  246. package/lib/registry/consolidation.mjs +147 -0
  247. package/lib/registry/generate-docs.mjs +75 -0
  248. package/lib/registry/skill-verification.mjs +57 -0
  249. package/lib/registry/surface-map.mjs +76 -0
  250. package/lib/registry/validate.mjs +135 -0
  251. package/lib/resources/budget.mjs +82 -0
  252. package/lib/resources/process-budget.mjs +45 -0
  253. package/lib/rules-delivery.mjs +9 -2
  254. package/lib/rules-read.mjs +26 -0
  255. package/lib/runtime-env.mjs +23 -0
  256. package/lib/runtime-pressure.mjs +51 -7
  257. package/lib/schema-infer.mjs +13 -2
  258. package/lib/server/chat-loop.mjs +622 -0
  259. package/lib/server/demo-preview.mjs +63 -0
  260. package/lib/server/index.mjs +259 -9
  261. package/lib/server/rate-limit.mjs +5 -3
  262. package/lib/server/webhook.mjs +3 -2
  263. package/lib/service-manager.mjs +60 -8
  264. package/lib/setup.mjs +70 -7
  265. package/lib/specialists/prompt-schema.mjs +19 -10
  266. package/lib/specialists/roster.mjs +43 -0
  267. package/lib/specialists/scaffold.mjs +56 -0
  268. package/lib/storage/backend.mjs +6 -6
  269. package/lib/storage/hybrid-query.mjs +7 -4
  270. package/lib/storage/state-source.mjs +5 -5
  271. package/lib/storage/sync.mjs +2 -3
  272. package/lib/telemetry/rule-calls.mjs +52 -0
  273. package/lib/template-registry.mjs +2 -2
  274. package/lib/templates/visual-requirements.mjs +27 -51
  275. package/lib/test-corpus-inventory.mjs +313 -0
  276. package/lib/uninstall/uninstall.mjs +19 -7
  277. package/lib/update.mjs +12 -0
  278. package/lib/upgrade.mjs +14 -0
  279. package/lib/wireframe.mjs +20 -14
  280. package/lib/worker/run.mjs +17 -4
  281. package/lib/worker/trace.mjs +11 -3
  282. package/package.json +28 -14
  283. package/personas/construct.md +2 -2
  284. package/platforms/claude/settings.template.json +36 -0
  285. package/rules/common/patterns.md +1 -1
  286. package/rules/common/release-gates.md +4 -3
  287. package/scripts/sync-specialists.mjs +41 -28
  288. package/skills/devops/data-engineering.md +1 -1
  289. package/skills/docs/adr-workflow.md +1 -0
  290. package/skills/docs/backlog-proposal-workflow.md +1 -0
  291. package/skills/docs/codebase-research-workflow.md +40 -0
  292. package/skills/docs/customer-profile-workflow.md +1 -0
  293. package/skills/docs/document-ingest-workflow.md +1 -0
  294. package/skills/docs/evidence-ingest-workflow.md +1 -0
  295. package/skills/docs/init-docs.md +2 -2
  296. package/skills/docs/init-project.md +7 -2
  297. package/skills/docs/prd-workflow.md +24 -1
  298. package/skills/docs/prfaq-workflow.md +1 -0
  299. package/skills/docs/product-intelligence-workflow.md +1 -0
  300. package/skills/docs/product-signal-workflow.md +1 -0
  301. package/skills/docs/research-workflow.md +54 -37
  302. package/skills/docs/runbook-workflow.md +1 -0
  303. package/skills/docs/strategy-workflow.md +1 -0
  304. package/skills/docs/user-research-workflow.md +40 -0
  305. package/skills/operating/orchestration-reference.md +1 -1
  306. package/skills/roles/architect.md +5 -0
  307. package/skills/roles/operator.docs.md +4 -0
  308. package/skills/routing.md +4 -2
  309. package/specialists/artifact-manifest.json +489 -0
  310. package/specialists/artifact-manifest.schema.json +83 -0
  311. package/specialists/audit-enrichments.json +454 -0
  312. package/specialists/contracts.json +37 -25
  313. package/specialists/prompts/_shared/validation-contract.md +26 -0
  314. package/specialists/prompts/cx-accessibility.md +21 -2
  315. package/specialists/prompts/cx-ai-engineer.md +24 -1
  316. package/specialists/prompts/cx-architect.md +4 -1
  317. package/specialists/prompts/cx-business-strategist.md +23 -2
  318. package/specialists/prompts/cx-data-analyst.md +22 -1
  319. package/specialists/prompts/cx-data-engineer.md +23 -2
  320. package/specialists/prompts/cx-debugger.md +21 -2
  321. package/specialists/prompts/cx-designer.md +26 -3
  322. package/specialists/prompts/cx-devil-advocate.md +19 -2
  323. package/specialists/prompts/cx-docs-keeper.md +28 -1
  324. package/specialists/prompts/cx-engineer.md +22 -1
  325. package/specialists/prompts/cx-evaluator.md +18 -1
  326. package/specialists/prompts/cx-explorer.md +21 -2
  327. package/specialists/prompts/cx-legal-compliance.md +21 -2
  328. package/specialists/prompts/cx-operations.md +21 -2
  329. package/specialists/prompts/cx-oracle.md +94 -0
  330. package/specialists/prompts/cx-orchestrator.md +20 -1
  331. package/specialists/prompts/cx-platform-engineer.md +25 -2
  332. package/specialists/prompts/cx-product-manager.md +32 -1
  333. package/specialists/prompts/cx-qa.md +24 -2
  334. package/specialists/prompts/cx-rd-lead.md +23 -2
  335. package/specialists/prompts/cx-release-manager.md +23 -2
  336. package/specialists/prompts/cx-researcher.md +22 -2
  337. package/specialists/prompts/cx-reviewer.md +18 -1
  338. package/specialists/prompts/cx-security.md +22 -2
  339. package/specialists/prompts/cx-sre.md +30 -3
  340. package/specialists/prompts/cx-test-automation.md +7 -1
  341. package/specialists/prompts/cx-trace-reviewer.md +22 -3
  342. package/specialists/prompts/cx-ux-researcher.md +21 -2
  343. package/specialists/registry.json +52 -173
  344. package/specialists/tone-profiles.json +42 -0
  345. package/templates/demos/playwright/demo-recording.config.mjs +47 -0
  346. package/templates/demos/recordings/agentic-platforms-prd.json +19 -0
  347. package/templates/demos/scripts/agentic-platforms-prd.json +44 -0
  348. package/templates/demos/specs/_helpers/scroll-artifact.ts +89 -0
  349. package/templates/demos/tapes/agentic-platforms-prd.tape +49 -0
  350. package/templates/demos/tapes/resource-guard-rails.tape +49 -0
  351. package/templates/demos/vhs/construct-cockpit.json +24 -0
  352. package/templates/distribution/construct-brand.typ +446 -0
  353. package/templates/distribution/construct-decision.typ +38 -0
  354. package/templates/distribution/construct-deck.html +95 -0
  355. package/templates/distribution/construct-pdf.typ +38 -0
  356. package/templates/distribution/construct-prd.typ +38 -0
  357. package/templates/distribution/construct-reference.docx +0 -0
  358. package/templates/distribution/construct-research.typ +38 -0
  359. package/templates/distribution/construct-web.html +92 -0
  360. package/templates/distribution/fonts/Geist-Bold.ttf +0 -0
  361. package/templates/distribution/fonts/Geist-Medium.ttf +0 -0
  362. package/templates/distribution/fonts/Geist-Regular.ttf +0 -0
  363. package/templates/distribution/fonts/Geist-SemiBold.ttf +0 -0
  364. package/templates/distribution/fonts/GeistMono-Medium.ttf +0 -0
  365. package/templates/distribution/fonts/GeistMono-Regular.ttf +0 -0
  366. package/templates/distribution/fonts/GeistMono-SemiBold.ttf +0 -0
  367. package/templates/distribution/fonts/IBMPlexMono-Regular.otf +0 -0
  368. package/templates/distribution/fonts/JetBrainsMono-Medium.ttf +0 -0
  369. package/templates/distribution/fonts/JetBrainsMono-Regular.ttf +0 -0
  370. package/templates/distribution/fonts/JetBrainsMono-SemiBold.ttf +0 -0
  371. package/templates/distribution/fonts/PlusJakartaSans-Bold.ttf +0 -0
  372. package/templates/distribution/fonts/PlusJakartaSans-Medium.ttf +0 -0
  373. package/templates/distribution/fonts/PlusJakartaSans-Regular.ttf +0 -0
  374. package/templates/distribution/fonts/PlusJakartaSans-SemiBold.ttf +0 -0
  375. package/templates/distribution/fonts/README.md +36 -0
  376. package/templates/distribution/fonts/SpaceGrotesk-Variable.ttf +0 -0
  377. package/templates/distribution/fonts/handwritten/Caveat.ttf +0 -0
  378. package/templates/distribution/fonts/legacy/IBMPlexMono-Regular.otf +0 -0
  379. package/templates/distribution/fonts/legacy/Inter-Medium.otf +0 -0
  380. package/templates/distribution/fonts/legacy/Inter-Regular.otf +0 -0
  381. package/templates/distribution/fonts/legacy/Inter-SemiBold.otf +0 -0
  382. package/templates/distribution/fonts/legacy/InterDisplay-SemiBold.otf +0 -0
  383. package/templates/distribution/fonts/legacy/SourceSerif4-Regular.otf +0 -0
  384. package/templates/distribution/fonts/legacy/SourceSerif4-Semibold.otf +0 -0
  385. package/templates/distribution/icons/activity.svg +15 -0
  386. package/templates/distribution/icons/alert-triangle.svg +17 -0
  387. package/templates/distribution/icons/book-open.svg +16 -0
  388. package/templates/distribution/icons/bot.svg +20 -0
  389. package/templates/distribution/icons/brain.svg +22 -0
  390. package/templates/distribution/icons/circle-check.svg +16 -0
  391. package/templates/distribution/icons/clipboard-check.svg +17 -0
  392. package/templates/distribution/icons/cpu.svg +28 -0
  393. package/templates/distribution/icons/database.svg +17 -0
  394. package/templates/distribution/icons/eye.svg +16 -0
  395. package/templates/distribution/icons/file-text.svg +19 -0
  396. package/templates/distribution/icons/gauge.svg +16 -0
  397. package/templates/distribution/icons/git-branch.svg +17 -0
  398. package/templates/distribution/icons/key.svg +17 -0
  399. package/templates/distribution/icons/layers.svg +17 -0
  400. package/templates/distribution/icons/list-checks.svg +19 -0
  401. package/templates/distribution/icons/lock.svg +16 -0
  402. package/templates/distribution/icons/message-square.svg +15 -0
  403. package/templates/distribution/icons/network.svg +19 -0
  404. package/templates/distribution/icons/route.svg +17 -0
  405. package/templates/distribution/icons/scale.svg +19 -0
  406. package/templates/distribution/icons/search.svg +16 -0
  407. package/templates/distribution/icons/send.svg +16 -0
  408. package/templates/distribution/icons/server.svg +18 -0
  409. package/templates/distribution/icons/shield-check.svg +16 -0
  410. package/templates/distribution/icons/users.svg +18 -0
  411. package/templates/distribution/icons/webhook.svg +17 -0
  412. package/templates/distribution/icons/workflow.svg +17 -0
  413. package/templates/distribution/icons/wrench.svg +15 -0
  414. package/templates/distribution/run.mjs +18 -1
  415. package/templates/docs/adr.md +7 -0
  416. package/templates/docs/construct_guide.md +8 -8
  417. package/templates/docs/customer-profile.md +4 -0
  418. package/templates/docs/one-pager.md +4 -0
  419. package/templates/docs/postmortem.md +31 -0
  420. package/templates/docs/prd-platform.md +19 -0
  421. package/templates/docs/prd.md +15 -0
  422. package/templates/docs/prfaq.md +7 -0
  423. package/templates/docs/qa-strategy.md +103 -0
  424. package/templates/docs/research-brief.md +8 -0
  425. package/templates/docs/rfc-platform.md +12 -0
  426. package/templates/docs/test-plan.md +7 -0
@@ -0,0 +1,175 @@
1
+ /**
2
+ * providers/slack/index.mjs — Slack provider.
3
+ *
4
+ * Transport: Slack Web API (direct fetch, no SDK).
5
+ * Auth: Bot token via SLACK_BOT_TOKEN env var, or config.token.
6
+ *
7
+ * Capabilities: read, write, watch
8
+ *
9
+ * read refs:
10
+ * "channels" → list of public channels the bot is in
11
+ * "channel:<id>:messages" → recent messages in a channel (default 20)
12
+ * "channel:<id>:messages:<n>" → last n messages
13
+ * "thread:<channel>:<ts>" → thread replies
14
+ * "user:<id>" → user profile
15
+ *
16
+ * write items:
17
+ * { type: 'message', channel, text, thread_ts? } → post a message
18
+ * { type: 'reaction', channel, timestamp, emoji } → add a reaction
19
+ *
20
+ * watch: poll a channel for new messages since last seen timestamp
21
+ * watch({ channel, since? }, callback) → returns unsubscribe fn
22
+ */
23
+
24
+ import { AuthError, NotFoundError, RateLimitError } from '../../errors.mjs';
25
+
26
+ const SLACK_API = 'https://slack.com/api';
27
+
28
+ export default {
29
+ name: 'slack',
30
+ capabilities: ['read', 'write', 'watch'],
31
+
32
+ _token: null,
33
+ _pollIntervals: new Map(),
34
+
35
+ async init(config = {}) {
36
+ const token = config.token ?? process.env.SLACK_BOT_TOKEN;
37
+ if (!token) {
38
+ throw new AuthError(
39
+ 'Slack provider requires SLACK_BOT_TOKEN or config.token',
40
+ { provider: 'slack' },
41
+ );
42
+ }
43
+ this._token = token;
44
+ const res = await this._call('auth.test', {});
45
+ if (!res.ok) {
46
+ throw new AuthError(`Slack auth failed: ${res.error}`, { provider: 'slack' });
47
+ }
48
+ },
49
+
50
+ async _call(method, params) {
51
+ const url = `${SLACK_API}/${method}`;
52
+ const res = await fetch(url, {
53
+ method: 'POST',
54
+ headers: {
55
+ Authorization: `Bearer ${this._token}`,
56
+ 'Content-Type': 'application/json; charset=utf-8',
57
+ },
58
+ body: JSON.stringify(params),
59
+ });
60
+ if (res.status === 429) {
61
+ const retryAfter = parseInt(res.headers.get('Retry-After') ?? '30', 10);
62
+ throw new RateLimitError('Slack rate limit hit', { provider: 'slack', retryAfter });
63
+ }
64
+ return res.json();
65
+ },
66
+
67
+ async read(ref, _opts = {}) {
68
+ if (ref === 'channels') {
69
+ const data = await this._call('conversations.list', { types: 'public_channel,private_channel', limit: 200 });
70
+ if (!data.ok) throw new Error(`Slack error: ${data.error}`);
71
+ return (data.channels ?? []).map((c) => ({
72
+ type: 'channel',
73
+ id: c.id,
74
+ name: c.name,
75
+ isPrivate: c.is_private,
76
+ memberCount: c.num_members,
77
+ }));
78
+ }
79
+
80
+ const channelMsgMatch = ref.match(/^channel:([^:]+):messages(?::(\d+))?$/);
81
+ if (channelMsgMatch) {
82
+ const channel = channelMsgMatch[1];
83
+ const limit = parseInt(channelMsgMatch[2] ?? '20', 10);
84
+ const data = await this._call('conversations.history', { channel, limit });
85
+ if (!data.ok) {
86
+ if (data.error === 'channel_not_found') throw new NotFoundError(`Channel not found: ${channel}`, { provider: 'slack' });
87
+ throw new Error(`Slack error: ${data.error}`);
88
+ }
89
+ return (data.messages ?? []).map(normalizeMessage);
90
+ }
91
+
92
+ const threadMatch = ref.match(/^thread:([^:]+):(.+)$/);
93
+ if (threadMatch) {
94
+ const [, channel, ts] = threadMatch;
95
+ const data = await this._call('conversations.replies', { channel, ts });
96
+ if (!data.ok) throw new Error(`Slack error: ${data.error}`);
97
+ return (data.messages ?? []).map(normalizeMessage);
98
+ }
99
+
100
+ if (ref.startsWith('user:')) {
101
+ const userId = ref.slice(5);
102
+ const data = await this._call('users.info', { user: userId });
103
+ if (!data.ok) {
104
+ if (data.error === 'user_not_found') throw new NotFoundError(`User not found: ${userId}`, { provider: 'slack' });
105
+ throw new Error(`Slack error: ${data.error}`);
106
+ }
107
+ const u = data.user;
108
+ return [{ type: 'user', id: u.id, name: u.name, realName: u.real_name, email: u.profile?.email }];
109
+ }
110
+
111
+ throw new NotFoundError(`Unknown Slack read ref: "${ref}"`, { provider: 'slack' });
112
+ },
113
+
114
+ async write(item) {
115
+ if (item.type === 'message') {
116
+ const params = { channel: item.channel, text: item.text };
117
+ if (item.thread_ts) params.thread_ts = item.thread_ts;
118
+ if (item.blocks) params.blocks = item.blocks;
119
+ const data = await this._call('chat.postMessage', params);
120
+ if (!data.ok) throw new Error(`Slack error: ${data.error}`);
121
+ return { type: 'message-posted', ts: data.ts, channel: data.channel };
122
+ }
123
+
124
+ if (item.type === 'reaction') {
125
+ const data = await this._call('reactions.add', {
126
+ channel: item.channel,
127
+ timestamp: item.timestamp,
128
+ name: item.emoji,
129
+ });
130
+ if (!data.ok && data.error !== 'already_reacted') throw new Error(`Slack error: ${data.error}`);
131
+ return { type: 'reaction-added', emoji: item.emoji };
132
+ }
133
+
134
+ throw new Error(`Unknown Slack write item type: "${item.type}"`);
135
+ },
136
+
137
+ watch(filter, callback) {
138
+ const channel = filter.channel;
139
+ let since = filter.since ?? String(Date.now() / 1000 - 60);
140
+ const intervalMs = filter.intervalMs ?? 15000;
141
+
142
+ const id = setInterval(async () => {
143
+ try {
144
+ const data = await this._call('conversations.history', {
145
+ channel,
146
+ oldest: since,
147
+ limit: 50,
148
+ });
149
+ if (!data.ok) return;
150
+ const messages = (data.messages ?? []).filter((m) => m.ts > since);
151
+ if (messages.length) {
152
+ since = messages[0].ts; // Slack returns newest first
153
+ for (const msg of messages.reverse()) callback(normalizeMessage(msg));
154
+ }
155
+ } catch { /* swallow poll errors — network blip shouldn't kill the watcher */ }
156
+ }, intervalMs);
157
+
158
+ this._pollIntervals.set(id, true);
159
+ return () => {
160
+ clearInterval(id);
161
+ this._pollIntervals.delete(id);
162
+ };
163
+ },
164
+ };
165
+
166
+ function normalizeMessage(m) {
167
+ return {
168
+ type: 'message',
169
+ ts: m.ts,
170
+ user: m.user ?? m.bot_id,
171
+ text: m.text,
172
+ threadTs: m.thread_ts ?? null,
173
+ replyCount: m.reply_count ?? 0,
174
+ };
175
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * providers/lib/contract-tests.mjs — shared contract tests for any provider.
3
+ *
4
+ * Import and call runContractTests(provider) from a provider's own test file.
5
+ * Uses node:test + node:assert — zero external deps.
6
+ */
7
+
8
+ import { describe, it } from 'node:test';
9
+ import assert from 'node:assert/strict';
10
+ import { validate, hasCapability, CAPABILITIES } from './interface.mjs';
11
+ import { CapabilityNotSupported } from './errors.mjs';
12
+
13
+ /**
14
+ * Run the standard contract test suite against a provider instance.
15
+ * Call this from your provider's test file:
16
+ *
17
+ * import { runContractTests } from '../../lib/providers/contract/contract-tests.mjs';
18
+ * import provider from './index.mjs';
19
+ * runContractTests(provider);
20
+ */
21
+ export function runContractTests(provider) {
22
+ describe(`Provider contract: ${provider?.name ?? 'unnamed'}`, () => {
23
+ it('passes interface validation', () => {
24
+ const result = validate(provider);
25
+ assert.ok(result.valid, `Validation errors: ${result.errors.join('; ')}`);
26
+ });
27
+
28
+ it('has a non-empty string name', () => {
29
+ assert.ok(typeof provider.name === 'string' && provider.name.length > 0);
30
+ });
31
+
32
+ it('declares capabilities as an array of known values', () => {
33
+ assert.ok(Array.isArray(provider.capabilities));
34
+ for (const cap of provider.capabilities) {
35
+ assert.ok(CAPABILITIES.includes(cap), `Unknown capability: ${cap}`);
36
+ }
37
+ });
38
+
39
+ it('implements a function for each declared capability', () => {
40
+ for (const cap of provider.capabilities) {
41
+ assert.equal(typeof provider[cap], 'function', `Missing function for capability "${cap}"`);
42
+ }
43
+ });
44
+
45
+ it('implements init as a function', () => {
46
+ assert.equal(typeof provider.init, 'function');
47
+ });
48
+
49
+ for (const cap of CAPABILITIES) {
50
+ if (provider && Array.isArray(provider.capabilities) && !provider.capabilities.includes(cap)) {
51
+ it(`does not claim unsupported capability "${cap}"`, () => {
52
+ assert.ok(!hasCapability(provider, cap));
53
+ });
54
+ }
55
+ }
56
+ });
57
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * providers/lib/errors.mjs — typed error hierarchy for providers.
3
+ *
4
+ * Core catches these by type to decide retry, fallback, or user-facing messaging.
5
+ */
6
+
7
+ export class ProviderError extends Error {
8
+ constructor(message, { provider, capability, code, cause } = {}) {
9
+ super(message, { cause });
10
+ this.name = 'ProviderError';
11
+ this.provider = provider;
12
+ this.capability = capability;
13
+ this.code = code;
14
+ }
15
+ }
16
+
17
+ export class CapabilityNotSupported extends ProviderError {
18
+ constructor(provider, capability) {
19
+ super(`Provider "${provider}" does not support capability "${capability}"`, {
20
+ provider,
21
+ capability,
22
+ code: 'CAPABILITY_NOT_SUPPORTED',
23
+ });
24
+ this.name = 'CapabilityNotSupported';
25
+ }
26
+ }
27
+
28
+ export class AuthError extends ProviderError {
29
+ constructor(message, opts = {}) {
30
+ super(message, { ...opts, code: 'AUTH_ERROR' });
31
+ this.name = 'AuthError';
32
+ }
33
+ }
34
+
35
+ export class RateLimitError extends ProviderError {
36
+ constructor(message, { retryAfter, ...opts } = {}) {
37
+ super(message, { ...opts, code: 'RATE_LIMIT' });
38
+ this.name = 'RateLimitError';
39
+ this.retryAfter = retryAfter;
40
+ }
41
+ }
42
+
43
+ export class NotFoundError extends ProviderError {
44
+ constructor(message, opts = {}) {
45
+ super(message, { ...opts, code: 'NOT_FOUND' });
46
+ this.name = 'NotFoundError';
47
+ }
48
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * providers/lib/interface.mjs — abstract provider interface and validation.
3
+ *
4
+ * Every provider must export an object matching this shape. The validate()
5
+ * function checks a provider at registration time; capability dispatch
6
+ * uses hasCapability() before calling.
7
+ */
8
+
9
+ const CAPABILITIES = ['read', 'write', 'search', 'watch', 'webhook'];
10
+
11
+ /**
12
+ * Validate a provider object against the interface contract.
13
+ * Returns { valid: boolean, errors: string[] }.
14
+ */
15
+ export function validate(provider) {
16
+ const errors = [];
17
+
18
+ if (!provider || typeof provider !== 'object') {
19
+ return { valid: false, errors: ['Provider must be a non-null object'] };
20
+ }
21
+ if (typeof provider.name !== 'string' || !provider.name) {
22
+ errors.push('Provider must have a non-empty string "name"');
23
+ }
24
+ if (!Array.isArray(provider.capabilities)) {
25
+ errors.push('Provider must declare "capabilities" as an array');
26
+ } else {
27
+ for (const cap of provider.capabilities) {
28
+ if (!CAPABILITIES.includes(cap)) {
29
+ errors.push(`Unknown capability "${cap}". Valid: ${CAPABILITIES.join(', ')}`);
30
+ }
31
+ if (typeof provider[cap] !== 'function') {
32
+ errors.push(`Provider declares capability "${cap}" but does not implement it as a function`);
33
+ }
34
+ }
35
+ }
36
+ if (typeof provider.init !== 'function') {
37
+ errors.push('Provider must implement init(config)');
38
+ }
39
+
40
+ return { valid: errors.length === 0, errors };
41
+ }
42
+
43
+ /**
44
+ * Check if a provider supports a given capability.
45
+ */
46
+ export function hasCapability(provider, capability) {
47
+ return Array.isArray(provider.capabilities) && provider.capabilities.includes(capability);
48
+ }
49
+
50
+ export { CAPABILITIES };
@@ -0,0 +1,102 @@
1
+ /**
2
+ * providers/lib/registry.mjs — load and manage provider instances.
3
+ *
4
+ * Reads provider config from .cx/providers.yaml (or programmatic config),
5
+ * validates each provider against the interface contract, and provides
6
+ * a dispatch surface for core.
7
+ */
8
+
9
+ import fs from 'node:fs';
10
+ import path from 'node:path';
11
+ import { validate, hasCapability } from './interface.mjs';
12
+ import { CapabilityNotSupported } from './errors.mjs';
13
+
14
+ /**
15
+ * In-memory provider registry.
16
+ */
17
+ export class ProviderRegistry {
18
+ #providers = new Map();
19
+
20
+ /**
21
+ * Register a provider instance. Validates against the interface contract.
22
+ * Throws if validation fails.
23
+ */
24
+ register(provider) {
25
+ const result = validate(provider);
26
+ if (!result.valid) {
27
+ throw new Error(`Invalid provider "${provider?.name ?? '(unnamed)'}": ${result.errors.join('; ')}`);
28
+ }
29
+ this.#providers.set(provider.name, provider);
30
+ }
31
+
32
+ /**
33
+ * Get a registered provider by name.
34
+ */
35
+ get(name) {
36
+ return this.#providers.get(name) ?? null;
37
+ }
38
+
39
+ /**
40
+ * List all registered provider names.
41
+ */
42
+ list() {
43
+ return [...this.#providers.keys()];
44
+ }
45
+
46
+ /**
47
+ * List providers that support a given capability.
48
+ */
49
+ withCapability(capability) {
50
+ return [...this.#providers.values()].filter((p) => hasCapability(p, capability));
51
+ }
52
+
53
+ /**
54
+ * Dispatch a capability call to a named provider.
55
+ * Throws CapabilityNotSupported if the provider doesn't implement it.
56
+ */
57
+ async dispatch(providerName, capability, ...args) {
58
+ const provider = this.#providers.get(providerName);
59
+ if (!provider) {
60
+ throw new Error(`Provider "${providerName}" not registered`);
61
+ }
62
+ if (!hasCapability(provider, capability)) {
63
+ throw new CapabilityNotSupported(providerName, capability);
64
+ }
65
+ return provider[capability](...args);
66
+ }
67
+
68
+ /**
69
+ * Initialize all registered providers with their configs.
70
+ */
71
+ async initAll(configs = {}) {
72
+ const results = [];
73
+ for (const [name, provider] of this.#providers) {
74
+ try {
75
+ await provider.init(configs[name] ?? {});
76
+ results.push({ name, status: 'ready' });
77
+ } catch (err) {
78
+ results.push({ name, status: 'error', error: err.message });
79
+ }
80
+ }
81
+ return results;
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Load provider config from a YAML file.
87
+ * Returns parsed config or null if file doesn't exist.
88
+ * Note: requires a YAML parser — deferred to avoid adding deps to provider lib.
89
+ * For now, returns raw file content for the caller to parse.
90
+ */
91
+ export function loadProviderConfigFile(projectRoot) {
92
+ const candidates = [
93
+ path.join(projectRoot, '.cx', 'providers.yaml'),
94
+ path.join(projectRoot, '.cx', 'providers.yml'),
95
+ ];
96
+ for (const candidate of candidates) {
97
+ if (fs.existsSync(candidate)) {
98
+ return { path: candidate, raw: fs.readFileSync(candidate, 'utf8') };
99
+ }
100
+ }
101
+ return null;
102
+ }