@geraldmaron/construct 1.0.0 → 1.0.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 (471) hide show
  1. package/.env.example +10 -7
  2. package/LICENSE +201 -21
  3. package/README.md +132 -257
  4. package/agents/contracts.json +387 -0
  5. package/agents/prompts/cx-accessibility.md +8 -0
  6. package/agents/prompts/cx-ai-engineer.md +92 -0
  7. package/agents/prompts/cx-architect.md +10 -2
  8. package/agents/prompts/cx-business-strategist.md +13 -0
  9. package/agents/prompts/cx-data-analyst.md +80 -0
  10. package/agents/prompts/cx-data-engineer.md +4 -0
  11. package/agents/prompts/cx-debugger.md +8 -0
  12. package/agents/prompts/cx-designer.md +19 -0
  13. package/agents/prompts/cx-devil-advocate.md +4 -0
  14. package/agents/prompts/cx-docs-keeper.md +128 -0
  15. package/agents/prompts/cx-engineer.md +13 -0
  16. package/agents/prompts/cx-evaluator.md +4 -0
  17. package/agents/prompts/cx-explorer.md +12 -0
  18. package/agents/prompts/cx-legal-compliance.md +13 -0
  19. package/agents/prompts/cx-operations.md +13 -0
  20. package/agents/prompts/cx-orchestrator.md +107 -4
  21. package/agents/prompts/cx-platform-engineer.md +75 -0
  22. package/agents/prompts/cx-product-manager.md +8 -0
  23. package/agents/prompts/cx-qa.md +100 -0
  24. package/agents/prompts/cx-rd-lead.md +13 -0
  25. package/agents/prompts/cx-release-manager.md +8 -0
  26. package/agents/prompts/cx-researcher.md +21 -1
  27. package/agents/prompts/cx-reviewer.md +8 -0
  28. package/agents/prompts/cx-security.md +104 -0
  29. package/agents/prompts/cx-sre.md +104 -0
  30. package/agents/prompts/cx-test-automation.md +4 -0
  31. package/agents/prompts/cx-trace-reviewer.md +7 -3
  32. package/agents/prompts/cx-ux-researcher.md +4 -0
  33. package/agents/registry.json +365 -90
  34. package/agents/role-manifests.json +217 -0
  35. package/bin/construct +3345 -141
  36. package/bin/construct-postinstall.mjs +87 -0
  37. package/commands/build/feature.md +6 -6
  38. package/commands/plan/feature.md +6 -5
  39. package/commands/plan/requirements.md +1 -1
  40. package/commands/ship/status.md +1 -1
  41. package/commands/work/drive.md +3 -3
  42. package/commands/work/optimize-prompts.md +3 -3
  43. package/db/{migrations → schema}/001_init.sql +2 -0
  44. package/db/schema/002_pgvector.sql +182 -0
  45. package/db/schema/003_intake.sql +47 -0
  46. package/examples/README.md +85 -0
  47. package/examples/internal/roles/architect/bad/clever-plan-without-contracts.md +30 -0
  48. package/examples/internal/roles/architect/golden/explicit-tradeoff-before-plan.md +23 -0
  49. package/examples/internal/roles/engineer/bad/speculative-abstraction.md +30 -0
  50. package/examples/internal/roles/engineer/golden/read-before-write.md +28 -0
  51. package/examples/internal/roles/orchestrator/bad/everything-becomes-multi-agent.md +29 -0
  52. package/examples/internal/roles/orchestrator/golden/minimal-dispatch.md +22 -0
  53. package/examples/internal/roles/qa/bad/coverage-theater.md +30 -0
  54. package/examples/internal/roles/qa/golden/regression-gate.md +23 -0
  55. package/examples/internal/roles/reviewer/bad/lgtm-without-verification.md +29 -0
  56. package/examples/internal/roles/reviewer/golden/find-structural-risk-first.md +28 -0
  57. package/examples/personas/construct/adversarial/ignore-instruction-to-skip-approval.md +22 -0
  58. package/examples/personas/construct/bad/commit-without-approval.md +30 -0
  59. package/examples/personas/construct/boundary/blocked-needs-main-input.md +29 -0
  60. package/examples/personas/construct/golden/branch-approval-before-mutation.md +36 -0
  61. package/examples/personas/construct/golden/focused-direct-answer.md +28 -0
  62. package/examples/provider-plugin/README.md +34 -0
  63. package/examples/provider-plugin/index.mjs +74 -0
  64. package/examples/provider-plugin/package.json +15 -0
  65. package/examples/seed-observations/README.md +38 -0
  66. package/examples/seed-observations/anti-patterns.md +44 -0
  67. package/examples/seed-observations/decisions.md +36 -0
  68. package/examples/seed-observations/patterns.md +42 -0
  69. package/lib/agent-contracts-enforce.mjs +158 -0
  70. package/lib/agent-contracts.mjs +231 -0
  71. package/lib/agents/postconditions.mjs +126 -0
  72. package/lib/agents/schema.mjs +124 -0
  73. package/lib/artifact-capture.mjs +183 -0
  74. package/lib/audit-trail.mjs +149 -0
  75. package/lib/auto-docs.mjs +245 -65
  76. package/lib/beads/auto-close.mjs +126 -0
  77. package/lib/beads/drift.mjs +171 -0
  78. package/lib/beads-automation.mjs +542 -0
  79. package/lib/beads-client.mjs +518 -0
  80. package/lib/beads-lock.mjs +377 -0
  81. package/lib/beads-optimistic.mjs +365 -0
  82. package/lib/bootstrap/built-ins.mjs +136 -0
  83. package/lib/bootstrap/lazy-install.mjs +161 -0
  84. package/lib/bootstrap/resources.mjs +120 -0
  85. package/lib/bootstrap.mjs +105 -0
  86. package/lib/cache-governor.js +213 -0
  87. package/lib/cache-strategy-anthropic.js +62 -0
  88. package/lib/cache-strategy-google.js +79 -0
  89. package/lib/cache-strategy-none.js +30 -0
  90. package/lib/cache-strategy-openai.js +48 -0
  91. package/lib/cache-strategy.js +91 -0
  92. package/lib/claude-allow.mjs +149 -0
  93. package/lib/cli-commands.mjs +413 -258
  94. package/lib/codex-config.mjs +3 -1
  95. package/lib/comment-lint.mjs +55 -6
  96. package/lib/completions.mjs +21 -6
  97. package/lib/config/alias.mjs +56 -0
  98. package/lib/config/project-config.mjs +335 -0
  99. package/lib/config/schema.mjs +159 -0
  100. package/lib/context-router.mjs +308 -0
  101. package/lib/cost-ledger.mjs +177 -0
  102. package/lib/cost.mjs +171 -10
  103. package/lib/dashboard-static.mjs +158 -0
  104. package/lib/deployment-mode.mjs +86 -0
  105. package/lib/deprecate.mjs +49 -0
  106. package/lib/dispatch-batch.js +183 -0
  107. package/lib/distill.mjs +21 -8
  108. package/lib/doc-stamp.mjs +164 -0
  109. package/lib/doc-verify.mjs +119 -0
  110. package/lib/docs-routing.mjs +89 -0
  111. package/lib/docs-verify.mjs +417 -0
  112. package/lib/doctor/audit.mjs +71 -0
  113. package/lib/doctor/cli.mjs +99 -0
  114. package/lib/doctor/escalate.mjs +29 -0
  115. package/lib/doctor/index.mjs +140 -0
  116. package/lib/doctor/report.mjs +170 -0
  117. package/lib/doctor/watchers/bd-watch.mjs +117 -0
  118. package/lib/doctor/watchers/cost.mjs +130 -0
  119. package/lib/doctor/watchers/disk.mjs +122 -0
  120. package/lib/doctor/watchers/handoffs.mjs +33 -0
  121. package/lib/doctor/watchers/process-pressure.mjs +60 -0
  122. package/lib/doctor/watchers/service-health.mjs +188 -0
  123. package/lib/document-extract.mjs +288 -0
  124. package/lib/document-ingest.mjs +230 -0
  125. package/lib/drop.mjs +282 -0
  126. package/lib/embed/approval-queue.mjs +176 -0
  127. package/lib/embed/artifact.mjs +349 -0
  128. package/lib/embed/authority-guard.mjs +155 -0
  129. package/lib/embed/cli.mjs +408 -0
  130. package/lib/embed/config.mjs +355 -0
  131. package/lib/embed/conflict-detection.mjs +264 -0
  132. package/lib/embed/customer-profiles.mjs +480 -0
  133. package/lib/embed/daemon.mjs +1309 -0
  134. package/lib/embed/demand-fetch.mjs +449 -0
  135. package/lib/embed/docs-lifecycle.mjs +349 -0
  136. package/lib/embed/inbox-live-watcher.mjs +119 -0
  137. package/lib/embed/inbox.mjs +343 -0
  138. package/lib/embed/intake-metrics.mjs +190 -0
  139. package/lib/embed/jobs/vector-sync.mjs +198 -0
  140. package/lib/embed/notifications.mjs +75 -0
  141. package/lib/embed/output.mjs +79 -0
  142. package/lib/embed/providers/github.mjs +295 -0
  143. package/lib/embed/providers/jira.mjs +192 -0
  144. package/lib/embed/providers/linear.mjs +186 -0
  145. package/lib/embed/providers/registry.mjs +115 -0
  146. package/lib/embed/providers/slack.mjs +203 -0
  147. package/lib/embed/recommendation-store.mjs +378 -0
  148. package/lib/embed/roadmap.mjs +374 -0
  149. package/lib/embed/role-framing.mjs +110 -0
  150. package/lib/embed/scheduler.mjs +99 -0
  151. package/lib/embed/semantic.mjs +325 -0
  152. package/lib/embed/snapshot.mjs +191 -0
  153. package/lib/embed/supervision.mjs +235 -0
  154. package/lib/embed/target-resolver.mjs +186 -0
  155. package/lib/embed/worker.mjs +62 -0
  156. package/lib/embed/workspaces.mjs +297 -0
  157. package/lib/engine/chunker-headings.mjs +110 -0
  158. package/lib/engine/compressor-heuristic.mjs +100 -0
  159. package/lib/engine/consolidate.mjs +287 -0
  160. package/lib/engine/contracts.mjs +126 -0
  161. package/lib/engine/defaults.mjs +129 -0
  162. package/lib/engine/eval-retrieval.mjs +148 -0
  163. package/lib/engine/fuser-rrf.mjs +62 -0
  164. package/lib/engine/index.mjs +37 -0
  165. package/lib/engine/registry.mjs +146 -0
  166. package/lib/engine/reranker-mmr.mjs +90 -0
  167. package/lib/engine/tokens.mjs +77 -0
  168. package/lib/entity-store.mjs +280 -0
  169. package/lib/env-config.mjs +69 -4
  170. package/lib/evals/retrieval-bench.mjs +159 -0
  171. package/lib/evaluator-optimizer.mjs +317 -0
  172. package/lib/features.mjs +159 -29
  173. package/lib/gates-audit.mjs +236 -0
  174. package/lib/git-hooks/prepare-commit-msg +58 -0
  175. package/lib/handoffs/cleanup.mjs +159 -0
  176. package/lib/handoffs/contract.mjs +162 -0
  177. package/lib/handoffs/inventory.mjs +120 -0
  178. package/lib/headhunt.mjs +28 -47
  179. package/lib/health-check.mjs +399 -0
  180. package/lib/hook-health.mjs +442 -0
  181. package/lib/hooks/_lib/log.mjs +82 -0
  182. package/lib/hooks/adaptive-lint.mjs +26 -2
  183. package/lib/hooks/agent-tracker.mjs +171 -14
  184. package/lib/hooks/audit-reads.mjs +109 -0
  185. package/lib/hooks/audit-trail.mjs +153 -0
  186. package/lib/hooks/bash-output-logger.mjs +71 -0
  187. package/lib/hooks/block-no-verify.mjs +41 -0
  188. package/lib/hooks/ci-status-check.mjs +82 -0
  189. package/lib/hooks/comment-lint.mjs +29 -7
  190. package/lib/hooks/config-protection.mjs +39 -18
  191. package/lib/hooks/context-watch.mjs +137 -0
  192. package/lib/hooks/context-window-recovery.mjs +4 -20
  193. package/lib/hooks/dep-audit.mjs +16 -0
  194. package/lib/hooks/doc-coupling-check.mjs +80 -0
  195. package/lib/hooks/edit-accumulator.mjs +3 -0
  196. package/lib/hooks/edit-error-recovery.mjs +3 -0
  197. package/lib/hooks/edit-guard.mjs +45 -4
  198. package/lib/hooks/env-check.mjs +3 -0
  199. package/lib/hooks/guard-bash.mjs +58 -1
  200. package/lib/hooks/mcp-audit.mjs +18 -20
  201. package/lib/hooks/mcp-health-check.mjs +36 -0
  202. package/lib/hooks/model-fallback.mjs +42 -56
  203. package/lib/hooks/policy-engine.mjs +209 -0
  204. package/lib/hooks/post-merge-docs-check.mjs +63 -0
  205. package/lib/hooks/pre-compact.mjs +4 -24
  206. package/lib/hooks/pre-push-gate.mjs +200 -37
  207. package/lib/hooks/proactive-activation.mjs +284 -0
  208. package/lib/hooks/read-tracker.mjs +27 -4
  209. package/lib/hooks/readme-age-check.mjs +77 -0
  210. package/lib/hooks/registry-sync.mjs +12 -5
  211. package/lib/hooks/scan-secrets.mjs +50 -7
  212. package/lib/hooks/session-optimize.mjs +311 -0
  213. package/lib/hooks/session-start.mjs +287 -28
  214. package/lib/hooks/stop-notify.mjs +236 -96
  215. package/lib/hooks/stop-typecheck.mjs +13 -1
  216. package/lib/hooks/test-watch.mjs +68 -0
  217. package/lib/host-capabilities.mjs +31 -10
  218. package/lib/init-docs.mjs +731 -291
  219. package/lib/init-unified.mjs +1116 -0
  220. package/lib/init-update.mjs +168 -0
  221. package/lib/init.mjs +107 -0
  222. package/lib/install/first-invocation.mjs +119 -0
  223. package/lib/install/stage-project.mjs +69 -0
  224. package/lib/intake/classify.mjs +278 -0
  225. package/lib/intake/feedback.mjs +273 -0
  226. package/lib/intake/filesystem-queue.mjs +158 -0
  227. package/lib/intake/intake-config.mjs +132 -0
  228. package/lib/intake/postgres-queue.mjs +198 -0
  229. package/lib/intake/prepare.mjs +139 -0
  230. package/lib/intake/queue.mjs +83 -0
  231. package/lib/intake/session-prelude.mjs +50 -0
  232. package/lib/integrations/intake-integrations.mjs +740 -0
  233. package/lib/intent-classifier.mjs +253 -0
  234. package/lib/knowledge/layout.mjs +72 -0
  235. package/lib/knowledge/rag.mjs +331 -0
  236. package/lib/knowledge/search.mjs +315 -0
  237. package/lib/knowledge/trends.mjs +261 -0
  238. package/lib/logger.mjs +85 -0
  239. package/lib/mcp/broker.mjs +124 -0
  240. package/lib/mcp/server.mjs +554 -854
  241. package/lib/mcp/tools/document.mjs +132 -0
  242. package/lib/mcp/tools/memory.mjs +209 -0
  243. package/lib/mcp/tools/project.mjs +349 -0
  244. package/lib/mcp/tools/skills.mjs +409 -0
  245. package/lib/mcp/tools/storage.mjs +60 -0
  246. package/lib/mcp/tools/telemetry.mjs +315 -0
  247. package/lib/mcp/tools/workflow.mjs +112 -0
  248. package/lib/mcp-catalog.json +54 -3
  249. package/lib/mcp-manager.mjs +96 -48
  250. package/lib/mcp-platform-config.mjs +22 -22
  251. package/lib/memory-stats.mjs +121 -0
  252. package/lib/mode-commands.mjs +124 -0
  253. package/lib/model-free-selector.mjs +184 -0
  254. package/lib/model-pricing.mjs +152 -0
  255. package/lib/model-registry.mjs +226 -0
  256. package/lib/model-router.mjs +362 -386
  257. package/lib/observation-store.mjs +391 -0
  258. package/lib/ollama-manager.mjs +428 -0
  259. package/lib/opencode-config.mjs +13 -3
  260. package/lib/opencode-runtime-plugin.mjs +70 -38
  261. package/lib/opencode-telemetry.mjs +64 -6
  262. package/lib/orchestration-policy.mjs +509 -6
  263. package/lib/overrides/resolver.mjs +207 -0
  264. package/lib/parity.mjs +147 -0
  265. package/lib/paths.mjs +33 -0
  266. package/lib/performance/generate.mjs +212 -0
  267. package/lib/plugin-registry.mjs +268 -0
  268. package/lib/policy/engine.mjs +130 -0
  269. package/lib/policy/unified-gates.mjs +96 -0
  270. package/lib/project-detection.mjs +129 -0
  271. package/lib/project-init-shared.mjs +272 -0
  272. package/lib/project-profile.mjs +447 -0
  273. package/lib/prompt-composer.js +434 -0
  274. package/lib/prompt-metadata.mjs +1 -1
  275. package/lib/provider-capabilities-anthropic.js +44 -0
  276. package/lib/provider-capabilities-deepseek.js +37 -0
  277. package/lib/provider-capabilities-generic.js +26 -0
  278. package/lib/provider-capabilities-google.js +47 -0
  279. package/lib/provider-capabilities-openai.js +45 -0
  280. package/lib/provider-capabilities.js +142 -0
  281. package/lib/providers/atlassian-confluence/index.mjs +103 -0
  282. package/lib/providers/atlassian-jira/index.mjs +100 -0
  283. package/lib/providers/auth-manager.mjs +126 -0
  284. package/lib/providers/circuit-breaker.mjs +124 -0
  285. package/lib/providers/contract.mjs +93 -0
  286. package/lib/providers/github/index.mjs +126 -0
  287. package/lib/providers/registry.mjs +184 -0
  288. package/lib/providers/salesforce/index.mjs +100 -0
  289. package/lib/providers/slack/index.mjs +80 -0
  290. package/lib/reflect.mjs +137 -0
  291. package/lib/research-lint.mjs +164 -0
  292. package/lib/resources/budget.mjs +259 -0
  293. package/lib/role-preload.mjs +21 -6
  294. package/lib/roles/approval-surface.mjs +54 -0
  295. package/lib/roles/cli.mjs +118 -0
  296. package/lib/roles/event-bus.mjs +79 -0
  297. package/lib/roles/fence.mjs +84 -0
  298. package/lib/roles/gateway.mjs +260 -0
  299. package/lib/roles/hook-emit.mjs +37 -0
  300. package/lib/roles/manifest.mjs +48 -0
  301. package/lib/roles/router.mjs +27 -0
  302. package/lib/runtime-pressure.mjs +360 -0
  303. package/lib/schema-artifact.mjs +134 -0
  304. package/lib/schema-infer.mjs +551 -0
  305. package/lib/server/auth.mjs +168 -0
  306. package/lib/server/chat.mjs +336 -0
  307. package/lib/server/cors.mjs +77 -0
  308. package/lib/server/csrf.mjs +91 -0
  309. package/lib/server/index.mjs +1927 -78
  310. package/lib/server/insights.mjs +765 -0
  311. package/lib/server/rate-limit.mjs +91 -0
  312. package/lib/server/static/assets/index-ab25c707.js +70 -0
  313. package/lib/server/static/assets/index-f0c80a2b.css +1 -0
  314. package/lib/server/static/index.html +12 -817
  315. package/lib/server/telemetry-login.mjs +108 -0
  316. package/lib/server/webhook.mjs +510 -0
  317. package/lib/service-manager.mjs +522 -58
  318. package/lib/services/pattern-promotion-service.mjs +167 -0
  319. package/lib/services/telemetry-backend.mjs +178 -0
  320. package/lib/session-store.mjs +374 -0
  321. package/lib/setup-prompts.mjs +96 -0
  322. package/lib/setup.mjs +525 -38
  323. package/lib/skills-apply.mjs +280 -0
  324. package/lib/skills-scope.mjs +118 -0
  325. package/lib/status.mjs +261 -70
  326. package/lib/storage/admin.mjs +355 -0
  327. package/lib/storage/backend.mjs +2 -1
  328. package/lib/storage/backup.mjs +347 -0
  329. package/lib/storage/embeddings-engine.mjs +133 -0
  330. package/lib/storage/embeddings-legacy.mjs +85 -0
  331. package/lib/storage/embeddings-local.mjs +108 -0
  332. package/lib/storage/embeddings-ollama.mjs +78 -0
  333. package/lib/storage/embeddings-openai.mjs +85 -0
  334. package/lib/storage/embeddings.mjs +92 -33
  335. package/lib/storage/file-lock.mjs +130 -0
  336. package/lib/storage/fusion.mjs +95 -0
  337. package/lib/storage/hybrid-query.mjs +34 -27
  338. package/lib/storage/migrations.mjs +187 -0
  339. package/lib/storage/postgres-backup.mjs +124 -0
  340. package/lib/storage/sql-store.mjs +5 -15
  341. package/lib/storage/state-source.mjs +12 -13
  342. package/lib/storage/store-version.mjs +115 -0
  343. package/lib/storage/sync.mjs +144 -35
  344. package/lib/storage/unified-storage.mjs +550 -0
  345. package/lib/storage/vector-client.mjs +286 -0
  346. package/lib/storage/vector-store.mjs +71 -30
  347. package/lib/task-graph/generate.mjs +135 -0
  348. package/lib/task-graph/schema.mjs +81 -0
  349. package/lib/task-graph/store.mjs +71 -0
  350. package/lib/telemetry/backends/local.mjs +62 -0
  351. package/lib/telemetry/backends/{langfuse.mjs → remote.mjs} +27 -14
  352. package/lib/telemetry/backfill.mjs +180 -0
  353. package/lib/telemetry/eval-datasets.mjs +203 -0
  354. package/lib/telemetry/{langfuse-ingest.mjs → ingest.mjs} +26 -20
  355. package/lib/telemetry/intent-verifications.mjs +86 -0
  356. package/lib/telemetry/llm-judge.mjs +350 -0
  357. package/lib/telemetry/model-pricing-catalog.mjs +557 -0
  358. package/lib/telemetry/setup.mjs +151 -0
  359. package/lib/telemetry/skill-calls.mjs +78 -0
  360. package/lib/telemetry/team-rollup.mjs +4 -4
  361. package/lib/token-engine.js +117 -0
  362. package/lib/token-estimator-anthropic.js +15 -0
  363. package/lib/token-estimator-deepseek.js +13 -0
  364. package/lib/token-estimator-default.js +13 -0
  365. package/lib/token-estimator-google.js +13 -0
  366. package/lib/token-estimator-openai.js +13 -0
  367. package/lib/toolkit-env.mjs +1 -1
  368. package/lib/tty-prompts.mjs +211 -0
  369. package/lib/uninstall/uninstall.mjs +423 -0
  370. package/lib/update.mjs +115 -0
  371. package/lib/upgrade.mjs +141 -0
  372. package/lib/validator.mjs +51 -2
  373. package/lib/validators/skills.mjs +142 -0
  374. package/lib/wireframe.mjs +422 -0
  375. package/lib/worker/entrypoint.mjs +241 -0
  376. package/lib/worker/evidence.mjs +107 -0
  377. package/lib/worker/run.mjs +154 -0
  378. package/lib/worker/trace.mjs +182 -0
  379. package/lib/workflow-state.mjs +14 -18
  380. package/package.json +21 -8
  381. package/personas/construct.md +53 -51
  382. package/platforms/claude/CLAUDE.md +1 -1
  383. package/platforms/claude/settings.template.json +115 -68
  384. package/platforms/opencode/config.template.json +3 -7
  385. package/rules/common/agents.md +11 -38
  386. package/rules/common/beads-hygiene.md +75 -0
  387. package/rules/common/code-review.md +11 -100
  388. package/rules/common/coding-style.md +5 -3
  389. package/rules/common/comments.md +30 -111
  390. package/rules/common/commit-approval.md +53 -0
  391. package/rules/common/cx-agent-routing.md +1 -0
  392. package/rules/common/development-workflow.md +23 -41
  393. package/rules/common/doc-ownership.md +54 -0
  394. package/rules/common/efficiency.md +57 -0
  395. package/rules/common/framing.md +76 -0
  396. package/rules/common/git-workflow.md +2 -4
  397. package/rules/common/patterns.md +3 -7
  398. package/rules/common/performance.md +15 -31
  399. package/rules/common/release-gates.md +69 -0
  400. package/rules/common/research.md +107 -0
  401. package/rules/common/security.md +6 -6
  402. package/rules/common/skill-composition.md +67 -0
  403. package/rules/common/testing.md +15 -27
  404. package/rules/golang/hooks.md +0 -4
  405. package/rules/policy/bootstrap.yaml +11 -0
  406. package/rules/policy/drive.yaml +8 -0
  407. package/rules/policy/task.yaml +9 -0
  408. package/rules/policy/workflow.yaml +9 -0
  409. package/rules/python/hooks.md +0 -4
  410. package/rules/swift/hooks.md +0 -4
  411. package/rules/typescript/hooks.md +0 -4
  412. package/rules/web/hooks.md +0 -2
  413. package/{sync-agents.mjs → scripts/sync-agents.mjs} +306 -61
  414. package/skills/ai/prompt-optimizer.md +7 -7
  415. package/skills/compliance/ai-disclosure.md +58 -0
  416. package/skills/compliance/data-privacy.md +46 -0
  417. package/skills/compliance/license-audit.md +40 -0
  418. package/skills/compliance/regulatory-review.md +61 -0
  419. package/skills/docs/document-ingest-workflow.md +52 -0
  420. package/skills/docs/evidence-ingest-workflow.md +9 -0
  421. package/skills/docs/init-docs.md +51 -18
  422. package/skills/docs/product-intelligence-workflow.md +12 -0
  423. package/skills/docs/product-signal-workflow.md +4 -0
  424. package/skills/docs/research-workflow.md +23 -8
  425. package/skills/docs/runbook-workflow.md +1 -1
  426. package/skills/operating/orchestration-reference.md +151 -0
  427. package/skills/roles/architect.md +5 -0
  428. package/skills/roles/engineer.md +32 -0
  429. package/skills/roles/operator.md +12 -0
  430. package/skills/roles/reviewer.md +23 -0
  431. package/skills/routing.md +1 -1
  432. package/templates/devcontainer/Dockerfile.devcontainer +38 -0
  433. package/templates/devcontainer/devcontainer.json +31 -0
  434. package/templates/distribution/bootstrap.ps1 +142 -0
  435. package/templates/distribution/bootstrap.sh +196 -0
  436. package/templates/distribution/run.mjs +187 -0
  437. package/templates/docs/adr.md +44 -8
  438. package/templates/docs/changelog-entry.md +43 -0
  439. package/templates/docs/construct_guide.md +149 -0
  440. package/templates/docs/evidence-brief.md +2 -2
  441. package/templates/docs/meta-prd.md +140 -19
  442. package/templates/docs/onboarding.md +57 -0
  443. package/templates/docs/prd.md +159 -15
  444. package/templates/docs/research-brief.md +4 -4
  445. package/templates/homebrew/construct.rb +67 -0
  446. package/langfuse/docker-compose.yml +0 -82
  447. package/lib/eval-harness.mjs +0 -59
  448. package/lib/hooks/bootstrap-guard.mjs +0 -90
  449. package/lib/hooks/console-warn.mjs +0 -43
  450. package/lib/hooks/continuation-enforcer.mjs +0 -72
  451. package/lib/hooks/drive-guard.mjs +0 -89
  452. package/lib/hooks/mcp-task-scope.mjs +0 -47
  453. package/lib/hooks/task-completed-guard.mjs +0 -43
  454. package/lib/hooks/teammate-idle-guard.mjs +0 -54
  455. package/lib/hooks/workflow-guard.mjs +0 -62
  456. package/lib/prompt-composer.mjs +0 -196
  457. package/lib/review.mjs +0 -429
  458. package/lib/server/static/app.js +0 -841
  459. package/lib/telemetry/langfuse-model-sync.mjs +0 -270
  460. package/rules/common/hooks.md +0 -35
  461. package/rules/zh/README.md +0 -113
  462. package/rules/zh/agents.md +0 -55
  463. package/rules/zh/code-review.md +0 -129
  464. package/rules/zh/coding-style.md +0 -53
  465. package/rules/zh/development-workflow.md +0 -49
  466. package/rules/zh/git-workflow.md +0 -29
  467. package/rules/zh/hooks.md +0 -35
  468. package/rules/zh/patterns.md +0 -36
  469. package/rules/zh/performance.md +0 -60
  470. package/rules/zh/security.md +0 -34
  471. package/rules/zh/testing.md +0 -34
