@geraldmaron/construct 1.2.2 → 1.3.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 (497) hide show
  1. package/README.md +7 -10
  2. package/bin/construct +286 -220
  3. package/bin/construct-postinstall.mjs +0 -21
  4. package/commands/work/optimize-prompts.md +1 -1
  5. package/examples/distribution/sources/adr.md +2 -2
  6. package/examples/seed-observations/decisions.md +1 -1
  7. package/lib/artifact-loop-core.mjs +412 -0
  8. package/lib/artifact-manifest.mjs +6 -0
  9. package/lib/artifact-release-gate.mjs +115 -49
  10. package/lib/audit-rules.mjs +2 -4
  11. package/lib/audit-skills.mjs +32 -20
  12. package/lib/audit-specialists.mjs +44 -26
  13. package/lib/auto-docs.mjs +6 -5
  14. package/lib/brand-prose.mjs +3 -3
  15. package/lib/brand-tokens.mjs +2 -2
  16. package/lib/certification/artifact-fixtures.mjs +4 -1
  17. package/lib/certification/demo-parity.mjs +6 -32
  18. package/lib/certification/real-llm-scenarios.mjs +58 -13
  19. package/lib/certification/role-cards.mjs +7 -6
  20. package/lib/certification/role-overlays.mjs +4 -4
  21. package/lib/certification/runner.mjs +9 -2
  22. package/lib/certification/skill-inventory.mjs +34 -22
  23. package/lib/certification/skill-scenarios.mjs +21 -8
  24. package/lib/certification/specialist-contracts.mjs +4 -3
  25. package/lib/certification/specialist-scenarios.mjs +7 -6
  26. package/lib/certification/status.mjs +5 -4
  27. package/lib/cli-commands.mjs +56 -57
  28. package/lib/comment-lint.mjs +1 -5
  29. package/lib/completions.mjs +20 -2
  30. package/lib/config/legacy-config-migration.mjs +125 -0
  31. package/lib/config/schema.mjs +5 -5
  32. package/lib/config/source-targets.mjs +80 -0
  33. package/lib/contracts/validate.mjs +119 -51
  34. package/lib/decisions/golden.mjs +3 -2
  35. package/lib/decisions/registry.mjs +11 -6
  36. package/lib/demo-project.mjs +188 -0
  37. package/lib/demo-recording.mjs +9 -34
  38. package/lib/demo-script.mjs +2 -2
  39. package/lib/demo-surface.mjs +13 -131
  40. package/lib/demo-tour-renderer.mjs +92 -0
  41. package/lib/demo.mjs +69 -54
  42. package/lib/diagram-export.mjs +63 -14
  43. package/lib/doctor/source-checkout.mjs +3 -4
  44. package/lib/doctor/watchers/consistency.mjs +90 -22
  45. package/lib/doctor/watchers/credential-parity.mjs +97 -0
  46. package/lib/doctor/watchers/mcp-protocol.mjs +1 -1
  47. package/lib/doctor/watchers/service-health.mjs +4 -32
  48. package/lib/document-export.mjs +73 -9
  49. package/lib/document-extract.mjs +10 -198
  50. package/lib/embed/artifact.mjs +2 -3
  51. package/lib/embed/cli.mjs +1 -1
  52. package/lib/embed/config.mjs +1 -2
  53. package/lib/embed/customer-profiles.mjs +1 -1
  54. package/lib/embed/daemon.mjs +5 -6
  55. package/lib/embed/demand-fetch.mjs +114 -2
  56. package/lib/embed/docs-lifecycle.mjs +9 -5
  57. package/lib/embed/intake-metrics.mjs +2 -2
  58. package/lib/embed/notifications.mjs +2 -3
  59. package/lib/embed/recommendation-store.mjs +25 -22
  60. package/lib/embed/role-framing.mjs +4 -9
  61. package/lib/embedded-contract/capability.mjs +4 -2
  62. package/lib/embedded-contract/contract-version.mjs +1 -1
  63. package/lib/env-config.mjs +2 -2
  64. package/lib/flavors/loader.mjs +21 -19
  65. package/lib/graph/build-from-registry.mjs +31 -7
  66. package/lib/graph/staleness.mjs +1 -1
  67. package/lib/headhunt.mjs +82 -35
  68. package/lib/hooks/agent-tracker.mjs +2 -2
  69. package/lib/hooks/config-protection.mjs +1 -1
  70. package/lib/hooks/registry-sync.mjs +3 -3
  71. package/lib/host-capabilities.mjs +5 -5
  72. package/lib/improvement/controller.mjs +2 -2
  73. package/lib/init-unified.mjs +19 -21
  74. package/lib/intake/classify.mjs +26 -0
  75. package/lib/intake/daemon.mjs +2 -3
  76. package/lib/intake/prepare.mjs +10 -3
  77. package/lib/intake/session-prelude.mjs +1 -1
  78. package/lib/intake/tables/creative.mjs +9 -9
  79. package/lib/intake/tables/operations.mjs +4 -4
  80. package/lib/intake/tables/research.mjs +2 -2
  81. package/lib/integrations/intake-integrations.mjs +9 -10
  82. package/lib/knowledge/research-store.mjs +2 -2
  83. package/lib/mcp/server.mjs +104 -61
  84. package/lib/mcp/tool-budget.mjs +1 -46
  85. package/lib/mcp/tool-recovery.mjs +44 -0
  86. package/lib/mcp/tools/artifact-author.mjs +36 -0
  87. package/lib/mcp/tools/find-tool.mjs +86 -0
  88. package/lib/mcp/tools/orchestration-run.mjs +107 -69
  89. package/lib/mcp/tools/project.mjs +4 -3
  90. package/lib/mcp/tools/{profile.mjs → scope.mjs} +54 -52
  91. package/lib/mcp/tools/skills.mjs +39 -22
  92. package/lib/mcp/tools/telemetry.mjs +2 -1
  93. package/lib/mcp/tools/workflow.mjs +1 -1
  94. package/lib/mcp-platform-config.mjs +7 -5
  95. package/lib/migrations/index.mjs +4 -2
  96. package/lib/migrations/v2-unified-registry.mjs +35 -0
  97. package/lib/model-router.mjs +203 -36
  98. package/lib/models/catalog.mjs +25 -9
  99. package/lib/models/execution-capability-profile.mjs +3 -3
  100. package/lib/models/execution-policy.mjs +7 -6
  101. package/lib/models/provider-poll.mjs +18 -4
  102. package/lib/opencode-config.mjs +56 -1
  103. package/lib/opencode-runtime-plugin.mjs +13 -10
  104. package/lib/oracle/artifact-gate.mjs +14 -4
  105. package/lib/oracle/cli.mjs +2 -0
  106. package/lib/oracle/dispatch.mjs +18 -1
  107. package/lib/oracle/execute.mjs +39 -7
  108. package/lib/oracle/index.mjs +1 -1
  109. package/lib/oracle/org-graph.mjs +10 -5
  110. package/lib/oracle/policy.mjs +6 -0
  111. package/lib/oracle/read-model.mjs +103 -6
  112. package/lib/oracle/reconcile.mjs +31 -4
  113. package/lib/oracle/remediation-dispatch.mjs +53 -0
  114. package/lib/oracle/routing.mjs +5 -0
  115. package/lib/oracle/synthesize.mjs +80 -3
  116. package/lib/orchestration/routing-tables.mjs +44 -10
  117. package/lib/orchestration/runtime.mjs +2 -0
  118. package/lib/orchestration/worker.mjs +1 -1
  119. package/lib/orchestration-policy.mjs +351 -62
  120. package/lib/overrides/resolver.mjs +1 -12
  121. package/lib/parity.mjs +37 -11
  122. package/lib/policy/engine.mjs +80 -15
  123. package/lib/prompt-composer.js +51 -15
  124. package/lib/prompt-metadata.mjs +3 -2
  125. package/lib/providers/connection-probe.mjs +58 -0
  126. package/lib/providers/copilot-auth.mjs +1 -1
  127. package/lib/providers/credential-bootstrap.mjs +1 -1
  128. package/lib/providers/op-run.mjs +3 -4
  129. package/lib/providers/secret-resolver.mjs +31 -0
  130. package/lib/publish-tooling.mjs +3 -11
  131. package/lib/publish.mjs +12 -29
  132. package/lib/reconcile/mcp-entry-reconcile.mjs +14 -9
  133. package/lib/reflect.mjs +2 -2
  134. package/lib/registry/agent-manifest.mjs +190 -0
  135. package/lib/registry/assemble.mjs +133 -0
  136. package/lib/registry/catalog.mjs +171 -0
  137. package/lib/registry/cli.mjs +590 -6
  138. package/lib/registry/consolidation.mjs +5 -4
  139. package/lib/registry/docs-sync.mjs +67 -0
  140. package/lib/registry/loader.mjs +147 -0
  141. package/lib/registry/org-io.mjs +76 -0
  142. package/lib/registry/retired-paths.mjs +71 -0
  143. package/lib/registry/surface-map.mjs +5 -7
  144. package/lib/registry/validator.mjs +438 -0
  145. package/lib/research-execution-policy.mjs +173 -0
  146. package/lib/roles/catalog.mjs +4 -9
  147. package/lib/roles/fence.mjs +107 -1
  148. package/lib/roles/flavor-bindings.mjs +68 -0
  149. package/lib/roles/gateway.mjs +140 -29
  150. package/lib/roles/manifest.mjs +22 -13
  151. package/lib/roles/router.mjs +1 -1
  152. package/lib/runtime-env.mjs +1 -1
  153. package/lib/scopes/enrich.mjs +67 -0
  154. package/lib/scopes/hooks.mjs +12 -0
  155. package/lib/{profiles → scopes}/lifecycle.mjs +70 -70
  156. package/lib/scopes/loader.mjs +104 -0
  157. package/lib/scopes/rebrand.mjs +32 -0
  158. package/lib/scopes/research-profile.mjs +16 -0
  159. package/lib/scopes/teams.mjs +98 -0
  160. package/lib/service-manager.mjs +1 -117
  161. package/lib/setup-prompts.mjs +1 -1
  162. package/lib/setup.mjs +17 -28
  163. package/lib/skills/composition-graph.mjs +98 -0
  164. package/lib/skills/router.mjs +80 -0
  165. package/lib/specialist-contracts.mjs +17 -18
  166. package/lib/specialists/postconditions.mjs +2 -2
  167. package/lib/specialists/prompt-schema.mjs +6 -5
  168. package/lib/specialists/roster.mjs +7 -12
  169. package/lib/specialists/schema.mjs +9 -6
  170. package/lib/status.mjs +25 -90
  171. package/lib/storage/file-lock.mjs +6 -3
  172. package/lib/telemetry/skill-calls.mjs +1 -1
  173. package/lib/templates/doc-presentation.mjs +63 -0
  174. package/lib/templates/visual-requirements.mjs +35 -2
  175. package/lib/term-format.mjs +107 -2
  176. package/lib/test-env-setup.mjs +21 -0
  177. package/lib/ui/components.mjs +42 -0
  178. package/lib/ui/glyphs.mjs +58 -0
  179. package/lib/ui/links.mjs +115 -0
  180. package/lib/ui/theme.mjs +108 -0
  181. package/lib/uninstall/uninstall.mjs +2 -1
  182. package/lib/validator.mjs +45 -8
  183. package/lib/validators/skill-effectiveness.mjs +174 -0
  184. package/lib/validators/skills.mjs +1 -1
  185. package/package.json +12 -7
  186. package/personas/construct.md +12 -3
  187. package/platforms/claude/CLAUDE.md +1 -1
  188. package/rules/common/beads-hygiene.md +52 -0
  189. package/rules/common/neurodivergent-output.md +4 -7
  190. package/rules/common/research.md +2 -0
  191. package/scripts/sync-specialists.mjs +260 -49
  192. package/skills/ai/prompt-optimizer.md +3 -3
  193. package/skills/brand/output-vibe.md +48 -0
  194. package/skills/docs/adr-workflow.md +3 -0
  195. package/skills/docs/backlog-proposal-workflow.md +3 -0
  196. package/skills/docs/codebase-research-workflow.md +5 -2
  197. package/skills/docs/customer-profile-workflow.md +3 -0
  198. package/skills/docs/document-ingest-workflow.md +3 -0
  199. package/skills/docs/evidence-ingest-workflow.md +4 -1
  200. package/skills/docs/init-project.md +1 -1
  201. package/skills/docs/prd-workflow.md +1 -1
  202. package/skills/docs/prfaq-workflow.md +3 -0
  203. package/skills/docs/product-intelligence-workflow.md +4 -1
  204. package/skills/docs/product-signal-workflow.md +3 -0
  205. package/skills/docs/research-workflow.md +13 -6
  206. package/skills/docs/runbook-workflow.md +3 -0
  207. package/skills/docs/strategy-workflow.md +3 -0
  208. package/skills/docs/user-research-workflow.md +6 -3
  209. package/skills/operating/orchestration-reference.md +1 -1
  210. package/skills/roles/{engineer.ai.md → ai-engineer.md} +2 -2
  211. package/skills/roles/architect.ai-systems.md +1 -1
  212. package/skills/roles/architect.data.md +1 -1
  213. package/skills/roles/architect.enterprise.md +1 -1
  214. package/skills/roles/architect.integration.md +1 -1
  215. package/skills/roles/architect.md +1 -1
  216. package/skills/roles/architect.platform.md +1 -1
  217. package/skills/roles/{product-manager.business-strategy.md → business-strategist.md} +3 -3
  218. package/skills/roles/data-analyst.experiment.md +1 -1
  219. package/skills/roles/data-analyst.md +1 -1
  220. package/skills/roles/data-analyst.product-intelligence.md +1 -1
  221. package/skills/roles/data-analyst.product.md +1 -1
  222. package/skills/roles/data-analyst.telemetry.md +1 -1
  223. package/skills/roles/{engineer.data.md → data-engineer.md} +2 -2
  224. package/skills/roles/data-engineer.pipeline.md +2 -2
  225. package/skills/roles/data-engineer.vector-retrieval.md +2 -2
  226. package/skills/roles/data-engineer.warehouse.md +2 -2
  227. package/skills/roles/debugger.md +1 -1
  228. package/skills/roles/designer.accessibility.md +1 -1
  229. package/skills/roles/designer.md +1 -1
  230. package/skills/roles/{reviewer.devil-advocate.md → devil-advocate.md} +2 -2
  231. package/skills/roles/{operator.docs.md → docs-keeper.md} +3 -3
  232. package/skills/roles/engineer.md +3 -7
  233. package/skills/roles/{reviewer.evaluator.md → evaluator.md} +2 -2
  234. package/skills/roles/{researcher.explorer.md → explorer.md} +2 -2
  235. package/skills/roles/{operator.md → operations.md} +2 -5
  236. package/skills/roles/orchestrator.md +1 -1
  237. package/skills/roles/{engineer.platform.md → platform-engineer.md} +2 -2
  238. package/skills/roles/product-manager.ai-product.md +1 -1
  239. package/skills/roles/product-manager.enterprise.md +1 -1
  240. package/skills/roles/product-manager.growth.md +1 -2
  241. package/skills/roles/product-manager.md +1 -2
  242. package/skills/roles/product-manager.platform.md +1 -1
  243. package/skills/roles/product-manager.product.md +1 -1
  244. package/skills/roles/qa.ai-eval.md +1 -1
  245. package/skills/roles/qa.api-contract.md +1 -1
  246. package/skills/roles/qa.data-pipeline.md +1 -1
  247. package/skills/roles/qa.md +1 -1
  248. package/skills/roles/qa.web-ui.md +1 -1
  249. package/skills/roles/{operator.release.md → release-manager.md} +3 -3
  250. package/skills/roles/researcher.md +1 -1
  251. package/skills/roles/reviewer.md +1 -1
  252. package/skills/roles/security.ai.md +1 -1
  253. package/skills/roles/security.appsec.md +1 -1
  254. package/skills/roles/security.cloud.md +1 -1
  255. package/skills/roles/security.legal-compliance.md +1 -1
  256. package/skills/roles/security.md +1 -1
  257. package/skills/roles/security.privacy.md +1 -1
  258. package/skills/roles/security.supply-chain.md +1 -1
  259. package/skills/roles/{operator.sre.md → sre.md} +3 -3
  260. package/skills/roles/{qa.test-automation.md → test-automation.md} +2 -2
  261. package/skills/roles/{reviewer.trace.md → trace-reviewer.md} +2 -2
  262. package/skills/roles/{researcher.ux.md → ux-researcher.md} +2 -2
  263. package/skills/routing.json +18 -0
  264. package/skills/routing.md +1 -1
  265. package/specialists/artifact-manifest.json +2 -1
  266. package/specialists/audit-enrichments.json +14 -14
  267. package/specialists/org/contracts/accessibility-to-qa.json +37 -0
  268. package/specialists/org/contracts/any-to-business-strategist.json +57 -0
  269. package/specialists/org/contracts/any-to-debugger.json +38 -0
  270. package/specialists/org/contracts/any-to-designer.json +33 -0
  271. package/specialists/org/contracts/any-to-docs-keeper.json +34 -0
  272. package/specialists/org/contracts/any-to-explorer.json +39 -0
  273. package/specialists/org/contracts/any-to-sre-incident.json +33 -0
  274. package/specialists/org/contracts/any-to-trace-reviewer.json +32 -0
  275. package/specialists/org/contracts/architect-to-ai-engineer.json +32 -0
  276. package/specialists/org/contracts/architect-to-data-engineer.json +52 -0
  277. package/specialists/org/contracts/architect-to-devil-advocate.json +38 -0
  278. package/specialists/org/contracts/architect-to-engineer.json +34 -0
  279. package/specialists/org/contracts/architect-to-evaluator.json +59 -0
  280. package/specialists/org/contracts/architect-to-legal-compliance.json +55 -0
  281. package/specialists/org/contracts/architect-to-operations.json +45 -0
  282. package/specialists/org/contracts/architect-to-platform-engineer.json +42 -0
  283. package/specialists/org/contracts/business-strategist-to-product-manager.json +39 -0
  284. package/specialists/org/contracts/construct-to-orchestrator.json +36 -0
  285. package/specialists/org/contracts/construct-to-rd-lead.json +53 -0
  286. package/specialists/org/contracts/data-analyst-to-product-manager.json +43 -0
  287. package/specialists/org/contracts/data-engineer-to-platform-engineer.json +36 -0
  288. package/specialists/org/contracts/designer-to-accessibility.json +36 -0
  289. package/specialists/org/contracts/engineer-to-qa.json +34 -0
  290. package/specialists/org/contracts/engineer-to-reviewer.json +52 -0
  291. package/specialists/org/contracts/explorer-to-engineer.json +38 -0
  292. package/specialists/org/contracts/legal-compliance-to-release-manager.json +43 -0
  293. package/specialists/org/contracts/platform-engineer-to-engineer.json +31 -0
  294. package/specialists/org/contracts/product-manager-to-architect.json +71 -0
  295. package/specialists/org/contracts/product-manager-to-data-analyst.json +49 -0
  296. package/specialists/org/contracts/product-manager-to-ux-researcher.json +51 -0
  297. package/specialists/org/contracts/qa-to-release-manager.json +42 -0
  298. package/specialists/org/contracts/qa-to-test-automation.json +42 -0
  299. package/specialists/org/contracts/rd-lead-to-architect.json +38 -0
  300. package/specialists/org/contracts/researcher-to-architect.json +40 -0
  301. package/specialists/org/contracts/researcher-to-product-manager.json +57 -0
  302. package/specialists/org/contracts/reviewer-to-security.json +41 -0
  303. package/specialists/org/contracts/sre-to-release-manager.json +36 -0
  304. package/specialists/org/contracts/test-automation-to-engineer.json +34 -0
  305. package/specialists/org/contracts/trace-reviewer-to-sre.json +41 -0
  306. package/specialists/org/contracts/user-to-construct.json +30 -0
  307. package/specialists/org/groups/engineering-group.json +43 -0
  308. package/specialists/org/groups/governance-group.json +38 -0
  309. package/specialists/org/groups/operations-group.json +41 -0
  310. package/specialists/org/groups/product-group.json +46 -0
  311. package/specialists/org/groups/quality-group.json +42 -0
  312. package/specialists/org/groups/strategy-group.json +41 -0
  313. package/specialists/org/policies/action-approval.json +13 -0
  314. package/specialists/org/policies/agents-routing.json +13 -0
  315. package/specialists/org/policies/architecture.json +20 -0
  316. package/specialists/org/policies/bash-safety.json +13 -0
  317. package/specialists/org/policies/beads-hygiene.json +13 -0
  318. package/specialists/org/policies/bootstrap-state.json +13 -0
  319. package/specialists/org/policies/code-review.json +13 -0
  320. package/specialists/org/policies/coding-style.json +13 -0
  321. package/specialists/org/policies/comments.json +13 -0
  322. package/specialists/org/policies/commit-approval.json +13 -0
  323. package/specialists/org/policies/contract-preconditions.json +13 -0
  324. package/specialists/org/policies/deployment.json +20 -0
  325. package/specialists/org/policies/description.json +14 -0
  326. package/specialists/org/policies/design-approval.json +19 -0
  327. package/specialists/org/policies/doc-ownership.json +13 -0
  328. package/specialists/org/policies/file-path-fence.json +13 -0
  329. package/specialists/org/policies/framing.json +13 -0
  330. package/specialists/org/policies/git-workflow.json +13 -0
  331. package/specialists/org/policies/incident-response.json +15 -0
  332. package/specialists/org/policies/intake-triage.json +15 -0
  333. package/specialists/org/policies/neurodivergent-output.json +13 -0
  334. package/specialists/org/policies/no-fabrication.json +13 -0
  335. package/specialists/org/policies/patterns.json +13 -0
  336. package/specialists/org/policies/quality-gate-approval.json +17 -0
  337. package/specialists/org/policies/release-gates.json +13 -0
  338. package/specialists/org/policies/research-evidence.json +13 -0
  339. package/specialists/org/policies/review-before-change.json +13 -0
  340. package/specialists/org/policies/rollback.json +15 -0
  341. package/specialists/org/policies/scope-change.json +20 -0
  342. package/specialists/org/policies/secret-scan.json +13 -0
  343. package/specialists/org/policies/security-approval.json +17 -0
  344. package/specialists/org/policies/security.json +13 -0
  345. package/specialists/org/policies/session-efficiency.json +13 -0
  346. package/specialists/org/policies/skill-routing.json +13 -0
  347. package/specialists/org/policies/strategic-prioritization.json +17 -0
  348. package/specialists/org/policies/testing.json +13 -0
  349. package/specialists/org/policies/tool-invisibility.json +14 -0
  350. package/specialists/org/scopes/creative.json +54 -0
  351. package/specialists/org/scopes/operations.json +51 -0
  352. package/specialists/org/scopes/research.json +60 -0
  353. package/specialists/org/scopes/rnd.json +81 -0
  354. package/specialists/org/specialists/cx-accessibility.json +69 -0
  355. package/specialists/org/specialists/cx-ai-engineer.json +75 -0
  356. package/specialists/org/specialists/cx-architect.json +89 -0
  357. package/specialists/org/specialists/cx-business-strategist.json +72 -0
  358. package/specialists/org/specialists/cx-data-analyst.json +68 -0
  359. package/specialists/org/specialists/cx-data-engineer.json +71 -0
  360. package/specialists/org/specialists/cx-debugger.json +75 -0
  361. package/specialists/org/specialists/cx-designer.json +85 -0
  362. package/specialists/org/specialists/cx-devil-advocate.json +71 -0
  363. package/specialists/org/specialists/cx-docs-keeper.json +82 -0
  364. package/specialists/org/specialists/cx-engineer.json +106 -0
  365. package/specialists/org/specialists/cx-evaluator.json +69 -0
  366. package/specialists/org/specialists/cx-explorer.json +69 -0
  367. package/specialists/org/specialists/cx-legal-compliance.json +74 -0
  368. package/specialists/org/specialists/cx-operations.json +72 -0
  369. package/specialists/org/specialists/cx-oracle.json +46 -0
  370. package/specialists/org/specialists/cx-orchestrator.json +81 -0
  371. package/specialists/org/specialists/cx-platform-engineer.json +80 -0
  372. package/specialists/org/specialists/cx-product-manager.json +102 -0
  373. package/specialists/org/specialists/cx-qa.json +79 -0
  374. package/specialists/org/specialists/cx-rd-lead.json +73 -0
  375. package/specialists/org/specialists/cx-release-manager.json +77 -0
  376. package/specialists/org/specialists/cx-researcher.json +82 -0
  377. package/specialists/org/specialists/cx-reviewer.json +71 -0
  378. package/specialists/org/specialists/cx-security.json +91 -0
  379. package/specialists/org/specialists/cx-sre.json +94 -0
  380. package/specialists/org/specialists/cx-test-automation.json +69 -0
  381. package/specialists/org/specialists/cx-trace-reviewer.json +69 -0
  382. package/specialists/org/specialists/cx-ux-researcher.json +68 -0
  383. package/specialists/org/teams/accessibility-team.json +39 -0
  384. package/specialists/org/teams/design-team.json +40 -0
  385. package/specialists/org/teams/engineering-team.json +50 -0
  386. package/specialists/org/teams/governance-team.json +41 -0
  387. package/specialists/org/teams/operations-team.json +46 -0
  388. package/specialists/org/teams/product-management-team.json +45 -0
  389. package/specialists/org/teams/quality-team.json +49 -0
  390. package/specialists/org/teams/research-team.json +39 -0
  391. package/specialists/org/teams/strategy-team.json +48 -0
  392. package/specialists/org/teams/ux-research-team.json +39 -0
  393. package/specialists/prompts/_shared/validation-contract.md +1 -1
  394. package/specialists/prompts/_team-template.md +10 -0
  395. package/specialists/prompts/cx-accessibility.md +1 -0
  396. package/specialists/prompts/cx-ai-engineer.md +1 -1
  397. package/specialists/prompts/cx-business-strategist.md +1 -1
  398. package/specialists/prompts/cx-data-engineer.md +1 -1
  399. package/specialists/prompts/cx-designer.md +1 -0
  400. package/specialists/prompts/cx-devil-advocate.md +1 -1
  401. package/specialists/prompts/cx-docs-keeper.md +1 -1
  402. package/specialists/prompts/cx-evaluator.md +1 -1
  403. package/specialists/prompts/cx-explorer.md +1 -1
  404. package/specialists/prompts/cx-operations.md +1 -1
  405. package/specialists/prompts/cx-oracle.md +7 -3
  406. package/specialists/prompts/cx-orchestrator.md +17 -1
  407. package/specialists/prompts/cx-platform-engineer.md +1 -1
  408. package/specialists/prompts/cx-product-manager.md +2 -0
  409. package/specialists/prompts/cx-release-manager.md +1 -1
  410. package/specialists/prompts/cx-researcher.md +7 -4
  411. package/specialists/prompts/cx-sre.md +1 -1
  412. package/specialists/prompts/cx-test-automation.md +2 -2
  413. package/specialists/prompts/cx-trace-reviewer.md +3 -3
  414. package/specialists/prompts/cx-ux-researcher.md +2 -1
  415. package/templates/demos/scripts/architecture-review-adr.json +30 -0
  416. package/templates/demos/scripts/capability-contract.json +25 -0
  417. package/templates/demos/scripts/intake-triage.json +25 -0
  418. package/templates/demos/scripts/profile-doctor-health.json +25 -0
  419. package/templates/demos/tapes/agentic-platforms-prd.tape +2 -2
  420. package/templates/demos/tapes/architecture-review-adr.tape +44 -0
  421. package/templates/demos/tapes/capability-contract.tape +39 -0
  422. package/templates/demos/tapes/intake-triage.tape +39 -0
  423. package/templates/demos/tapes/profile-doctor-health.tape +39 -0
  424. package/templates/distribution/construct-brand.typ +23 -18
  425. package/templates/distribution/construct-decision.typ +1 -1
  426. package/templates/distribution/construct-pdf.typ +1 -1
  427. package/templates/distribution/construct-prd.typ +1 -1
  428. package/templates/distribution/construct-research.typ +1 -1
  429. package/templates/distribution/mermaid-puppeteer.json +8 -0
  430. package/templates/docs/persona-artifact.md +1 -1
  431. package/templates/docs/prd.md +6 -0
  432. package/lib/boundary.mjs +0 -127
  433. package/lib/certification/dashboard-api.mjs +0 -71
  434. package/lib/chat/cli.mjs +0 -333
  435. package/lib/chat/command-suggest.mjs +0 -161
  436. package/lib/chat/commands.mjs +0 -215
  437. package/lib/chat/config.mjs +0 -142
  438. package/lib/chat/context-compactor.mjs +0 -250
  439. package/lib/chat/context-continuation.mjs +0 -253
  440. package/lib/chat/continuation-source.mjs +0 -58
  441. package/lib/chat/demo-guide.mjs +0 -61
  442. package/lib/chat/design-tokens.mjs +0 -91
  443. package/lib/chat/desktop-binary.mjs +0 -81
  444. package/lib/chat/desktop-build.mjs +0 -130
  445. package/lib/chat/desktop-launcher.mjs +0 -133
  446. package/lib/chat/evidence.mjs +0 -145
  447. package/lib/chat/export.mjs +0 -74
  448. package/lib/chat/harness/driver.mjs +0 -91
  449. package/lib/chat/list-picker.mjs +0 -112
  450. package/lib/chat/model-picker.mjs +0 -356
  451. package/lib/chat/openrouter-fallback.mjs +0 -151
  452. package/lib/chat/permission-prompt.mjs +0 -33
  453. package/lib/chat/picker-catalog.mjs +0 -45
  454. package/lib/chat/policy-telemetry.mjs +0 -34
  455. package/lib/chat/present.mjs +0 -246
  456. package/lib/chat/session-context.mjs +0 -39
  457. package/lib/chat/session-persist.mjs +0 -73
  458. package/lib/chat/session-restore.mjs +0 -71
  459. package/lib/chat/session-settings.mjs +0 -53
  460. package/lib/chat/system-prompt.mjs +0 -52
  461. package/lib/chat/transparency.mjs +0 -93
  462. package/lib/chat/tui/color-scheme.mjs +0 -42
  463. package/lib/chat/tui/markdown.mjs +0 -123
  464. package/lib/chat/tui/presentation.mjs +0 -100
  465. package/lib/chat/tui/render.mjs +0 -500
  466. package/lib/chat/tui/turn-block.mjs +0 -284
  467. package/lib/chat/tui/turn-present.mjs +0 -18
  468. package/lib/chat/tui/turn-state.mjs +0 -88
  469. package/lib/chat/tui/usage.mjs +0 -122
  470. package/lib/chat/web-commands.mjs +0 -146
  471. package/lib/chat/web-launcher.mjs +0 -63
  472. package/lib/chat/web-picker-keys.mjs +0 -46
  473. package/lib/chat/web-session.mjs +0 -159
  474. package/lib/config/alias.mjs +0 -57
  475. package/lib/dashboard-demo.mjs +0 -71
  476. package/lib/dashboard-static.mjs +0 -175
  477. package/lib/install/desktop-binary-download.mjs +0 -88
  478. package/lib/profiles/loader.mjs +0 -123
  479. package/lib/profiles/rebrand.mjs +0 -46
  480. package/lib/server/auth.mjs +0 -169
  481. package/lib/server/chat-loop.mjs +0 -622
  482. package/lib/server/chat.mjs +0 -336
  483. package/lib/server/cors.mjs +0 -77
  484. package/lib/server/csrf.mjs +0 -103
  485. package/lib/server/demo-preview.mjs +0 -63
  486. package/lib/server/index.mjs +0 -2641
  487. package/lib/server/insights.mjs +0 -780
  488. package/lib/server/langfuse-login.mjs +0 -58
  489. package/lib/server/rate-limit.mjs +0 -93
  490. package/lib/server/telemetry-login.mjs +0 -100
  491. package/lib/server/webhook.mjs +0 -512
  492. package/specialists/contracts.json +0 -1032
  493. package/specialists/contracts.schema.json +0 -83
  494. package/specialists/policy-inventory.json +0 -188
  495. package/specialists/registry.json +0 -1412
  496. package/specialists/role-manifests.json +0 -217
  497. package/specialists/teams.json +0 -94
