@geraldmaron/construct 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +10 -7
- 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 +1116 -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 +525 -38
- 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,408 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/embed/cli.mjs — CLI handler for `construct embed <subcommand>`.
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* start [--config <path>] Fork detached embed daemon
|
|
6
|
+
* stop Send SIGTERM to running daemon
|
|
7
|
+
* status Print daemon status + last snapshot summary
|
|
8
|
+
* snapshot [--config <path>] Run a one-shot snapshot and print to stdout
|
|
9
|
+
*
|
|
10
|
+
* Exports:
|
|
11
|
+
* resolveEmbedStatus(env, homeDir) — returns { level, label, detail }
|
|
12
|
+
* level: 'running' | 'stopped' | 'none'
|
|
13
|
+
* Consumed by session-start hook and dashboard /api/embed/status endpoint.
|
|
14
|
+
*
|
|
15
|
+
* autoStartEmbedIfNeeded(env, rootDir, homeDir) — spawns daemon when
|
|
16
|
+
* provider credentials are present but daemon is stopped. No-op if already
|
|
17
|
+
* running or no credentials. Returns { started: bool, pid?, reason? }.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import fs from 'node:fs';
|
|
21
|
+
import os from 'node:os';
|
|
22
|
+
import path from 'node:path';
|
|
23
|
+
import { spawn } from 'node:child_process';
|
|
24
|
+
|
|
25
|
+
const STATE_FILE = 'embed-daemon.json';
|
|
26
|
+
const LOG_FILE = 'embed-daemon.log';
|
|
27
|
+
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Paths
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
function runtimeDir(homeDir = os.homedir()) {
|
|
33
|
+
return path.join(homeDir, '.cx', 'runtime');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function statePath(homeDir = os.homedir()) {
|
|
37
|
+
return path.join(runtimeDir(homeDir), STATE_FILE);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function logPath(homeDir = os.homedir()) {
|
|
41
|
+
return path.join(runtimeDir(homeDir), LOG_FILE);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// State helpers
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
function readState(homeDir = os.homedir()) {
|
|
49
|
+
const p = statePath(homeDir);
|
|
50
|
+
if (!fs.existsSync(p)) return null;
|
|
51
|
+
try { return JSON.parse(fs.readFileSync(p, 'utf8')); } catch (err) { process.stderr.write('[cli.mjs] readState: ' + (err?.message ?? String(err)) + '\n'); return null; }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function writeState(obj, homeDir = os.homedir()) {
|
|
55
|
+
const dir = runtimeDir(homeDir);
|
|
56
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
57
|
+
fs.writeFileSync(statePath(homeDir), JSON.stringify(obj, null, 2));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function clearState(homeDir = os.homedir()) {
|
|
61
|
+
const p = statePath(homeDir);
|
|
62
|
+
if (fs.existsSync(p)) fs.rmSync(p, { force: true });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function processExists(pid) {
|
|
66
|
+
if (!pid) return false;
|
|
67
|
+
try { process.kill(Number(pid), 0); return true; } catch (err) { process.stderr.write('[cli.mjs] processExists: ' + (err?.message ?? String(err)) + '\n'); return false; }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function readRunningState(homeDir = os.homedir()) {
|
|
71
|
+
const s = readState(homeDir);
|
|
72
|
+
if (!s) return null;
|
|
73
|
+
if (!processExists(s.pid)) { clearState(homeDir); return null; }
|
|
74
|
+
return s;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
// Exported status + auto-start utilities
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Resolve embed daemon status without side effects.
|
|
83
|
+
*
|
|
84
|
+
* @param {object} [env] - Env object (default: process.env)
|
|
85
|
+
* @param {string} [homeDir] - Home dir override
|
|
86
|
+
* @returns {{ level: 'running'|'stopped'|'none', label: string, detail: string }}
|
|
87
|
+
* level='none' — no provider credentials configured; embed not applicable
|
|
88
|
+
* level='stopped' — credentials present but daemon not running
|
|
89
|
+
* level='running' — daemon process is live
|
|
90
|
+
*/
|
|
91
|
+
export function resolveEmbedStatus(env = process.env, homeDir = os.homedir()) {
|
|
92
|
+
const hasProviders = !!(
|
|
93
|
+
env.GITHUB_TOKEN || env.GITHUB_PERSONAL_ACCESS_TOKEN ||
|
|
94
|
+
env.SLACK_BOT_TOKEN ||
|
|
95
|
+
env.LINEAR_API_KEY ||
|
|
96
|
+
(env.JIRA_API_TOKEN && env.JIRA_USER_EMAIL && env.JIRA_BASE_URL)
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
if (!hasProviders) {
|
|
100
|
+
return { level: 'none', label: 'embed: no providers', detail: 'no provider credentials in config.env' };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const state = readRunningState(homeDir);
|
|
104
|
+
if (state) {
|
|
105
|
+
return {
|
|
106
|
+
level: 'running',
|
|
107
|
+
label: `embed: running (pid ${state.pid})`,
|
|
108
|
+
detail: `started ${state.startedAt ?? 'unknown'} · config: ${state.configPath ?? 'auto'}`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
level: 'stopped',
|
|
114
|
+
label: 'embed: providers configured, daemon stopped',
|
|
115
|
+
detail: 'run `construct embed start` or set CX_AUTO_EMBED=1',
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Auto-start the embed daemon when credentials are present but daemon is stopped.
|
|
121
|
+
* Silently no-ops if already running or no credentials.
|
|
122
|
+
*
|
|
123
|
+
* @param {object} [env] - Env object (default: process.env)
|
|
124
|
+
* @param {string} [rootDir] - Construct root dir (where lib/embed/worker.mjs lives)
|
|
125
|
+
* @param {string} [homeDir] - Home dir override
|
|
126
|
+
* @returns {{ started: boolean, pid?: number, reason?: string }}
|
|
127
|
+
*/
|
|
128
|
+
export async function autoStartEmbedIfNeeded(env = process.env, rootDir, homeDir = os.homedir()) {
|
|
129
|
+
if (!env.CX_AUTO_EMBED && env.CX_AUTO_EMBED !== '1') {
|
|
130
|
+
return { started: false, reason: 'CX_AUTO_EMBED not set' };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const status = resolveEmbedStatus(env, homeDir);
|
|
134
|
+
if (status.level !== 'stopped') {
|
|
135
|
+
return { started: false, reason: status.level === 'running' ? 'already_running' : 'no_providers' };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const resolvedRoot = rootDir ?? new URL('../..', import.meta.url).pathname;
|
|
139
|
+
try {
|
|
140
|
+
const workerPath = path.join(resolvedRoot, 'lib', 'embed', 'worker.mjs');
|
|
141
|
+
const log = logPath(homeDir);
|
|
142
|
+
fs.mkdirSync(path.dirname(log), { recursive: true });
|
|
143
|
+
const fd = fs.openSync(log, 'a');
|
|
144
|
+
|
|
145
|
+
const child = spawn(process.execPath, [workerPath], {
|
|
146
|
+
detached: true,
|
|
147
|
+
stdio: ['ignore', fd, fd],
|
|
148
|
+
env: { ...env },
|
|
149
|
+
});
|
|
150
|
+
child.unref();
|
|
151
|
+
|
|
152
|
+
writeState({ pid: child.pid, configPath: 'auto', startedAt: new Date().toISOString() }, homeDir);
|
|
153
|
+
return { started: true, pid: child.pid };
|
|
154
|
+
} catch (err) {
|
|
155
|
+
return { started: false, reason: `spawn_failed: ${err.message}` };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
// Parse args helpers
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
|
|
163
|
+
function parseArgs(args) {
|
|
164
|
+
const flags = {};
|
|
165
|
+
for (let i = 0; i < args.length; i++) {
|
|
166
|
+
if ((args[i] === '--config' || args[i] === '-c') && args[i + 1]) {
|
|
167
|
+
flags.config = args[++i];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return flags;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
// Subcommand: start
|
|
175
|
+
// ---------------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
async function cmdEmbedStart(args, { homeDir = os.homedir(), rootDir } = {}) {
|
|
178
|
+
const existing = readRunningState(homeDir);
|
|
179
|
+
if (existing) {
|
|
180
|
+
process.stdout.write(`embed daemon already running (pid ${existing.pid})\n`);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const { config } = parseArgs(args);
|
|
185
|
+
const configPath = config
|
|
186
|
+
? path.resolve(config)
|
|
187
|
+
: fs.existsSync(path.join(os.homedir(), '.construct', 'embed.yaml'))
|
|
188
|
+
? path.join(os.homedir(), '.construct', 'embed.yaml')
|
|
189
|
+
: null;
|
|
190
|
+
|
|
191
|
+
const workerPath = path.join(rootDir, 'lib', 'embed', 'worker.mjs');
|
|
192
|
+
const workerArgs = configPath ? [workerPath, '--config', configPath] : [workerPath];
|
|
193
|
+
const log = logPath(homeDir);
|
|
194
|
+
fs.mkdirSync(path.dirname(log), { recursive: true });
|
|
195
|
+
const fd = fs.openSync(log, 'a');
|
|
196
|
+
|
|
197
|
+
const child = spawn(process.execPath, workerArgs, {
|
|
198
|
+
detached: true,
|
|
199
|
+
stdio: ['ignore', fd, fd],
|
|
200
|
+
env: { ...process.env },
|
|
201
|
+
});
|
|
202
|
+
child.unref();
|
|
203
|
+
|
|
204
|
+
writeState({ pid: child.pid, configPath: configPath ?? 'auto', startedAt: new Date().toISOString() }, homeDir);
|
|
205
|
+
process.stdout.write(`embed daemon started (pid ${child.pid})\n`);
|
|
206
|
+
process.stdout.write(`config: ${configPath ?? 'auto-discover from config.env'}\n`);
|
|
207
|
+
process.stdout.write(`log: ${log}\n`);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
// Subcommand: stop
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
|
|
214
|
+
function cmdEmbedStop(_args, { homeDir = os.homedir() } = {}) {
|
|
215
|
+
const state = readRunningState(homeDir);
|
|
216
|
+
if (!state) {
|
|
217
|
+
process.stdout.write('embed daemon is not running\n');
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
try {
|
|
221
|
+
process.kill(Number(state.pid), 'SIGTERM');
|
|
222
|
+
clearState(homeDir);
|
|
223
|
+
process.stdout.write(`embed daemon stopped (pid ${state.pid})\n`);
|
|
224
|
+
} catch (err) {
|
|
225
|
+
process.stderr.write(`Failed to stop daemon: ${err.message}\n`);
|
|
226
|
+
clearState(homeDir);
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ---------------------------------------------------------------------------
|
|
232
|
+
// Subcommand: status
|
|
233
|
+
// ---------------------------------------------------------------------------
|
|
234
|
+
|
|
235
|
+
function cmdEmbedStatus(_args, { homeDir = os.homedir() } = {}) {
|
|
236
|
+
const state = readRunningState(homeDir);
|
|
237
|
+
if (!state) {
|
|
238
|
+
process.stdout.write('embed daemon: stopped\n');
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
process.stdout.write(`embed daemon: running\n`);
|
|
242
|
+
process.stdout.write(` pid: ${state.pid}\n`);
|
|
243
|
+
process.stdout.write(` config: ${state.configPath}\n`);
|
|
244
|
+
process.stdout.write(` started at: ${state.startedAt}\n`);
|
|
245
|
+
process.stdout.write(` log: ${logPath(homeDir)}\n`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// ---------------------------------------------------------------------------
|
|
249
|
+
// Subcommand: snapshot (one-shot, in-process)
|
|
250
|
+
// ---------------------------------------------------------------------------
|
|
251
|
+
|
|
252
|
+
async function cmdEmbedSnapshot(args, { homeDir = os.homedir() } = {}) {
|
|
253
|
+
const { config } = parseArgs(args);
|
|
254
|
+
const configPath = config
|
|
255
|
+
? path.resolve(config)
|
|
256
|
+
: path.join(os.homedir(), '.construct', 'embed.yaml');
|
|
257
|
+
|
|
258
|
+
const { loadEmbedConfig, EMPTY_CONFIG } = await import('./config.mjs');
|
|
259
|
+
const { SnapshotEngine, renderMarkdown } = await import('./snapshot.mjs');
|
|
260
|
+
const { ProviderRegistry } = await import('./providers/registry.mjs');
|
|
261
|
+
const { loadConstructEnv } = await import('../env-config.mjs');
|
|
262
|
+
|
|
263
|
+
const env = loadConstructEnv();
|
|
264
|
+
const registry = await ProviderRegistry.fromEnv(env);
|
|
265
|
+
|
|
266
|
+
let cfg;
|
|
267
|
+
if (fs.existsSync(configPath)) {
|
|
268
|
+
cfg = loadEmbedConfig(configPath);
|
|
269
|
+
} else {
|
|
270
|
+
cfg = { ...EMPTY_CONFIG, sources: registry.autoSources(env) };
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (!cfg.sources.length) {
|
|
274
|
+
process.stderr.write('embed snapshot: no sources configured and no credentials found in config.env\n');
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const engine = new SnapshotEngine(registry, cfg);
|
|
279
|
+
|
|
280
|
+
process.stderr.write('embed: generating snapshot…\n');
|
|
281
|
+
const snapshot = await engine.generate();
|
|
282
|
+
process.stdout.write(renderMarkdown(snapshot));
|
|
283
|
+
process.stderr.write(`\n${snapshot.summary.totalItems} items, ${snapshot.summary.errorCount} errors\n`);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ---------------------------------------------------------------------------
|
|
287
|
+
// Main export
|
|
288
|
+
// ---------------------------------------------------------------------------
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Entry point called by bin/construct.
|
|
292
|
+
* @param {string[]} args - argv after 'embed'
|
|
293
|
+
* @param {object} [opts] - { homeDir, rootDir }
|
|
294
|
+
*/
|
|
295
|
+
export async function runEmbedCli(args, opts = {}) {
|
|
296
|
+
const sub = args[0];
|
|
297
|
+
const subArgs = args.slice(1);
|
|
298
|
+
const homeDir = opts.homeDir ?? os.homedir();
|
|
299
|
+
const rootDir = opts.rootDir ?? new URL('../..', import.meta.url).pathname;
|
|
300
|
+
|
|
301
|
+
switch (sub) {
|
|
302
|
+
case 'start': return cmdEmbedStart(subArgs, { homeDir, rootDir });
|
|
303
|
+
case 'stop': return cmdEmbedStop(subArgs, { homeDir });
|
|
304
|
+
case 'status': return cmdEmbedStatus(subArgs, { homeDir });
|
|
305
|
+
case 'snapshot': return cmdEmbedSnapshot(subArgs, { homeDir });
|
|
306
|
+
case 'migrate-model': return cmdEmbedMigrateModel(subArgs);
|
|
307
|
+
case 'supervise': {
|
|
308
|
+
const { installSupervision } = await import('./supervision.mjs');
|
|
309
|
+
const result = await installSupervision();
|
|
310
|
+
process.stdout.write(`embed daemon supervised via ${result.method}\n`);
|
|
311
|
+
if (result.file) process.stdout.write(` service file: ${result.file}\n`);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
case 'unsupervise': {
|
|
315
|
+
const { uninstallSupervision } = await import('./supervision.mjs');
|
|
316
|
+
const result = await uninstallSupervision();
|
|
317
|
+
if (result.wasInstalled) {
|
|
318
|
+
process.stdout.write(`supervision removed (${result.method})\n`);
|
|
319
|
+
} else {
|
|
320
|
+
process.stdout.write(`supervision was not installed\n`);
|
|
321
|
+
}
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
default:
|
|
325
|
+
process.stderr.write(
|
|
326
|
+
`Usage: construct embed <start|stop|status|snapshot|migrate-model|supervise|unsupervise> [--config <path>]\n`,
|
|
327
|
+
);
|
|
328
|
+
if (sub && sub !== '--help' && sub !== '-h') {
|
|
329
|
+
process.stderr.write(`Unknown subcommand: ${sub}\n`);
|
|
330
|
+
process.exit(1);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Reconcile the pgvector schema with the engine's currently-active embedding
|
|
337
|
+
* model and re-embed the corpus. Run this after changing
|
|
338
|
+
* CONSTRUCT_EMBEDDING_MODEL when the new model produces a different
|
|
339
|
+
* dimensionality than the on-disk schema. The pass:
|
|
340
|
+
* 1. Resolves the engine's active model + dim.
|
|
341
|
+
* 2. Reads the actual `construct_embeddings.embedding` column dim from
|
|
342
|
+
* `pg_attribute` and compares.
|
|
343
|
+
* 3. If they differ AND the operator passed `--apply`, truncates
|
|
344
|
+
* `construct_embeddings` and re-types the column.
|
|
345
|
+
* 4. Re-runs `syncFileStateToSql` to repopulate embeddings at the new dim.
|
|
346
|
+
*
|
|
347
|
+
* Without `--apply`, prints what would change and exits.
|
|
348
|
+
*/
|
|
349
|
+
async function cmdEmbedMigrateModel(args) {
|
|
350
|
+
const apply = args.includes('--apply');
|
|
351
|
+
const { getEmbeddingModelInfo } = await import('../storage/embeddings-engine.mjs');
|
|
352
|
+
const { createSqlClient, closeSqlClient } = await import('../storage/backend.mjs');
|
|
353
|
+
const { syncFileStateToSql } = await import('../storage/sync.mjs');
|
|
354
|
+
|
|
355
|
+
const info = await getEmbeddingModelInfo();
|
|
356
|
+
const targetDim = info.dimensions;
|
|
357
|
+
process.stdout.write(`Active engine model: ${info.model} (${targetDim}d)\n`);
|
|
358
|
+
|
|
359
|
+
const client = createSqlClient(process.env);
|
|
360
|
+
if (!client) {
|
|
361
|
+
process.stderr.write('No DATABASE_URL configured — nothing to migrate.\n');
|
|
362
|
+
process.exit(1);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
try {
|
|
366
|
+
const rows = await client`
|
|
367
|
+
SELECT format_type(atttypid, atttypmod) AS pg_type
|
|
368
|
+
FROM pg_attribute
|
|
369
|
+
WHERE attrelid = 'construct_embeddings'::regclass
|
|
370
|
+
AND attname = 'embedding'
|
|
371
|
+
AND NOT attisdropped
|
|
372
|
+
`;
|
|
373
|
+
const declared = rows?.[0]?.pg_type || '';
|
|
374
|
+
const match = declared.match(/vector\((\d+)\)/);
|
|
375
|
+
const schemaDim = match ? Number(match[1]) : null;
|
|
376
|
+
|
|
377
|
+
if (schemaDim === null) {
|
|
378
|
+
process.stdout.write(`Schema column type is '${declared}'; cannot migrate automatically. Run migrations first.\n`);
|
|
379
|
+
process.exit(1);
|
|
380
|
+
}
|
|
381
|
+
if (schemaDim === targetDim) {
|
|
382
|
+
process.stdout.write(`Schema is already ${schemaDim}d — nothing to migrate.\n`);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
process.stdout.write(`Schema declares vector(${schemaDim}); engine produces ${targetDim}d.\n`);
|
|
387
|
+
if (!apply) {
|
|
388
|
+
process.stdout.write('Re-run with --apply to truncate construct_embeddings and re-type the column.\n');
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
process.stdout.write(`Applying migration: TRUNCATE + ALTER COLUMN to vector(${targetDim})…\n`);
|
|
393
|
+
await client.unsafe(
|
|
394
|
+
`BEGIN; TRUNCATE TABLE construct_embeddings; ` +
|
|
395
|
+
`ALTER TABLE construct_embeddings ALTER COLUMN embedding TYPE vector(${targetDim}); COMMIT;`
|
|
396
|
+
);
|
|
397
|
+
process.stdout.write('Re-embedding the corpus…\n');
|
|
398
|
+
const result = await syncFileStateToSql(process.cwd());
|
|
399
|
+
process.stdout.write(
|
|
400
|
+
`Done. embeddingsSynced=${result.embeddingsSynced} model=${result.embeddingModel}\n`
|
|
401
|
+
);
|
|
402
|
+
} catch (err) {
|
|
403
|
+
process.stderr.write(`migrate-model failed: ${err.message}\n`);
|
|
404
|
+
process.exit(1);
|
|
405
|
+
} finally {
|
|
406
|
+
await closeSqlClient(client);
|
|
407
|
+
}
|
|
408
|
+
}
|