@@ -0,0 +1,151 @@
1
+ <!--
2
+ skills/operating/orchestration-reference.md — detailed orchestration reference loaded on demand.
3
+
4
+ Holds the execution contract, handoff template, intent and work-category
5
+ classification, parallel dispatch, horizontal routing, and efficiency
6
+ discipline. Called via get_skill("operating/orchestration-reference") by
7
+ specialists and personas when they need the full context; short essentials
8
+ stay in sharedGuidance so they load every turn.
9
+ -->
10
+
11
+ # Orchestration Reference
12
+
13
+ Loaded on demand via `get_skill("operating/orchestration-reference")`.
14
+
15
+ This is the detailed reference for Construct's orchestration contract. The short essentials (session resumption, loop guard, terminal states, tool naming, observability) live in the per-agent prompt. Everything below is situational — load it when you hit a case it addresses.
16
+
17
+ ## System model
18
+
19
+ Construct is the underlying orchestration system for the **current project**. Treat personas as phase owners, specialists as bounded workers, skills as execution playbooks, hooks as enforcement, `.cx/workflow.json` as the durable cross-task workflow ledger, `.cx/task-graphs/<id>.json` as the per-signal execution plans derived from R&D intake triage, and memory / .cx artifacts as persistent project state.
20
+
21
+ The two task-shaped surfaces are siblings, not duplicates:
22
+
23
+ - **`.cx/workflow.json`** — single project-wide workflow file. Holds the cross-cutting task ledger and intent / category metadata. Drives `workflow_status` and `project_context` MCP tools.
24
+ - **`.cx/task-graphs/<id>.json`** — per-incoming-signal plan generated by `construct graph from-intake <intake-id>`. One graph per triaged inbox file, one node per persona in the recommendedChain, evidence records gating `done`. See [Concepts → Intake and triage](/concepts/intake-and-triage).
25
+
26
+ A signal that becomes durable cross-session work crosses over: the graph nodes are executed, the resulting work is tracked in `.cx/workflow.json` and in beads. The intake queue and task graphs are how new signals enter the loop; the workflow ledger and beads are how durable work is carried.
27
+
28
+ ## Perspective architecture
29
+
30
+ Each specialist carries a distinct cognitive profile shaped by professional prior, characteristic suspicion, and productive tension with adjacent roles. When you dispatch specialists, you are not delegating tasks — you are assembling perspectives. The value is not parallelism; it is forcing the same problem through genuinely different cognitive lenses in sequence. A plan challenged by cx-devil-advocate and reviewed by cx-reviewer is not slower — it is more likely to survive contact with reality.
31
+
32
+ ## Execution contract
33
+
34
+ For every non-trivial task: classify intent, create or update `.cx/workflow.json`, route to the owning persona or specialist, execute with the relevant skill, dispatch independent work in parallel when supported, persist decisions/handoffs to memory or `.cx`, validate through the validation phase before release.
35
+
36
+ ### Intent classes
37
+
38
+ - `research` — read-only investigation
39
+ - `implementation` — code changes
40
+ - `investigation` — debugging, tracing
41
+ - `evaluation` — quality gates, review
42
+ - `fix` — bug repair
43
+
44
+ Tag every workflow task with its intent class. Let intent drive agent selection and depth of work.
45
+
46
+ ### Work categories
47
+
48
+ - `visual` (UI/CSS/design) → standard tier
49
+ - `deep` (complex reasoning, architecture) → reasoning tier
50
+ - `quick` (single-file, trivial) → fast tier
51
+ - `writing` (docs, prose) → fast tier
52
+ - `analysis` (data, metrics, review) → standard tier
53
+
54
+ ## Workflow state
55
+
56
+ Task packets include an optional `mcpScope` field: list MCP server names relevant to this task (e.g. `["github", "context7"]`). The mcp-task-scope hook warns when out-of-scope MCPs are called. The mcp-audit hook records all MCP usage per task key to `.cx/mcp-audit.json`.
57
+
58
+ Every delegated task needs a stable `TASK_KEY`, `phase`, `owner`, `status`, `readFirst`, `doNotChange`, `acceptanceCriteria`, and `verification` evidence before done. Run `construct workflow align` at phase transitions.
59
+
60
+ ## Native surfaces
61
+
62
+ Use native skills, plugins, slash commands, MCP tools, and project instructions when they exist and match the task. Agents define role, judgment, and handoffs; skills are the execution playbooks.
63
+
64
+ If a native skill or project instruction conflicts with this registry, obey the higher-priority system, tool, and repository instructions. Surface the conflict, the decision made, and any follow-up needed.
65
+
66
+ Do not duplicate skill internals inside agent prompts. Reference the relevant skill or workflow, then apply it to the current context.
67
+
68
+ ## Agent-to-agent service contracts
69
+
70
+ Every producer→consumer pair has an explicit contract in `agents/contracts.json`, loaded via `lib/agent-contracts.mjs`. Specialists call the MCP tool `agent_contract` at the start of a handoff to see:
71
+
72
+ - `input.mustContain` — fields the packet must carry
73
+ - `input.schema` — JSON schema (when applicable) from `lib/schemas/`
74
+ - `preconditions` — what must be true before work starts
75
+ - `output.schema` / `output.shape` — expected return shape
76
+ - `postconditions` — what must be true before marking DONE
77
+
78
+ Examples of contracts (full list in `agents/contracts.json`):
79
+
80
+ - `researcher-to-architect` — research brief with ≥2 primary sources → decision
81
+ - `product-manager-to-architect` — PRD handoff → decision with Rejected alternatives
82
+ - `architect-to-devil-advocate` — framing proposal → challenge report (blocks if framing is weak)
83
+ - `architect-to-engineer` — decision → implementation
84
+ - `engineer-to-reviewer` — implementation → review verdict
85
+ - `engineer-to-qa` — implementation → test report
86
+ - `reviewer-to-security` — review with auth/secrets scope → specialized security review
87
+ - `any-to-docs-keeper` — any DONE mutation that changed core docs → doc sync
88
+
89
+ `routeRequest` returns a `contractChain` that enumerates which of these fire for a given request. Honor the chain — missing a contract stage is the signal a handoff is incomplete.
90
+
91
+ ## Legacy handoff contract (fallback)
92
+
93
+ When a contract isn't registered for a specific pair, fall back to this minimum:
94
+
95
+ - **TASK** (one atomic goal)
96
+ - **EXPECTED OUTCOME** (deliverable + acceptance signal)
97
+ - **REQUIRED TOOLS**
98
+ - **MUST DO** (exhaustive)
99
+ - **MUST NOT DO** (anticipate drift)
100
+ - **CONTEXT** (files, decisions, constraints)
101
+ - **READ FIRST**
102
+ - **DO NOT CHANGE**
103
+
104
+ Missing required fields mean the handoff is incomplete.
105
+
106
+ ## Primary persona contract
107
+
108
+ Personas own user interaction. When a worker returns `NEEDS_MAIN_INPUT`, ask the question in the main session, update `.cx/workflow.json` to `blocked_needs_user`, then resume or re-dispatch the worker after the user answers.
109
+
110
+ ## Parallel dispatch
111
+
112
+ When two or more specialists can work independently, write `[parallel: cx-agent-a, cx-agent-b]` before the handoff list and give each agent a disjoint scope. Do not mark dependent work as parallel.
113
+
114
+ ## Horizontal routing
115
+
116
+ When your output directly feeds another specialist (e.g. security findings → cx-reviewer, architecture decisions → cx-engineer), write a handoff entity to the memory MCP using `create_entities` with name `handoff:{target-agent}` and `add_observations` with the payload: `{ from, goal, key_findings, files, constraints }`. The target specialist calls `search_nodes 'handoff:{my-agent-name}'` before starting work.
117
+
118
+ ## Context & efficiency (enforced)
119
+
120
+ These are enforced by hooks, not advisory:
121
+
122
+ - `context-watch` hook (UserPromptSubmit) injects compaction guidance at ~60% / ~80% of the context window.
123
+ - `repeated-read-guard` hook (PreToolUse on Read) blocks broad re-reads of files already read twice in this session — steers to Grep or offset+limit.
124
+ - `bash-output-logger` hook (PostToolUse on Bash) persists outputs >4KB to `~/.cx/bash-logs/` and tells the model to grep the log rather than re-run.
125
+
126
+ Advisory companions:
127
+
128
+ - Use `Grep` and `Glob` to narrow scope before `Read`.
129
+ - Prefer targeted reads under 400 lines.
130
+ - Probe file size before bulk reads: `Glob`, `wc -l`, or a `limit=50` probe.
131
+ - Keep response summaries under 100 words unless the user asks for more detail.
132
+
133
+ ## Deliberation cap
134
+
135
+ If you reason about the same decision across two consecutive turns without a new file read, tool call, or user answer, stop. Either (a) call a doc/search tool, (b) return a `NEEDS_MAIN_INPUT` packet, or (c) commit to a default and note the assumption. Never a third round of internal debate.
136
+
137
+ ## Speculation rule
138
+
139
+ When choosing between named options (SDK vs SDK, library vs library, pattern vs pattern), the answer comes from `context7_query-docs`, `WebFetch`, the user, or an explicit default — never from internal reasoning rounds alone.
140
+
141
+ ## Dispatch-first test
142
+
143
+ If work touches 3+ files across 2+ modules, or introduces a new contract/dependency/SDK, the persona must not produce the implementation plan itself — dispatch cx-architect. In-persona implementation planning for complex work is the primary failure mode this rule exists to prevent.
144
+
145
+ ## Executive communication
146
+
147
+ Treat the user as the Customer and Executive. Proactive reporting on status, immediate escalation of strategic blockers, seeking input on all user-facing changes (UX/UI). When in doubt, clarify intent rather than assuming a product decision.
148
+
149
+ ## Comment hygiene
150
+
151
+ Avoid pointless comments. Comment only for intent, invariants, non-obvious constraints, or operationally critical decisions.
@@ -1,6 +1,11 @@
1
1
  <!--