@@ -55,13 +55,17 @@
55
55
  #let construct-font-display = ("Space Grotesk",)
56
56
  #let construct-font-mono = ("JetBrains Mono",)
57
57
 
58
+ #let horizontalrule = block(width: 100%, above: 0.85em, below: 0.95em)[
59
+ #line(length: 100%, stroke: 0.6pt + hairline-strong)
60
+ ]
61
+
58
62
  // Type scale. One modular ramp shared by every document type so sizing never
59
63
  // drifts between a PRD, a research brief, and a decision record.
60
64
 
61
65
  #let fs-micro = 8pt
62
66
  #let fs-small = 8.5pt
63
67
  #let fs-meta = 9pt
64
- #let fs-body = 10pt
68
+ #let fs-body = 10.4pt
65
69
  #let fs-h4 = 8.5pt
66
70
  #let fs-h3 = 11pt
67
71
  #let fs-h2 = 13pt
@@ -76,8 +80,8 @@
76
80
  #let wt-semibold = 600
77
81
  #let wt-bold = 700
78
82
 
79
- #let construct-figure-max-width = 58%
80
- #let construct-figure-max-height = 2.35in
83
+ #let construct-figure-max-width = 92%
84
+ #let construct-figure-max-height = 3.4in
81
85
 
82
86
  // A document-type word maps to a compact badge so the masthead reads as a
