@geraldmaron/construct 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +9 -6
- package/LICENSE +201 -21
- package/README.md +132 -257
- package/agents/contracts.json +387 -0
- package/agents/prompts/cx-accessibility.md +8 -0
- package/agents/prompts/cx-ai-engineer.md +92 -0
- package/agents/prompts/cx-architect.md +10 -2
- package/agents/prompts/cx-business-strategist.md +13 -0
- package/agents/prompts/cx-data-analyst.md +80 -0
- package/agents/prompts/cx-data-engineer.md +4 -0
- package/agents/prompts/cx-debugger.md +8 -0
- package/agents/prompts/cx-designer.md +19 -0
- package/agents/prompts/cx-devil-advocate.md +4 -0
- package/agents/prompts/cx-docs-keeper.md +128 -0
- package/agents/prompts/cx-engineer.md +13 -0
- package/agents/prompts/cx-evaluator.md +4 -0
- package/agents/prompts/cx-explorer.md +12 -0
- package/agents/prompts/cx-legal-compliance.md +13 -0
- package/agents/prompts/cx-operations.md +13 -0
- package/agents/prompts/cx-orchestrator.md +107 -4
- package/agents/prompts/cx-platform-engineer.md +75 -0
- package/agents/prompts/cx-product-manager.md +8 -0
- package/agents/prompts/cx-qa.md +100 -0
- package/agents/prompts/cx-rd-lead.md +13 -0
- package/agents/prompts/cx-release-manager.md +8 -0
- package/agents/prompts/cx-researcher.md +21 -1
- package/agents/prompts/cx-reviewer.md +8 -0
- package/agents/prompts/cx-security.md +104 -0
- package/agents/prompts/cx-sre.md +104 -0
- package/agents/prompts/cx-test-automation.md +4 -0
- package/agents/prompts/cx-trace-reviewer.md +7 -3
- package/agents/prompts/cx-ux-researcher.md +4 -0
- package/agents/registry.json +365 -90
- package/agents/role-manifests.json +217 -0
- package/bin/construct +3345 -141
- package/bin/construct-postinstall.mjs +87 -0
- package/commands/build/feature.md +6 -6
- package/commands/plan/feature.md +6 -5
- package/commands/plan/requirements.md +1 -1
- package/commands/ship/status.md +1 -1
- package/commands/work/drive.md +3 -3
- package/commands/work/optimize-prompts.md +3 -3
- package/db/{migrations → schema}/001_init.sql +2 -0
- package/db/schema/002_pgvector.sql +182 -0
- package/db/schema/003_intake.sql +47 -0
- package/examples/README.md +85 -0
- package/examples/internal/roles/architect/bad/clever-plan-without-contracts.md +30 -0
- package/examples/internal/roles/architect/golden/explicit-tradeoff-before-plan.md +23 -0
- package/examples/internal/roles/engineer/bad/speculative-abstraction.md +30 -0
- package/examples/internal/roles/engineer/golden/read-before-write.md +28 -0
- package/examples/internal/roles/orchestrator/bad/everything-becomes-multi-agent.md +29 -0
- package/examples/internal/roles/orchestrator/golden/minimal-dispatch.md +22 -0
- package/examples/internal/roles/qa/bad/coverage-theater.md +30 -0
- package/examples/internal/roles/qa/golden/regression-gate.md +23 -0
- package/examples/internal/roles/reviewer/bad/lgtm-without-verification.md +29 -0
- package/examples/internal/roles/reviewer/golden/find-structural-risk-first.md +28 -0
- package/examples/personas/construct/adversarial/ignore-instruction-to-skip-approval.md +22 -0
- package/examples/personas/construct/bad/commit-without-approval.md +30 -0
- package/examples/personas/construct/boundary/blocked-needs-main-input.md +29 -0
- package/examples/personas/construct/golden/branch-approval-before-mutation.md +36 -0
- package/examples/personas/construct/golden/focused-direct-answer.md +28 -0
- package/examples/provider-plugin/README.md +34 -0
- package/examples/provider-plugin/index.mjs +74 -0
- package/examples/provider-plugin/package.json +15 -0
- package/examples/seed-observations/README.md +38 -0
- package/examples/seed-observations/anti-patterns.md +44 -0
- package/examples/seed-observations/decisions.md +36 -0
- package/examples/seed-observations/patterns.md +42 -0
- package/lib/agent-contracts-enforce.mjs +158 -0
- package/lib/agent-contracts.mjs +231 -0
- package/lib/agents/postconditions.mjs +126 -0
- package/lib/agents/schema.mjs +124 -0
- package/lib/artifact-capture.mjs +183 -0
- package/lib/audit-trail.mjs +149 -0
- package/lib/auto-docs.mjs +245 -65
- package/lib/beads/auto-close.mjs +126 -0
- package/lib/beads/drift.mjs +171 -0
- package/lib/beads-automation.mjs +542 -0
- package/lib/beads-client.mjs +518 -0
- package/lib/beads-lock.mjs +377 -0
- package/lib/beads-optimistic.mjs +365 -0
- package/lib/bootstrap/built-ins.mjs +136 -0
- package/lib/bootstrap/lazy-install.mjs +161 -0
- package/lib/bootstrap/resources.mjs +120 -0
- package/lib/bootstrap.mjs +105 -0
- package/lib/cache-governor.js +213 -0
- package/lib/cache-strategy-anthropic.js +62 -0
- package/lib/cache-strategy-google.js +79 -0
- package/lib/cache-strategy-none.js +30 -0
- package/lib/cache-strategy-openai.js +48 -0
- package/lib/cache-strategy.js +91 -0
- package/lib/claude-allow.mjs +149 -0
- package/lib/cli-commands.mjs +413 -258
- package/lib/codex-config.mjs +3 -1
- package/lib/comment-lint.mjs +55 -6
- package/lib/completions.mjs +21 -6
- package/lib/config/alias.mjs +56 -0
- package/lib/config/project-config.mjs +335 -0
- package/lib/config/schema.mjs +159 -0
- package/lib/context-router.mjs +308 -0
- package/lib/cost-ledger.mjs +177 -0
- package/lib/cost.mjs +171 -10
- package/lib/dashboard-static.mjs +158 -0
- package/lib/deployment-mode.mjs +86 -0
- package/lib/deprecate.mjs +49 -0
- package/lib/dispatch-batch.js +183 -0
- package/lib/distill.mjs +21 -8
- package/lib/doc-stamp.mjs +164 -0
- package/lib/doc-verify.mjs +119 -0
- package/lib/docs-routing.mjs +89 -0
- package/lib/docs-verify.mjs +417 -0
- package/lib/doctor/audit.mjs +71 -0
- package/lib/doctor/cli.mjs +99 -0
- package/lib/doctor/escalate.mjs +29 -0
- package/lib/doctor/index.mjs +140 -0
- package/lib/doctor/report.mjs +170 -0
- package/lib/doctor/watchers/bd-watch.mjs +117 -0
- package/lib/doctor/watchers/cost.mjs +130 -0
- package/lib/doctor/watchers/disk.mjs +122 -0
- package/lib/doctor/watchers/handoffs.mjs +33 -0
- package/lib/doctor/watchers/process-pressure.mjs +60 -0
- package/lib/doctor/watchers/service-health.mjs +188 -0
- package/lib/document-extract.mjs +288 -0
- package/lib/document-ingest.mjs +230 -0
- package/lib/drop.mjs +282 -0
- package/lib/embed/approval-queue.mjs +176 -0
- package/lib/embed/artifact.mjs +349 -0
- package/lib/embed/authority-guard.mjs +155 -0
- package/lib/embed/cli.mjs +408 -0
- package/lib/embed/config.mjs +355 -0
- package/lib/embed/conflict-detection.mjs +264 -0
- package/lib/embed/customer-profiles.mjs +480 -0
- package/lib/embed/daemon.mjs +1309 -0
- package/lib/embed/demand-fetch.mjs +449 -0
- package/lib/embed/docs-lifecycle.mjs +349 -0
- package/lib/embed/inbox-live-watcher.mjs +119 -0
- package/lib/embed/inbox.mjs +343 -0
- package/lib/embed/intake-metrics.mjs +190 -0
- package/lib/embed/jobs/vector-sync.mjs +198 -0
- package/lib/embed/notifications.mjs +75 -0
- package/lib/embed/output.mjs +79 -0
- package/lib/embed/providers/github.mjs +295 -0
- package/lib/embed/providers/jira.mjs +192 -0
- package/lib/embed/providers/linear.mjs +186 -0
- package/lib/embed/providers/registry.mjs +115 -0
- package/lib/embed/providers/slack.mjs +203 -0
- package/lib/embed/recommendation-store.mjs +378 -0
- package/lib/embed/roadmap.mjs +374 -0
- package/lib/embed/role-framing.mjs +110 -0
- package/lib/embed/scheduler.mjs +99 -0
- package/lib/embed/semantic.mjs +325 -0
- package/lib/embed/snapshot.mjs +191 -0
- package/lib/embed/supervision.mjs +235 -0
- package/lib/embed/target-resolver.mjs +186 -0
- package/lib/embed/worker.mjs +62 -0
- package/lib/embed/workspaces.mjs +297 -0
- package/lib/engine/chunker-headings.mjs +110 -0
- package/lib/engine/compressor-heuristic.mjs +100 -0
- package/lib/engine/consolidate.mjs +287 -0
- package/lib/engine/contracts.mjs +126 -0
- package/lib/engine/defaults.mjs +129 -0
- package/lib/engine/eval-retrieval.mjs +148 -0
- package/lib/engine/fuser-rrf.mjs +62 -0
- package/lib/engine/index.mjs +37 -0
- package/lib/engine/registry.mjs +146 -0
- package/lib/engine/reranker-mmr.mjs +90 -0
- package/lib/engine/tokens.mjs +77 -0
- package/lib/entity-store.mjs +280 -0
- package/lib/env-config.mjs +69 -4
- package/lib/evals/retrieval-bench.mjs +159 -0
- package/lib/evaluator-optimizer.mjs +317 -0
- package/lib/features.mjs +159 -29
- package/lib/gates-audit.mjs +236 -0
- package/lib/git-hooks/prepare-commit-msg +58 -0
- package/lib/handoffs/cleanup.mjs +159 -0
- package/lib/handoffs/contract.mjs +162 -0
- package/lib/handoffs/inventory.mjs +120 -0
- package/lib/headhunt.mjs +28 -47
- package/lib/health-check.mjs +399 -0
- package/lib/hook-health.mjs +442 -0
- package/lib/hooks/_lib/log.mjs +82 -0
- package/lib/hooks/adaptive-lint.mjs +26 -2
- package/lib/hooks/agent-tracker.mjs +171 -14
- package/lib/hooks/audit-reads.mjs +109 -0
- package/lib/hooks/audit-trail.mjs +153 -0
- package/lib/hooks/bash-output-logger.mjs +71 -0
- package/lib/hooks/block-no-verify.mjs +41 -0
- package/lib/hooks/ci-status-check.mjs +82 -0
- package/lib/hooks/comment-lint.mjs +29 -7
- package/lib/hooks/config-protection.mjs +39 -18
- package/lib/hooks/context-watch.mjs +137 -0
- package/lib/hooks/context-window-recovery.mjs +4 -20
- package/lib/hooks/dep-audit.mjs +16 -0
- package/lib/hooks/doc-coupling-check.mjs +80 -0
- package/lib/hooks/edit-accumulator.mjs +3 -0
- package/lib/hooks/edit-error-recovery.mjs +3 -0
- package/lib/hooks/edit-guard.mjs +45 -4
- package/lib/hooks/env-check.mjs +3 -0
- package/lib/hooks/guard-bash.mjs +58 -1
- package/lib/hooks/mcp-audit.mjs +18 -20
- package/lib/hooks/mcp-health-check.mjs +36 -0
- package/lib/hooks/model-fallback.mjs +42 -56
- package/lib/hooks/policy-engine.mjs +209 -0
- package/lib/hooks/post-merge-docs-check.mjs +63 -0
- package/lib/hooks/pre-compact.mjs +4 -24
- package/lib/hooks/pre-push-gate.mjs +200 -37
- package/lib/hooks/proactive-activation.mjs +284 -0
- package/lib/hooks/read-tracker.mjs +27 -4
- package/lib/hooks/readme-age-check.mjs +77 -0
- package/lib/hooks/registry-sync.mjs +12 -5
- package/lib/hooks/scan-secrets.mjs +50 -7
- package/lib/hooks/session-optimize.mjs +311 -0
- package/lib/hooks/session-start.mjs +287 -28
- package/lib/hooks/stop-notify.mjs +236 -96
- package/lib/hooks/stop-typecheck.mjs +13 -1
- package/lib/hooks/test-watch.mjs +68 -0
- package/lib/host-capabilities.mjs +31 -10
- package/lib/init-docs.mjs +731 -291
- package/lib/init-unified.mjs +1000 -0
- package/lib/init-update.mjs +168 -0
- package/lib/init.mjs +107 -0
- package/lib/install/first-invocation.mjs +119 -0
- package/lib/install/stage-project.mjs +69 -0
- package/lib/intake/classify.mjs +278 -0
- package/lib/intake/feedback.mjs +273 -0
- package/lib/intake/filesystem-queue.mjs +158 -0
- package/lib/intake/intake-config.mjs +132 -0
- package/lib/intake/postgres-queue.mjs +198 -0
- package/lib/intake/prepare.mjs +139 -0
- package/lib/intake/queue.mjs +83 -0
- package/lib/intake/session-prelude.mjs +50 -0
- package/lib/integrations/intake-integrations.mjs +740 -0
- package/lib/intent-classifier.mjs +253 -0
- package/lib/knowledge/layout.mjs +72 -0
- package/lib/knowledge/rag.mjs +331 -0
- package/lib/knowledge/search.mjs +315 -0
- package/lib/knowledge/trends.mjs +261 -0
- package/lib/logger.mjs +85 -0
- package/lib/mcp/broker.mjs +124 -0
- package/lib/mcp/server.mjs +554 -854
- package/lib/mcp/tools/document.mjs +132 -0
- package/lib/mcp/tools/memory.mjs +209 -0
- package/lib/mcp/tools/project.mjs +349 -0
- package/lib/mcp/tools/skills.mjs +409 -0
- package/lib/mcp/tools/storage.mjs +60 -0
- package/lib/mcp/tools/telemetry.mjs +315 -0
- package/lib/mcp/tools/workflow.mjs +112 -0
- package/lib/mcp-catalog.json +54 -3
- package/lib/mcp-manager.mjs +96 -48
- package/lib/mcp-platform-config.mjs +22 -22
- package/lib/memory-stats.mjs +121 -0
- package/lib/mode-commands.mjs +124 -0
- package/lib/model-free-selector.mjs +184 -0
- package/lib/model-pricing.mjs +152 -0
- package/lib/model-registry.mjs +226 -0
- package/lib/model-router.mjs +362 -386
- package/lib/observation-store.mjs +391 -0
- package/lib/ollama-manager.mjs +428 -0
- package/lib/opencode-config.mjs +13 -3
- package/lib/opencode-runtime-plugin.mjs +70 -38
- package/lib/opencode-telemetry.mjs +64 -6
- package/lib/orchestration-policy.mjs +509 -6
- package/lib/overrides/resolver.mjs +207 -0
- package/lib/parity.mjs +147 -0
- package/lib/paths.mjs +33 -0
- package/lib/performance/generate.mjs +212 -0
- package/lib/plugin-registry.mjs +268 -0
- package/lib/policy/engine.mjs +130 -0
- package/lib/policy/unified-gates.mjs +96 -0
- package/lib/project-detection.mjs +129 -0
- package/lib/project-init-shared.mjs +272 -0
- package/lib/project-profile.mjs +447 -0
- package/lib/prompt-composer.js +434 -0
- package/lib/prompt-metadata.mjs +1 -1
- package/lib/provider-capabilities-anthropic.js +44 -0
- package/lib/provider-capabilities-deepseek.js +37 -0
- package/lib/provider-capabilities-generic.js +26 -0
- package/lib/provider-capabilities-google.js +47 -0
- package/lib/provider-capabilities-openai.js +45 -0
- package/lib/provider-capabilities.js +142 -0
- package/lib/providers/atlassian-confluence/index.mjs +103 -0
- package/lib/providers/atlassian-jira/index.mjs +100 -0
- package/lib/providers/auth-manager.mjs +126 -0
- package/lib/providers/circuit-breaker.mjs +124 -0
- package/lib/providers/contract.mjs +93 -0
- package/lib/providers/github/index.mjs +126 -0
- package/lib/providers/registry.mjs +184 -0
- package/lib/providers/salesforce/index.mjs +100 -0
- package/lib/providers/slack/index.mjs +80 -0
- package/lib/reflect.mjs +137 -0
- package/lib/research-lint.mjs +164 -0
- package/lib/resources/budget.mjs +259 -0
- package/lib/role-preload.mjs +21 -6
- package/lib/roles/approval-surface.mjs +54 -0
- package/lib/roles/cli.mjs +118 -0
- package/lib/roles/event-bus.mjs +79 -0
- package/lib/roles/fence.mjs +84 -0
- package/lib/roles/gateway.mjs +260 -0
- package/lib/roles/hook-emit.mjs +37 -0
- package/lib/roles/manifest.mjs +48 -0
- package/lib/roles/router.mjs +27 -0
- package/lib/runtime-pressure.mjs +360 -0
- package/lib/schema-artifact.mjs +134 -0
- package/lib/schema-infer.mjs +551 -0
- package/lib/server/auth.mjs +168 -0
- package/lib/server/chat.mjs +336 -0
- package/lib/server/cors.mjs +77 -0
- package/lib/server/csrf.mjs +91 -0
- package/lib/server/index.mjs +1927 -78
- package/lib/server/insights.mjs +765 -0
- package/lib/server/rate-limit.mjs +91 -0
- package/lib/server/static/assets/index-ab25c707.js +70 -0
- package/lib/server/static/assets/index-f0c80a2b.css +1 -0
- package/lib/server/static/index.html +12 -817
- package/lib/server/telemetry-login.mjs +108 -0
- package/lib/server/webhook.mjs +510 -0
- package/lib/service-manager.mjs +522 -58
- package/lib/services/pattern-promotion-service.mjs +167 -0
- package/lib/services/telemetry-backend.mjs +178 -0
- package/lib/session-store.mjs +374 -0
- package/lib/setup-prompts.mjs +96 -0
- package/lib/setup.mjs +523 -36
- package/lib/skills-apply.mjs +280 -0
- package/lib/skills-scope.mjs +118 -0
- package/lib/status.mjs +261 -70
- package/lib/storage/admin.mjs +355 -0
- package/lib/storage/backend.mjs +2 -1
- package/lib/storage/backup.mjs +347 -0
- package/lib/storage/embeddings-engine.mjs +133 -0
- package/lib/storage/embeddings-legacy.mjs +85 -0
- package/lib/storage/embeddings-local.mjs +108 -0
- package/lib/storage/embeddings-ollama.mjs +78 -0
- package/lib/storage/embeddings-openai.mjs +85 -0
- package/lib/storage/embeddings.mjs +92 -33
- package/lib/storage/file-lock.mjs +130 -0
- package/lib/storage/fusion.mjs +95 -0
- package/lib/storage/hybrid-query.mjs +34 -27
- package/lib/storage/migrations.mjs +187 -0
- package/lib/storage/postgres-backup.mjs +124 -0
- package/lib/storage/sql-store.mjs +5 -15
- package/lib/storage/state-source.mjs +12 -13
- package/lib/storage/store-version.mjs +115 -0
- package/lib/storage/sync.mjs +144 -35
- package/lib/storage/unified-storage.mjs +550 -0
- package/lib/storage/vector-client.mjs +286 -0
- package/lib/storage/vector-store.mjs +71 -30
- package/lib/task-graph/generate.mjs +135 -0
- package/lib/task-graph/schema.mjs +81 -0
- package/lib/task-graph/store.mjs +71 -0
- package/lib/telemetry/backends/local.mjs +62 -0
- package/lib/telemetry/backends/{langfuse.mjs → remote.mjs} +27 -14
- package/lib/telemetry/backfill.mjs +180 -0
- package/lib/telemetry/eval-datasets.mjs +203 -0
- package/lib/telemetry/{langfuse-ingest.mjs → ingest.mjs} +26 -20
- package/lib/telemetry/intent-verifications.mjs +86 -0
- package/lib/telemetry/llm-judge.mjs +350 -0
- package/lib/telemetry/model-pricing-catalog.mjs +557 -0
- package/lib/telemetry/setup.mjs +151 -0
- package/lib/telemetry/skill-calls.mjs +78 -0
- package/lib/telemetry/team-rollup.mjs +4 -4
- package/lib/token-engine.js +117 -0
- package/lib/token-estimator-anthropic.js +15 -0
- package/lib/token-estimator-deepseek.js +13 -0
- package/lib/token-estimator-default.js +13 -0
- package/lib/token-estimator-google.js +13 -0
- package/lib/token-estimator-openai.js +13 -0
- package/lib/toolkit-env.mjs +1 -1
- package/lib/tty-prompts.mjs +211 -0
- package/lib/uninstall/uninstall.mjs +423 -0
- package/lib/update.mjs +115 -0
- package/lib/upgrade.mjs +141 -0
- package/lib/validator.mjs +51 -2
- package/lib/validators/skills.mjs +142 -0
- package/lib/wireframe.mjs +422 -0
- package/lib/worker/entrypoint.mjs +241 -0
- package/lib/worker/evidence.mjs +107 -0
- package/lib/worker/run.mjs +154 -0
- package/lib/worker/trace.mjs +182 -0
- package/lib/workflow-state.mjs +14 -18
- package/package.json +21 -8
- package/personas/construct.md +53 -51
- package/platforms/claude/CLAUDE.md +1 -1
- package/platforms/claude/settings.template.json +115 -68
- package/platforms/opencode/config.template.json +3 -7
- package/rules/common/agents.md +11 -38
- package/rules/common/beads-hygiene.md +75 -0
- package/rules/common/code-review.md +11 -100
- package/rules/common/coding-style.md +5 -3
- package/rules/common/comments.md +30 -111
- package/rules/common/commit-approval.md +53 -0
- package/rules/common/cx-agent-routing.md +1 -0
- package/rules/common/development-workflow.md +23 -41
- package/rules/common/doc-ownership.md +54 -0
- package/rules/common/efficiency.md +57 -0
- package/rules/common/framing.md +76 -0
- package/rules/common/git-workflow.md +2 -4
- package/rules/common/patterns.md +3 -7
- package/rules/common/performance.md +15 -31
- package/rules/common/release-gates.md +69 -0
- package/rules/common/research.md +107 -0
- package/rules/common/security.md +6 -6
- package/rules/common/skill-composition.md +67 -0
- package/rules/common/testing.md +15 -27
- package/rules/golang/hooks.md +0 -4
- package/rules/policy/bootstrap.yaml +11 -0
- package/rules/policy/drive.yaml +8 -0
- package/rules/policy/task.yaml +9 -0
- package/rules/policy/workflow.yaml +9 -0
- package/rules/python/hooks.md +0 -4
- package/rules/swift/hooks.md +0 -4
- package/rules/typescript/hooks.md +0 -4
- package/rules/web/hooks.md +0 -2
- package/{sync-agents.mjs → scripts/sync-agents.mjs} +306 -61
- package/skills/ai/prompt-optimizer.md +7 -7
- package/skills/compliance/ai-disclosure.md +58 -0
- package/skills/compliance/data-privacy.md +46 -0
- package/skills/compliance/license-audit.md +40 -0
- package/skills/compliance/regulatory-review.md +61 -0
- package/skills/docs/document-ingest-workflow.md +52 -0
- package/skills/docs/evidence-ingest-workflow.md +9 -0
- package/skills/docs/init-docs.md +51 -18
- package/skills/docs/product-intelligence-workflow.md +12 -0
- package/skills/docs/product-signal-workflow.md +4 -0
- package/skills/docs/research-workflow.md +23 -8
- package/skills/docs/runbook-workflow.md +1 -1
- package/skills/operating/orchestration-reference.md +151 -0
- package/skills/roles/architect.md +5 -0
- package/skills/roles/engineer.md +32 -0
- package/skills/roles/operator.md +12 -0
- package/skills/roles/reviewer.md +23 -0
- package/skills/routing.md +1 -1
- package/templates/devcontainer/Dockerfile.devcontainer +38 -0
- package/templates/devcontainer/devcontainer.json +31 -0
- package/templates/distribution/bootstrap.ps1 +142 -0
- package/templates/distribution/bootstrap.sh +196 -0
- package/templates/distribution/run.mjs +187 -0
- package/templates/docs/adr.md +44 -8
- package/templates/docs/changelog-entry.md +43 -0
- package/templates/docs/construct_guide.md +149 -0
- package/templates/docs/evidence-brief.md +2 -2
- package/templates/docs/meta-prd.md +140 -19
- package/templates/docs/onboarding.md +57 -0
- package/templates/docs/prd.md +159 -15
- package/templates/docs/research-brief.md +4 -4
- package/templates/homebrew/construct.rb +67 -0
- package/langfuse/docker-compose.yml +0 -82
- package/lib/eval-harness.mjs +0 -59
- package/lib/hooks/bootstrap-guard.mjs +0 -90
- package/lib/hooks/console-warn.mjs +0 -43
- package/lib/hooks/continuation-enforcer.mjs +0 -72
- package/lib/hooks/drive-guard.mjs +0 -89
- package/lib/hooks/mcp-task-scope.mjs +0 -47
- package/lib/hooks/task-completed-guard.mjs +0 -43
- package/lib/hooks/teammate-idle-guard.mjs +0 -54
- package/lib/hooks/workflow-guard.mjs +0 -62
- package/lib/prompt-composer.mjs +0 -196
- package/lib/review.mjs +0 -429
- package/lib/server/static/app.js +0 -841
- package/lib/telemetry/langfuse-model-sync.mjs +0 -270
- package/rules/common/hooks.md +0 -35
- package/rules/zh/README.md +0 -113
- package/rules/zh/agents.md +0 -55
- package/rules/zh/code-review.md +0 -129
- package/rules/zh/coding-style.md +0 -53
- package/rules/zh/development-workflow.md +0 -49
- package/rules/zh/git-workflow.md +0 -29
- package/rules/zh/hooks.md +0 -35
- package/rules/zh/patterns.md +0 -36
- package/rules/zh/performance.md +0 -60
- package/rules/zh/security.md +0 -34
- 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.
|
package/skills/roles/engineer.md
CHANGED
|
@@ -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
|
+
|
package/skills/roles/operator.md
CHANGED
|
@@ -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
|
package/skills/roles/reviewer.md
CHANGED
|
@@ -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
|
|
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
|