2
2
  skills/roles/architect.md — Anti-pattern guidance for the Architect role.
3
3
 
4
+ ## Improvement Note (auto-generated 2026-04-29)
5
+ - Improve specificity in technical guidance; provide detailed steps or code snippets rather than vague suggestions.
6
+ - Ensure that responses directly address the user's request; avoid unrelated topics or general advice that doesn't pertain to the task.
7
+ - Incorporate thorough explanations for any proposed solutions or changes to clarify their importance and methodology.
8
+
4
9
  Loaded at sync time to inline role-specific failure modes into specialist agent prompts.
5
10
  Covers common failure modes for the architect domain and counter-moves to avoid them.
6
11
  Applies to: cx-architect, cx-rd-lead.
@@ -83,3 +83,35 @@ Load this before drafting. These are the failure modes that separate strong role
83
83
  - [ ] Diff is narrow and on-topic
84
84
  - [ ] No more than two consecutive thinking turns about the same decision without a tool call or input
85
85
  - [ ] Any `Read` over 200 lines was preceded by a size probe
86
+
87
+ ## Hard release gates (blocking, run locally — never push and pray)
88
+
89
+ Run all four before declaring work done. CI is a backstop, not the primary gate. See `rules/common/release-gates.md`.
90
+
91
+ - [ ] `npm test` — 0 failed
92
+ - [ ] `node bin/construct lint:comments` — 0 errors AND 0 warnings
93
+ - [ ] `node bin/construct docs:verify` — all checks passed, no warnings
94
+ - [ ] `node bin/construct docs:update --check` — AUTO regions clean
95
+ - [ ] `npm run lint:templates` — commit subjects + PR body match templates
96
+
97
+ Shortcut: `npm run release:check`.
98
+
99
+ ## Tracker + docs contract
100
+
101
+ - [ ] Beads issue exists for this change (`bd ready`/`bd show <id>`/`bd update <id> --claim`)
102
+ - [ ] `plan.md` reflects the change (mark done, add new rows, remove stale)
103
+ - [ ] `docs/architecture.md` updated if runtime shape, contracts, or boundaries changed
104
+ - [ ] `docs/README.md` updated if the docs surface or maintenance contract changed
105
+ - [ ] `.cx/context.md` and `.cx/context.json` updated if active work, decisions, or assumptions changed
106
+ - [ ] `CHANGELOG.md` has an entry
107
+ - [ ] `bd close <id>` happens after CI is green, not before
108
+
109
+
110
+ ## Learned Patterns
111
+
112
+ ### L1. Read file and callers before changing
113
+ **Context**: General
114
+ **Effective Action**: Before modifying a function, read the full file and grep for callers with `grep -r 'functionName' src/`...
115
+ **Evidence**: Score 0.89, used 8 times, 2 projects
116
+ *Last reinforced: 2026-05-04*
117
+
@@ -52,10 +52,21 @@ Load this before producing operator output — SRE, ops, release, and durable-kn
52
52
  **Counter-move**: every non-trivial release has a changelog entry, a rollback plan, and a comms channel notified.