83
87
  // labelled artifact rather than a bare title.
@@ -290,20 +294,18 @@
290
294
 
291
295
  #let construct-theme(body) = {
292
296
  set text(font: construct-font-sans, size: fs-body, fill: ink-body, lang: "en", tracking: 0.002em)
293
- set par(justify: false, leading: 0.82em, spacing: 1.15em)
297
+ set par(justify: false, leading: 0.9em, spacing: 1.24em)
294
298
  set heading(numbering: none, outlined: true)
295
299
 
296
300
  show strong: set text(font: construct-font-sans, weight: wt-semibold, fill: ink)
297
301
  show emph: set text(style: "italic")
298
302
 
299
- // Lists inherit the open body leading; a per-item block gap keeps a wrapped
300
- // bullet from reading as two bullets, with the gap clearly wider than the
301
- // line leading within an item.
303
+ // Lists need looser vertical rhythm than body prose, but ordered lists must
304
+ // preserve Typst's native counter context or every item will render as `1.`.
305
+ // Spacing belongs on the list container, not on a wrapped enum.item block.
302
306
 
303
- show list.item: it => block(below: 0.6em, it)
304
- show enum.item: it => block(below: 0.6em, it)
305
- set list(marker: (text(fill: ink)[•], text(fill: ink-muted)[‣], text(fill: ink-faint)[–]), indent: 2pt, body-indent: 8pt, spacing: 0.9em)
306
- set enum(indent: 2pt, body-indent: 8pt, spacing: 0.9em)
307
+ set list(marker: (text(fill: ink)[•], text(fill: ink-muted)[‣], text(fill: ink-faint)[–]), indent: 2pt, body-indent: 9pt, spacing: 1.02em)
308
+ set enum(numbering: "1.", indent: 2pt, body-indent: 9pt, spacing: 1.02em)
307
309
 
