@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
|
@@ -8,7 +8,8 @@ import { readFileSync, readdirSync, existsSync } from 'node:fs';
|
|
|
8
8
|
import { loadRegistry } from '../../registry/loader.mjs';
|
|
9
9
|
import { join, resolve } from 'node:path';
|
|
10
10
|
import { homedir } from 'node:os';
|
|
11
|
-
import {
|
|
11
|
+
import { execFileSync } from 'node:child_process';
|
|
12
|
+
import { resolveWithinRoot } from '../../path-policy.mjs';
|
|
12
13
|
import { loadConstructEnv } from '../../env-config.mjs';
|
|
13
14
|
import { inspectContextState } from '../../context-state.mjs';
|
|
14
15
|
import { loadWorkflow, summarizeWorkflow, inspectWorkflowHealth } from '../../workflow-state.mjs';
|
|
@@ -16,8 +17,11 @@ import { resolveExecutionContractModelMetadata, selectModelTierForWorkCategory }
|
|
|
16
17
|
import { buildPublicHealthSurface } from '../../status.mjs';
|
|
17
18
|
import { doctorRoot } from '../../config/xdg.mjs';
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
// Model-controlled refs reach these git calls. Run git through argv with no shell so a
|
|
21
|
+
// base_ref like `$(...)` is handed to git as one literal argument, never evaluated.
|
|
22
|
+
|
|
23
|
+
function runGit(argv, cwd) {
|
|
24
|
+
return execFileSync('git', argv, { stdio: 'pipe', timeout: 10000, cwd }).toString().trim();
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
export function readJSON(filePath) {
|
|
@@ -140,10 +144,16 @@ export function summarizeDiff(args) {
|
|
|
140
144
|
const baseRef = args.base_ref ?? 'HEAD~1';
|
|
141
145
|
const cwd = args.cwd ? resolve(args.cwd) : process.cwd();
|
|
142
146
|
|
|
147
|
+
// A ref that starts with `-` would be read by git as an option, not a revision;
|
|
148
|
+
// control characters never belong in a ref. Reject both before argv handoff.
|
|
149
|
+
if (typeof baseRef !== 'string' || baseRef.startsWith('-') || /[\0\n\r]/.test(baseRef)) {
|
|
150
|
+
return { error: 'Invalid base_ref' };
|
|
151
|
+
}
|
|
152
|
+
|
|
143
153
|
let stat, nameStatus;
|
|
144
154
|
try {
|
|
145
|
-
stat =
|
|
146
|
-
nameStatus =
|
|
155
|
+
stat = runGit(['diff', '--stat', baseRef], cwd);
|
|
156
|
+
nameStatus = runGit(['diff', '--name-status', baseRef], cwd);
|
|
147
157
|
} catch {
|
|
148
158
|
return { error: 'Not a git repository or git not available' };
|
|
149
159
|
}
|
|
@@ -184,7 +194,14 @@ export function summarizeDiff(args) {
|
|
|
184
194
|
}
|
|
185
195
|
|
|
186
196
|
export function scanFile(args) {
|
|
187
|
-
const
|
|
197
|
+
const root = args.cwd ? resolve(args.cwd) : process.cwd();
|
|
198
|
+
|
|
199
|
+
let filePath;
|
|
200
|
+
try {
|
|
201
|
+
filePath = resolveWithinRoot(root, args.file_path);
|
|
202
|
+
} catch (err) {
|
|
203
|
+
return { error: err.message };
|
|
204
|
+
}
|
|
188
205
|
|
|
189
206
|
let rawBuffer;
|
|
190
207
|
try {
|
|
@@ -302,14 +319,14 @@ export function projectContext(args, { ROOT_DIR }) {
|
|
|
302
319
|
let changed_files = [];
|
|
303
320
|
|
|
304
321
|
try {
|
|
305
|
-
const log =
|
|
322
|
+
const log = runGit(['log', '--oneline', '-10'], cwd);
|
|
306
323
|
recent_commits = log.split('\n').filter(Boolean);
|
|
307
324
|
} catch {
|
|
308
325
|
// not a git repo or no commits
|
|
309
326
|
}
|
|
310
327
|
|
|
311
328
|
try {
|
|
312
|
-
const status =
|
|
329
|
+
const status = runGit(['status', '--short'], cwd);
|
|
313
330
|
const statusLines = status.split('\n').filter(Boolean);
|
|
314
331
|
changed_files = statusLines.map((l) => l.trim());
|
|
315
332
|
working_tree_status = statusLines.length > 0 ? 'dirty' : 'clean';
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/mcp/tools/provider-write.mjs — provider_write MCP tool (LMCP-I7).
|
|
3
|
+
*
|
|
4
|
+
* The only MCP-reachable path from a host agent (Claude Code, OpenCode) to an
|
|
5
|
+
* external write. Classified destructive in lib/mcp/tool-safety.mjs, so
|
|
6
|
+
* server.mjs's dispatch-time checkDestructiveGate() call already refuses the
|
|
7
|
+
* execute path without a valid out-of-band approval_token before this module
|
|
8
|
+
* ever runs — this file does not re-implement that check, it is downstream
|
|
9
|
+
* of it.
|
|
10
|
+
*
|
|
11
|
+
* Two modes, selected by `dry_run` (default true):
|
|
12
|
+
* - dry_run=true: resolves the governed-write adapter for `provider` and
|
|
13
|
+
* asks it to render the payload it would submit (adapter.renderDryRun),
|
|
14
|
+
* which runs field/shape validation only. Never calls
|
|
15
|
+
* lib/writes/envelope.mjs and never reaches adapter.write() — no network
|
|
16
|
+
* call, no side effect, regardless of token presence.
|
|
17
|
+
* - dry_run=false (execute): the destructive gate has already run in
|
|
18
|
+
* server.mjs by the time dispatchToolByName reaches this module, so
|
|
19
|
+
* arriving here at all means a token was consumed. Dispatches through
|
|
20
|
+
* writeWithEnvelope() (LMCP-J2) — idempotency key, sent-log dedup,
|
|
21
|
+
* policy/approval gate, retry, audit — which is the only caller of
|
|
22
|
+
* adapter.write(). This module never calls adapter.write() directly.
|
|
23
|
+
*
|
|
24
|
+
* E4 respect: when args.specialist_id is present (an embedded-specialist
|
|
25
|
+
* caller), the proposed provider+writeKind is checked against that
|
|
26
|
+
* specialist's embedBindings grant via AuthorityGuard before either mode
|
|
27
|
+
* proceeds. A specialist outside its grant is denied here, before the
|
|
28
|
+
* adapter is even resolved — independent of and in addition to the
|
|
29
|
+
* destructive-gate token check server.mjs already performed.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { writeWithEnvelope } from '../../writes/envelope.mjs';
|
|
33
|
+
import { WriteSentLog } from '../../writes/sent-log.mjs';
|
|
34
|
+
import { AuthorityGuard } from '../../embed/authority-guard.mjs';
|
|
35
|
+
import { mergedEmbedBindings } from '../../embed/capability-jobs.mjs';
|
|
36
|
+
import { createGovernedJiraProvider } from '../../providers/contract/adapters/jira/governed-write.mjs';
|
|
37
|
+
import { createJiraTransport } from '../../providers/contract/adapters/jira/transport.mjs';
|
|
38
|
+
import { createGovernedConfluenceProvider } from '../../providers/contract/adapters/confluence/governed-write.mjs';
|
|
39
|
+
import { createConfluenceTransport } from '../../providers/contract/adapters/confluence/transport.mjs';
|
|
40
|
+
import { createGovernedGithubProvider } from '../../providers/contract/adapters/github/governed-write.mjs';
|
|
41
|
+
import githubAdapter from '../../providers/contract/adapters/github/index.mjs';
|
|
42
|
+
|
|
43
|
+
// Real transports read credentials from process.env at construction time
|
|
44
|
+
// (JIRA_URL/JIRA_EMAIL/JIRA_TOKEN, CONFLUENCE_URL/CONFLUENCE_EMAIL/
|
|
45
|
+
// CONFLUENCE_TOKEN); github's transport is the gh CLI, already
|
|
46
|
+
// credential-free at construction. Building the transport lazily per call
|
|
47
|
+
// (rather than once at module load) keeps a missing-credential AuthError
|
|
48
|
+
// scoped to the one call that needed it.
|
|
49
|
+
|
|
50
|
+
const ADAPTER_FACTORIES = {
|
|
51
|
+
jira: () => createGovernedJiraProvider({ jiraTransport: createJiraTransport() }),
|
|
52
|
+
confluence: () => createGovernedConfluenceProvider({ confluenceTransport: createConfluenceTransport() }),
|
|
53
|
+
github: () => createGovernedGithubProvider({ ghAdapter: githubAdapter }),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Resolve the governed-write adapter for a provider name. Isolated as its
|
|
58
|
+
* own function so tests can override resolution via the `deps.resolveAdapter`
|
|
59
|
+
* injection point without touching this module's real-transport wiring.
|
|
60
|
+
*
|
|
61
|
+
* @param {string} provider
|
|
62
|
+
* @returns {{ meta: object, write: Function, search?: Function, renderDryRun?: Function }}
|
|
63
|
+
*/
|
|
64
|
+
function resolveAdapter(provider) {
|
|
65
|
+
const factory = ADAPTER_FACTORIES[provider];
|
|
66
|
+
if (!factory) {
|
|
67
|
+
const known = Object.keys(ADAPTER_FACTORIES).join(', ');
|
|
68
|
+
throw new Error(`provider_write: unknown provider "${provider}" (known: ${known})`);
|
|
69
|
+
}
|
|
70
|
+
return factory();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Check an embedded-specialist caller's proposal against its embedBindings
|
|
75
|
+
* grant. Returns null (no opinion) when args carries no specialist_id, so
|
|
76
|
+
* non-embed callers are unaffected — additive enforcement layered in front
|
|
77
|
+
* of the destructive gate, mirroring lib/embed/capability-jobs.mjs's
|
|
78
|
+
* checkProposalAuthority for the daemon path.
|
|
79
|
+
*
|
|
80
|
+
* @param {object} args
|
|
81
|
+
* @param {{ rootDir?: string, env?: object, embedBindings?: object }} opts
|
|
82
|
+
* @returns {Promise<{ allowed: boolean, reason?: string }|null>}
|
|
83
|
+
*/
|
|
84
|
+
async function checkE4Binding(args, { rootDir, env = process.env, embedBindings } = {}) {
|
|
85
|
+
if (!args.specialist_id) return null;
|
|
86
|
+
|
|
87
|
+
const bindings = embedBindings ?? mergedEmbedBindings({ rootDir, env });
|
|
88
|
+
const guard = new AuthorityGuard({ authority: {} }, null, bindings);
|
|
89
|
+
const result = await guard.check('externalPost', {
|
|
90
|
+
proposal: {
|
|
91
|
+
specialistId: args.specialist_id,
|
|
92
|
+
providerId: args.provider,
|
|
93
|
+
writeKind: args.item?.type,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Only a binding-scoped denial (mode: 'denied' with no queueId) short-circuits
|
|
98
|
+
// provider_write; a queued/autonomous authority-level outcome is not this
|
|
99
|
+
// tool's concern — the destructive gate + J2 envelope already own approval.
|
|
100
|
+
if (result.mode === 'denied' && !result.allowed) {
|
|
101
|
+
return { allowed: false, reason: result.reason };
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* provider_write tool implementation.
|
|
108
|
+
*
|
|
109
|
+
* @param {object} args
|
|
110
|
+
* @param {string} args.provider - 'jira' | 'confluence' | 'github'
|
|
111
|
+
* @param {object} args.item - write payload, shape depends on provider (see governed-write.mjs per adapter)
|
|
112
|
+
* @param {boolean} [args.dry_run=true] - render-only when true; never touches adapter.write()
|
|
113
|
+
* @param {string} [args.specialist_id] - embedded-specialist caller id (LMCP-E4 binding check)
|
|
114
|
+
* @param {string} [args.idempotency_key] - explicit idempotency key forwarded to the J2 envelope
|
|
115
|
+
* @param {object} [deps] - injection points for tests
|
|
116
|
+
* @param {Function} [deps.resolveAdapter] - override adapter resolution
|
|
117
|
+
* @param {WriteSentLog} [deps.sentLog] - override sent-log instance
|
|
118
|
+
* @param {object} [deps.embedBindings] - override merged embedBindings map
|
|
119
|
+
* @param {string} [deps.rootDir]
|
|
120
|
+
* @param {object} [deps.env]
|
|
121
|
+
* @returns {Promise<object>}
|
|
122
|
+
*/
|
|
123
|
+
export async function providerWrite(args = {}, deps = {}) {
|
|
124
|
+
const provider = args.provider;
|
|
125
|
+
const item = args.item;
|
|
126
|
+
const dryRun = args.dry_run !== false;
|
|
127
|
+
|
|
128
|
+
if (!provider) return { error: 'provider_write: args.provider is required' };
|
|
129
|
+
if (!item || typeof item !== 'object') return { error: 'provider_write: args.item is required' };
|
|
130
|
+
|
|
131
|
+
const bindingDenial = await checkE4Binding(args, {
|
|
132
|
+
rootDir: deps.rootDir,
|
|
133
|
+
env: deps.env,
|
|
134
|
+
embedBindings: deps.embedBindings,
|
|
135
|
+
});
|
|
136
|
+
if (bindingDenial) {
|
|
137
|
+
return { status: 'denied', provider, dryRun, reason: bindingDenial.reason };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const resolve = deps.resolveAdapter ?? resolveAdapter;
|
|
141
|
+
let adapter;
|
|
142
|
+
try {
|
|
143
|
+
adapter = resolve(provider);
|
|
144
|
+
} catch (err) {
|
|
145
|
+
return { error: err.message ?? String(err) };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (dryRun) {
|
|
149
|
+
if (typeof adapter.renderDryRun !== 'function') {
|
|
150
|
+
return {
|
|
151
|
+
status: 'dry-run',
|
|
152
|
+
provider,
|
|
153
|
+
dryRun: true,
|
|
154
|
+
diff: null,
|
|
155
|
+
note: `provider "${provider}" adapter has no renderDryRun; payload echoed verbatim, no validation performed.`,
|
|
156
|
+
payload: item,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const diff = adapter.renderDryRun(item);
|
|
161
|
+
return { status: 'dry-run', provider, dryRun: true, diff };
|
|
162
|
+
} catch (err) {
|
|
163
|
+
return { status: 'dry-run-invalid', provider, dryRun: true, error: err.message ?? String(err) };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const sentLog = deps.sentLog ?? new WriteSentLog({ persistPath: WriteSentLog.resolvePersistPath(deps.rootDir ?? process.cwd()) });
|
|
168
|
+
|
|
169
|
+
const envelopeResult = await writeWithEnvelope({
|
|
170
|
+
provider: adapter,
|
|
171
|
+
config: {},
|
|
172
|
+
payload: item,
|
|
173
|
+
dryRun: false,
|
|
174
|
+
sentLog,
|
|
175
|
+
idempotencyKey: args.idempotency_key,
|
|
176
|
+
requestedBy: args.specialist_id ? { role: `cx-${args.specialist_id}` } : {},
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
return {
|
|
180
|
+
status: envelopeResult.status,
|
|
181
|
+
provider,
|
|
182
|
+
dryRun: false,
|
|
183
|
+
envelope: envelopeResult.envelope,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export default providerWrite;
|
package/lib/mcp/tools/scope.mjs
CHANGED
|
@@ -201,9 +201,6 @@ export function scopeCreate(args = {}) {
|
|
|
201
201
|
// Mutating, gated, destructive: archive a curated scope.
|
|
202
202
|
|
|
203
203
|
export function scopeArchive(args = {}) {
|
|
204
|
-
if (args.confirm !== true) {
|
|
205
|
-
return { error: 'scope_archive requires confirm=true (destructive: moves files into archive/scopes/)' };
|
|
206
|
-
}
|
|
207
204
|
if (!args.id || !args.reason || String(args.reason).trim().length < 8) {
|
|
208
205
|
return { error: 'scope_archive requires id:string and reason:string (>=8 chars)' };
|
|
209
206
|
}
|
package/lib/mcp/tools/skills.mjs
CHANGED
|
@@ -253,7 +253,7 @@ export async function orchestrationPolicy(args) {
|
|
|
253
253
|
const { emitTraceEvent, newTraceId } = await import('../../worker/trace.mjs');
|
|
254
254
|
const cwd = process.cwd();
|
|
255
255
|
const queue = createIntakeQueue(cwd, process.env);
|
|
256
|
-
const intake = queue.read(intakeId);
|
|
256
|
+
const intake = await queue.read(intakeId);
|
|
257
257
|
if (!intake) {
|
|
258
258
|
intakeError = `intake packet not found: ${intakeId}`;
|
|
259
259
|
} else if (!intake.triage) {
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* lib/mcp/tools/storage.mjs — Storage MCP tools: status, sync, reset, and artifact deletion.
|
|
3
3
|
*
|
|
4
4
|
* All functions are async. Wraps lib/storage/admin.mjs and lib/storage/sync.mjs.
|
|
5
|
-
*
|
|
5
|
+
* Destructive operations (reset, delete) require confirm=true plus a one-time out-of-band
|
|
6
|
+
* approval token, since these tools are reachable only through the model's argument channel.
|
|
6
7
|
*/
|
|
7
8
|
import { resolve } from 'node:path';
|
|
8
9
|
import { deleteIngestedArtifacts, getStorageStatus, inferProjectName, purgeExpiredData, resetStorage } from '../../storage/admin.mjs';
|
|
9
10
|
import { syncFileStateToSql } from '../../storage/sync.mjs';
|
|
10
|
-
|
|
11
11
|
export async function storageStatus(args) {
|
|
12
12
|
const cwd = args.cwd ? resolve(String(args.cwd)) : process.cwd();
|
|
13
13
|
const project = args.project ? String(args.project) : inferProjectName(cwd);
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/mcp/tools/web-search-governance.mjs — the single F08 grader for web evidence.
|
|
3
|
+
*
|
|
4
|
+
* Every web result any specialist or tool ever sees passes through governWebResults here,
|
|
5
|
+
* so the F08 governance invariants (ADR-0017) are produced in exactly one place: a
|
|
6
|
+
* claim-relative class, an Admiralty grade defaulting to C3 with a derived confidence,
|
|
7
|
+
* a normalized date with a 12-month staleness flag, most-recent-first ordering, and the
|
|
8
|
+
* OWASP-LLM01 `trust: 'untrusted'` stamp on externally-sourced text. Results without a
|
|
9
|
+
* verifiable http(s) URL are dropped, never guessed. web-search.mjs (the governed
|
|
10
|
+
* provider tool), the orchestration worker's provider-native web path, and the remote
|
|
11
|
+
* orchestration ingress guard all re-use this grader so a citation can never reach a
|
|
12
|
+
* specialist ungoverned or mislabeled as trusted.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const COMMUNITY_HOSTS = ['reddit.com', 'stackoverflow.com', 'news.ycombinator.com', 'discord.com', 'github.com'];
|
|
16
|
+
const HIGH_CONFIDENCE_GRADES = new Set(['A1', 'A2', 'B1']);
|
|
17
|
+
const STALE_AFTER_DAYS = 365;
|
|
18
|
+
|
|
19
|
+
export function normalizeDate(it) {
|
|
20
|
+
const raw = it.date || it.publishedAt || it.published || it.published_at || it.datePublished || null;
|
|
21
|
+
if (!raw) return null;
|
|
22
|
+
const t = Date.parse(raw);
|
|
23
|
+
return Number.isNaN(t) ? null : new Date(t).toISOString().slice(0, 10);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Claim-relative class (ADR-0017): community content is admissible primary evidence for
|
|
27
|
+
// sentiment/demand claims under a checklist the tool cannot verify deterministically, so
|
|
28
|
+
// community hosts default to `tertiary` (conservative for factual claims) and everything
|
|
29
|
+
// else to `secondary`, leaving the researcher to promote a community source when the claim
|
|
30
|
+
// is about experience.
|
|
31
|
+
|
|
32
|
+
export function classifyResult(url) {
|
|
33
|
+
try {
|
|
34
|
+
const host = new URL(url).hostname.replace(/^www\./, '');
|
|
35
|
+
return COMMUNITY_HOSTS.some((h) => host === h || host.endsWith('.' + h)) ? 'tertiary' : 'secondary';
|
|
36
|
+
} catch {
|
|
37
|
+
return 'tertiary';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Confidence maps from the Admiralty grade; `high` is reserved for A1/A2/B1 (ADR-0017). A
|
|
42
|
+
// grade with reliability A/B or credibility 1/2 is `medium`; anything weaker is `low`.
|
|
43
|
+
|
|
44
|
+
export function confidenceFromGrade(grade) {
|
|
45
|
+
if (HIGH_CONFIDENCE_GRADES.has(grade)) return 'high';
|
|
46
|
+
const reliability = grade?.[0];
|
|
47
|
+
const credibility = grade?.[1];
|
|
48
|
+
if (reliability === 'A' || reliability === 'B' || credibility === '1' || credibility === '2') return 'medium';
|
|
49
|
+
return 'low';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Grade one raw item into a governed web result, or null when it carries no verifiable
|
|
53
|
+
// http(s) URL. A raw item may come from a governed provider (may carry its own admiralty)
|
|
54
|
+
// or a provider-native citation (never does — defaults to C3 + needsGrading).
|
|
55
|
+
|
|
56
|
+
export function governWebResult(it, { now = Date.now() } = {}) {
|
|
57
|
+
if (!it || typeof it.url !== 'string' || !/^https?:\/\//.test(it.url)) return null;
|
|
58
|
+
const graded = typeof it.admiralty === 'string' && /^[A-F][1-6]$/.test(it.admiralty);
|
|
59
|
+
const admiralty = graded ? it.admiralty : 'C3';
|
|
60
|
+
const date = normalizeDate(it);
|
|
61
|
+
const stale = date != null && (now - Date.parse(date)) > STALE_AFTER_DAYS * 86_400_000;
|
|
62
|
+
return {
|
|
63
|
+
source: 'web',
|
|
64
|
+
url: it.url,
|
|
65
|
+
title: typeof it.title === 'string' && it.title ? it.title : it.url,
|
|
66
|
+
snippet: typeof it.snippet === 'string' ? it.snippet : '',
|
|
67
|
+
class: classifyResult(it.url),
|
|
68
|
+
admiralty,
|
|
69
|
+
confidence: confidenceFromGrade(admiralty),
|
|
70
|
+
date,
|
|
71
|
+
stale,
|
|
72
|
+
needsGrading: !graded,
|
|
73
|
+
// OWASP LLM01: web snippets are externally-sourced data — must not be treated as instructions
|
|
74
|
+
trust: 'untrusted',
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Order most-recent-first: fresh dated results, then undated (input order kept by the
|
|
79
|
+
// stable sort), then stale ones; newest first within a tier.
|
|
80
|
+
|
|
81
|
+
function recencyTier(r) {
|
|
82
|
+
return r.date && !r.stale ? 0 : r.date ? 2 : 1;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function governWebResults(items, { now = Date.now() } = {}) {
|
|
86
|
+
const results = (Array.isArray(items) ? items : [])
|
|
87
|
+
.map((it) => governWebResult(it, { now }))
|
|
88
|
+
.filter(Boolean);
|
|
89
|
+
results.sort((a, b) => {
|
|
90
|
+
const t = recencyTier(a) - recencyTier(b);
|
|
91
|
+
if (t !== 0) return t;
|
|
92
|
+
if (a.date && b.date) return Date.parse(b.date) - Date.parse(a.date);
|
|
93
|
+
return 0;
|
|
94
|
+
});
|
|
95
|
+
return results;
|
|
96
|
+
}
|
|
@@ -8,29 +8,12 @@
|
|
|
8
8
|
* Admiralty grade with a derived confidence (ADR-0017) — results without a URL are dropped, not
|
|
9
9
|
* guessed; (2) every result is labeled `source: 'web'` and the tool never falls back to repo/source
|
|
10
10
|
* search; (3) when no governed provider is configured or the provider is unreachable, the tool
|
|
11
|
-
* returns a typed degradation and zero results rather than claiming it searched the web.
|
|
11
|
+
* returns a typed degradation and zero results rather than claiming it searched the web. The grading
|
|
12
|
+
* itself lives in web-search-governance.mjs, the single chokepoint shared with the orchestration
|
|
13
|
+
* worker's provider-native web path (ADR-0050).
|
|
12
14
|
*/
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
const HIGH_CONFIDENCE_GRADES = new Set(['A1', 'A2', 'B1']);
|
|
16
|
-
|
|
17
|
-
// Recency enforcement (rules/common/research.md §1, research-execution-policy
|
|
18
|
-
// recencyRule). The researcher is told to search most-recent-first and treat
|
|
19
|
-
// sources older than 12 months as stale, but the provider returns relevance- and
|
|
20
|
-
// authority-ranked results with the date dropped, so older established sources
|
|
21
|
-
// surface over newer ones. Normalize a date from whatever field the provider
|
|
22
|
-
// supplies, flag staleness against the 12-month window, and reorder
|
|
23
|
-
// most-recent-first. Admiralty-derived `confidence` is left intact (ADR-0017);
|
|
24
|
-
// recency rides alongside it as `date` + `stale` rather than folded into it.
|
|
25
|
-
|
|
26
|
-
const STALE_AFTER_DAYS = 365;
|
|
27
|
-
|
|
28
|
-
function normalizeDate(it) {
|
|
29
|
-
const raw = it.date || it.publishedAt || it.published || it.published_at || it.datePublished || null;
|
|
30
|
-
if (!raw) return null;
|
|
31
|
-
const t = Date.parse(raw);
|
|
32
|
-
return Number.isNaN(t) ? null : new Date(t).toISOString().slice(0, 10);
|
|
33
|
-
}
|
|
16
|
+
import { governWebResults } from './web-search-governance.mjs';
|
|
34
17
|
|
|
35
18
|
function providerConfig(env) {
|
|
36
19
|
const url = env.WEB_SEARCH_URL;
|
|
@@ -38,31 +21,6 @@ function providerConfig(env) {
|
|
|
38
21
|
return { url, key: env.WEB_SEARCH_KEY || null };
|
|
39
22
|
}
|
|
40
23
|
|
|
41
|
-
// Claim-relative class (ADR-0017): community content is admissible primary evidence for sentiment/
|
|
42
|
-
// demand claims under a checklist the tool cannot verify deterministically, so it defaults community
|
|
43
|
-
// hosts to `tertiary` (conservative for factual claims) and everything else to `secondary`, leaving
|
|
44
|
-
// the researcher to promote a community source to primary when the claim is about experience.
|
|
45
|
-
|
|
46
|
-
function classifyResult(url) {
|
|
47
|
-
try {
|
|
48
|
-
const host = new URL(url).hostname.replace(/^www\./, '');
|
|
49
|
-
return COMMUNITY_HOSTS.some((h) => host === h || host.endsWith('.' + h)) ? 'tertiary' : 'secondary';
|
|
50
|
-
} catch {
|
|
51
|
-
return 'tertiary';
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Confidence maps from the Admiralty grade; `high` is reserved for A1/A2/B1 (ADR-0017). A grade with
|
|
56
|
-
// reliability A/B or credibility 1/2 is `medium`; anything weaker is `low`.
|
|
57
|
-
|
|
58
|
-
function confidenceFromGrade(grade) {
|
|
59
|
-
if (HIGH_CONFIDENCE_GRADES.has(grade)) return 'high';
|
|
60
|
-
const reliability = grade?.[0];
|
|
61
|
-
const credibility = grade?.[1];
|
|
62
|
-
if (reliability === 'A' || reliability === 'B' || credibility === '1' || credibility === '2') return 'medium';
|
|
63
|
-
return 'low';
|
|
64
|
-
}
|
|
65
|
-
|
|
66
24
|
function degraded(reason, note) {
|
|
67
25
|
return { source: 'web', degraded: true, degradationReason: reason, results: [], note };
|
|
68
26
|
}
|
|
@@ -92,36 +50,7 @@ export async function webSearch(args = {}, { env = process.env, fetchImpl = glob
|
|
|
92
50
|
}
|
|
93
51
|
|
|
94
52
|
const items = Array.isArray(payload?.results) ? payload.results : [];
|
|
95
|
-
const results = items
|
|
96
|
-
.filter((it) => it && typeof it.url === 'string' && /^https?:\/\//.test(it.url))
|
|
97
|
-
.map((it) => {
|
|
98
|
-
const admiralty = typeof it.admiralty === 'string' && /^[A-F][1-6]$/.test(it.admiralty) ? it.admiralty : 'C3';
|
|
99
|
-
const date = normalizeDate(it);
|
|
100
|
-
const stale = date != null && (now - Date.parse(date)) > STALE_AFTER_DAYS * 86_400_000;
|
|
101
|
-
return {
|
|
102
|
-
source: 'web',
|
|
103
|
-
url: it.url,
|
|
104
|
-
title: typeof it.title === 'string' && it.title ? it.title : it.url,
|
|
105
|
-
snippet: typeof it.snippet === 'string' ? it.snippet : '',
|
|
106
|
-
class: classifyResult(it.url),
|
|
107
|
-
admiralty,
|
|
108
|
-
confidence: confidenceFromGrade(admiralty),
|
|
109
|
-
date,
|
|
110
|
-
stale,
|
|
111
|
-
needsGrading: !(typeof it.admiralty === 'string' && /^[A-F][1-6]$/.test(it.admiralty)),
|
|
112
|
-
};
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// Order most-recent-first: fresh dated results, then undated (provider order
|
|
116
|
-
// kept by the stable sort), then stale ones; newest first within a tier.
|
|
117
|
-
|
|
118
|
-
const tier = (r) => (r.date && !r.stale ? 0 : r.date ? 2 : 1);
|
|
119
|
-
results.sort((a, b) => {
|
|
120
|
-
const t = tier(a) - tier(b);
|
|
121
|
-
if (t !== 0) return t;
|
|
122
|
-
if (a.date && b.date) return Date.parse(b.date) - Date.parse(a.date);
|
|
123
|
-
return 0;
|
|
124
|
-
});
|
|
53
|
+
const results = governWebResults(items, { now });
|
|
125
54
|
|
|
126
55
|
return { source: 'web', degraded: false, query, claim, results, dropped: items.length - results.length };
|
|
127
56
|
}
|