53
53
 
54
54
  ### 8. Unbounded retries
55
+
55
56
  **Symptom**: failures retried forever or with naive backoff; retries hide underlying capacity issues.
57
+
56
58
  **Why it fails**: retry storms amplify outages. A transient failure becomes a full incident.
59
+
57
60
  **Counter-move**: bounded retries. Exponential backoff with jitter. Circuit breakers on downstream dependencies.
58
61
 
62
+ ### 9. Execution gap blindness
63
+
64
+ **Symptom**: strategy/PRDs/RFCs document what should be built, but Jira tickets don't reflect the full scope. Work drifts without detection.
65
+
66
+ **Why it fails**: no systematic comparison between planned work (documents) and actual work (tickets). Gaps accumulate silently until delivery dates slip.
67
+
68
+ **Counter-move**: run periodic gap analysis: query strategy/PRDs/RFCs from knowledge base, compare with Jira tickets via search, identify missing tickets. Create补缺 tickets automatically (or queue for approval). Treat "execution gap" as a first-class risk signal.
69
+
59
70
  ## Self-check before shipping
60
71
 
61
72
  - [ ] Each runbook step names its purpose and expected output
@@ -66,3 +77,4 @@ Load this before producing operator output — SRE, ops, release, and durable-kn
66
77
  - [ ] Operational docs have a last-tested or last-reviewed date