308
310
  // Links carry ink with a hairline underline so citations stay legible without
309
311
  // introducing color.
@@ -322,7 +324,7 @@
322
324
  text(font: construct-font-display, size: fs-h1, weight: wt-semibold, fill: ink, tracking: -0.015em)[#it.body]
323
325
  v(0.22em)
324
326
  line(length: 100%, stroke: 0.5pt + hairline)
325
- v(0.55em, weak: true)
327
+ v(0.7em, weak: true)
326
328
  })
327
329
  }
328
330
  show heading.where(level: 2): it => {
@@ -331,14 +333,14 @@
331
333
  text(font: construct-font-display, size: fs-h2, weight: wt-semibold, fill: ink, tracking: -0.01em)[#it.body]
332
334
  v(0.4em)
333
335
  line(length: 26pt, stroke: 1.5pt + ink)
334
- v(0.62em, weak: true)
336
+ v(0.78em, weak: true)
335
337
  })
336
338
  }
337
339
  show heading.where(level: 3): it => {
338
340
  v(1.15em, weak: true)
339
341
  block(sticky: true, {
340
342
  text(font: construct-font-sans, size: fs-h3, weight: wt-semibold, fill: ink-strong)[#it.body]
341
- v(0.38em, weak: true)
343
+ v(0.48em, weak: true)
342
344
  })
343
345
  }
344
346
  show heading.where(level: 4): it => {
@@ -414,10 +416,13 @@
414
416
  radius: 4pt,
415
417
  )[
416
418
  #align(center)[
417
- #box(width: construct-figure-max-width)[
418
- #show image: img => image(img, width: 100%, height: construct-figure-max-height, fit: "contain")
419
- #it.body
420
- ]
419
+ #show image: img => image(
420
+ img,
421
+ width: construct-figure-max-width,
422
+ height: construct-figure-max-height,
423
+ fit: "contain",
424
+ )
425
+ #it.body
421
426
  ]
