@geraldmaron/construct 1.2.2 → 1.3.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/README.md +7 -10
- package/bin/construct +286 -220
- package/bin/construct-postinstall.mjs +0 -21
- package/commands/work/optimize-prompts.md +1 -1
- package/examples/distribution/sources/adr.md +2 -2
- package/examples/seed-observations/decisions.md +1 -1
- package/lib/artifact-loop-core.mjs +412 -0
- package/lib/artifact-manifest.mjs +6 -0
- package/lib/artifact-release-gate.mjs +115 -49
- package/lib/audit-rules.mjs +2 -4
- package/lib/audit-skills.mjs +32 -20
- package/lib/audit-specialists.mjs +44 -26
- package/lib/auto-docs.mjs +6 -5
- package/lib/brand-prose.mjs +3 -3
- package/lib/brand-tokens.mjs +2 -2
- package/lib/certification/artifact-fixtures.mjs +4 -1
- package/lib/certification/demo-parity.mjs +6 -32
- package/lib/certification/real-llm-scenarios.mjs +58 -13
- package/lib/certification/role-cards.mjs +7 -6
- package/lib/certification/role-overlays.mjs +4 -4
- package/lib/certification/runner.mjs +9 -2
- package/lib/certification/skill-inventory.mjs +34 -22
- package/lib/certification/skill-scenarios.mjs +21 -8
- package/lib/certification/specialist-contracts.mjs +4 -3
- package/lib/certification/specialist-scenarios.mjs +7 -6
- package/lib/certification/status.mjs +5 -4
- package/lib/cli-commands.mjs +56 -57
- package/lib/comment-lint.mjs +1 -5
- package/lib/completions.mjs +20 -2
- package/lib/config/legacy-config-migration.mjs +125 -0
- package/lib/config/schema.mjs +5 -5
- package/lib/config/source-targets.mjs +80 -0
- package/lib/contracts/validate.mjs +119 -51
- package/lib/decisions/golden.mjs +3 -2
- package/lib/decisions/registry.mjs +11 -6
- package/lib/demo-project.mjs +188 -0
- package/lib/demo-recording.mjs +9 -34
- package/lib/demo-script.mjs +2 -2
- package/lib/demo-surface.mjs +13 -131
- package/lib/demo-tour-renderer.mjs +92 -0
- package/lib/demo.mjs +69 -54
- package/lib/diagram-export.mjs +63 -14
- package/lib/doctor/source-checkout.mjs +3 -4
- package/lib/doctor/watchers/consistency.mjs +90 -22
- package/lib/doctor/watchers/credential-parity.mjs +97 -0
- package/lib/doctor/watchers/mcp-protocol.mjs +1 -1
- package/lib/doctor/watchers/service-health.mjs +4 -32
- package/lib/document-export.mjs +73 -9
- package/lib/document-extract.mjs +10 -198
- package/lib/embed/artifact.mjs +2 -3
- package/lib/embed/cli.mjs +1 -1
- package/lib/embed/config.mjs +1 -2
- package/lib/embed/customer-profiles.mjs +1 -1
- package/lib/embed/daemon.mjs +5 -6
- package/lib/embed/demand-fetch.mjs +114 -2
- package/lib/embed/docs-lifecycle.mjs +9 -5
- package/lib/embed/intake-metrics.mjs +2 -2
- package/lib/embed/notifications.mjs +2 -3
- package/lib/embed/recommendation-store.mjs +25 -22
- package/lib/embed/role-framing.mjs +4 -9
- package/lib/embedded-contract/capability.mjs +4 -2
- package/lib/embedded-contract/contract-version.mjs +1 -1
- package/lib/env-config.mjs +2 -2
- package/lib/flavors/loader.mjs +21 -19
- package/lib/graph/build-from-registry.mjs +31 -7
- package/lib/graph/staleness.mjs +1 -1
- package/lib/headhunt.mjs +82 -35
- package/lib/hooks/agent-tracker.mjs +2 -2
- package/lib/hooks/config-protection.mjs +1 -1
- package/lib/hooks/registry-sync.mjs +3 -3
- package/lib/host-capabilities.mjs +5 -5
- package/lib/improvement/controller.mjs +2 -2
- package/lib/init-unified.mjs +19 -21
- package/lib/intake/classify.mjs +26 -0
- package/lib/intake/daemon.mjs +2 -3
- package/lib/intake/prepare.mjs +10 -3
- package/lib/intake/session-prelude.mjs +1 -1
- package/lib/intake/tables/creative.mjs +9 -9
- package/lib/intake/tables/operations.mjs +4 -4
- package/lib/intake/tables/research.mjs +2 -2
- package/lib/integrations/intake-integrations.mjs +9 -10
- package/lib/knowledge/research-store.mjs +2 -2
- package/lib/mcp/server.mjs +104 -61
- package/lib/mcp/tool-budget.mjs +1 -46
- package/lib/mcp/tool-recovery.mjs +44 -0
- package/lib/mcp/tools/artifact-author.mjs +36 -0
- package/lib/mcp/tools/find-tool.mjs +86 -0
- package/lib/mcp/tools/orchestration-run.mjs +107 -69
- package/lib/mcp/tools/project.mjs +4 -3
- package/lib/mcp/tools/{profile.mjs → scope.mjs} +54 -52
- package/lib/mcp/tools/skills.mjs +39 -22
- package/lib/mcp/tools/telemetry.mjs +2 -1
- package/lib/mcp/tools/workflow.mjs +1 -1
- package/lib/mcp-platform-config.mjs +7 -5
- package/lib/migrations/index.mjs +4 -2
- package/lib/migrations/v2-unified-registry.mjs +35 -0
- package/lib/model-router.mjs +203 -36
- package/lib/models/catalog.mjs +25 -9
- package/lib/models/execution-capability-profile.mjs +3 -3
- package/lib/models/execution-policy.mjs +7 -6
- package/lib/models/provider-poll.mjs +18 -4
- package/lib/opencode-config.mjs +56 -1
- package/lib/opencode-runtime-plugin.mjs +13 -10
- package/lib/oracle/artifact-gate.mjs +14 -4
- package/lib/oracle/cli.mjs +2 -0
- package/lib/oracle/dispatch.mjs +18 -1
- package/lib/oracle/execute.mjs +39 -7
- package/lib/oracle/index.mjs +1 -1
- package/lib/oracle/org-graph.mjs +10 -5
- package/lib/oracle/policy.mjs +6 -0
- package/lib/oracle/read-model.mjs +103 -6
- package/lib/oracle/reconcile.mjs +31 -4
- package/lib/oracle/remediation-dispatch.mjs +53 -0
- package/lib/oracle/routing.mjs +5 -0
- package/lib/oracle/synthesize.mjs +80 -3
- package/lib/orchestration/routing-tables.mjs +44 -10
- package/lib/orchestration/runtime.mjs +2 -0
- package/lib/orchestration/worker.mjs +1 -1
- package/lib/orchestration-policy.mjs +351 -62
- package/lib/overrides/resolver.mjs +1 -12
- package/lib/parity.mjs +37 -11
- package/lib/policy/engine.mjs +80 -15
- package/lib/prompt-composer.js +51 -15
- package/lib/prompt-metadata.mjs +3 -2
- package/lib/providers/connection-probe.mjs +58 -0
- package/lib/providers/copilot-auth.mjs +1 -1
- package/lib/providers/credential-bootstrap.mjs +1 -1
- package/lib/providers/op-run.mjs +3 -4
- package/lib/providers/secret-resolver.mjs +31 -0
- package/lib/publish-tooling.mjs +3 -11
- package/lib/publish.mjs +12 -29
- package/lib/reconcile/mcp-entry-reconcile.mjs +14 -9
- package/lib/reflect.mjs +2 -2
- package/lib/registry/agent-manifest.mjs +190 -0
- package/lib/registry/assemble.mjs +133 -0
- package/lib/registry/catalog.mjs +171 -0
- package/lib/registry/cli.mjs +590 -6
- package/lib/registry/consolidation.mjs +5 -4
- package/lib/registry/docs-sync.mjs +67 -0
- package/lib/registry/loader.mjs +147 -0
- package/lib/registry/org-io.mjs +76 -0
- package/lib/registry/retired-paths.mjs +71 -0
- package/lib/registry/surface-map.mjs +5 -7
- package/lib/registry/validator.mjs +438 -0
- package/lib/research-execution-policy.mjs +173 -0
- package/lib/roles/catalog.mjs +4 -9
- package/lib/roles/fence.mjs +107 -1
- package/lib/roles/flavor-bindings.mjs +68 -0
- package/lib/roles/gateway.mjs +140 -29
- package/lib/roles/manifest.mjs +22 -13
- package/lib/roles/router.mjs +1 -1
- package/lib/runtime-env.mjs +1 -1
- package/lib/scopes/enrich.mjs +67 -0
- package/lib/scopes/hooks.mjs +12 -0
- package/lib/{profiles → scopes}/lifecycle.mjs +70 -70
- package/lib/scopes/loader.mjs +104 -0
- package/lib/scopes/rebrand.mjs +32 -0
- package/lib/scopes/research-profile.mjs +16 -0
- package/lib/scopes/teams.mjs +98 -0
- package/lib/service-manager.mjs +1 -117
- package/lib/setup-prompts.mjs +1 -1
- package/lib/setup.mjs +17 -28
- package/lib/skills/composition-graph.mjs +98 -0
- package/lib/skills/router.mjs +80 -0
- package/lib/specialist-contracts.mjs +17 -18
- package/lib/specialists/postconditions.mjs +2 -2
- package/lib/specialists/prompt-schema.mjs +6 -5
- package/lib/specialists/roster.mjs +7 -12
- package/lib/specialists/schema.mjs +9 -6
- package/lib/status.mjs +25 -90
- package/lib/storage/file-lock.mjs +6 -3
- package/lib/telemetry/skill-calls.mjs +1 -1
- package/lib/templates/doc-presentation.mjs +63 -0
- package/lib/templates/visual-requirements.mjs +35 -2
- package/lib/term-format.mjs +107 -2
- package/lib/test-env-setup.mjs +21 -0
- package/lib/ui/components.mjs +42 -0
- package/lib/ui/glyphs.mjs +58 -0
- package/lib/ui/links.mjs +115 -0
- package/lib/ui/theme.mjs +108 -0
- package/lib/uninstall/uninstall.mjs +2 -1
- package/lib/validator.mjs +45 -8
- package/lib/validators/skill-effectiveness.mjs +174 -0
- package/lib/validators/skills.mjs +1 -1
- package/package.json +12 -7
- package/personas/construct.md +12 -3
- package/platforms/claude/CLAUDE.md +1 -1
- package/rules/common/beads-hygiene.md +52 -0
- package/rules/common/neurodivergent-output.md +4 -7
- package/rules/common/research.md +2 -0
- package/scripts/sync-specialists.mjs +260 -49
- package/skills/ai/prompt-optimizer.md +3 -3
- package/skills/brand/output-vibe.md +48 -0
- package/skills/docs/adr-workflow.md +3 -0
- package/skills/docs/backlog-proposal-workflow.md +3 -0
- package/skills/docs/codebase-research-workflow.md +5 -2
- package/skills/docs/customer-profile-workflow.md +3 -0
- package/skills/docs/document-ingest-workflow.md +3 -0
- package/skills/docs/evidence-ingest-workflow.md +4 -1
- package/skills/docs/init-project.md +1 -1
- package/skills/docs/prd-workflow.md +1 -1
- package/skills/docs/prfaq-workflow.md +3 -0
- package/skills/docs/product-intelligence-workflow.md +4 -1
- package/skills/docs/product-signal-workflow.md +3 -0
- package/skills/docs/research-workflow.md +13 -6
- package/skills/docs/runbook-workflow.md +3 -0
- package/skills/docs/strategy-workflow.md +3 -0
- package/skills/docs/user-research-workflow.md +6 -3
- package/skills/operating/orchestration-reference.md +1 -1
- package/skills/roles/{engineer.ai.md → ai-engineer.md} +2 -2
- package/skills/roles/architect.ai-systems.md +1 -1
- package/skills/roles/architect.data.md +1 -1
- package/skills/roles/architect.enterprise.md +1 -1
- package/skills/roles/architect.integration.md +1 -1
- package/skills/roles/architect.md +1 -1
- package/skills/roles/architect.platform.md +1 -1
- package/skills/roles/{product-manager.business-strategy.md → business-strategist.md} +3 -3
- package/skills/roles/data-analyst.experiment.md +1 -1
- package/skills/roles/data-analyst.md +1 -1
- package/skills/roles/data-analyst.product-intelligence.md +1 -1
- package/skills/roles/data-analyst.product.md +1 -1
- package/skills/roles/data-analyst.telemetry.md +1 -1
- package/skills/roles/{engineer.data.md → data-engineer.md} +2 -2
- package/skills/roles/data-engineer.pipeline.md +2 -2
- package/skills/roles/data-engineer.vector-retrieval.md +2 -2
- package/skills/roles/data-engineer.warehouse.md +2 -2
- package/skills/roles/debugger.md +1 -1
- package/skills/roles/designer.accessibility.md +1 -1
- package/skills/roles/designer.md +1 -1
- package/skills/roles/{reviewer.devil-advocate.md → devil-advocate.md} +2 -2
- package/skills/roles/{operator.docs.md → docs-keeper.md} +3 -3
- package/skills/roles/engineer.md +3 -7
- package/skills/roles/{reviewer.evaluator.md → evaluator.md} +2 -2
- package/skills/roles/{researcher.explorer.md → explorer.md} +2 -2
- package/skills/roles/{operator.md → operations.md} +2 -5
- package/skills/roles/orchestrator.md +1 -1
- package/skills/roles/{engineer.platform.md → platform-engineer.md} +2 -2
- package/skills/roles/product-manager.ai-product.md +1 -1
- package/skills/roles/product-manager.enterprise.md +1 -1
- package/skills/roles/product-manager.growth.md +1 -2
- package/skills/roles/product-manager.md +1 -2
- package/skills/roles/product-manager.platform.md +1 -1
- package/skills/roles/product-manager.product.md +1 -1
- package/skills/roles/qa.ai-eval.md +1 -1
- package/skills/roles/qa.api-contract.md +1 -1
- package/skills/roles/qa.data-pipeline.md +1 -1
- package/skills/roles/qa.md +1 -1
- package/skills/roles/qa.web-ui.md +1 -1
- package/skills/roles/{operator.release.md → release-manager.md} +3 -3
- package/skills/roles/researcher.md +1 -1
- package/skills/roles/reviewer.md +1 -1
- package/skills/roles/security.ai.md +1 -1
- package/skills/roles/security.appsec.md +1 -1
- package/skills/roles/security.cloud.md +1 -1
- package/skills/roles/security.legal-compliance.md +1 -1
- package/skills/roles/security.md +1 -1
- package/skills/roles/security.privacy.md +1 -1
- package/skills/roles/security.supply-chain.md +1 -1
- package/skills/roles/{operator.sre.md → sre.md} +3 -3
- package/skills/roles/{qa.test-automation.md → test-automation.md} +2 -2
- package/skills/roles/{reviewer.trace.md → trace-reviewer.md} +2 -2
- package/skills/roles/{researcher.ux.md → ux-researcher.md} +2 -2
- package/skills/routing.json +18 -0
- package/skills/routing.md +1 -1
- package/specialists/artifact-manifest.json +2 -1
- package/specialists/audit-enrichments.json +14 -14
- package/specialists/org/contracts/accessibility-to-qa.json +37 -0
- package/specialists/org/contracts/any-to-business-strategist.json +57 -0
- package/specialists/org/contracts/any-to-debugger.json +38 -0
- package/specialists/org/contracts/any-to-designer.json +33 -0
- package/specialists/org/contracts/any-to-docs-keeper.json +34 -0
- package/specialists/org/contracts/any-to-explorer.json +39 -0
- package/specialists/org/contracts/any-to-sre-incident.json +33 -0
- package/specialists/org/contracts/any-to-trace-reviewer.json +32 -0
- package/specialists/org/contracts/architect-to-ai-engineer.json +32 -0
- package/specialists/org/contracts/architect-to-data-engineer.json +52 -0
- package/specialists/org/contracts/architect-to-devil-advocate.json +38 -0
- package/specialists/org/contracts/architect-to-engineer.json +34 -0
- package/specialists/org/contracts/architect-to-evaluator.json +59 -0
- package/specialists/org/contracts/architect-to-legal-compliance.json +55 -0
- package/specialists/org/contracts/architect-to-operations.json +45 -0
- package/specialists/org/contracts/architect-to-platform-engineer.json +42 -0
- package/specialists/org/contracts/business-strategist-to-product-manager.json +39 -0
- package/specialists/org/contracts/construct-to-orchestrator.json +36 -0
- package/specialists/org/contracts/construct-to-rd-lead.json +53 -0
- package/specialists/org/contracts/data-analyst-to-product-manager.json +43 -0
- package/specialists/org/contracts/data-engineer-to-platform-engineer.json +36 -0
- package/specialists/org/contracts/designer-to-accessibility.json +36 -0
- package/specialists/org/contracts/engineer-to-qa.json +34 -0
- package/specialists/org/contracts/engineer-to-reviewer.json +52 -0
- package/specialists/org/contracts/explorer-to-engineer.json +38 -0
- package/specialists/org/contracts/legal-compliance-to-release-manager.json +43 -0
- package/specialists/org/contracts/platform-engineer-to-engineer.json +31 -0
- package/specialists/org/contracts/product-manager-to-architect.json +71 -0
- package/specialists/org/contracts/product-manager-to-data-analyst.json +49 -0
- package/specialists/org/contracts/product-manager-to-ux-researcher.json +51 -0
- package/specialists/org/contracts/qa-to-release-manager.json +42 -0
- package/specialists/org/contracts/qa-to-test-automation.json +42 -0
- package/specialists/org/contracts/rd-lead-to-architect.json +38 -0
- package/specialists/org/contracts/researcher-to-architect.json +40 -0
- package/specialists/org/contracts/researcher-to-product-manager.json +57 -0
- package/specialists/org/contracts/reviewer-to-security.json +41 -0
- package/specialists/org/contracts/sre-to-release-manager.json +36 -0
- package/specialists/org/contracts/test-automation-to-engineer.json +34 -0
- package/specialists/org/contracts/trace-reviewer-to-sre.json +41 -0
- package/specialists/org/contracts/user-to-construct.json +30 -0
- package/specialists/org/groups/engineering-group.json +43 -0
- package/specialists/org/groups/governance-group.json +38 -0
- package/specialists/org/groups/operations-group.json +41 -0
- package/specialists/org/groups/product-group.json +46 -0
- package/specialists/org/groups/quality-group.json +42 -0
- package/specialists/org/groups/strategy-group.json +41 -0
- package/specialists/org/policies/action-approval.json +13 -0
- package/specialists/org/policies/agents-routing.json +13 -0
- package/specialists/org/policies/architecture.json +20 -0
- package/specialists/org/policies/bash-safety.json +13 -0
- package/specialists/org/policies/beads-hygiene.json +13 -0
- package/specialists/org/policies/bootstrap-state.json +13 -0
- package/specialists/org/policies/code-review.json +13 -0
- package/specialists/org/policies/coding-style.json +13 -0
- package/specialists/org/policies/comments.json +13 -0
- package/specialists/org/policies/commit-approval.json +13 -0
- package/specialists/org/policies/contract-preconditions.json +13 -0
- package/specialists/org/policies/deployment.json +20 -0
- package/specialists/org/policies/description.json +14 -0
- package/specialists/org/policies/design-approval.json +19 -0
- package/specialists/org/policies/doc-ownership.json +13 -0
- package/specialists/org/policies/file-path-fence.json +13 -0
- package/specialists/org/policies/framing.json +13 -0
- package/specialists/org/policies/git-workflow.json +13 -0
- package/specialists/org/policies/incident-response.json +15 -0
- package/specialists/org/policies/intake-triage.json +15 -0
- package/specialists/org/policies/neurodivergent-output.json +13 -0
- package/specialists/org/policies/no-fabrication.json +13 -0
- package/specialists/org/policies/patterns.json +13 -0
- package/specialists/org/policies/quality-gate-approval.json +17 -0
- package/specialists/org/policies/release-gates.json +13 -0
- package/specialists/org/policies/research-evidence.json +13 -0
- package/specialists/org/policies/review-before-change.json +13 -0
- package/specialists/org/policies/rollback.json +15 -0
- package/specialists/org/policies/scope-change.json +20 -0
- package/specialists/org/policies/secret-scan.json +13 -0
- package/specialists/org/policies/security-approval.json +17 -0
- package/specialists/org/policies/security.json +13 -0
- package/specialists/org/policies/session-efficiency.json +13 -0
- package/specialists/org/policies/skill-routing.json +13 -0
- package/specialists/org/policies/strategic-prioritization.json +17 -0
- package/specialists/org/policies/testing.json +13 -0
- package/specialists/org/policies/tool-invisibility.json +14 -0
- package/specialists/org/scopes/creative.json +54 -0
- package/specialists/org/scopes/operations.json +51 -0
- package/specialists/org/scopes/research.json +60 -0
- package/specialists/org/scopes/rnd.json +81 -0
- package/specialists/org/specialists/cx-accessibility.json +69 -0
- package/specialists/org/specialists/cx-ai-engineer.json +75 -0
- package/specialists/org/specialists/cx-architect.json +89 -0
- package/specialists/org/specialists/cx-business-strategist.json +72 -0
- package/specialists/org/specialists/cx-data-analyst.json +68 -0
- package/specialists/org/specialists/cx-data-engineer.json +71 -0
- package/specialists/org/specialists/cx-debugger.json +75 -0
- package/specialists/org/specialists/cx-designer.json +85 -0
- package/specialists/org/specialists/cx-devil-advocate.json +71 -0
- package/specialists/org/specialists/cx-docs-keeper.json +82 -0
- package/specialists/org/specialists/cx-engineer.json +106 -0
- package/specialists/org/specialists/cx-evaluator.json +69 -0
- package/specialists/org/specialists/cx-explorer.json +69 -0
- package/specialists/org/specialists/cx-legal-compliance.json +74 -0
- package/specialists/org/specialists/cx-operations.json +72 -0
- package/specialists/org/specialists/cx-oracle.json +46 -0
- package/specialists/org/specialists/cx-orchestrator.json +81 -0
- package/specialists/org/specialists/cx-platform-engineer.json +80 -0
- package/specialists/org/specialists/cx-product-manager.json +102 -0
- package/specialists/org/specialists/cx-qa.json +79 -0
- package/specialists/org/specialists/cx-rd-lead.json +73 -0
- package/specialists/org/specialists/cx-release-manager.json +77 -0
- package/specialists/org/specialists/cx-researcher.json +82 -0
- package/specialists/org/specialists/cx-reviewer.json +71 -0
- package/specialists/org/specialists/cx-security.json +91 -0
- package/specialists/org/specialists/cx-sre.json +94 -0
- package/specialists/org/specialists/cx-test-automation.json +69 -0
- package/specialists/org/specialists/cx-trace-reviewer.json +69 -0
- package/specialists/org/specialists/cx-ux-researcher.json +68 -0
- package/specialists/org/teams/accessibility-team.json +39 -0
- package/specialists/org/teams/design-team.json +40 -0
- package/specialists/org/teams/engineering-team.json +50 -0
- package/specialists/org/teams/governance-team.json +41 -0
- package/specialists/org/teams/operations-team.json +46 -0
- package/specialists/org/teams/product-management-team.json +45 -0
- package/specialists/org/teams/quality-team.json +49 -0
- package/specialists/org/teams/research-team.json +39 -0
- package/specialists/org/teams/strategy-team.json +48 -0
- package/specialists/org/teams/ux-research-team.json +39 -0
- package/specialists/prompts/_shared/validation-contract.md +1 -1
- package/specialists/prompts/_team-template.md +10 -0
- package/specialists/prompts/cx-accessibility.md +1 -0
- package/specialists/prompts/cx-ai-engineer.md +1 -1
- package/specialists/prompts/cx-business-strategist.md +1 -1
- package/specialists/prompts/cx-data-engineer.md +1 -1
- package/specialists/prompts/cx-designer.md +1 -0
- package/specialists/prompts/cx-devil-advocate.md +1 -1
- package/specialists/prompts/cx-docs-keeper.md +1 -1
- package/specialists/prompts/cx-evaluator.md +1 -1
- package/specialists/prompts/cx-explorer.md +1 -1
- package/specialists/prompts/cx-operations.md +1 -1
- package/specialists/prompts/cx-oracle.md +7 -3
- package/specialists/prompts/cx-orchestrator.md +17 -1
- package/specialists/prompts/cx-platform-engineer.md +1 -1
- package/specialists/prompts/cx-product-manager.md +2 -0
- package/specialists/prompts/cx-release-manager.md +1 -1
- package/specialists/prompts/cx-researcher.md +7 -4
- package/specialists/prompts/cx-sre.md +1 -1
- package/specialists/prompts/cx-test-automation.md +2 -2
- package/specialists/prompts/cx-trace-reviewer.md +3 -3
- package/specialists/prompts/cx-ux-researcher.md +2 -1
- package/templates/demos/scripts/architecture-review-adr.json +30 -0
- package/templates/demos/scripts/capability-contract.json +25 -0
- package/templates/demos/scripts/intake-triage.json +25 -0
- package/templates/demos/scripts/profile-doctor-health.json +25 -0
- package/templates/demos/tapes/agentic-platforms-prd.tape +2 -2
- package/templates/demos/tapes/architecture-review-adr.tape +44 -0
- package/templates/demos/tapes/capability-contract.tape +39 -0
- package/templates/demos/tapes/intake-triage.tape +39 -0
- package/templates/demos/tapes/profile-doctor-health.tape +39 -0
- package/templates/distribution/construct-brand.typ +23 -18
- package/templates/distribution/construct-decision.typ +1 -1
- package/templates/distribution/construct-pdf.typ +1 -1
- package/templates/distribution/construct-prd.typ +1 -1
- package/templates/distribution/construct-research.typ +1 -1
- package/templates/distribution/mermaid-puppeteer.json +8 -0
- package/templates/docs/persona-artifact.md +1 -1
- package/templates/docs/prd.md +6 -0
- package/lib/boundary.mjs +0 -127
- package/lib/certification/dashboard-api.mjs +0 -71
- package/lib/chat/cli.mjs +0 -333
- package/lib/chat/command-suggest.mjs +0 -161
- package/lib/chat/commands.mjs +0 -215
- package/lib/chat/config.mjs +0 -142
- package/lib/chat/context-compactor.mjs +0 -250
- package/lib/chat/context-continuation.mjs +0 -253
- package/lib/chat/continuation-source.mjs +0 -58
- package/lib/chat/demo-guide.mjs +0 -61
- package/lib/chat/design-tokens.mjs +0 -91
- package/lib/chat/desktop-binary.mjs +0 -81
- package/lib/chat/desktop-build.mjs +0 -130
- package/lib/chat/desktop-launcher.mjs +0 -133
- package/lib/chat/evidence.mjs +0 -145
- package/lib/chat/export.mjs +0 -74
- package/lib/chat/harness/driver.mjs +0 -91
- package/lib/chat/list-picker.mjs +0 -112
- package/lib/chat/model-picker.mjs +0 -356
- package/lib/chat/openrouter-fallback.mjs +0 -151
- package/lib/chat/permission-prompt.mjs +0 -33
- package/lib/chat/picker-catalog.mjs +0 -45
- package/lib/chat/policy-telemetry.mjs +0 -34
- package/lib/chat/present.mjs +0 -246
- package/lib/chat/session-context.mjs +0 -39
- package/lib/chat/session-persist.mjs +0 -73
- package/lib/chat/session-restore.mjs +0 -71
- package/lib/chat/session-settings.mjs +0 -53
- package/lib/chat/system-prompt.mjs +0 -52
- package/lib/chat/transparency.mjs +0 -93
- package/lib/chat/tui/color-scheme.mjs +0 -42
- package/lib/chat/tui/markdown.mjs +0 -123
- package/lib/chat/tui/presentation.mjs +0 -100
- package/lib/chat/tui/render.mjs +0 -500
- package/lib/chat/tui/turn-block.mjs +0 -284
- package/lib/chat/tui/turn-present.mjs +0 -18
- package/lib/chat/tui/turn-state.mjs +0 -88
- package/lib/chat/tui/usage.mjs +0 -122
- package/lib/chat/web-commands.mjs +0 -146
- package/lib/chat/web-launcher.mjs +0 -63
- package/lib/chat/web-picker-keys.mjs +0 -46
- package/lib/chat/web-session.mjs +0 -159
- package/lib/config/alias.mjs +0 -57
- package/lib/dashboard-demo.mjs +0 -71
- package/lib/dashboard-static.mjs +0 -175
- package/lib/install/desktop-binary-download.mjs +0 -88
- package/lib/profiles/loader.mjs +0 -123
- package/lib/profiles/rebrand.mjs +0 -46
- package/lib/server/auth.mjs +0 -169
- package/lib/server/chat-loop.mjs +0 -622
- package/lib/server/chat.mjs +0 -336
- package/lib/server/cors.mjs +0 -77
- package/lib/server/csrf.mjs +0 -103
- package/lib/server/demo-preview.mjs +0 -63
- package/lib/server/index.mjs +0 -2641
- package/lib/server/insights.mjs +0 -780
- package/lib/server/langfuse-login.mjs +0 -58
- package/lib/server/rate-limit.mjs +0 -93
- package/lib/server/telemetry-login.mjs +0 -100
- package/lib/server/webhook.mjs +0 -512
- package/specialists/contracts.json +0 -1032
- package/specialists/contracts.schema.json +0 -83
- package/specialists/policy-inventory.json +0 -188
- package/specialists/registry.json +0 -1412
- package/specialists/role-manifests.json +0 -217
- package/specialists/teams.json +0 -94
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/chat/desktop-launcher.mjs — start dashboard and open Construct chat in the native window.
|
|
3
|
-
*
|
|
4
|
-
* Launch order when the construct-chat binary is missing: build it from the Tauri
|
|
5
|
-
* source on disk (dev/branch path), else download the prebuilt release asset, else
|
|
6
|
-
* fail loudly with remediation. Chrome app-mode is never an implicit substitute —
|
|
7
|
-
* the native window is the contract, and `construct chat --web` is the explicit
|
|
8
|
-
* browser path.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { spawn } from 'node:child_process';
|
|
12
|
-
import os from 'node:os';
|
|
13
|
-
import { startDashboard, readDashboardState } from '../service-manager.mjs';
|
|
14
|
-
import { hasGuiDisplay, resolveDesktopBinary } from './desktop-binary.mjs';
|
|
15
|
-
import { buildDesktopBinary, hasDesktopSource } from './desktop-build.mjs';
|
|
16
|
-
|
|
17
|
-
async function ensureDashboard({ cwd, env, errorOutput }) {
|
|
18
|
-
let dash = readDashboardState();
|
|
19
|
-
if (dash?.port) return dash;
|
|
20
|
-
|
|
21
|
-
const result = await startDashboard({
|
|
22
|
-
rootDir: cwd,
|
|
23
|
-
preferredPort: parseInt(env.PORT || env.DASHBOARD_PORT || '4242', 10),
|
|
24
|
-
});
|
|
25
|
-
if (result.started || result.reused) {
|
|
26
|
-
return { port: result.port, url: result.url || `http://127.0.0.1:${result.port}` };
|
|
27
|
-
}
|
|
28
|
-
errorOutput.write(`Failed to start dashboard: ${result.reason || 'unknown error'}\n`);
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function waitForChild(child) {
|
|
33
|
-
return new Promise((resolve) => {
|
|
34
|
-
let settled = false;
|
|
35
|
-
const finish = (code) => {
|
|
36
|
-
if (settled) return;
|
|
37
|
-
settled = true;
|
|
38
|
-
resolve(code ?? 0);
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
if (child) {
|
|
42
|
-
child.on('exit', (code) => finish(code));
|
|
43
|
-
child.on('error', () => finish(1));
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const onSignal = () => {
|
|
47
|
-
try { child?.kill('SIGTERM'); } catch { /* already exited */ }
|
|
48
|
-
finish(0);
|
|
49
|
-
};
|
|
50
|
-
process.once('SIGINT', onSignal);
|
|
51
|
-
process.once('SIGTERM', onSignal);
|
|
52
|
-
|
|
53
|
-
if (!child) finish(0);
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function spawnDesktopBinary(bin, chatUrl, env) {
|
|
58
|
-
if (/\.(mjs|cjs|js)$/i.test(bin)) {
|
|
59
|
-
return spawn(process.execPath, [bin, '--url', chatUrl], {
|
|
60
|
-
env: { ...env, CONSTRUCT_CHAT_URL: chatUrl },
|
|
61
|
-
stdio: 'ignore',
|
|
62
|
-
detached: false,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
return spawn(bin, ['--url', chatUrl], {
|
|
66
|
-
env: { ...env, CONSTRUCT_CHAT_URL: chatUrl },
|
|
67
|
-
stdio: 'ignore',
|
|
68
|
-
detached: false,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async function tryDownloadBinary(env) {
|
|
73
|
-
try {
|
|
74
|
-
const { downloadDesktopBinary } = await import('../install/desktop-binary-download.mjs');
|
|
75
|
-
const result = await downloadDesktopBinary({ homeDir: os.homedir(), env });
|
|
76
|
-
if (result.status === 'downloaded') return resolveDesktopBinary();
|
|
77
|
-
} catch {
|
|
78
|
-
/* fall through to loud failure below */
|
|
79
|
-
}
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function resolveBinaryToLaunch({ cwd, env, output, errorOutput }) {
|
|
84
|
-
const existing = resolveDesktopBinary({ repoRoot: cwd, env });
|
|
85
|
-
if (existing) return existing;
|
|
86
|
-
|
|
87
|
-
if (hasDesktopSource(cwd)) {
|
|
88
|
-
const built = buildDesktopBinary({ repoRoot: cwd, env, output, errorOutput });
|
|
89
|
-
if (built.ok) return built.binaryPath;
|
|
90
|
-
errorOutput.write(`Could not build the Construct Chat window: ${built.reason}\n`);
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export async function runDesktopChat({
|
|
98
|
-
cwd = process.cwd(),
|
|
99
|
-
env = process.env,
|
|
100
|
-
output = process.stdout,
|
|
101
|
-
errorOutput = process.stderr,
|
|
102
|
-
binaryPath = null,
|
|
103
|
-
dashOverride = null,
|
|
104
|
-
} = {}) {
|
|
105
|
-
if (!hasGuiDisplay(env)) {
|
|
106
|
-
errorOutput.write('No graphical display available. Use `construct chat --plain` for terminal mode.\n');
|
|
107
|
-
return 1;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
let bin = binaryPath || resolveBinaryToLaunch({ cwd, env, output, errorOutput });
|
|
111
|
-
|
|
112
|
-
if (!bin && !hasDesktopSource(cwd)) {
|
|
113
|
-
bin = await tryDownloadBinary(env);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (!bin) {
|
|
117
|
-
errorOutput.write(
|
|
118
|
-
'The Construct Chat native window is unavailable.\n'
|
|
119
|
-
+ 'Build it with: npm run build:chat-desktop (requires the Rust toolchain from https://rustup.rs)\n'
|
|
120
|
-
+ 'Or open chat in a browser tab with: construct chat --web\n',
|
|
121
|
-
);
|
|
122
|
-
return 1;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const dash = dashOverride || await ensureDashboard({ cwd, env, errorOutput });
|
|
126
|
-
if (!dash) return 1;
|
|
127
|
-
|
|
128
|
-
const base = (dash.url || `http://127.0.0.1:${dash.port}`).replace(/\/$/, '');
|
|
129
|
-
const chatUrl = `${base}/chat/?surface=desktop`;
|
|
130
|
-
|
|
131
|
-
const child = spawnDesktopBinary(bin, chatUrl, env);
|
|
132
|
-
return waitForChild(child);
|
|
133
|
-
}
|
package/lib/chat/evidence.mjs
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/** Per-turn evidence provenance for chat surfaces. */
|
|
2
|
-
|
|
3
|
-
export const EVIDENCE_SCHEMA_VERSION = 1;
|
|
4
|
-
|
|
5
|
-
const REPO_EVIDENCE_TOOLS = new Set(['read', 'grep', 'glob']);
|
|
6
|
-
const GLOB_META_RE = /[*?\[\]{}]/;
|
|
7
|
-
|
|
8
|
-
function freeze(value) {
|
|
9
|
-
if (Array.isArray(value)) value.forEach(freeze);
|
|
10
|
-
else if (value && typeof value === 'object') Object.values(value).forEach(freeze);
|
|
11
|
-
return Object.freeze(value);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function concreteTarget(value) {
|
|
15
|
-
if (typeof value !== 'string' || !value.trim() || GLOB_META_RE.test(value)) return null;
|
|
16
|
-
return value;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function toolResult(tool = {}) {
|
|
20
|
-
const result = tool.content ?? tool.result;
|
|
21
|
-
return result && typeof result === 'object' ? result : null;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function concreteTargets(tool = {}) {
|
|
25
|
-
const result = toolResult(tool);
|
|
26
|
-
const name = String(tool.title || tool.kind || '');
|
|
27
|
-
if (!result) return [];
|
|
28
|
-
if (name === 'read') return [concreteTarget(result.path || tool.input?.path)].filter(Boolean);
|
|
29
|
-
|
|
30
|
-
// grep/glob requests describe a search, not a source. Only the concrete files
|
|
31
|
-
// returned by a successful result become evidence records.
|
|
32
|
-
const matches = Array.isArray(result.matches) ? result.matches : [];
|
|
33
|
-
return [...new Set(matches.map((match) => concreteTarget(typeof match === 'string' ? match : match?.file || match?.path)).filter(Boolean))];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function evidenceTarget(tool = {}) {
|
|
37
|
-
return concreteTargets(tool)[0] || null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function isSuccessfulEvidenceTool(tool = {}) {
|
|
41
|
-
if (!REPO_EVIDENCE_TOOLS.has(String(tool.title || tool.kind || ''))) return false;
|
|
42
|
-
if (tool.status !== 'completed') return false;
|
|
43
|
-
const result = toolResult(tool);
|
|
44
|
-
return Boolean(result && result.ok !== false && result.denied !== true && !result.error && concreteTargets(tool).length);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function evidenceRecords(tools = [], { turnId = null } = {}) {
|
|
48
|
-
const records = [];
|
|
49
|
-
for (const tool of tools) {
|
|
50
|
-
if (!isSuccessfulEvidenceTool(tool)) continue;
|
|
51
|
-
for (const target of concreteTargets(tool)) {
|
|
52
|
-
records.push(freeze({
|
|
53
|
-
schemaVersion: EVIDENCE_SCHEMA_VERSION,
|
|
54
|
-
recordId: `${turnId || 'turn'}:${String(tool.id || '')}:${target}`,
|
|
55
|
-
turnId: turnId ? String(turnId) : null,
|
|
56
|
-
toolId: String(tool.id || ''),
|
|
57
|
-
tool: String(tool.title || tool.kind),
|
|
58
|
-
requestedTarget: String(tool.input?.path || tool.input?.glob || tool.input?.pattern || ''),
|
|
59
|
-
target,
|
|
60
|
-
sourceId: `repo:${target}`,
|
|
61
|
-
completion: 'completed',
|
|
62
|
-
result: 'success',
|
|
63
|
-
}));
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return freeze(records);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function escapeRegExp(value) {
|
|
70
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function citationMatches(text, record) {
|
|
74
|
-
const target = String(record?.target || '');
|
|
75
|
-
const sourceId = String(record?.sourceId || '');
|
|
76
|
-
if (!target) return false;
|
|
77
|
-
const escapedTarget = escapeRegExp(target);
|
|
78
|
-
const targetPattern = new RegExp(`(^|[^A-Za-z0-9_./-])${escapedTarget}(?=$|[^A-Za-z0-9_./-])`);
|
|
79
|
-
const sourcePattern = sourceId
|
|
80
|
-
? new RegExp(`\\[source:\\s*${escapeRegExp(sourceId)}\\s*\\]`, 'i')
|
|
81
|
-
: null;
|
|
82
|
-
return targetPattern.test(text) || Boolean(sourcePattern?.test(text));
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function verdict({ status, records = [], citations = [], reasonCodes = [] }) {
|
|
86
|
-
return freeze({
|
|
87
|
-
schemaVersion: EVIDENCE_SCHEMA_VERSION,
|
|
88
|
-
status,
|
|
89
|
-
records: [...records],
|
|
90
|
-
citations: [...new Set(citations)],
|
|
91
|
-
reasonCodes: [...reasonCodes],
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function deriveEvidenceVerdict({ id = null, overlay = null, tools = [], assistant = '', evidenceVisible = true, migration = false } = {}) {
|
|
96
|
-
const required = overlay?.assumptionsBlocked || overlay?.externalResearch?.required;
|
|
97
|
-
const migrationCode = migration ? ['legacy_snapshot_without_evidence'] : [];
|
|
98
|
-
if (!required) return verdict({ status: 'not_applicable', reasonCodes: ['evidence_not_required', ...migrationCode] });
|
|
99
|
-
if (!evidenceVisible) return verdict({ status: 'insufficient_evidence', reasonCodes: ['evidence_layer_hidden', ...migrationCode] });
|
|
100
|
-
|
|
101
|
-
const records = evidenceRecords(tools, { turnId: id });
|
|
102
|
-
if (!records.length) return verdict({ status: 'insufficient_evidence', records, reasonCodes: ['no_successful_concrete_evidence', ...migrationCode] });
|
|
103
|
-
const text = String(assistant || '');
|
|
104
|
-
const citations = records.filter((record) => citationMatches(text, record)).map((record) => record.target);
|
|
105
|
-
if (!citations.length) return verdict({ status: 'uncited_evidence', records, citations, reasonCodes: ['evidence_not_cited', ...migrationCode] });
|
|
106
|
-
return verdict({
|
|
107
|
-
status: citations.length === records.length ? 'verified' : 'partially_verified',
|
|
108
|
-
records,
|
|
109
|
-
citations,
|
|
110
|
-
reasonCodes: [citations.length === records.length ? 'all_recorded_evidence_cited' : 'some_recorded_evidence_uncited', ...migrationCode],
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export function migrateEvidenceVerdict(turn = {}) {
|
|
115
|
-
if (turn.evidence?.schemaVersion === EVIDENCE_SCHEMA_VERSION) return turn.evidence;
|
|
116
|
-
if (turn.evidence?.status) {
|
|
117
|
-
const records = (turn.evidence.records || []).map((record, index) => freeze({
|
|
118
|
-
schemaVersion: EVIDENCE_SCHEMA_VERSION,
|
|
119
|
-
recordId: record.recordId || `${turn.id || 'turn'}:${record.toolId || ''}:${record.target || index}`,
|
|
120
|
-
turnId: record.turnId || turn.id || null,
|
|
121
|
-
toolId: record.toolId || '',
|
|
122
|
-
tool: record.tool || 'unknown',
|
|
123
|
-
requestedTarget: record.requestedTarget || record.target || '',
|
|
124
|
-
target: record.target || '',
|
|
125
|
-
sourceId: record.sourceId || `repo:${record.target || ''}`,
|
|
126
|
-
completion: record.completion || 'completed',
|
|
127
|
-
result: record.result || 'success',
|
|
128
|
-
})).filter((record) => record.target);
|
|
129
|
-
return verdict({
|
|
130
|
-
status: turn.evidence.status,
|
|
131
|
-
records,
|
|
132
|
-
citations: turn.evidence.citations || [],
|
|
133
|
-
reasonCodes: [...(turn.evidence.reasonCodes || []), 'legacy_evidence_unversioned'],
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
return deriveEvidenceVerdict({ ...turn, migration: true });
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export function evidenceNotice(verdict) {
|
|
140
|
-
if (!verdict || verdict.status === 'not_applicable' || verdict.status === 'verified') return null;
|
|
141
|
-
if (verdict.reasonCodes?.includes('evidence_layer_hidden')) return 'Evidence tools were hidden for this turn, so no source was verified';
|
|
142
|
-
if (verdict.status === 'uncited_evidence') return 'Evidence was read but the answer does not cite its recorded paths — treat claims as unverified';
|
|
143
|
-
if (verdict.status === 'partially_verified') return 'Only some recorded evidence paths are cited — treat uncited claims as unverified';
|
|
144
|
-
return 'Answer produced without successful recorded repo evidence — treat as unverified';
|
|
145
|
-
}
|
package/lib/chat/export.mjs
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/chat/export.mjs — plain markdown export for construct chat turns.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import fs from 'node:fs';
|
|
6
|
-
import path from 'node:path';
|
|
7
|
-
import { resolveProjectScopedPath } from '../project-root.mjs';
|
|
8
|
-
import { summarizeSources } from './tui/turn-present.mjs';
|
|
9
|
-
import { rehydrateContinuation } from './context-continuation.mjs';
|
|
10
|
-
import { createContinuationResolver } from './continuation-source.mjs';
|
|
11
|
-
|
|
12
|
-
function exportDir({ cwd }) {
|
|
13
|
-
const base = resolveProjectScopedPath('chat-sessions', { cwd, ensureDir: true });
|
|
14
|
-
const dir = path.join(base, 'exports');
|
|
15
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
16
|
-
return dir;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Render a persisted continuation packet by rehydrating it through the one shared
|
|
20
|
-
// resolver (AC3): reconstructible layers re-derive via the same composer a live
|
|
21
|
-
// turn runs, elided layers report as summarized, and the budget accounting stays
|
|
22
|
-
// re-verifiable in the export.
|
|
23
|
-
|
|
24
|
-
function continuationToMarkdown(packet, { cwd }) {
|
|
25
|
-
if (!packet || typeof packet !== 'object') return '';
|
|
26
|
-
const resolver = createContinuationResolver({ cwd });
|
|
27
|
-
const layers = rehydrateContinuation(packet, { resolveSource: resolver.resolveSource });
|
|
28
|
-
const budget = packet.budget || {};
|
|
29
|
-
const lines = ['### context continuation', '',
|
|
30
|
-
`compacted to fit ~${budget.triggerTokens ?? 'n/a'} tokens — retained ${budget.retainedTokens ?? 0}, summarized ${budget.elidedTokens ?? 0}, referenced ${budget.referencedCount ?? 0}`];
|
|
31
|
-
if (packet.blocker) {
|
|
32
|
-
lines.push('', `blocker: ${packet.blocker.reason} (required ${packet.blocker.requiredTokens} > budget ${packet.blocker.budgetTokens})`);
|
|
33
|
-
}
|
|
34
|
-
const reconstructed = layers.filter((l) => l.sourceId || l.elided);
|
|
35
|
-
if (reconstructed.length) {
|
|
36
|
-
lines.push('', 'layers on rehydrate:');
|
|
37
|
-
for (const layer of reconstructed) {
|
|
38
|
-
if (layer.elided) lines.push(`- ${layer.kind}: summarized (elided)`);
|
|
39
|
-
else lines.push(`- ${layer.kind}: ${layer.resolved ? `re-derived from ${layer.sourceId}` : `unresolved (${layer.sourceId})`}`);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return lines.join('\n');
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function turnToMarkdown(turn, { cwd = process.cwd() } = {}) {
|
|
46
|
-
const lines = [`## you`, '', turn.userText || '', ''];
|
|
47
|
-
const evidence = turn.evidence || null;
|
|
48
|
-
if (evidence) lines.push(`evidence: ${evidence.status}${evidence.reasonCodes?.length ? ` (${evidence.reasonCodes.join(', ')})` : ''}`, '');
|
|
49
|
-
const src = summarizeSources(evidence?.records?.map((record) => ({ tool: record.tool, ref: record.target })) || turn.sources || []);
|
|
50
|
-
if (src.total) {
|
|
51
|
-
lines.push(`sources: ${src.refs.join(', ')}`, '');
|
|
52
|
-
}
|
|
53
|
-
lines.push('## construct', '', turn.assistant || '(no answer)', '');
|
|
54
|
-
if (turn.continuation) {
|
|
55
|
-
const cont = continuationToMarkdown(turn.continuation, { cwd });
|
|
56
|
-
if (cont) lines.push('', cont, '');
|
|
57
|
-
}
|
|
58
|
-
return lines.join('\n');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function exportTurns(turnBlocks, { scope = 'last', cwd = process.cwd() } = {}) {
|
|
62
|
-
const turns = turnBlocks.filter((item) => item.kind === 'turn').map((item) => item.block);
|
|
63
|
-
if (!turns.length) return { ok: false, error: 'no turns to export' };
|
|
64
|
-
|
|
65
|
-
let selected = turns;
|
|
66
|
-
if (scope === 'last') selected = [turns[turns.length - 1]];
|
|
67
|
-
else if (scope === 'turn' && turns.length) selected = [turns[turns.length - 1]];
|
|
68
|
-
|
|
69
|
-
const body = selected.map((turn) => turnToMarkdown(turn, { cwd })).join('\n---\n\n');
|
|
70
|
-
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
71
|
-
const file = path.join(exportDir({ cwd }), `${stamp}-${scope}-answer.md`);
|
|
72
|
-
fs.writeFileSync(file, `${body}\n`, 'utf8');
|
|
73
|
-
return { ok: true, path: file, count: selected.length };
|
|
74
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/chat/harness/driver.mjs — normalized harness driver contract for the
|
|
3
|
-
* construct terminal chat surface.
|
|
4
|
-
*
|
|
5
|
-
* A driver runs the agent loop and normalizes its streaming output into one event
|
|
6
|
-
* model, so the transparency engine and the TUI never depend on how the loop is
|
|
7
|
-
* produced. ADR-0041: Construct's owned loop (apps/chat/engine) implements this
|
|
8
|
-
* contract; the union stays the stable seam between the engine and the renderers.
|
|
9
|
-
* Every driver exposes the same shape:
|
|
10
|
-
* start() opens a session and returns { sessionId, capabilities }
|
|
11
|
-
* prompt(text, opts) async-iterable of normalized events for one turn; opts may
|
|
12
|
-
* carry { model, sandbox, permissionMode } when the host supports them
|
|
13
|
-
* cancel() aborts the active turn
|
|
14
|
-
* stop() tears down the host process / connection
|
|
15
|
-
* listModels() optional: returns [{ id, label, ... }] when the host can enumerate models
|
|
16
|
-
*
|
|
17
|
-
* Normalized event union consumed by the rest of the surface:
|
|
18
|
-
* { type: 'thinking', text, messageId } agent internal reasoning chunk
|
|
19
|
-
* { type: 'text', text, messageId } agent message chunk
|
|
20
|
-
* { type: 'plan', entries } planned path / task entries
|
|
21
|
-
* { type: 'tool_call', id, title, kind, status }
|
|
22
|
-
* { type: 'tool_update', id, status, content }
|
|
23
|
-
* { type: 'usage', tokens, cost, context, model }
|
|
24
|
-
* tokens: { input, output, cacheRead, cacheWrite, reasoning, total }
|
|
25
|
-
* cost: { amount, currency } context: { used, size }
|
|
26
|
-
* every field optional — adapters emit only what the host
|
|
27
|
-
* reports (no fabricated splits)
|
|
28
|
-
* { type: 'specialist', role, status, detail } construct orchestration overlay
|
|
29
|
-
* { type: 'permission', requestId, toolCall, options }
|
|
30
|
-
* { type: 'notice', level, code, message } surface-visible advisory (e.g. context-pressure)
|
|
31
|
-
* { type: 'context_continuation', packet, compacted } persisted continuation packet (construct-6zga.1.10)
|
|
32
|
-
* { type: 'error', message }
|
|
33
|
-
* { type: 'done', stopReason }
|
|
34
|
-
*
|
|
35
|
-
* Keeping this union stable is what lets ACP agents and per-host adapters be
|
|
36
|
-
* swapped without touching the transparency or rendering layers.
|
|
37
|
-
*/
|
|
38
|
-
|
|
39
|
-
export const EVENT_TYPES = Object.freeze({
|
|
40
|
-
THINKING: 'thinking',
|
|
41
|
-
TEXT: 'text',
|
|
42
|
-
PLAN: 'plan',
|
|
43
|
-
TOOL_CALL: 'tool_call',
|
|
44
|
-
TOOL_UPDATE: 'tool_update',
|
|
45
|
-
USAGE: 'usage',
|
|
46
|
-
SPECIALIST: 'specialist',
|
|
47
|
-
PERMISSION: 'permission',
|
|
48
|
-
NOTICE: 'notice',
|
|
49
|
-
CONTEXT_CONTINUATION: 'context_continuation',
|
|
50
|
-
ERROR: 'error',
|
|
51
|
-
DONE: 'done',
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// A single-producer/single-consumer queue that is also an async iterable. The
|
|
55
|
-
// line-router pushes normalized events as they arrive; the turn loop awaits them
|
|
56
|
-
// until the producer closes the queue on stop reason or error.
|
|
57
|
-
|
|
58
|
-
export class AsyncEventQueue {
|
|
59
|
-
constructor() {
|
|
60
|
-
this.buffer = [];
|
|
61
|
-
this.waiters = [];
|
|
62
|
-
this.closed = false;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
push(value) {
|
|
66
|
-
if (this.closed) return;
|
|
67
|
-
const waiter = this.waiters.shift();
|
|
68
|
-
if (waiter) waiter({ value, done: false });
|
|
69
|
-
else this.buffer.push(value);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
close() {
|
|
73
|
-
if (this.closed) return;
|
|
74
|
-
this.closed = true;
|
|
75
|
-
while (this.waiters.length) this.waiters.shift()({ value: undefined, done: true });
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
[Symbol.asyncIterator]() {
|
|
79
|
-
return {
|
|
80
|
-
next: () => {
|
|
81
|
-
if (this.buffer.length) return Promise.resolve({ value: this.buffer.shift(), done: false });
|
|
82
|
-
if (this.closed) return Promise.resolve({ value: undefined, done: true });
|
|
83
|
-
return new Promise((resolve) => this.waiters.push(resolve));
|
|
84
|
-
},
|
|
85
|
-
return: () => {
|
|
86
|
-
this.close();
|
|
87
|
-
return Promise.resolve({ value: undefined, done: true });
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
}
|
package/lib/chat/list-picker.mjs
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lib/chat/list-picker.mjs — searchable list picker for construct chat Ink.
|
|
3
|
-
*
|
|
4
|
-
* Pure state/helpers for arrow-key overlays: type-to-filter, windowed viewport,
|
|
5
|
-
* and selection index clamping for model, setting, and permission pickers.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export function filterPickerItems(items = [], query = '') {
|
|
9
|
-
const q = String(query || '').trim().toLowerCase();
|
|
10
|
-
if (!q) return items;
|
|
11
|
-
return items.filter((item) => {
|
|
12
|
-
const hay = [item.id, item.label, item.detail, item.tag]
|
|
13
|
-
.filter(Boolean)
|
|
14
|
-
.join(' ')
|
|
15
|
-
.toLowerCase();
|
|
16
|
-
return hay.includes(q);
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function pickerStartIndex(items, selectedId, idKey = 'id') {
|
|
21
|
-
if (!items?.length) return 0;
|
|
22
|
-
const idx = items.findIndex((item) => item[idKey] === selectedId);
|
|
23
|
-
if (idx >= 0 && !items[idx]?.disabled) return idx;
|
|
24
|
-
const firstEnabled = items.findIndex((item) => !item.disabled);
|
|
25
|
-
if (firstEnabled >= 0) return firstEnabled;
|
|
26
|
-
return idx >= 0 ? idx : 0;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function windowPickerItems(items, index, windowSize = 12) {
|
|
30
|
-
if (!items?.length) return { items: [], offset: 0 };
|
|
31
|
-
const size = Math.max(5, windowSize);
|
|
32
|
-
let start = Math.max(0, index - Math.floor(size / 2));
|
|
33
|
-
if (start + size > items.length) start = Math.max(0, items.length - size);
|
|
34
|
-
return { items: items.slice(start, start + size), offset: start };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function clampPickerIndex(state) {
|
|
38
|
-
const visible = filterPickerItems(state.items, state.query);
|
|
39
|
-
const max = Math.max(0, visible.length - 1);
|
|
40
|
-
return { ...state, index: Math.min(state.index, max) };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @param {{
|
|
45
|
-
* kind?: string,
|
|
46
|
-
* title?: string,
|
|
47
|
-
* items?: Array<Record<string, unknown>>,
|
|
48
|
-
* selectedId?: string | null,
|
|
49
|
-
* context?: string | null,
|
|
50
|
-
* query?: string,
|
|
51
|
-
* }} [opts]
|
|
52
|
-
*/
|
|
53
|
-
export function createListPickerState({
|
|
54
|
-
kind, title, items, selectedId = null, context = null, query = '',
|
|
55
|
-
} = {}) {
|
|
56
|
-
const visible = filterPickerItems(items, query);
|
|
57
|
-
return {
|
|
58
|
-
kind,
|
|
59
|
-
title,
|
|
60
|
-
items,
|
|
61
|
-
query,
|
|
62
|
-
index: pickerStartIndex(visible, selectedId),
|
|
63
|
-
context,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function getPickerVisibleItems(state) {
|
|
68
|
-
return filterPickerItems(state?.items || [], state?.query || '');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function getPickerSelectedItem(state) {
|
|
72
|
-
const visible = getPickerVisibleItems(state);
|
|
73
|
-
return visible[state?.index ?? 0] || null;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function movePickerIndex(state, delta) {
|
|
77
|
-
const visible = getPickerVisibleItems(state);
|
|
78
|
-
if (!visible.length) return state;
|
|
79
|
-
let idx = state.index ?? 0;
|
|
80
|
-
for (let step = 0; step < visible.length; step++) {
|
|
81
|
-
idx = Math.max(0, Math.min(visible.length - 1, idx + delta));
|
|
82
|
-
if (!visible[idx]?.disabled) return { ...state, index: idx };
|
|
83
|
-
if ((delta < 0 && idx === 0) || (delta > 0 && idx === visible.length - 1)) break;
|
|
84
|
-
}
|
|
85
|
-
return { ...state, index: idx };
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export function appendPickerQuery(state, char) {
|
|
89
|
-
if (!char) return state;
|
|
90
|
-
return clampPickerIndex({ ...state, query: `${state.query || ''}${char}`, index: 0 });
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function backspacePickerQuery(state) {
|
|
94
|
-
return clampPickerIndex({ ...state, query: (state.query || '').slice(0, -1), index: 0 });
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function reducePickerKey(state, { char, key } = {}) {
|
|
98
|
-
if (!state) return { state: null, action: 'none' };
|
|
99
|
-
if (key?.escape) return { state: null, action: 'cancel' };
|
|
100
|
-
if (key?.return) return { state, action: 'commit' };
|
|
101
|
-
if (key?.upArrow) return { state: movePickerIndex(state, -1), action: 'none' };
|
|
102
|
-
if (key?.downArrow) return { state: movePickerIndex(state, 1), action: 'none' };
|
|
103
|
-
if (key?.backspace || key?.delete) return { state: backspacePickerQuery(state), action: 'none' };
|
|
104
|
-
if (char && !key?.ctrl && !key?.meta) return { state: appendPickerQuery(state, char), action: 'none' };
|
|
105
|
-
return { state, action: 'none' };
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export function pickerViewport(state, windowSize = 14) {
|
|
109
|
-
const visible = getPickerVisibleItems(state);
|
|
110
|
-
const clamped = clampPickerIndex({ ...state, items: visible });
|
|
111
|
-
return windowPickerItems(visible, clamped.index, windowSize);
|
|
112
|
-
}
|