@geraldmaron/construct 1.4.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +36 -0
- package/README.md +41 -7
- package/bin/construct +1029 -65
- package/bin/construct-postinstall.mjs +27 -2
- package/config/tag-vocabulary.json +264 -0
- package/examples/distribution/sources/deck-one-pager.md +1 -1
- package/lib/acp/server.mjs +21 -7
- package/lib/adapters-sync.mjs +2 -1
- package/lib/audit-trail.mjs +185 -2
- package/lib/beads/auto-close.mjs +2 -1
- package/lib/beads/drift.mjs +2 -1
- package/lib/bridges/copilot-proxy.mjs +20 -5
- package/lib/certification/skill-inventory.mjs +10 -1
- package/lib/cli/approvals.mjs +147 -0
- package/lib/cli-commands.mjs +105 -14
- package/lib/comment-lint.mjs +127 -8
- package/lib/config/schema.mjs +7 -30
- package/lib/config/source-target-registry.mjs +70 -0
- package/lib/config/source-targets.mjs +179 -205
- package/lib/contracts/coverage.mjs +77 -0
- package/lib/contracts/validate.mjs +102 -13
- package/lib/contracts/violation-log.mjs +50 -4
- package/lib/db/migrate.mjs +69 -0
- package/lib/db/migrations/001_orchestration_runs.sql +9 -0
- package/lib/db/migrations/002_queue_provider.sql +50 -0
- package/lib/db/migrations/003_worker_registry.sql +17 -0
- package/lib/db/migrations/004_trace_events.sql +16 -0
- package/lib/db/migrations/005_shared_memory.sql +15 -0
- package/lib/db/migrations/006_orchestration_runs_tenant.sql +5 -0
- package/lib/decisions/enforced-baseline.json +0 -2
- package/lib/decisions/registry.mjs +3 -2
- package/lib/deployment/parity-contract.mjs +1 -1
- package/lib/deployment-mode.mjs +78 -2
- package/lib/diagram-export.mjs +10 -1
- package/lib/distill.mjs +5 -2
- package/lib/docs-verify.mjs +2 -1
- package/lib/doctor/cli.mjs +1 -0
- package/lib/doctor/command-on-path.mjs +24 -0
- package/lib/doctor/diagnosis.mjs +109 -0
- package/lib/doctor/embedding-health.mjs +50 -0
- package/lib/doctor/engine-health.mjs +93 -0
- package/lib/doctor/graph-validate.mjs +47 -0
- package/lib/doctor/index.mjs +23 -4
- package/lib/doctor/sidecar-providers.mjs +56 -0
- package/lib/doctor/watchers/consistency.mjs +93 -1
- package/lib/doctor/watchers/cx-budget.mjs +1 -1
- package/lib/doctor/watchers/graph-staleness.mjs +1 -1
- package/lib/doctor/watchers/mcp-protocol.mjs +17 -0
- package/lib/doctor/watchers/oracle-liveness.mjs +92 -0
- package/lib/doctor/watchers/orchestration-runs.mjs +108 -0
- package/lib/doctor/watchers/provider-breaker.mjs +78 -0
- package/lib/document-export.mjs +52 -27
- package/lib/document-extract/docling-client.mjs +9 -5
- package/lib/document-extract/docling-sidecar.py +30 -0
- package/lib/document-extract.mjs +1 -1
- package/lib/document-ingest.mjs +9 -0
- package/lib/embed/approval-queue.mjs +184 -88
- package/lib/embed/authority-guard.mjs +65 -2
- package/lib/embed/capability-jobs.mjs +365 -0
- package/lib/embed/capability-lifecycle.mjs +219 -0
- package/lib/embed/capability-loader.mjs +303 -0
- package/lib/embed/capability-runtime.mjs +58 -0
- package/lib/embed/cli.mjs +185 -8
- package/lib/embed/config.mjs +4 -0
- package/lib/embed/daemon.mjs +125 -6
- package/lib/embed/demand-fetch.mjs +190 -54
- package/lib/embed/inbox.mjs +12 -10
- package/lib/embed/presets/ops-triage.mjs +236 -0
- package/lib/embed/presets/pm-feedback.mjs +341 -0
- package/lib/embed/presets/tpm.mjs +401 -0
- package/lib/embed/providers/jira.mjs +72 -1
- package/lib/embed/providers/registry.mjs +140 -33
- package/lib/embed/worker.mjs +5 -0
- package/lib/embedded-contract/capability.mjs +4 -0
- package/lib/embedded-contract/execution.mjs +1 -1
- package/lib/embedded-contract/model-resolve.mjs +53 -3
- package/lib/embedded-contract/workflow-defs.mjs +48 -73
- package/lib/embedded-contract/workflow-invoke.mjs +144 -4
- package/lib/embedded-contract/workflows/architecture-review.manifest.json +15 -0
- package/lib/embedded-contract/workflows/data-structure.manifest.json +14 -0
- package/lib/embedded-contract/workflows/evidence-ingest.manifest.json +14 -0
- package/lib/embedded-contract/workflows/memo-draft.manifest.json +14 -0
- package/lib/embedded-contract/workflows/operations-triage.manifest.json +18 -0
- package/lib/embedded-contract/workflows/operations.manifest.json +18 -0
- package/lib/embedded-contract/workflows/pm-feedback.manifest.json +18 -0
- package/lib/embedded-contract/workflows/prd-draft.manifest.json +15 -0
- package/lib/embedded-contract/workflows/proposal-review.manifest.json +15 -0
- package/lib/embedded-contract/workflows/research-synthesis.manifest.json +14 -0
- package/lib/embedded-contract/workflows/risk-review.manifest.json +15 -0
- package/lib/embedded-contract/workflows/structure-notes.manifest.json +14 -0
- package/lib/embedded-contract/workflows/transcript-process.manifest.json +14 -0
- package/lib/embedded-contract/workflows/triage.manifest.json +14 -0
- package/lib/env-config.mjs +60 -11
- package/lib/export-validate.mjs +34 -2
- package/lib/extensions/index.mjs +27 -0
- package/lib/extensions/loader.mjs +120 -0
- package/lib/extensions/manifest-schema.mjs +141 -0
- package/lib/extensions/manifests/anthropic.manifest.json +12 -0
- package/lib/extensions/manifests/atlassian-confluence.manifest.json +12 -0
- package/lib/extensions/manifests/atlassian-jira.manifest.json +53 -0
- package/lib/extensions/manifests/directory.manifest.json +12 -0
- package/lib/extensions/manifests/docling.manifest.json +37 -0
- package/lib/extensions/manifests/echo.manifest.json +8 -0
- package/lib/extensions/manifests/feedback.manifest.json +12 -0
- package/lib/extensions/manifests/github-copilot.manifest.json +12 -0
- package/lib/extensions/manifests/github.manifest.json +52 -0
- package/lib/extensions/manifests/linear.manifest.json +50 -0
- package/lib/extensions/manifests/local.manifest.json +12 -0
- package/lib/extensions/manifests/ollama.manifest.json +12 -0
- package/lib/extensions/manifests/openai.manifest.json +12 -0
- package/lib/extensions/manifests/openrouter-anthropic.manifest.json +12 -0
- package/lib/extensions/manifests/openrouter-deepseek.manifest.json +12 -0
- package/lib/extensions/manifests/openrouter-google.manifest.json +12 -0
- package/lib/extensions/manifests/openrouter-llama.manifest.json +12 -0
- package/lib/extensions/manifests/openrouter-qwen.manifest.json +12 -0
- package/lib/extensions/manifests/openrouter.manifest.json +12 -0
- package/lib/extensions/manifests/postgres.manifest.json +12 -0
- package/lib/extensions/manifests/salesforce.manifest.json +12 -0
- package/lib/extensions/manifests/slack.manifest.json +58 -0
- package/lib/extensions/manifests/whisper.manifest.json +36 -0
- package/lib/extensions/validate.mjs +175 -0
- package/lib/features.mjs +13 -9
- package/lib/flows/checkpoint.mjs +184 -0
- package/lib/flows/constants.mjs +27 -0
- package/lib/flows/define.mjs +146 -0
- package/lib/flows/engine.mjs +249 -0
- package/lib/flows/errors.mjs +19 -0
- package/lib/flows/index.mjs +27 -0
- package/lib/flows/joins.mjs +18 -0
- package/lib/flows/schema.mjs +90 -0
- package/lib/flows/state.mjs +31 -0
- package/lib/frameworks/loader.mjs +99 -0
- package/lib/frameworks/schema.mjs +157 -0
- package/lib/graph/build-from-corpus.mjs +67 -0
- package/lib/graph/build-from-embed.mjs +82 -0
- package/lib/graph/build-from-registry.mjs +164 -3
- package/lib/graph/cli.mjs +456 -12
- package/lib/graph/gap-queries.mjs +156 -0
- package/lib/graph/gaps.mjs +41 -0
- package/lib/graph/impacted.mjs +129 -0
- package/lib/graph/runtime-evidence.mjs +177 -0
- package/lib/graph/security-coverage.mjs +113 -0
- package/lib/graph/staleness.mjs +241 -10
- package/lib/graph/store.mjs +24 -7
- package/lib/graph/validate.mjs +161 -0
- package/lib/headhunt.mjs +9 -8
- package/lib/health-check.mjs +15 -7
- package/lib/hook-health.mjs +1 -1
- package/lib/hooks/agent-tracker.mjs +10 -4
- package/lib/hooks/edit-guard.mjs +3 -3
- package/lib/hooks/graph-impact-advisory.mjs +2 -2
- package/lib/hooks/guard-bash.mjs +41 -15
- package/lib/hooks/mcp-health-check.mjs +11 -4
- package/lib/hooks/model-fallback.mjs +50 -6
- package/lib/hooks/orchestration-dispatch-guard.mjs +14 -3
- package/lib/hooks/pre-compact.mjs +181 -173
- package/lib/hooks/rule-verifier.mjs +2 -1
- package/lib/hooks/session-reflect.mjs +2 -1
- package/lib/hooks/session-start.mjs +3 -3
- package/lib/host/readiness.mjs +109 -0
- package/lib/host-capabilities.mjs +13 -2
- package/lib/host-disposition.mjs +29 -8
- package/lib/identity.mjs +92 -0
- package/lib/ingest/degraded-extract.mjs +96 -0
- package/lib/ingest/docling-remote.mjs +2 -1
- package/lib/ingest/provider-extract.mjs +7 -19
- package/lib/ingest/sidecar-providers.mjs +196 -0
- package/lib/ingest-tooling.mjs +11 -5
- package/lib/init-unified.mjs +55 -38
- package/lib/init-update.mjs +2 -1
- package/lib/install/legacy-global-cleanup.mjs +25 -0
- package/lib/install/stage-project.mjs +41 -4
- package/lib/intake/daemon.mjs +99 -8
- package/lib/intake/git-queue.mjs +110 -38
- package/lib/intake/prepare.mjs +2 -0
- package/lib/intake/queue-registry.mjs +50 -0
- package/lib/intake/queue.mjs +133 -17
- package/lib/intake/session-prelude.mjs +57 -8
- package/lib/integrations/intake-integrations.mjs +61 -111
- package/lib/intent-classifier.mjs +43 -5
- package/lib/libreoffice-export.mjs +8 -8
- package/lib/logging/rotate.mjs +5 -4
- package/lib/mcp/broker.mjs +332 -17
- package/lib/mcp/denied-store.mjs +95 -0
- package/lib/mcp/destructive-approval.mjs +57 -0
- package/lib/mcp/destructive-gate.mjs +30 -0
- package/lib/mcp/dispatch-envelope.mjs +199 -0
- package/lib/mcp/memory-bridge.mjs +2 -1
- package/lib/mcp/server.mjs +185 -1268
- package/lib/mcp/tool-definitions-memory.mjs +376 -0
- package/lib/mcp/tool-definitions-project.mjs +271 -0
- package/lib/mcp/tool-definitions-skills.mjs +311 -0
- package/lib/mcp/tool-definitions-workflow.mjs +398 -0
- package/lib/mcp/tool-definitions.mjs +25 -0
- package/lib/mcp/tool-rate-limit.mjs +47 -0
- package/lib/mcp/tool-registry.mjs +107 -0
- package/lib/mcp/tool-safety.mjs +95 -0
- package/lib/mcp/tool-surface-parity.mjs +60 -0
- package/lib/mcp/tools/orchestration-delegation-next.tool.mjs +68 -0
- package/lib/mcp/tools/orchestration-run.mjs +197 -19
- package/lib/mcp/tools/orchestration-task-result.tool.mjs +77 -0
- package/lib/mcp/tools/project.mjs +25 -8
- package/lib/mcp/tools/provider-write.mjs +187 -0
- package/lib/mcp/tools/scope.mjs +0 -3
- package/lib/mcp/tools/skills.mjs +1 -1
- package/lib/mcp/tools/storage.mjs +2 -2
- package/lib/mcp/tools/web-search-governance.mjs +96 -0
- package/lib/mcp/tools/web-search.mjs +5 -76
- package/lib/mcp/transport/auth.mjs +238 -0
- package/lib/mcp/transport/http.mjs +136 -0
- package/lib/mcp/transport/mode.mjs +31 -0
- package/lib/mcp/transport/stdio.mjs +22 -0
- package/lib/mcp-catalog.json +4 -4
- package/lib/mcp-manager.mjs +34 -23
- package/lib/mcp-platform-config.mjs +53 -20
- package/lib/mode-capabilities.mjs +109 -0
- package/lib/model-router.mjs +42 -9
- package/lib/models/catalog.mjs +40 -1
- package/lib/net-guard.mjs +247 -0
- package/lib/observation-store.mjs +6 -2
- package/lib/ollama/provision-context.mjs +2 -1
- package/lib/opencode-config.mjs +22 -3
- package/lib/opencode-runtime-plugin.mjs +120 -2
- package/lib/oracle/actions.mjs +204 -10
- package/lib/oracle/cli.mjs +24 -3
- package/lib/oracle/daemon-entry.mjs +6 -0
- package/lib/oracle/dispatch.mjs +2 -1
- package/lib/oracle/execute.mjs +2 -2
- package/lib/oracle/gaps.mjs +3 -3
- package/lib/oracle/heartbeat.mjs +53 -0
- package/lib/oracle/read-model.mjs +69 -13
- package/lib/oracle/reconcile.mjs +3 -46
- package/lib/oracle/routing.mjs +37 -31
- package/lib/oracle/synthesize.mjs +1 -1
- package/lib/orchestration/classification.mjs +434 -0
- package/lib/orchestration/delegation-flow.mjs +132 -0
- package/lib/orchestration/flow-selection.mjs +418 -0
- package/lib/orchestration/gates.mjs +244 -0
- package/lib/orchestration/host-sampling.mjs +121 -0
- package/lib/orchestration/policy-constants.mjs +48 -0
- package/lib/orchestration/provider-outcome.mjs +197 -0
- package/lib/orchestration/readiness.mjs +114 -13
- package/lib/orchestration/run-store-postgres.mjs +32 -26
- package/lib/orchestration/run-store-sqlite.mjs +8 -14
- package/lib/orchestration/run-store.mjs +25 -12
- package/lib/orchestration/runtime.mjs +508 -62
- package/lib/orchestration/store.mjs +87 -12
- package/lib/orchestration/trace-store.mjs +125 -0
- package/lib/orchestration/web-capability.mjs +60 -0
- package/lib/orchestration/worker-runtime.mjs +162 -0
- package/lib/orchestration/worker.mjs +763 -80
- package/lib/orchestration-policy.mjs +67 -1111
- package/lib/output-quality.mjs +61 -2
- package/lib/packs/cli.mjs +144 -0
- package/lib/packs/core-pack.mjs +112 -0
- package/lib/packs/enablement.mjs +187 -0
- package/lib/packs/index.mjs +23 -0
- package/lib/packs/loader.mjs +176 -0
- package/lib/packs/manifest-schema.mjs +58 -0
- package/lib/packs/prompts.mjs +120 -0
- package/lib/packs/validate.mjs +208 -0
- package/lib/path-policy.mjs +56 -0
- package/lib/plugin-registry.mjs +4 -5
- package/lib/policy/audit-gate.mjs +42 -0
- package/lib/policy/consumption-budget.mjs +149 -0
- package/lib/policy/engine.mjs +81 -6
- package/lib/policy/role-authority.mjs +89 -0
- package/lib/prompt-composer.js +19 -3
- package/lib/providers/contract/adapters/confluence/governed-write.mjs +215 -0
- package/lib/providers/contract/adapters/confluence/manifest.json +17 -0
- package/lib/providers/contract/adapters/confluence/transport.mjs +135 -0
- package/lib/providers/contract/adapters/github/governed-write.mjs +121 -0
- package/lib/providers/contract/adapters/github/index.mjs +38 -3
- package/lib/providers/contract/adapters/jira/adf.mjs +151 -0
- package/lib/providers/contract/adapters/jira/createmeta.mjs +143 -0
- package/lib/providers/contract/adapters/jira/governed-write.mjs +182 -0
- package/lib/providers/contract/adapters/jira/manifest.json +17 -0
- package/lib/providers/contract/adapters/jira/transport.mjs +119 -0
- package/lib/providers/contract.mjs +207 -0
- package/lib/providers/credential-bootstrap.mjs +7 -4
- package/lib/providers/credential-sources.mjs +14 -2
- package/lib/providers/directory/index.mjs +261 -0
- package/lib/providers/feedback/index.mjs +392 -0
- package/lib/providers/filter-audit.mjs +68 -0
- package/lib/providers/filter-schema.mjs +54 -0
- package/lib/providers/github/index.mjs +31 -0
- package/lib/providers/instance-config.mjs +215 -0
- package/lib/providers/op-locate.mjs +96 -0
- package/lib/providers/op-run.mjs +64 -9
- package/lib/providers/registry.mjs +26 -3
- package/lib/providers/secret-audit-wiring.mjs +41 -18
- package/lib/providers/secret-resolver.mjs +263 -31
- package/lib/publish-template.mjs +6 -3
- package/lib/publish-tooling.mjs +4 -0
- package/lib/publish.mjs +32 -4
- package/lib/queue/pg-queue.mjs +395 -0
- package/lib/reflect.mjs +2 -1
- package/lib/registry/assemble.mjs +28 -2
- package/lib/registry/catalog.mjs +6 -0
- package/lib/registry/consolidation.mjs +8 -1
- package/lib/registry/custom-scaffold.mjs +200 -0
- package/lib/registry/custom-schema.mjs +137 -0
- package/lib/registry/loader.mjs +15 -4
- package/lib/registry/manifests/format-engines.default.json +15 -0
- package/lib/registry/manifests/surface-map.default.json +46 -0
- package/lib/registry/retired-paths.mjs +1 -0
- package/lib/registry/surface-map.mjs +100 -50
- package/lib/registry/validate.mjs +3 -3
- package/lib/render-visual-check.mjs +240 -0
- package/lib/resources/budget.mjs +40 -17
- package/lib/roles/flavor-bindings.mjs +36 -14
- package/lib/roles/gateway.mjs +15 -8
- package/lib/roots.mjs +107 -0
- package/lib/runtime/uv-bootstrap.mjs +32 -6
- package/lib/runtime/whisper-bootstrap.mjs +11 -3
- package/lib/runtime-env.mjs +5 -2
- package/lib/sandbox.mjs +1 -1
- package/lib/scheduler/index.mjs +8 -20
- package/lib/schema-infer.mjs +31 -2
- package/lib/scopes/lifecycle.mjs +29 -25
- package/lib/scopes/loader.mjs +49 -12
- package/lib/scopes/teams.mjs +1 -1
- package/lib/security/ingest-boundary.mjs +80 -0
- package/lib/security/recall-wrapper.mjs +99 -0
- package/lib/security/trust.mjs +132 -0
- package/lib/service-manager.mjs +93 -24
- package/lib/setup.mjs +41 -23
- package/lib/skills-apply.mjs +4 -2
- package/lib/specialists/postconditions.mjs +2 -2
- package/lib/state-root.mjs +147 -0
- package/lib/status.mjs +597 -6
- package/lib/storage/admin.mjs +84 -7
- package/lib/storage/backend-registry.mjs +73 -0
- package/lib/storage/backend.mjs +63 -9
- package/lib/storage/embeddings-openai.mjs +12 -2
- package/lib/storage/hybrid-query.mjs +11 -3
- package/lib/storage/retrieval-hardening.mjs +384 -0
- package/lib/storage/shared-memory.mjs +158 -0
- package/lib/storage/vector-client.mjs +69 -2
- package/lib/team/health.mjs +72 -0
- package/lib/telemetry/backends/local.mjs +9 -3
- package/lib/telemetry/client.mjs +3 -7
- package/lib/template-registry.mjs +10 -12
- package/lib/tenant/context.mjs +82 -0
- package/lib/tenant/isolation.mjs +129 -0
- package/lib/test-corpus-inventory.mjs +103 -2
- package/lib/uninstall/uninstall.mjs +78 -12
- package/lib/validator.mjs +4 -6
- package/lib/worker/entrypoint.mjs +2 -1
- package/lib/worker/run.mjs +2 -2
- package/lib/worker/trace.mjs +5 -11
- package/lib/workflow-state.mjs +52 -8
- package/lib/workflows/liveness.mjs +203 -0
- package/lib/workflows/loader.mjs +177 -0
- package/lib/workflows/manifest-schema.mjs +71 -0
- package/lib/workflows/surface-parity.mjs +118 -0
- package/lib/workflows/validate.mjs +127 -0
- package/lib/writes/control-plane.mjs +140 -0
- package/lib/writes/envelope.mjs +206 -0
- package/lib/writes/sent-log.mjs +86 -0
- package/lib/writes/write-intent.mjs +109 -0
- package/package.json +20 -7
- package/personas/construct.md +12 -3
- package/registry/agent-manifest.json +117 -0
- package/registry/capabilities.json +1987 -0
- package/rules/common/comments.md +1 -0
- package/schemas/brand-voice.schema.json +24 -0
- package/schemas/capability-registry.schema.json +72 -0
- package/schemas/certification-run.schema.json +130 -0
- package/schemas/demo-recording.schema.json +46 -0
- package/schemas/eval-dataset.schema.json +79 -0
- package/schemas/execution-capability-profile.schema.json +46 -0
- package/schemas/execution-policy.schema.json +114 -0
- package/schemas/improvement-proposal.schema.json +65 -0
- package/schemas/mcp-tool-output.schema.json +61 -0
- package/schemas/platform-capabilities.schema.json +83 -0
- package/schemas/project-config.schema.json +215 -0
- package/schemas/project-demo.schema.json +60 -0
- package/schemas/provider-behavior-matrix.schema.json +91 -0
- package/schemas/scope.schema.json +197 -0
- package/schemas/specialist-trace.schema.json +107 -0
- package/schemas/team.schema.json +99 -0
- package/schemas/unified-registry.schema.json +546 -0
- package/scripts/sync-specialists.mjs +336 -106
- package/skills/docs/adr-workflow.md +1 -1
- package/skills/docs/codebase-research-workflow.md +3 -3
- package/skills/docs/prd-workflow.md +5 -6
- package/skills/docs/runbook-workflow.md +2 -2
- package/skills/docs/user-research-workflow.md +3 -3
- package/skills/operating/fleet-health-routing.md +77 -0
- package/skills/roles/ai-engineer.md +1 -1
- package/skills/roles/architect.md +0 -1
- package/skills/roles/business-strategist.md +1 -1
- package/skills/roles/data-analyst.telemetry.md +1 -1
- package/skills/roles/data-engineer.md +1 -1
- package/skills/roles/data-engineer.pipeline.md +1 -1
- package/skills/roles/data-engineer.vector-retrieval.md +1 -2
- package/skills/roles/data-engineer.warehouse.md +1 -1
- package/skills/roles/designer.accessibility.md +1 -1
- package/skills/roles/designer.md +0 -1
- package/skills/roles/devil-advocate.md +1 -1
- package/skills/roles/docs-keeper.md +1 -1
- package/skills/roles/evaluator.md +1 -1
- package/skills/roles/explorer.md +1 -1
- package/skills/roles/platform-engineer.md +1 -1
- package/skills/roles/qa.ai-eval.md +1 -2
- package/skills/roles/qa.api-contract.md +0 -1
- package/skills/roles/qa.data-pipeline.md +0 -1
- package/skills/roles/qa.md +0 -1
- package/skills/roles/qa.web-ui.md +0 -1
- package/skills/roles/release-manager.md +1 -1
- package/skills/roles/researcher.md +0 -2
- package/skills/roles/reviewer.md +0 -3
- package/skills/roles/security.ai.md +1 -1
- package/skills/roles/security.legal-compliance.md +1 -1
- package/skills/roles/security.md +0 -1
- package/skills/roles/security.privacy.md +0 -1
- package/skills/roles/security.supply-chain.md +1 -1
- package/skills/roles/sre.md +1 -1
- package/skills/roles/test-automation.md +1 -1
- package/skills/roles/trace-reviewer.md +1 -1
- package/skills/roles/ux-researcher.md +1 -1
- package/specialists/artifact-manifest.json +36 -36
- package/specialists/org/contracts/accessibility-to-qa.json +11 -3
- package/specialists/org/contracts/any-to-business-strategist.json +19 -7
- package/specialists/org/contracts/any-to-debugger.json +7 -1
- package/specialists/org/contracts/any-to-designer.json +7 -1
- package/specialists/org/contracts/any-to-docs-keeper.json +18 -4
- package/specialists/org/contracts/any-to-explorer.json +13 -4
- package/specialists/org/contracts/any-to-sre-incident.json +6 -2
- package/specialists/org/contracts/any-to-trace-reviewer.json +16 -4
- package/specialists/org/contracts/architect-to-ai-engineer.json +6 -2
- package/specialists/org/contracts/architect-to-data-engineer.json +17 -5
- package/specialists/org/contracts/architect-to-devil-advocate.json +11 -3
- package/specialists/org/contracts/architect-to-engineer.json +20 -4
- package/specialists/org/contracts/architect-to-evaluator.json +15 -5
- package/specialists/org/contracts/architect-to-legal-compliance.json +15 -5
- package/specialists/org/contracts/architect-to-operations.json +17 -4
- package/specialists/org/contracts/architect-to-platform-engineer.json +20 -4
- package/specialists/org/contracts/construct-to-orchestrator.json +10 -2
- package/specialists/org/contracts/data-analyst-to-product-manager.json +11 -2
- package/specialists/org/contracts/engineer-to-qa.json +20 -4
- package/specialists/org/contracts/engineer-to-reviewer.json +29 -5
- package/specialists/org/contracts/explorer-to-engineer.json +11 -3
- package/specialists/org/contracts/legal-compliance-to-release-manager.json +12 -4
- package/specialists/org/contracts/operations-to-user.json +53 -0
- package/specialists/org/contracts/operations-triage-output.json +53 -0
- package/specialists/org/contracts/pm-requirements-candidates.json +53 -0
- package/specialists/org/contracts/product-manager-to-architect.json +30 -10
- package/specialists/org/contracts/product-manager-to-data-analyst.json +13 -3
- package/specialists/org/contracts/product-manager-to-ux-researcher.json +15 -5
- package/specialists/org/contracts/qa-to-release-manager.json +11 -3
- package/specialists/org/contracts/researcher-to-architect.json +10 -2
- package/specialists/org/contracts/researcher-to-product-manager.json +16 -5
- package/specialists/org/contracts/reviewer-to-security.json +17 -3
- package/specialists/org/contracts/test-automation-to-engineer.json +11 -3
- package/specialists/org/contracts/trace-reviewer-to-sre.json +12 -4
- package/specialists/org/contracts/user-to-construct.json +11 -4
- package/specialists/org/frameworks/cx-architect-constraint-option-failure.md +66 -0
- package/specialists/org/frameworks/cx-engineer-feasibility-blast-radius.md +66 -0
- package/specialists/org/frameworks/cx-ops-dependency-sequencing.md +74 -0
- package/specialists/org/frameworks/cx-pm-value-tradeoff.md +66 -0
- package/specialists/org/frameworks/cx-qa-risk-based-coverage.md +69 -0
- package/specialists/org/groups/engineering-group.json +2 -6
- package/specialists/org/groups/governance-group.json +2 -3
- package/specialists/org/groups/operations-group.json +5 -8
- package/specialists/org/groups/product-group.json +4 -8
- package/specialists/org/groups/quality-group.json +3 -7
- package/specialists/org/groups/strategy-group.json +6 -9
- package/specialists/org/models.json.example +8 -0
- package/specialists/org/scopes/creative.json +6 -1
- package/specialists/org/scopes/operations.json +7 -1
- package/specialists/org/scopes/research.json +6 -1
- package/specialists/org/scopes/rnd.json +7 -1
- package/specialists/org/specialists/cx-architect.json +27 -8
- package/specialists/org/specialists/cx-designer.json +22 -8
- package/specialists/org/specialists/cx-engineer.json +71 -7
- package/specialists/org/specialists/cx-operations.json +89 -15
- package/specialists/org/specialists/cx-orchestrator.json +16 -4
- package/specialists/org/specialists/cx-product-manager.json +28 -9
- package/specialists/org/specialists/cx-qa.json +16 -6
- package/specialists/org/specialists/cx-researcher.json +41 -7
- package/specialists/org/specialists/cx-reviewer.json +61 -11
- package/specialists/org/specialists/cx-security.json +30 -10
- package/specialists/org/teams/design-team.json +3 -4
- package/specialists/org/teams/engineering-team.json +3 -10
- package/specialists/org/teams/governance-team.json +3 -5
- package/specialists/org/teams/operations-team.json +6 -12
- package/specialists/org/teams/product-management-team.json +2 -3
- package/specialists/org/teams/quality-team.json +4 -12
- package/specialists/org/teams/research-team.json +3 -3
- package/specialists/org/teams/strategy-team.json +7 -14
- package/specialists/prompts/cx-architect.md +20 -1
- package/specialists/prompts/cx-data-analyst.md +1 -1
- package/specialists/prompts/cx-designer.md +12 -4
- package/specialists/prompts/cx-engineer.md +15 -1
- package/specialists/prompts/cx-operations.md +14 -2
- package/specialists/prompts/cx-orchestrator.md +9 -5
- package/specialists/prompts/cx-product-manager.md +5 -1
- package/specialists/prompts/cx-qa.md +6 -2
- package/specialists/prompts/cx-researcher.md +27 -31
- package/specialists/prompts/cx-reviewer.md +19 -1
- package/specialists/prompts/cx-security.md +5 -1
- package/templates/distribution/construct-brand.typ +123 -59
- package/templates/distribution/construct-decision.typ +6 -3
- package/templates/distribution/construct-pdf.typ +11 -4
- package/templates/distribution/construct-prd.typ +6 -3
- package/templates/distribution/construct-research.typ +7 -4
- package/vendor/pandoc-ext/README.md +3 -0
- package/vendor/pandoc-ext/diagram.lua +687 -0
- package/lib/providers/contract/adapters/git/index.mjs +0 -115
- package/lib/providers/contract/adapters/slack/index.mjs +0 -175
- package/specialists/org/contracts/business-strategist-to-product-manager.json +0 -39
- package/specialists/org/contracts/construct-to-rd-lead.json +0 -53
- package/specialists/org/contracts/data-engineer-to-platform-engineer.json +0 -36
- package/specialists/org/contracts/designer-to-accessibility.json +0 -36
- package/specialists/org/contracts/platform-engineer-to-engineer.json +0 -31
- package/specialists/org/contracts/qa-to-test-automation.json +0 -42
- package/specialists/org/contracts/rd-lead-to-architect.json +0 -38
- package/specialists/org/contracts/sre-to-release-manager.json +0 -36
- package/specialists/org/specialists/cx-accessibility.json +0 -69
- package/specialists/org/specialists/cx-ai-engineer.json +0 -75
- package/specialists/org/specialists/cx-business-strategist.json +0 -72
- package/specialists/org/specialists/cx-data-engineer.json +0 -71
- package/specialists/org/specialists/cx-devil-advocate.json +0 -71
- package/specialists/org/specialists/cx-docs-keeper.json +0 -82
- package/specialists/org/specialists/cx-evaluator.json +0 -69
- package/specialists/org/specialists/cx-explorer.json +0 -69
- package/specialists/org/specialists/cx-legal-compliance.json +0 -74
- package/specialists/org/specialists/cx-oracle.json +0 -46
- package/specialists/org/specialists/cx-platform-engineer.json +0 -80
- package/specialists/org/specialists/cx-rd-lead.json +0 -73
- package/specialists/org/specialists/cx-release-manager.json +0 -77
- package/specialists/org/specialists/cx-sre.json +0 -94
- package/specialists/org/specialists/cx-test-automation.json +0 -69
- package/specialists/org/specialists/cx-trace-reviewer.json +0 -69
- package/specialists/org/specialists/cx-ux-researcher.json +0 -68
- package/specialists/org/teams/accessibility-team.json +0 -39
- package/specialists/org/teams/ux-research-team.json +0 -39
- package/specialists/prompts/cx-accessibility.md +0 -55
- package/specialists/prompts/cx-ai-engineer.md +0 -124
- package/specialists/prompts/cx-business-strategist.md +0 -58
- package/specialists/prompts/cx-data-engineer.md +0 -55
- package/specialists/prompts/cx-devil-advocate.md +0 -59
- package/specialists/prompts/cx-docs-keeper.md +0 -164
- package/specialists/prompts/cx-evaluator.md +0 -49
- package/specialists/prompts/cx-explorer.md +0 -71
- package/specialists/prompts/cx-legal-compliance.md +0 -58
- package/specialists/prompts/cx-oracle.md +0 -98
- package/specialists/prompts/cx-platform-engineer.md +0 -97
- package/specialists/prompts/cx-rd-lead.md +0 -59
- package/specialists/prompts/cx-release-manager.md +0 -54
- package/specialists/prompts/cx-sre.md +0 -111
- package/specialists/prompts/cx-test-automation.md +0 -55
- package/specialists/prompts/cx-trace-reviewer.md +0 -101
- package/specialists/prompts/cx-ux-researcher.md +0 -53
package/lib/storage/admin.mjs
CHANGED
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* lib/storage/admin.mjs — storage administration and maintenance.
|
|
3
|
+
*
|
|
4
|
+
* purgeExpiredData() is the TTL/size eviction path for the machine-scoped
|
|
5
|
+
* vector-indexed observations store (ADR-0066: <stateRoot>/lancedb,
|
|
6
|
+
* construct-rf26.17). Checking or pruning never provisions the LanceDB
|
|
7
|
+
* index as a side effect — a project that never ran `construct ingest`
|
|
8
|
+
* has no lancedb/ dir yet, so the call is a no-op rather than a trigger to
|
|
9
|
+
* materialize one. Caps resolve env var > construct.config.json
|
|
10
|
+
* (resources.disk.observationsMaxDays / observationsMaxRows) > default,
|
|
11
|
+
* matching the precedence documented in lib/config/project-config.mjs.
|
|
3
12
|
*/
|
|
4
13
|
import fs from 'node:fs';
|
|
5
14
|
import path from 'node:path';
|
|
15
|
+
import { resolveWithinRoot } from '../path-policy.mjs';
|
|
16
|
+
import { resolveStateDir } from '../state-root.mjs';
|
|
17
|
+
import { loadProjectConfig, resolveSetting } from '../config/project-config.mjs';
|
|
18
|
+
import { VectorClient } from './vector-client.mjs';
|
|
19
|
+
|
|
20
|
+
const OBSERVATIONS_MAX_DAYS_DEFAULT = 90;
|
|
21
|
+
const OBSERVATIONS_MAX_ROWS_DEFAULT = 5000;
|
|
6
22
|
|
|
7
23
|
export function inferProjectName(cwd) {
|
|
8
24
|
return path.basename(cwd) || 'construct';
|
|
@@ -18,14 +34,24 @@ function countFiles(dir) {
|
|
|
18
34
|
return count;
|
|
19
35
|
}
|
|
20
36
|
|
|
21
|
-
export async function getStorageStatus(rootDir, { env = process.env, project = 'construct' } = {}) {
|
|
37
|
+
export async function getStorageStatus(rootDir, { env = process.env, project = 'construct', fsExistsSync = fs.existsSync } = {}) {
|
|
22
38
|
const internalDir = path.join(rootDir, '.cx', 'knowledge', 'internal');
|
|
23
39
|
const count = countFiles(internalDir);
|
|
24
40
|
|
|
41
|
+
// Health mirrors probeStorageHealth (lib/status.mjs), derived from filesystem state
|
|
42
|
+
// rather than hardcoded: no .cx/ is unavailable, no lancedb store yet is degraded
|
|
43
|
+
// (no vector index), both present is healthy. The lancedb store itself resolves
|
|
44
|
+
// through the same machine-scoped state root (ADR-0066) resetStorage below already
|
|
45
|
+
// uses, not a project-relative `.cx/lancedb` — an override wins when set.
|
|
46
|
+
|
|
47
|
+
const cxExists = fsExistsSync(path.join(rootDir, '.cx'));
|
|
48
|
+
const lancedbExists = fsExistsSync(env.CONSTRUCT_LANCEDB_PATH || resolveStateDir(rootDir, 'lancedb', { ensureDir: false }));
|
|
49
|
+
const status = !cxExists ? 'unavailable' : lancedbExists ? 'healthy' : 'degraded';
|
|
50
|
+
|
|
25
51
|
return {
|
|
26
52
|
backend: 'lancedb',
|
|
27
53
|
project,
|
|
28
|
-
status
|
|
54
|
+
status,
|
|
29
55
|
ingested: {
|
|
30
56
|
count,
|
|
31
57
|
label: 'Ingested documents'
|
|
@@ -35,7 +61,7 @@ export async function getStorageStatus(rootDir, { env = process.env, project = '
|
|
|
35
61
|
|
|
36
62
|
export async function resetStorage(rootDir, { env = process.env, project = 'construct', resetVector = true, resetIngested = false } = {}) {
|
|
37
63
|
if (resetVector) {
|
|
38
|
-
const dbPath = env.CONSTRUCT_LANCEDB_PATH ||
|
|
64
|
+
const dbPath = env.CONSTRUCT_LANCEDB_PATH || resolveStateDir(rootDir, 'lancedb', { ensureDir: false });
|
|
39
65
|
if (fs.existsSync(dbPath)) {
|
|
40
66
|
fs.rmSync(dbPath, { recursive: true, force: true });
|
|
41
67
|
}
|
|
@@ -54,8 +80,12 @@ export async function deleteIngestedArtifacts(rootDir, { files = [], confirm = f
|
|
|
54
80
|
let deletedCount = 0;
|
|
55
81
|
const internalDir = path.join(rootDir, '.cx', 'knowledge', 'internal');
|
|
56
82
|
|
|
57
|
-
|
|
58
|
-
|
|
83
|
+
// Resolve every model-supplied entry against the ingested root first; an escaping
|
|
84
|
+
// path throws before any deletion, so a ../ traversal can neither delete an out-of-root
|
|
85
|
+
// file nor partially delete the set.
|
|
86
|
+
|
|
87
|
+
const targets = files.map((f) => resolveWithinRoot(internalDir, f));
|
|
88
|
+
for (const p of targets) {
|
|
59
89
|
if (fs.existsSync(p)) {
|
|
60
90
|
fs.rmSync(p);
|
|
61
91
|
deletedCount++;
|
|
@@ -73,6 +103,53 @@ export async function deleteIngestedArtifacts(rootDir, { files = [], confirm = f
|
|
|
73
103
|
return { status: 'deleted', deletedCount };
|
|
74
104
|
}
|
|
75
105
|
|
|
76
|
-
|
|
77
|
-
|
|
106
|
+
// Recursive byte count for the "current size" figure doctor/prune report —
|
|
107
|
+
// LanceDB stores each table as a directory of Lance fragment files, so a
|
|
108
|
+
// single stat() on the db path itself would always read as 0.
|
|
109
|
+
|
|
110
|
+
function dirSizeBytes(dir) {
|
|
111
|
+
if (!fs.existsSync(dir)) return 0;
|
|
112
|
+
let bytes = 0;
|
|
113
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
114
|
+
const full = path.join(dir, entry.name);
|
|
115
|
+
bytes += entry.isDirectory() ? dirSizeBytes(full) : fs.statSync(full).size;
|
|
116
|
+
}
|
|
117
|
+
return bytes;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Evict expired/overflow rows from the machine-scoped observations_v1 table.
|
|
122
|
+
* A no-op when the vector index was never provisioned — nothing to evict,
|
|
123
|
+
* and provisioning one just to check would defeat the lazy-index contract.
|
|
124
|
+
* Returns { status: 'skipped', reason } in that case, or
|
|
125
|
+
* { status: 'ok', evictedCount, remainingCount, oldestRetainedAt, sizeBytes,
|
|
126
|
+
* maxAgeDays, maxRows } once a purge ran.
|
|
127
|
+
*/
|
|
128
|
+
export async function purgeExpiredData(rootDir, { env = process.env, project = 'construct', maxAgeDays, maxRows } = {}) {
|
|
129
|
+
const dbPath = env.CONSTRUCT_LANCEDB_PATH || resolveStateDir(rootDir, 'lancedb', { ensureDir: false });
|
|
130
|
+
if (!fs.existsSync(dbPath)) {
|
|
131
|
+
return { status: 'skipped', reason: 'no vector index provisioned yet' };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const { config } = loadProjectConfig(rootDir, env);
|
|
135
|
+
const resolvedMaxAgeDays = maxAgeDays ?? Number(resolveSetting({
|
|
136
|
+
config, env, jsonPath: 'resources.disk.observationsMaxDays',
|
|
137
|
+
envKey: 'CONSTRUCT_OBSERVATIONS_MAX_DAYS', defaultValue: OBSERVATIONS_MAX_DAYS_DEFAULT,
|
|
138
|
+
}).value);
|
|
139
|
+
const resolvedMaxRows = maxRows ?? Number(resolveSetting({
|
|
140
|
+
config, env, jsonPath: 'resources.disk.observationsMaxRows',
|
|
141
|
+
envKey: 'CONSTRUCT_OBSERVATIONS_MAX_ROWS', defaultValue: OBSERVATIONS_MAX_ROWS_DEFAULT,
|
|
142
|
+
}).value);
|
|
143
|
+
|
|
144
|
+
const vectorClient = new VectorClient({ env: { ...env, CONSTRUCT_LANCEDB_PATH: dbPath } });
|
|
145
|
+
const result = await vectorClient.pruneObservations({ maxAgeDays: resolvedMaxAgeDays, maxRows: resolvedMaxRows });
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
status: 'ok',
|
|
149
|
+
project,
|
|
150
|
+
...result,
|
|
151
|
+
sizeBytes: dirSizeBytes(dbPath),
|
|
152
|
+
maxAgeDays: resolvedMaxAgeDays,
|
|
153
|
+
maxRows: resolvedMaxRows,
|
|
154
|
+
};
|
|
78
155
|
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/storage/backend-registry.mjs — kind:'storage' provider resolution.
|
|
3
|
+
*
|
|
4
|
+
* Run-store selection uses the same extension-manifest substrate as queue
|
|
5
|
+
* selection: builtin backends are always available, while project/user storage
|
|
6
|
+
* manifests can name an implementation without central dispatch edits.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { loadManifestsFromDir, mergeManifests, resolveManifestDirs } from '../extensions/loader.mjs';
|
|
10
|
+
|
|
11
|
+
export const BUILTIN_STORAGE_BACKENDS = ['filesystem', 'sqlite', 'postgres'];
|
|
12
|
+
export const SUPPORTED_RUN_STORE_IMPLEMENTATIONS = ['filesystem', 'sqlite', 'postgres'];
|
|
13
|
+
|
|
14
|
+
export class UnregisteredStorageProviderError extends Error {
|
|
15
|
+
constructor(backend) {
|
|
16
|
+
super(
|
|
17
|
+
`Storage backend '${backend}' has no registered kind:'storage' provider. ` +
|
|
18
|
+
`Builtin providers: ${BUILTIN_STORAGE_BACKENDS.join(', ')}.`,
|
|
19
|
+
);
|
|
20
|
+
this.name = 'UnregisteredStorageProviderError';
|
|
21
|
+
this.backend = backend;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class UnsupportedStorageProviderError extends Error {
|
|
26
|
+
constructor(backend, implementation) {
|
|
27
|
+
super(
|
|
28
|
+
`Storage backend '${backend}' resolves to unsupported run-store implementation ` +
|
|
29
|
+
`'${implementation || 'unknown'}'. Supported implementations: ` +
|
|
30
|
+
`${SUPPORTED_RUN_STORE_IMPLEMENTATIONS.join(', ')}.`,
|
|
31
|
+
);
|
|
32
|
+
this.name = 'UnsupportedStorageProviderError';
|
|
33
|
+
this.backend = backend;
|
|
34
|
+
this.implementation = implementation || null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function listStorageProviders({ rootDir = process.cwd(), env = process.env } = {}) {
|
|
39
|
+
const homeDir = env?.HOME || env?.USERPROFILE || undefined;
|
|
40
|
+
const dirs = resolveManifestDirs({ rootDir, homeDir });
|
|
41
|
+
const builtin = loadManifestsFromDir(dirs.builtin).manifests;
|
|
42
|
+
const user = loadManifestsFromDir(dirs.user).manifests;
|
|
43
|
+
const project = loadManifestsFromDir(dirs.project).manifests;
|
|
44
|
+
return mergeManifests(builtin, user, project).filter((m) => m.kind === 'storage');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function findStorageProvider(backend, { rootDir = process.cwd(), env = process.env } = {}) {
|
|
48
|
+
if (!backend) return null;
|
|
49
|
+
return listStorageProviders({ rootDir, env }).find((m) => m.id === backend) || null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function runStoreImplementationFor(provider) {
|
|
53
|
+
const impl = provider?.operations?.runStore || provider?.runStore || provider?.implementation;
|
|
54
|
+
return typeof impl === 'string' && impl.trim() ? impl.trim().toLowerCase() : null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function resolveStorageBackend(backend, { rootDir = process.cwd(), env = process.env } = {}) {
|
|
58
|
+
const requested = String(backend || '').trim().toLowerCase();
|
|
59
|
+
if (!requested) return null;
|
|
60
|
+
if (BUILTIN_STORAGE_BACKENDS.includes(requested)) {
|
|
61
|
+
return { backend: requested, implementation: requested, provider: null };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const provider = findStorageProvider(requested, { rootDir, env });
|
|
65
|
+
if (!provider) throw new UnregisteredStorageProviderError(requested);
|
|
66
|
+
|
|
67
|
+
const implementation = runStoreImplementationFor(provider);
|
|
68
|
+
if (!SUPPORTED_RUN_STORE_IMPLEMENTATIONS.includes(implementation)) {
|
|
69
|
+
throw new UnsupportedStorageProviderError(requested, implementation);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return { backend: requested, implementation, provider };
|
|
73
|
+
}
|
package/lib/storage/backend.mjs
CHANGED
|
@@ -1,22 +1,76 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* lib/storage/backend.mjs — shared storage backend helpers.
|
|
3
3
|
*
|
|
4
|
-
* Construct uses embedded LanceDB and Git-backed state.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Construct uses embedded LanceDB and Git-backed state by default. When a
|
|
5
|
+
* Postgres URL is configured, createSqlClient returns the optional Postgres.js
|
|
6
|
+
* tagged-template client for shared run-store and migration paths.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// no effect here.
|
|
9
|
+
import { createRequire } from 'node:module';
|
|
10
|
+
import { resolveDatabaseUrl } from '../env-config.mjs';
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
const require = createRequire(import.meta.url);
|
|
13
|
+
|
|
14
|
+
function clean(value) {
|
|
15
|
+
return String(value ?? '').trim();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function positiveInt(value, fallback) {
|
|
19
|
+
const parsed = Number(value);
|
|
20
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function resolvePostgresUrl(env) {
|
|
24
|
+
return clean(env?.DATABASE_URL || env?.CONSTRUCT_DATABASE_URL || resolveDatabaseUrl(env));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function resolveSsl(value) {
|
|
28
|
+
const raw = clean(value).toLowerCase();
|
|
29
|
+
if (!raw || raw === 'false' || raw === '0' || raw === 'disable') return false;
|
|
30
|
+
if (raw === 'true' || raw === '1') return true;
|
|
31
|
+
if (['require', 'prefer', 'verify-full'].includes(raw)) return raw;
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function loadPostgresFactory(postgresFactory) {
|
|
36
|
+
if (postgresFactory) return postgresFactory;
|
|
37
|
+
try {
|
|
38
|
+
const mod = require('postgres');
|
|
39
|
+
return mod.default || mod;
|
|
40
|
+
} catch (err) {
|
|
41
|
+
if (err?.code === 'MODULE_NOT_FOUND' || err?.code === 'ERR_MODULE_NOT_FOUND') return null;
|
|
42
|
+
throw err;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function createSqlClient(env = process.env, { postgresFactory } = {}) {
|
|
47
|
+
const url = resolvePostgresUrl(env);
|
|
48
|
+
if (!url) return null;
|
|
49
|
+
|
|
50
|
+
const postgres = loadPostgresFactory(postgresFactory);
|
|
51
|
+
if (!postgres) return null;
|
|
52
|
+
|
|
53
|
+
return postgres(url, {
|
|
54
|
+
max: positiveInt(env?.CONSTRUCT_DB_MAX_CONNECTIONS, 5),
|
|
55
|
+
idle_timeout: positiveInt(env?.CONSTRUCT_DB_IDLE_TIMEOUT_SECONDS, 20),
|
|
56
|
+
connect_timeout: positiveInt(env?.CONSTRUCT_DB_CONNECT_TIMEOUT_SECONDS, 10),
|
|
57
|
+
ssl: resolveSsl(env?.CONSTRUCT_DB_SSL || env?.PGSSLMODE),
|
|
58
|
+
prepare: true,
|
|
59
|
+
onnotice: false,
|
|
60
|
+
connection: { application_name: clean(env?.CONSTRUCT_DB_APPLICATION_NAME) || 'construct' },
|
|
61
|
+
});
|
|
14
62
|
}
|
|
15
63
|
|
|
16
64
|
export async function probeSqlClient(client) {
|
|
17
|
-
return { status: 'unavailable', message: 'SQL
|
|
65
|
+
if (!client) return { status: 'unavailable', message: 'SQL client is not configured. Set DATABASE_URL or CONSTRUCT_DATABASE_URL.' };
|
|
66
|
+
try {
|
|
67
|
+
await client`SELECT 1 AS ok`;
|
|
68
|
+
return { status: 'available', message: 'Postgres connection succeeded' };
|
|
69
|
+
} catch (err) {
|
|
70
|
+
return { status: 'unavailable', message: err?.message || String(err) };
|
|
71
|
+
}
|
|
18
72
|
}
|
|
19
73
|
|
|
20
74
|
export async function closeSqlClient(client) {
|
|
21
|
-
|
|
75
|
+
if (client?.end) await client.end({ timeout: 5 });
|
|
22
76
|
}
|
|
@@ -5,10 +5,20 @@
|
|
|
5
5
|
* Supports native batching for up to 2048 inputs per request.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { resolveSecret } from '../providers/secret-resolver.mjs';
|
|
9
|
+
|
|
8
10
|
const MODEL_ID = 'text-embedding-3-small';
|
|
9
11
|
const DIMENSIONS = 1536;
|
|
10
12
|
const MAX_BATCH_SIZE = 2048;
|
|
11
13
|
|
|
14
|
+
function resolveOpenAiKey(env) {
|
|
15
|
+
try {
|
|
16
|
+
return resolveSecret('OPENAI_API_KEY', { env, allowAmbient: env === process.env });
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
12
22
|
async function openaiEmbed(key, input) {
|
|
13
23
|
const res = await fetch('https://api.openai.com/v1/embeddings', {
|
|
14
24
|
method: 'POST',
|
|
@@ -34,7 +44,7 @@ async function openaiEmbed(key, input) {
|
|
|
34
44
|
* @returns {Promise<{ embedding: Float32Array, model: string, dimensions: number }>}
|
|
35
45
|
*/
|
|
36
46
|
export async function embed(text, { env = process.env } = {}) {
|
|
37
|
-
const key = env
|
|
47
|
+
const key = resolveOpenAiKey(env);
|
|
38
48
|
if (!key) throw new Error('OPENAI_API_KEY required for OpenAI embeddings');
|
|
39
49
|
|
|
40
50
|
const data = await openaiEmbed(key, text);
|
|
@@ -52,7 +62,7 @@ export async function embed(text, { env = process.env } = {}) {
|
|
|
52
62
|
* @returns {Promise<{ embedding: Float32Array, model: string, dimensions: number }[]>}
|
|
53
63
|
*/
|
|
54
64
|
export async function embedBatch(texts, { env = process.env } = {}) {
|
|
55
|
-
const key = env
|
|
65
|
+
const key = resolveOpenAiKey(env);
|
|
56
66
|
if (!key) throw new Error('OPENAI_API_KEY required for OpenAI embeddings');
|
|
57
67
|
|
|
58
68
|
const results = [];
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* lib/storage/hybrid-query.mjs — unified search across knowledge and facts.
|
|
3
3
|
*
|
|
4
|
-
* Stub for the LanceDB-backed search.
|
|
4
|
+
* Stub for the LanceDB-backed search. Results pass through the N4
|
|
5
|
+
* retrieval-hardening pipeline (lib/storage/retrieval-hardening.mjs) before
|
|
6
|
+
* being returned, so vector-store poisoning defenses (trust-weighted
|
|
7
|
+
* ranking, per-source recall cap, similarity sanity threshold, duplicate
|
|
8
|
+
* collapse) apply to every hybrid-query caller uniformly.
|
|
5
9
|
*/
|
|
6
10
|
import { VectorClient } from './vector-client.mjs';
|
|
11
|
+
import { hardenRetrieval } from './retrieval-hardening.mjs';
|
|
7
12
|
|
|
8
13
|
export async function buildHybridSearchResultsAsync(rootDir, query, { limit = 10, env = process.env } = {}) {
|
|
9
14
|
// Embed the query
|
|
@@ -17,8 +22,11 @@ export async function buildHybridSearchResultsAsync(rootDir, query, { limit = 10
|
|
|
17
22
|
const docs = await client.searchDocuments({ project: 'construct', queryEmbedding: embedding, limit });
|
|
18
23
|
const obs = await client.searchObservations({ project: 'construct', queryEmbedding: embedding, limit });
|
|
19
24
|
|
|
20
|
-
// Merge both result sets
|
|
25
|
+
// Merge both result sets, then rank by similarity, provenance, and recall
|
|
26
|
+
// caps rather than similarity alone — an adversarial embedding tuned for
|
|
27
|
+
// top cosine similarity must not dominate assembled context.
|
|
21
28
|
|
|
22
29
|
const all = [...docs.map(d => ({ ...d, type: 'document' })), ...obs.map(o => ({ ...o, type: 'observation' }))];
|
|
23
|
-
|
|
30
|
+
const ranked = all.sort((a, b) => b.similarity - a.similarity);
|
|
31
|
+
return hardenRetrieval(ranked, { limit });
|
|
24
32
|
}
|