67
78
  - [ ] Every release has a changelog, rollback, and comms plan
68
79
  - [ ] Retries are bounded; circuit breakers protect dependencies
80
+ - [ ] Execution gaps between strategy/PRDs/RFCs and Jira tickets are detected and closed
@@ -66,3 +66,26 @@ Load this before drafting. These are the failure modes that separate strong role
66
66
  - [ ] New behavior has a test that would catch its regression
67
67
  - [ ] High-risk domains (auth, payments, data) explicitly scrutinized
68
68
  - [ ] Rewrote only when asked; otherwise described the issue
69
+
70
+ ## Hard release gates (block approval if any fail)
71
+
72
+ A review that approves while these gates would fail in CI is a failed review. Run or confirm the author ran:
73
+
74
+ - [ ] `npm test` — 0 failed
75
+ - [ ] `node bin/construct lint:comments` — 0 errors AND 0 warnings (treat warnings as blocking)
76
+ - [ ] `node bin/construct docs:verify` — all checks passed, no warnings
77
+ - [ ] `node bin/construct docs:update --check` — AUTO regions up to date
78
+ - [ ] `npm run lint:templates` — commit subjects + PR body match the canonical templates
79
+
80
+ See `rules/common/release-gates.md`. Block approval until evidence is in the PR body.
81
+
82
+ ## Tracker + docs contract
83
+
84
+ Reject a change that ships code without the matching documentation update. Specifically check:
85
+
86
+ - [ ] Beads issue exists and is linked
87
+ - [ ] `plan.md` reflects the change
88
+ - [ ] `docs/architecture.md` updated when runtime shape, contracts, or boundaries changed
89
+ - [ ] `docs/README.md` updated when the docs surface or maintenance contract changed
90
+ - [ ] `.cx/context.md` and `.cx/context.json` updated when active work, decisions, or assumptions changed
91
+ - [ ] `CHANGELOG.md` has an entry that names what changed and why
package/skills/routing.md CHANGED
@@ -59,7 +59,7 @@ Read the matching skill file before responding when the user's request matches t
59
59
  | workflow state, orchestration state, task key, handoff contract, phase gate, project alignment | `skills/ai/orchestration-workflow.md` | Construct-style workflow state and phase alignment |