422
427
  ]
423
428
  if it.caption != none {
@@ -8,7 +8,7 @@
8
8
 
9
9
  #set page(
10
10
  paper: "a4",
11
- margin: (x: 2cm, top: 1.8cm, bottom: 2.2cm),
11
+ margin: (x: 2.15cm, top: 1.95cm, bottom: 2.35cm),
12
12
  numbering: "1",
13
13
  header: construct-running-header(
14
14
  "$if(title)$$title$$endif$",
@@ -8,7 +8,7 @@
8
8
 
9
9
  #set page(
10
10
  paper: "a4",
11
- margin: (x: 2cm, top: 1.8cm, bottom: 2.2cm),
11
+ margin: (x: 2.15cm, top: 1.95cm, bottom: 2.35cm),
12
12
  numbering: "1",
13
13
  header: construct-running-header(
14
14
  "$if(title)$$title$$endif$",
@@ -8,7 +8,7 @@
8
8
 
9
9
  #set page(
10
10
  paper: "a4",
11
- margin: (x: 2cm, top: 1.8cm, bottom: 2.2cm),
11
+ margin: (x: 2.15cm, top: 1.95cm, bottom: 2.35cm),
12
12
  numbering: "1",
13
13
  header: construct-running-header(
14
14
  "$if(title)$$title$$endif$",
@@ -8,7 +8,7 @@
8
8
 
9
9
  #set page(
10
10
  paper: "a4",
11
- margin: (x: 1.85cm, top: 1.75cm, bottom: 2.1cm),
11
+ margin: (x: 2cm, top: 1.9cm, bottom: 2.25cm),
12
12
  numbering: "1",
13
13
  header: construct-running-header(
14
14
  "$if(title)$$title$$endif$",
@@ -0,0 +1,8 @@
1
+ {
2
+ "args": [
3
+ "--no-sandbox",
4
+ "--disable-setuid-sandbox",
5
+ "--disable-dev-shm-usage",
6
+ "--disable-gpu"
7
+ ]
8
+ }
@@ -1,6 +1,6 @@
1
1
  # <Role display name>
2
2
 
3
- > Anchor doc for the <role-id> persona. Methodology: `docs/guides/concepts/persona-research.md`. This file is generated by `construct profile create` and is part of the discover + frame phases. The persona is not promotable until every section below is filled from evidence, not opinion.
3
+ > Anchor doc for the <role-id> persona. Methodology: `docs/guides/concepts/persona-research.md`. This file is generated by `construct scope create` and is part of the discover + frame phases. The persona is not promotable until every section below is filled from evidence, not opinion.
4
4
 
5
5
  ## Goals
6
6
 
@@ -20,6 +20,8 @@ not the whole document. Keep em dashes rare; prefer commas, periods, or parenthe
20
20
  -->
21
21
 
22
22
  ## Summary
23
+ This PRD defines {title} for {primary user or customer segment}. It explains the current friction, the measurable outcome this work should unlock, and the smallest shippable path to prove the change works. Replace this paragraph with evidence-backed product context before review.
24
+
23
25
  <!--
24
26
  One paragraph (3-5 sentences) that a busy reader can use as the whole PRD.
25
27
  What the change is, who it's for, why now, and what changes when it ships.
@@ -27,6 +29,8 @@ No solutions in this section that aren't decided. No ticket IDs. No team names.
27
29
  -->
28
30
 
29
31
  ## Background
32
+ Today, {current workflow or system} creates avoidable friction for {affected users}. The evidence that matters for this PRD should include observed behavior, quantitative signals, or qualitative research, and the links below should let reviewers verify the claim without relying on memory.
33
+
30
34
  <!--
31
35
  Context the reader needs to evaluate this PRD without asking around.
32
36
  Include relevant prior work (linked PRDs, ADRs, RFCs), observed signals, and
@@ -38,6 +42,8 @@ Avoid roadmap-speak ("this is a Q3 priority"); state what is happening to users.
38
42
  -->
39
43
 
40
44
  ## Problem
45
+ {Affected users} cannot reliably achieve {desired outcome} because {constraint or failure mode}. The problem is important now because the current workaround is costly, error-prone, or blocks adoption for a clearly named segment.
46
+
41
47
  <!--
42
48
  The specific user or business outcome that is currently blocked. One or two
43
49
  paragraphs. State the pain, not the solution.
package/lib/boundary.mjs DELETED
@@ -1,127 +0,0 @@
1
- /**
2
- * lib/boundary.mjs — Authenticated parent/child boundary registration.
3
- *
4
- * Verifies a parent Construct instance is reachable, validates an HMAC
5
- * signature over `childInstanceId|nonce` when a shared secret is configured,
6
- * and persists the binding to boundary.json in the XDG config dir (mode 0600). A
7
- * different parent rotates the registration only when explicitly allowed via
8
- * CONSTRUCT_BOUNDARY_ALLOW_OVERRIDE=1; prior configs are archived alongside
9
- * the active one. Exposed as a standalone module so the dashboard endpoint
10
- * and the functional tests share the same logic.
11
- */
12
-
13
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
14
- import { join } from 'node:path';
15
- import { homedir } from 'node:os';
16
- import { createHmac, timingSafeEqual, randomBytes } from 'node:crypto';
17
- import { request as httpRequest } from 'node:http';
18
- import { request as httpsRequest } from 'node:https';
19
- import { configDir } from './config/xdg.mjs';
20
-
21
- export const BOUNDARY_VERSION = '1.0';
22
-
23
- function boundaryDir(home = homedir()) {
24
- return configDir(home);
25
- }
26
-
27
- export function boundaryConfigPath(home = homedir()) {
28
- return join(boundaryDir(home), 'boundary.json');
29
- }
30
-
31
- export async function registerBoundary({
32
- parentInstance,
33
- parentUrl,
34
- childInstanceId,
35
- nonce,
36
- signature,
37
- sharedSecret = null,
38
- home = homedir(),
39
- allowOverride = process.env.CONSTRUCT_BOUNDARY_ALLOW_OVERRIDE === '1',
40
- probe = probeParent,
41
- }) {
42
- if (!parentInstance || !parentUrl) {
43
- return { ok: false, status: 400, error: 'parentInstance and parentUrl are required' };
44
- }
45
- if (!childInstanceId) {
46
- return { ok: false, status: 400, error: 'childInstanceId is required' };
47
- }
48
-
49
- if (sharedSecret) {
50
- if (!nonce || !signature) {
51
- return { ok: false, status: 401, error: 'nonce and signature are required when a shared secret is configured' };
52
- }
53
- const expected = createHmac('sha256', sharedSecret).update(`${childInstanceId}|${nonce}`).digest('hex');
54
- const a = Buffer.from(expected, 'hex');
55
- let b;
56
- try { b = Buffer.from(String(signature), 'hex'); } catch { return { ok: false, status: 401, error: 'invalid signature encoding' }; }
57
- if (a.length !== b.length || !timingSafeEqual(a, b)) {
58
- return { ok: false, status: 401, error: 'signature mismatch' };
59
- }
60
- }
61
-
62
- const reachable = await probe(parentUrl);
63
- if (!reachable.ok) {
64
- return { ok: false, status: 502, error: `parent unreachable: ${reachable.error}` };
65
- }
66
-
67
- const dir = boundaryDir(home);
68
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
69
- const cfgPath = boundaryConfigPath(home);
70
-
71
- let prior = null;
72
- if (existsSync(cfgPath)) {
73
- try { prior = JSON.parse(readFileSync(cfgPath, 'utf8')); } catch { prior = null; }
74
- }
75
-
76
- if (prior && prior.parentInstance && prior.parentInstance !== parentInstance) {
77
- if (!allowOverride) {
78
- return {
79
- ok: false,
80
- status: 409,
81
- error: `child already bound to parent '${prior.parentInstance}'; set CONSTRUCT_BOUNDARY_ALLOW_OVERRIDE=1 to rotate`,
82
- };
83
- }
84
- const archivePath = join(dir, `boundary.${Date.now()}.json`);
85
- try { writeFileSync(archivePath, JSON.stringify(prior, null, 2)); } catch { /* archive is best effort */ }
86
- }
87
-
88
- const config = {
89
- parentInstance,
90
- parentUrl,
91
- childInstanceId,
92
- registeredAt: new Date().toISOString(),
93
- rotatedFrom: prior?.parentInstance || null,
94
- nonce: nonce || randomBytes(16).toString('hex'),
95
- boundaryVersion: BOUNDARY_VERSION,
96
- };
97
-
98
- writeFileSync(cfgPath, JSON.stringify(config, null, 2), { mode: 0o600 });
99
- return { ok: true, config, path: cfgPath };
100
- }
101
-
102
- export function probeParent(parentUrl) {
103
- return new Promise((resolve) => {
104
- let parsed;
105
- try { parsed = new URL(parentUrl); } catch { return resolve({ ok: false, error: 'invalid URL' }); }
106
- if (!/^https?:$/.test(parsed.protocol)) return resolve({ ok: false, error: 'unsupported protocol' });
107
- const fn = parsed.protocol === 'https:' ? httpsRequest : httpRequest;
108
- const req = fn({
109
- method: 'HEAD',
110
- protocol: parsed.protocol,
111
- hostname: parsed.hostname,
112
- port: parsed.port,
113
- path: parsed.pathname || '/',
114
- timeout: 3000,
115
- }, (response) => {
116
- resolve({ ok: response.statusCode < 500 });
117
- response.resume();
118
- });
119
- req.on('timeout', () => { req.destroy(); resolve({ ok: false, error: 'timeout' }); });
120
- req.on('error', (err) => resolve({ ok: false, error: err.message }));
121
- req.end();
122
- });
123
- }
124
-
125
- export function signBoundaryRequest({ childInstanceId, nonce, sharedSecret }) {
126
- return createHmac('sha256', sharedSecret).update(`${childInstanceId}|${nonce}`).digest('hex');
127
- }
@@ -1,71 +0,0 @@
1
- /**
2
- * lib/certification/dashboard-api.mjs — dashboard-safe certification status payload.
3
- *
4
- * Mirrors construct certify status for GET /api/certification/status without secrets.
5
- */
6
-
7
- import fs from 'node:fs';
8
- import path from 'node:path';
9
-
10
- import { buildCertificationStatus } from './status.mjs';
11
- import { loadCertificationStatus } from './stale-impact.mjs';
12
- import { certificationRunDir, certificationRunsRoot, listCertificationRunIds, readCertificationRun } from './store.mjs';
13
-
14
- function findConstructRoot(startPath = process.cwd()) {
15
- let current = path.resolve(startPath);
16
- while (true) {
17
- if (fs.existsSync(path.join(current, 'package.json'))) return current;
18
- const parent = path.dirname(current);
19
- if (parent === current) return path.resolve(startPath);
20
- current = parent;
21
- }
22
- }
23
-
24
- function buildStaleRows({ rootDir }) {
25
- const { status } = loadCertificationStatus({ rootDir });
26
- if (!status?.capabilities) return [];
27
- return Object.entries(status.capabilities)
28
- .filter(([, entry]) => entry.status === 'stale')
29
- .map(([capabilityId, entry]) => ({
30
- capabilityId,
31
- staleSince: entry.staleSince ?? null,
32
- staleReason: entry.staleReason ?? null,
33
- stalePaths: entry.stalePaths ?? [],
34
- }));
35
- }
36
-
37
- export function buildCertificationDashboard({ rootDir = process.cwd() } = {}) {
38
- const root = findConstructRoot(rootDir);
39
- const report = buildCertificationStatus({ rootDir: root });
40
- const runs = [];
41
- for (const runId of listCertificationRunIds({ rootDir: root }).slice(-20)) {
42
- try {
43
- const { run } = readCertificationRun(runId, { rootDir: root });
44
- const dir = certificationRunDir(runId, root);
45
- runs.push({
46
- id: run.id,
47
- scenarioId: run.scenarioId,
48
- capabilityId: run.capabilityId,
49
- status: run.verdict?.status ?? 'unknown',
50
- createdAt: run.createdAt,
51
- artifactPath: path.relative(root, path.join(dir, 'run.json')),
52
- });
53
- } catch { /* skip corrupt */ }
54
- }
55
- return {
56
- generatedAt: report.generatedAt,
57
- capabilities: report.capabilities,
58
- specialists: report.specialists,
59
- skills: report.skills,
60
- artifactTypes: report.artifactTypes,
61
- documentCategories: report.documentCategories,
62
- demos: report.demos,
63
- stale: buildStaleRows({ rootDir: root }),
64
- runs,
65
- runsDir: path.relative(root, certificationRunsRoot(root)),
66
- artifactLinks: {
67
- runsRoot: '.cx/certification/runs',
68
- recentRunIds: runs.map((r) => r.id),
69
- },
70
- };
71
- }