@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,167 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* lib/services/pattern-promotion-service.mjs — Bounded pattern replication engine.
|
|
4
|
+
*
|
|
5
|
+
* Analyzes observations, scores candidate patterns, promotes high-quality ones to permanent
|
|
6
|
+
* learned patterns in role skill files. Prevents unbounded growth with hard limits.
|
|
7
|
+
*
|
|
8
|
+
* Limits:
|
|
9
|
+
* - Max 15 learned patterns per role
|
|
10
|
+
* - Min confidence 0.85, usage 3, score 0.8
|
|
11
|
+
* - Semantic + exact deduplication
|
|
12
|
+
* - Pruning of low-effectiveness patterns
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import fs from 'node:fs';
|
|
16
|
+
import path from 'node:path';
|
|
17
|
+
|
|
18
|
+
const ROOT_DIR = process.cwd();
|
|
19
|
+
const SKILLS_DIR = path.join(ROOT_DIR, 'skills', 'roles');
|
|
20
|
+
const OBS_DIR = path.join(process.cwd(), '.cx', 'observations', 'agent-outcomes');
|
|
21
|
+
|
|
22
|
+
const MAX_PATTERNS = 15;
|
|
23
|
+
const MIN_CONFIDENCE = 0.85;
|
|
24
|
+
const MIN_USAGE = 3;
|
|
25
|
+
const MIN_SCORE = 0.8;
|
|
26
|
+
const MAX_TOKENS_FILE = 2500; // Approx tokens
|
|
27
|
+
|
|
28
|
+
const LEARNED_SECTION_MARKER = '## Learned Patterns';
|
|
29
|
+
|
|
30
|
+
function scorePattern(obs) {
|
|
31
|
+
const confidenceWeight = 0.3;
|
|
32
|
+
const usageWeight = 0.2;
|
|
33
|
+
const successWeight = 0.4;
|
|
34
|
+
const crossProjectWeight = 0.1;
|
|
35
|
+
|
|
36
|
+
const normalizedUsage = Math.min((obs.usage_count || 0) / 10, 1.0);
|
|
37
|
+
const crossProject = (obs.projects && obs.projects.length >= 2) ? 1.0 : 0.5;
|
|
38
|
+
const successRate = obs.success_rate || 0.5;
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
(obs.confidence || 0) * confidenceWeight +
|
|
42
|
+
normalizedUsage * usageWeight +
|
|
43
|
+
successRate * successWeight +
|
|
44
|
+
crossProject * crossProjectWeight
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function normalizeSummary(summary) {
|
|
49
|
+
return summary.toLowerCase().replace(/[^\w\s]/g, '').trim();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function isDuplicate(newObs, existingPatterns) {
|
|
53
|
+
const newNorm = normalizeSummary(newObs.summary);
|
|
54
|
+
for (const pat of existingPatterns) {
|
|
55
|
+
const patNorm = normalizeSummary(pat.summary);
|
|
56
|
+
if (newNorm.includes(patNorm.slice(0, Math.min(50, patNorm.length))) ||
|
|
57
|
+
patNorm.includes(newNorm.slice(0, Math.min(50, newNorm.length)))) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function parseLearnedPatterns(content) {
|
|
65
|
+
const match = content.match(new RegExp(`${LEARNED_SECTION_MARKER}[\\s\\S]*?(?=## |$)`));
|
|
66
|
+
if (!match) return [];
|
|
67
|
+
|
|
68
|
+
const section = match[0];
|
|
69
|
+
return section.split('\n\n').slice(1).filter(Boolean).map(block => {
|
|
70
|
+
const lines = block.split('\n');
|
|
71
|
+
return {
|
|
72
|
+
summary: lines[0].replace(/^###\s*L\d+\.\s*/, ''),
|
|
73
|
+
content: block
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function generatePatternEntry(obs, index) {
|
|
79
|
+
return `### L${index}. ${obs.summary}
|
|
80
|
+
**Context**: ${obs.context || 'General'}
|
|
81
|
+
**Effective Action**: ${obs.content.slice(0, 120)}...
|
|
82
|
+
**Evidence**: Score ${(obs.score || 0).toFixed(2)}, used ${(obs.usage_count || 0)} times, ${(obs.projects || []).length} projects
|
|
83
|
+
*Last reinforced: ${new Date().toISOString().split('T')[0]}*
|
|
84
|
+
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function updateSkillFile(roleName, candidate) {
|
|
89
|
+
const skillFile = path.join(SKILLS_DIR, `${roleName}.md`);
|
|
90
|
+
if (!fs.existsSync(skillFile)) {
|
|
91
|
+
console.warn(`Skill file not found: ${skillFile}`);
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let content = fs.readFileSync(skillFile, 'utf8');
|
|
96
|
+
|
|
97
|
+
// Check token limit (rough char/4)
|
|
98
|
+
if (content.length > MAX_TOKENS_FILE * 4) {
|
|
99
|
+
console.warn(`Skill file too large: ${skillFile}`);
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const existingPatterns = parseLearnedPatterns(content);
|
|
104
|
+
if (existingPatterns.length >= MAX_PATTERNS || isDuplicate(candidate, existingPatterns)) {
|
|
105
|
+
console.log(`Skipped ${candidate.summary} (dupe or limit reached)`);
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const entry = generatePatternEntry(candidate, existingPatterns.length + 1);
|
|
110
|
+
let newContent;
|
|
111
|
+
|
|
112
|
+
const sectionExists = content.includes(LEARNED_SECTION_MARKER);
|
|
113
|
+
if (sectionExists) {
|
|
114
|
+
const markerIndex = content.indexOf(LEARNED_SECTION_MARKER);
|
|
115
|
+
const afterMarker = content.slice(markerIndex);
|
|
116
|
+
const endMatch = afterMarker.match(/\n\n## /) || afterMarker.match(/$/);
|
|
117
|
+
const insertPos = markerIndex + afterMarker.indexOf(endMatch[0]);
|
|
118
|
+
newContent = content.slice(0, insertPos) + '\n\n' + entry + content.slice(insertPos);
|
|
119
|
+
} else {
|
|
120
|
+
newContent = content + '\n\n' + LEARNED_SECTION_MARKER + '\n\n' + entry;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
fs.writeFileSync(skillFile, newContent);
|
|
124
|
+
console.log(`Added pattern to ${roleName}.md: ${candidate.summary}`);
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function getCandidates() {
|
|
129
|
+
if (!fs.existsSync(OBS_DIR)) return [];
|
|
130
|
+
|
|
131
|
+
const files = fs.readdirSync(OBS_DIR).filter(f => f.endsWith('.json'));
|
|
132
|
+
const candidates = [];
|
|
133
|
+
|
|
134
|
+
for (const file of files) {
|
|
135
|
+
try {
|
|
136
|
+
const obs = JSON.parse(fs.readFileSync(path.join(OBS_DIR, file), 'utf8'));
|
|
137
|
+
if (obs.category === 'pattern' &&
|
|
138
|
+
(obs.confidence || 0) >= MIN_CONFIDENCE &&
|
|
139
|
+
(obs.usage_count || 0) >= MIN_USAGE) {
|
|
140
|
+
obs.score = scorePattern(obs);
|
|
141
|
+
if (obs.score >= MIN_SCORE) {
|
|
142
|
+
candidates.push(obs);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} catch (e) {
|
|
146
|
+
// Skip invalid
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return candidates.sort((a, b) => b.score - a.score).slice(0, 5); // Top 5
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function promotePatterns() {
|
|
154
|
+
const candidates = getCandidates();
|
|
155
|
+
let promoted = 0;
|
|
156
|
+
|
|
157
|
+
for (const candidate of candidates) {
|
|
158
|
+
const roleName = candidate.role.replace(/^cx-/, '') || 'engineer'; // Fallback
|
|
159
|
+
if (updateSkillFile(roleName, candidate)) promoted++;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
console.log(`Pattern promotion complete: ${promoted}/${candidates.length} promoted`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
166
|
+
promotePatterns();
|
|
167
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/services/telemetry-backend.mjs — local services stack management.
|
|
3
|
+
*
|
|
4
|
+
* Manages the local Postgres service (services/docker-compose.yml).
|
|
5
|
+
* In solo mode, Postgres runs as a Docker container with pgvector enabled.
|
|
6
|
+
*
|
|
7
|
+
* Remote telemetry backends (for trace ingestion) are configured via
|
|
8
|
+
* CONSTRUCT_TELEMETRY_URL / CONSTRUCT_TELEMETRY_PUBLIC_KEY /
|
|
9
|
+
* CONSTRUCT_TELEMETRY_SECRET_KEY env vars. This module handles local
|
|
10
|
+
* infrastructure only — it does not manage telemetry dashboard services.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { spawnSync } from 'node:child_process';
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
import os from 'node:os';
|
|
16
|
+
import path from 'node:path';
|
|
17
|
+
|
|
18
|
+
import { getUserEnvPath, writeEnvValues } from '../env-config.mjs';
|
|
19
|
+
|
|
20
|
+
/** Local Postgres port (within Construct's 54329-54339 reserved block). */
|
|
21
|
+
export const POSTGRES_LOCAL_PORT = 54332;
|
|
22
|
+
|
|
23
|
+
export function isRemoteTelemetry(url = '') {
|
|
24
|
+
if (!url) return false;
|
|
25
|
+
return !url.includes('localhost') && !url.includes('127.0.0.1');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function servicesComposePath(rootDir) {
|
|
29
|
+
return path.join(rootDir, 'services', 'docker-compose.yml');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Keep only the N most recent stash pairs (.dump + .json) in the stash dir.
|
|
33
|
+
export function pruneStashDir(dir, keep = 3) {
|
|
34
|
+
try {
|
|
35
|
+
const dumps = fs.readdirSync(dir)
|
|
36
|
+
.filter((f) => f.endsWith('.dump'))
|
|
37
|
+
.sort()
|
|
38
|
+
.reverse();
|
|
39
|
+
for (const dump of dumps.slice(keep)) {
|
|
40
|
+
fs.rmSync(path.join(dir, dump), { force: true });
|
|
41
|
+
fs.rmSync(path.join(dir, dump.replace('.dump', '.json')), { force: true });
|
|
42
|
+
}
|
|
43
|
+
} catch { /* non-critical */ }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Verify that the Postgres service is reachable. Returns a status object.
|
|
48
|
+
* Verifies the Postgres service is up and ready.
|
|
49
|
+
*/
|
|
50
|
+
export async function verifyPostgresHealth({
|
|
51
|
+
port = POSTGRES_LOCAL_PORT,
|
|
52
|
+
fetchFn = globalThis.fetch,
|
|
53
|
+
maxRetries = 5,
|
|
54
|
+
intervalMs = 2000,
|
|
55
|
+
} = {}) {
|
|
56
|
+
// We can't use fetch against Postgres (it's not HTTP), so just check pg_isready via docker
|
|
57
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
58
|
+
try {
|
|
59
|
+
const result = spawnSync('docker', [
|
|
60
|
+
'exec', 'construct-postgres',
|
|
61
|
+
'pg_isready', '-U', 'construct', '-d', 'construct',
|
|
62
|
+
], { stdio: 'pipe', timeout: 3000 });
|
|
63
|
+
if (result.status === 0) return { status: 'verified' };
|
|
64
|
+
} catch { /* not ready yet */ }
|
|
65
|
+
if (attempt < maxRetries - 1) await new Promise((r) => setTimeout(r, intervalMs));
|
|
66
|
+
}
|
|
67
|
+
return { status: 'unreachable' };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Verify telemetry backend keys (remote HTTP).
|
|
72
|
+
*
|
|
73
|
+
*/
|
|
74
|
+
export async function verifyTelemetryKeys({
|
|
75
|
+
baseUrl,
|
|
76
|
+
publicKey,
|
|
77
|
+
secretKey,
|
|
78
|
+
composeRunner,
|
|
79
|
+
composeFile,
|
|
80
|
+
homeDir = os.homedir(),
|
|
81
|
+
maxRetries = 5,
|
|
82
|
+
intervalMs = 2000,
|
|
83
|
+
spawnSyncFn = spawnSync,
|
|
84
|
+
fetchFn = globalThis.fetch,
|
|
85
|
+
overallTimeoutMs = 0,
|
|
86
|
+
} = {}) {
|
|
87
|
+
const resolvedBaseUrl =
|
|
88
|
+
baseUrl ??
|
|
89
|
+
process.env.CONSTRUCT_TELEMETRY_URL ??
|
|
90
|
+
'';
|
|
91
|
+
const resolvedPublicKey =
|
|
92
|
+
publicKey ??
|
|
93
|
+
process.env.CONSTRUCT_TELEMETRY_PUBLIC_KEY ??
|
|
94
|
+
'';
|
|
95
|
+
const resolvedSecretKey =
|
|
96
|
+
secretKey ??
|
|
97
|
+
process.env.CONSTRUCT_TELEMETRY_SECRET_KEY ??
|
|
98
|
+
'';
|
|
99
|
+
|
|
100
|
+
if (!resolvedPublicKey || !resolvedSecretKey || !resolvedBaseUrl) {
|
|
101
|
+
return { status: 'unconfigured' };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function doVerify() {
|
|
105
|
+
const auth = `Basic ${Buffer.from(`${resolvedPublicKey}:${resolvedSecretKey}`).toString('base64')}`;
|
|
106
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
107
|
+
try {
|
|
108
|
+
const controller = new AbortController();
|
|
109
|
+
const timer = setTimeout(() => controller.abort(), 3000);
|
|
110
|
+
const res = await fetchFn(`${resolvedBaseUrl}/api/public/health`, {
|
|
111
|
+
signal: controller.signal,
|
|
112
|
+
}).finally(() => clearTimeout(timer));
|
|
113
|
+
if (res.ok) break;
|
|
114
|
+
} catch { /* not ready yet */ }
|
|
115
|
+
if (attempt < maxRetries - 1) await new Promise((r) => setTimeout(r, intervalMs));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const controller = new AbortController();
|
|
120
|
+
const timer = setTimeout(() => controller.abort(), 5000);
|
|
121
|
+
const res = await fetchFn(`${resolvedBaseUrl}/api/public/traces?limit=1`, {
|
|
122
|
+
headers: { Authorization: auth },
|
|
123
|
+
signal: controller.signal,
|
|
124
|
+
}).finally(() => clearTimeout(timer));
|
|
125
|
+
if (res.ok) return { status: 'verified' };
|
|
126
|
+
} catch {
|
|
127
|
+
return { status: 'unreachable' };
|
|
128
|
+
}
|
|
129
|
+
return { status: 'auth-failed', reseeded: false };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (overallTimeoutMs > 0) {
|
|
133
|
+
return Promise.race([
|
|
134
|
+
doVerify(),
|
|
135
|
+
new Promise((_, reject) =>
|
|
136
|
+
setTimeout(() => reject(new Error('verifyTelemetryKeys timeout')), overallTimeoutMs),
|
|
137
|
+
),
|
|
138
|
+
]);
|
|
139
|
+
}
|
|
140
|
+
return doVerify();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Bring up the local Postgres service via services/docker-compose.yml.
|
|
145
|
+
* Starts the local Postgres service via services/docker-compose.yml.
|
|
146
|
+
*/
|
|
147
|
+
export async function startManagedServices({
|
|
148
|
+
rootDir,
|
|
149
|
+
homeDir = os.homedir(),
|
|
150
|
+
env = process.env,
|
|
151
|
+
composeRunner,
|
|
152
|
+
spawnDetached,
|
|
153
|
+
} = {}) {
|
|
154
|
+
if (!rootDir) throw new Error('startManagedServices: rootDir is required');
|
|
155
|
+
if (!composeRunner) throw new Error('startManagedServices: composeRunner is required');
|
|
156
|
+
if (!spawnDetached) throw new Error('startManagedServices: spawnDetached is required');
|
|
157
|
+
|
|
158
|
+
const composeFile = servicesComposePath(rootDir);
|
|
159
|
+
if (!fs.existsSync(composeFile)) {
|
|
160
|
+
return { status: 'unavailable', note: `services compose file missing at ${composeFile}` };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const { logPath } = spawnDetached(
|
|
164
|
+
composeRunner.command,
|
|
165
|
+
[...composeRunner.argsPrefix, '-p', 'construct-services', '-f', composeFile, 'up', '-d'],
|
|
166
|
+
homeDir,
|
|
167
|
+
'services.log',
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
status: 'started',
|
|
172
|
+
note: `Postgres started — connect at localhost:${POSTGRES_LOCAL_PORT}`,
|
|
173
|
+
composeFile,
|
|
174
|
+
logPath,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
|