60
60
  | LLM security, prompt injection, jailbreak, guardrail | `skills/ai/llm-security.md` | LLM security and guardrails |
61
61
  | prompt engineering, model evaluation, benchmark, fine-tuning | `skills/ai/prompt-and-eval.md` | Prompt engineering and evaluation |
62
- | prompt optimization, improve prompt, optimize agent, quality score, staging prompt, promotion | `skills/ai/prompt-optimizer.md` | Closed-loop prompt auto-optimization via Langfuse traces |
62
+ | prompt optimization, improve prompt, optimize agent, quality score, staging prompt, promotion | `skills/ai/prompt-optimizer.md` | Closed-loop prompt auto-optimization via telemetry traces |
63
63
  | MLOps, ML pipeline, model registry, model deployment, feature store, drift detection, model monitoring, training pipeline | `skills/ai/ml-ops.md` | ML operations and model lifecycle |
64
64
 
65
65
  ## DevOps Domain
@@ -0,0 +1,38 @@
1
+ # Dockerfile.devcontainer — development container for Construct projects.
2
+ #
3
+ # This is NOT the production image (see Dockerfile in the project root).
4
+ # It bundles a full Node.js dev environment + Construct pre-installed so
5
+ # any team member can open the project in VS Code / Codespaces and have
6
+ # a working Construct environment without any host-side setup.
7
+ #
8
+ # Usage via construct init --devcontainer:
9
+ # - Copies this file + devcontainer.json into .devcontainer/
10
+ # - Commits both files; teammates open the project and VS Code prompts to
11
+ # "Reopen in Container"
12
+
13
+ ARG NODE_VERSION=22
14
+ ARG CONSTRUCT_VERSION=latest
15
+
16
+ FROM node:${NODE_VERSION}-bookworm-slim
17
+
18
+ # Install system deps for development (git, curl, docker CLI for resource spinup)
19
+ RUN apt-get update && apt-get install -y --no-install-recommends \
20
+ git curl ca-certificates gnupg \
21
+ && curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker.gpg \
22
+ && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker.gpg] \
23
+ https://download.docker.com/linux/debian bookworm stable" \
24
+ > /etc/apt/sources.list.d/docker.list \
25
+ && apt-get update && apt-get install -y --no-install-recommends docker-ce-cli \
26
+ && apt-get clean && rm -rf /var/lib/apt/lists/*
27
+
28
+ # Install Construct globally so `construct` command is available everywhere.
29
+ # The version is pinned by the ARG so the container is reproducible.
30
+ RUN npm install -g @geraldmaron/construct@${CONSTRUCT_VERSION}
31
+
32
+ # Pre-warm npx cache so the first `npx construct` is instant.
33
+ RUN npx --yes @geraldmaron/construct@${CONSTRUCT_VERSION} --version 2>/dev/null || true
34
+
35
+ WORKDIR /workspace
36
+
37
+ # Project files are bind-mounted at runtime; this just ensures the dir exists.
38
+ CMD ["bash"]
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "Construct Dev",
3
+ "build": {
4
+ "dockerfile": "Dockerfile.devcontainer",
5
+ "context": ".."
6
+ },
7
+ "features": {
8
+ "ghcr.io/devcontainers/features/git:1": {},
9
+ "ghcr.io/devcontainers/features/docker-in-docker:2": {}
10
+ },
11
+ "forwardPorts": [4242],
12
+ "portsAttributes": {
13
+ "4242": {
14
+ "label": "Construct Dashboard",
15
+ "onAutoForward": "notify"
16
+ }
17
+ },
18
+ "postCreateCommand": "node .construct/run.mjs setup --auto",
19
+ "remoteEnv": {
20
+ "CONSTRUCT_VERSION": "${localEnv:CONSTRUCT_VERSION}",
21
+ "ANTHROPIC_API_KEY": "${localEnv:ANTHROPIC_API_KEY}"
22
+ },
23
+ "customizations": {
24
+ "vscode": {
25
+ "extensions": ["anthropic.claude-code"],
26
+ "settings": {
27
+ "terminal.integrated.defaultProfile.linux": "bash"
28
+ }
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,142 @@
1
+ # .construct/bootstrap.ps1 — Windows PowerShell bootstrap shim.
2
+ #
3
+ # Usage:
4
+ # powershell -ExecutionPolicy Bypass -File .construct\bootstrap.ps1 # probe + plan
5
+ # powershell -ExecutionPolicy Bypass -File .construct\bootstrap.ps1 -Install # ensure runtime
6
+ # powershell -ExecutionPolicy Bypass -File .construct\bootstrap.ps1 -- <args…> # invoke with args
7
+ #
8
+ # Mirrors bootstrap.sh: same resolution order (node_modules → npx → global →
9
+ # cached binary → docker → fail). Forwards every argument and stream.
10
+
11
+ [CmdletBinding()]
12
+ param(
13
+ [switch]$Install,
14
+ [Parameter(ValueFromRemainingArguments=$true)]
15
+ [string[]]$ConstructArgs
16
+ )
17
+
18
+ $ErrorActionPreference = 'Stop'
19
+
20
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
21
+ $ProjectRoot = Resolve-Path (Join-Path $ScriptDir '..')
22
+ $VersionFile = Join-Path $ScriptDir 'version'
23
+ $CacheBinDir = Join-Path $ScriptDir 'cache\bin'
24
+
25
+ $Version = ''
26
+ if (Test-Path $VersionFile) {
27
+ $Version = (Get-Content $VersionFile -Raw).Trim()
28
+ }
29
+
30
+ function Test-NodeMin18 {
31
+ if (-not (Get-Command node -ErrorAction SilentlyContinue)) { return $false }
32
+ $v = (node --version) -replace '^v',''
33
+ $major = [int]($v.Split('.')[0])
34
+ return ($major -ge 18)
35
+ }
36
+
37
+ function Resolve-Arch {
38
+ switch ($env:PROCESSOR_ARCHITECTURE) {
39
+ 'AMD64' { return 'x64' }
40
+ 'ARM64' { return 'arm64' }
41
+ default { return '' }
42
+ }
43
+ }
44
+
45
+ function Invoke-NodeModules {
46
+ param([string[]]$Args)
47
+ $bin = Join-Path $ProjectRoot 'node_modules\@geraldmaron\construct\bin\construct'
48
+ if (-not (Test-Path $bin)) { return $false }
49
+ & node $bin @Args
50
+ exit $LASTEXITCODE
51
+ }
52
+
53
+ function Invoke-Npx {
54
+ param([string[]]$Args)
55
+ if (-not (Test-NodeMin18)) { return $false }
56
+ if (-not (Get-Command npx -ErrorAction SilentlyContinue)) { return $false }
57
+ $spec = if ($Version) { "@geraldmaron/construct@$Version" } else { '@geraldmaron/construct' }
58
+ & npx -p $spec -- construct @Args
59
+ exit $LASTEXITCODE
60
+ }
61
+
62
+ function Invoke-Global {
63
+ param([string[]]$Args)
64
+ if (-not (Get-Command construct -ErrorAction SilentlyContinue)) { return $false }
65
+ & construct @Args
66
+ exit $LASTEXITCODE
67
+ }
68
+
69
+ function Invoke-CachedBinary {
70
+ param([string[]]$Args)
71
+ $arch = Resolve-Arch
72
+ if (-not $arch) { return $false }
73
+ $bin = Join-Path $CacheBinDir "construct-windows-$arch.exe"
74
+ if (-not (Test-Path $bin)) { return $false }
75
+ & $bin @Args
76
+ exit $LASTEXITCODE
77
+ }
78
+
79
+ function Invoke-Docker {
80
+ param([string[]]$Args)
81
+ if (-not (Get-Command docker -ErrorAction SilentlyContinue)) { return $false }
82
+ $image = 'ghcr.io/geraldmaron/construct'
83
+ if ($Version) { $image = "${image}:$Version" } else { $image = "${image}:latest" }
84
+ & docker run --rm `
85
+ -v "${ProjectRoot}:/work" -w /work `
86
+ -v "$env:USERPROFILE\.construct:/data/.construct" `
87
+ -e CONSTRUCT_PROJECT_ROOT=/work `
88
+ $image @Args
89
+ exit $LASTEXITCODE
90
+ }
91
+
92
+ if ($Install) {
93
+ $bin = Join-Path $ProjectRoot 'node_modules\@geraldmaron\construct\bin\construct'
94
+ if (Test-Path $bin) {
95
+ Write-Host "[construct] node_modules install ready: $bin"
96
+ exit 0
97
+ }
98
+ if ((Test-NodeMin18) -and (Get-Command npx -ErrorAction SilentlyContinue)) {
99
+ Write-Host '[construct] npx will resolve construct on first invocation.'
100
+ exit 0
101
+ }
102
+ if (Get-Command docker -ErrorAction SilentlyContinue) {
103
+ Write-Host '[construct] docker available — bootstrap will use the container image on next run.'
104
+ exit 0
105
+ }
106
+ $arch = Resolve-Arch
107
+ if ($arch -and $Version -and (Get-Command curl -ErrorAction SilentlyContinue)) {
108
+ $url = "https://github.com/geraldmaron/construct/releases/download/v$Version/construct-windows-$arch.exe"
109
+ New-Item -ItemType Directory -Force -Path $CacheBinDir | Out-Null
110
+ $target = Join-Path $CacheBinDir "construct-windows-$arch.exe"
111
+ Write-Host "[construct] downloading binary to $target…"
112
+ try {
113
+ Invoke-WebRequest -Uri $url -OutFile $target -UseBasicParsing
114
+ Write-Host '[construct] binary cached. Subsequent invocations use it.'
115
+ exit 0
116
+ } catch {
117
+ Write-Host "[construct] binary download failed; falling through."
118
+ }
119
+ }
120
+ Write-Error '[construct] No installable runtime detected. Install Node.js 18+, Docker, or curl + a release binary.'
121
+ exit 127
122
+ }
123
+
124
+ # Default — resolve and invoke.
125
+ try { Invoke-NodeModules $ConstructArgs } catch {}
126
+ try { Invoke-Npx $ConstructArgs } catch {}
127
+ try { Invoke-Global $ConstructArgs } catch {}
128
+ try { Invoke-CachedBinary $ConstructArgs } catch {}
129
+ try { Invoke-Docker $ConstructArgs } catch {}
130
+
131
+ $msg = @"
132
+ [construct] No Construct install found.
133
+
134
+ This project pins Construct$($Version ? " $Version" : '') but no runtime resolved.
135
+
136
+ Pick one:
137
+ - Install Node.js 18+ from https://nodejs.org and re-run.
138
+ - powershell -File .construct\bootstrap.ps1 -Install (download a binary)
139
+ - npm install -g @geraldmaron/construct
140
+ "@
141
+ Write-Error $msg
142
+ exit 127
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env bash
2
+ # .construct/bootstrap.sh — POSIX bootstrap shim.
3
+ #
4
+ # Usage:
5
+ # ./.construct/bootstrap.sh # probe environment, print plan
6
+ # ./.construct/bootstrap.sh --install # ensure a working Construct is reachable
7
+ # ./.construct/bootstrap.sh -- <args…> # invoke construct directly with args
8
+ #
9
+ # Forwards everything after `--` to construct via the same resolution order
10
+ # as `.construct/run.mjs`. Useful for non-Node environments where settings.json
11
+ # hooks aren't enough — e.g. CI scripts, Makefiles, pre-commit hooks in
12
+ # language-agnostic projects.
13
+ #
14
+ # Exit codes:
15
+ # 0 command succeeded
16
+ # 1 construct exited non-zero
17
+ # 127 no Construct install reachable
18
+
19
+ set -eu
20
+
21
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
22
+ VERSION_FILE="${SCRIPT_DIR}/version"
23
+ PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
24
+ CACHE_BIN_DIR="${SCRIPT_DIR}/cache/bin"
25
+
26
+ VERSION=""
27
+ if [ -r "${VERSION_FILE}" ]; then
28
+ VERSION="$(tr -d '[:space:]' < "${VERSION_FILE}")"
29
+ fi
30
+
31
+ INSTALL_MODE=""
32
+ if [ "$#" -gt 0 ] && [ "$1" = "--install" ]; then
33
+ INSTALL_MODE="1"
34
+ shift
35
+ fi
36
+
37
+ if [ "$#" -gt 0 ] && [ "$1" = "--" ]; then
38
+ shift
39
+ fi
40
+
41
+ probe_node() {
42
+ command -v node >/dev/null 2>&1 || return 1
43
+ node --version | sed 's/^v//' | awk -F. '{ exit ($1 < 18) }'
44
+ }
45
+
46
+ probe_npx() { command -v npx >/dev/null 2>&1; }
47
+ probe_docker() { command -v docker >/dev/null 2>&1; }
48
+ probe_curl() { command -v curl >/dev/null 2>&1; }
49
+
50
+ resolve_arch() {
51
+ case "$(uname -m)" in
52
+ arm64|aarch64) echo "arm64" ;;
53
+ x86_64|amd64) echo "x64" ;;
54
+ *) echo "" ;;
55
+ esac
56
+ }
57
+
58
+ resolve_os() {
59
+ case "$(uname -s)" in
60
+ Darwin) echo "darwin" ;;
61
+ Linux) echo "linux" ;;
62
+ *) echo "" ;;
63
+ esac
64
+ }
65
+
66
+ local_construct_in_node_modules() {
67
+ echo "${PROJECT_ROOT}/node_modules/@geraldmaron/construct/bin/construct"
68
+ }
69
+
70
+ invoke_via_node_modules() {
71
+ local bin
72
+ bin="$(local_construct_in_node_modules)"
73
+ [ -x "${bin}" ] || return 1
74
+ exec node "${bin}" "$@"
75
+ }
76
+
77
+ invoke_via_npx() {
78
+ probe_node || return 1
79
+ probe_npx || return 1
80
+ if [ -n "${VERSION}" ]; then
81
+ exec npx -p "@geraldmaron/construct@${VERSION}" -- construct "$@"
82
+ else
83
+ exec npx -p "@geraldmaron/construct" -- construct "$@"
84
+ fi
85
+ }
86
+
87
+ invoke_via_global() {
88
+ command -v construct >/dev/null 2>&1 || return 1
89
+ exec construct "$@"
90
+ }
91
+
92
+ invoke_via_cached_binary() {
93
+ local os arch ext binary
94
+ os="$(resolve_os)"
95
+ arch="$(resolve_arch)"
96
+ [ -n "${os}" ] && [ -n "${arch}" ] || return 1
97
+ binary="${CACHE_BIN_DIR}/construct-${os}-${arch}"
98
+ [ -x "${binary}" ] || return 1
99
+ exec "${binary}" "$@"
100
+ }
101
+
102
+ invoke_via_docker() {
103
+ probe_docker || return 1
104
+ local image="ghcr.io/geraldmaron/construct"
105
+ if [ -n "${VERSION}" ]; then image="${image}:${VERSION}"; else image="${image}:latest"; fi
106
+ exec docker run --rm \
107
+ -v "${PROJECT_ROOT}:/work" -w /work \
108
+ -v "${HOME}/.construct:/data/.construct" \
109
+ -e CONSTRUCT_PROJECT_ROOT=/work \
110
+ "${image}" "$@"
111
+ }
112
+
113
+ # Compute the SHA-256 of a file using whichever tool is available, and compare
114
+ # to the expected digest. Accepts the digest as either a bare hex string or a
115
+ # `sha256sum -c`-style line ("<sha> <filename>"); we only consume the first
116
+ # 64 hex chars. Returns 0 on match, non-zero otherwise.
117
+ verify_sha256() {
118
+ local file="$1"
119
+ local expected_raw="$2"
120
+ local expected
121
+ local actual
122
+ expected="$(echo "${expected_raw}" | tr -d '[:space:]' | cut -c1-64)"
123
+ if [ -z "${expected}" ] || [ "${#expected}" -ne 64 ]; then
124
+ return 1
125
+ fi
126
+ if command -v sha256sum >/dev/null 2>&1; then
127
+ actual="$(sha256sum "${file}" | cut -c1-64)"
128
+ elif command -v shasum >/dev/null 2>&1; then
129
+ actual="$(shasum -a 256 "${file}" | cut -c1-64)"
130
+ else
131
+ return 2
132
+ fi
133
+ [ "${actual}" = "${expected}" ]
134
+ }
135
+
136
+ if [ "${INSTALL_MODE}" = "1" ]; then
137
+ if invoke_via_node_modules --version >/dev/null 2>&1; then
138
+ echo "[construct] node_modules install ready: $(local_construct_in_node_modules)"
139
+ exit 0
140
+ fi
141
+ if probe_node && probe_npx; then
142
+ echo "[construct] npx will resolve construct on first invocation."
143
+ exit 0
144
+ fi
145
+ if probe_docker; then
146
+ echo "[construct] docker available — bootstrap will use the container image on next run."
147
+ exit 0
148
+ fi
149
+ os="$(resolve_os)"
150
+ arch="$(resolve_arch)"
151
+ if probe_curl && [ -n "${os}" ] && [ -n "${arch}" ] && [ -n "${VERSION}" ]; then
152
+ binary_url="https://github.com/geraldmaron/construct/releases/download/v${VERSION}/construct-${os}-${arch}"
153
+ sha_url="${binary_url}.sha256"
154
+ mkdir -p "${CACHE_BIN_DIR}"
155
+ target="${CACHE_BIN_DIR}/construct-${os}-${arch}"
156
+ target_sha="${target}.sha256"
157
+ echo "[construct] downloading binary to ${target}…"
158
+ if ! curl -fL "${binary_url}" -o "${target}"; then
159
+ echo "[construct] binary download failed; falling through." >&2
160
+ rm -f "${target}"
161
+ elif ! curl -fL "${sha_url}" -o "${target_sha}"; then
162
+ echo "[construct] SHA-256 download failed at ${sha_url}; refusing to install an unverified binary." >&2
163
+ rm -f "${target}" "${target_sha}"
164
+ elif ! verify_sha256 "${target}" "$(cat "${target_sha}")"; then
165
+ echo "[construct] SHA-256 mismatch; refusing to install. Re-run to retry." >&2
166
+ rm -f "${target}" "${target_sha}"
167
+ else
168
+ chmod +x "${target}"
169
+ rm -f "${target_sha}"
170
+ echo "[construct] binary cached and SHA-verified. Subsequent invocations use it."
171
+ exit 0
172
+ fi
173
+ fi
174
+ echo "[construct] No installable runtime detected." >&2
175
+ echo " Install one of: Node.js 18+, Docker, or curl + a release binary." >&2
176
+ exit 127
177
+ fi
178
+
179
+ # Default mode — resolve and invoke construct with whatever args were passed.
180
+ invoke_via_node_modules "$@" 2>/dev/null || true
181
+ invoke_via_npx "$@" 2>/dev/null || true
182
+ invoke_via_global "$@" 2>/dev/null || true
183
+ invoke_via_cached_binary "$@" 2>/dev/null || true
184
+ invoke_via_docker "$@" 2>/dev/null || true
185
+
186
+ cat >&2 <<EOF
187
+ [construct] No Construct install found.
188
+
189
+ This project pins Construct${VERSION:+ ${VERSION}} but no runtime resolved.
190
+
191
+ Pick one:
192
+ - Install Node.js 18+ from https://nodejs.org and re-run.
193
+ - Run ./.construct/bootstrap.sh --install to download a binary.
194
+ - Install Construct globally: npm install -g @geraldmaron/construct
195
+ EOF
196
+ exit 127