avorelo 0.3.8 → 0.4.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +16 -23
- package/README.md +62 -72
- package/bin/avorelo +9 -0
- package/package.json +147 -139
- package/scripts/README.md +40 -0
- package/scripts/avorelo-session-collision-guard.js +540 -0
- package/scripts/avorelo-workstream-preflight.js +918 -0
- package/scripts/cco-dashboard.js +346 -0
- package/scripts/cco-posttooluse.js +504 -0
- package/scripts/cco-pretooluse.js +381 -0
- package/scripts/cco-status.js +540 -0
- package/scripts/cco-stop.js +77 -0
- package/scripts/cco-userprompt-submit.js +83 -0
- package/scripts/lib/activation/account-state.js +37 -0
- package/scripts/lib/activation/activate-command.js +114 -0
- package/scripts/lib/activation/activation-runner.js +607 -0
- package/scripts/lib/activation/activation-self-healing.js +481 -0
- package/scripts/lib/activation/activation-state.js +96 -0
- package/scripts/lib/activation/activation-summary.js +241 -0
- package/scripts/lib/activation/adapters/claude-code.js +77 -0
- package/scripts/lib/activation/adapters/codex-cli.js +52 -0
- package/scripts/lib/activation/adapters/cursor.js +37 -0
- package/scripts/lib/activation/adapters/github-agent.js +39 -0
- package/scripts/lib/activation/adapters/terminal.js +42 -0
- package/scripts/lib/activation/adapters/vscode.js +39 -0
- package/scripts/lib/activation/adapters/windsurf.js +37 -0
- package/scripts/lib/activation/ai-surface-detector.js +151 -0
- package/scripts/lib/activation/connect-account.js +145 -0
- package/scripts/lib/activation/detect-environment.js +75 -0
- package/scripts/lib/activation/detect-hosts.js +62 -0
- package/scripts/lib/activation/format-activation-output.js +109 -0
- package/scripts/lib/activation/next-action.js +43 -0
- package/scripts/lib/activation/repair-engine.js +219 -0
- package/scripts/lib/activation/run-entry.js +346 -0
- package/scripts/lib/activation-distribution-readiness.js +507 -0
- package/scripts/lib/adapter-conformance.js +176 -0
- package/scripts/lib/adapter-readiness.js +428 -0
- package/scripts/lib/adapter-safety-boundaries.js +335 -0
- package/scripts/lib/adapter-technical-readiness-gate.js +205 -0
- package/scripts/lib/agent-access-governance.js +455 -0
- package/scripts/lib/agent-activation-readiness.js +878 -0
- package/scripts/lib/agent-enforcement.js +765 -0
- package/scripts/lib/agent-evolution-loop.js +479 -0
- package/scripts/lib/agent-policy-profile.js +210 -0
- package/scripts/lib/agent-security/action-evaluator.js +507 -0
- package/scripts/lib/agent-security/adapter-registry.js +98 -0
- package/scripts/lib/agent-security/auto-policy.js +139 -0
- package/scripts/lib/agent-security/bounded-scan.js +93 -0
- package/scripts/lib/agent-security/enforcement-adapter.js +174 -0
- package/scripts/lib/agent-security/enforcement-engine.js +1129 -0
- package/scripts/lib/agent-security/file-write-adapter.js +183 -0
- package/scripts/lib/agent-security/file-write-rules.js +178 -0
- package/scripts/lib/agent-security/index.js +3342 -0
- package/scripts/lib/agent-security/instruction-risk.js +181 -0
- package/scripts/lib/agent-security/mcp-action-adapter.js +185 -0
- package/scripts/lib/agent-security/mcp-action-rules.js +184 -0
- package/scripts/lib/agent-security/package-action-adapter.js +175 -0
- package/scripts/lib/agent-security/package-action-rules.js +233 -0
- package/scripts/lib/agent-security/performance.js +148 -0
- package/scripts/lib/agent-security/permission-minimizer.js +403 -0
- package/scripts/lib/agent-security/scan-cache.js +74 -0
- package/scripts/lib/agent-security/source-trust.js +146 -0
- package/scripts/lib/ai-efficiency-dogfood-pack.js +437 -0
- package/scripts/lib/ai-efficiency-eval.js +207 -0
- package/scripts/lib/ai-efficiency-guard-contract.js +209 -0
- package/scripts/lib/ai-efficiency-measured-value.js +106 -0
- package/scripts/lib/ai-install-prompt.js +293 -0
- package/scripts/lib/ai-task-inference.js +155 -0
- package/scripts/lib/ai-value-ledger.js +121 -0
- package/scripts/lib/ai-value-proof-table.js +151 -0
- package/scripts/lib/ai-work-efficiency-routing.js +623 -0
- package/scripts/lib/ai-workspace-hygiene.js +1499 -0
- package/scripts/lib/alpha-activation.js +520 -0
- package/scripts/lib/alpha-feedback.js +263 -0
- package/scripts/lib/alpha-readiness-gate.js +332 -0
- package/scripts/lib/anti-gaming.js +169 -0
- package/scripts/lib/artifact-health.js +431 -0
- package/scripts/lib/artifact-receipt-hygiene.js +619 -0
- package/scripts/lib/attribution.js +180 -0
- package/scripts/lib/audit.js +289 -0
- package/scripts/lib/avorelo-skill-registry.js +810 -0
- package/scripts/lib/batch-jobs.js +71 -0
- package/scripts/lib/brain-pack.js +578 -0
- package/scripts/lib/brand-boundary.js +424 -0
- package/scripts/lib/brand.js +74 -0
- package/scripts/lib/browser-capability.js +1048 -0
- package/scripts/lib/browser-proof-governed-workflow.js +1020 -0
- package/scripts/lib/browser-proof-preflight.js +321 -0
- package/scripts/lib/cache-readiness.js +296 -0
- package/scripts/lib/canonical-reentry.js +162 -0
- package/scripts/lib/capability-contract-validator.js +177 -0
- package/scripts/lib/capability-hygiene.js +504 -0
- package/scripts/lib/capability-intake-quarantine.js +789 -0
- package/scripts/lib/capability-kernel-registry.js +566 -0
- package/scripts/lib/capability-kernel.js +202 -0
- package/scripts/lib/capability-manifest.js +255 -0
- package/scripts/lib/capability-outcome-normalizer.js +104 -0
- package/scripts/lib/capability-packs.js +314 -0
- package/scripts/lib/capability-recommender.js +513 -0
- package/scripts/lib/capability-registry.js +1062 -0
- package/scripts/lib/carry-forward-surfacing.js +194 -0
- package/scripts/lib/ccusage-adapter.js +188 -0
- package/scripts/lib/claude-session-evidence/index.js +1027 -0
- package/scripts/lib/cli-output-sanitizer.js +118 -0
- package/scripts/lib/company-loop.js +1149 -0
- package/scripts/lib/config.js +641 -0
- package/scripts/lib/context-acquisition-plan.js +359 -0
- package/scripts/lib/context-authority-rules.js +138 -0
- package/scripts/lib/context-budget-guard.js +170 -0
- package/scripts/lib/context-budget-scanner.js +257 -0
- package/scripts/lib/context-budget.js +167 -0
- package/scripts/lib/context-claim-safety.js +116 -0
- package/scripts/lib/context-compiler.js +236 -0
- package/scripts/lib/context-optimizer.js +715 -0
- package/scripts/lib/context-packet.js +121 -0
- package/scripts/lib/context-receipt.js +57 -0
- package/scripts/lib/context-reduction-plan.js +179 -0
- package/scripts/lib/context-safety.js +88 -0
- package/scripts/lib/context-savings-engine.js +158 -0
- package/scripts/lib/context-source-registry.js +393 -0
- package/scripts/lib/context-task-profiles.js +147 -0
- package/scripts/lib/cost-abuse-guard.js +975 -0
- package/scripts/lib/cost-evidence.js +287 -0
- package/scripts/lib/cost-to-outcome-signals.js +639 -0
- package/scripts/lib/cross-host-install-plan.js +308 -0
- package/scripts/lib/cross-host-install-readiness.js +242 -0
- package/scripts/lib/cross-host-value-flow.js +268 -0
- package/scripts/lib/dashboard.js +1056 -0
- package/scripts/lib/data-permissions-guard.js +1187 -0
- package/scripts/lib/deployment-environment-guard.js +1236 -0
- package/scripts/lib/design-partner-feedback.js +346 -0
- package/scripts/lib/dogfood-evidence-freshness.js +567 -0
- package/scripts/lib/efficiency-receipt.js +354 -0
- package/scripts/lib/entitlements.js +100 -0
- package/scripts/lib/execution-packet.js +559 -0
- package/scripts/lib/execution-route-governor.js +179 -0
- package/scripts/lib/experimentation-events.js +547 -0
- package/scripts/lib/external-capability-compliance.js +107 -0
- package/scripts/lib/external-readiness/ai-visibility/ai-visibility-runner.js +322 -0
- package/scripts/lib/external-readiness/calibration/benchmark-site-catalog.js +121 -0
- package/scripts/lib/external-readiness/calibration/completion-gate.js +112 -0
- package/scripts/lib/external-readiness/calibration/real-site-benchmark-runner.js +284 -0
- package/scripts/lib/external-readiness/drift-detector.js +100 -0
- package/scripts/lib/external-readiness/endpoint-prober.js +332 -0
- package/scripts/lib/external-readiness/external-readiness-runner.js +112 -0
- package/scripts/lib/external-readiness/full-agent-readiness-scorer.js +220 -0
- package/scripts/lib/external-readiness/golden-path-runner.js +333 -0
- package/scripts/lib/external-readiness/inside-out-runner.js +118 -0
- package/scripts/lib/external-readiness/proof-receipt-writer.js +112 -0
- package/scripts/lib/external-readiness/safe-fix-executor.js +117 -0
- package/scripts/lib/external-readiness/skills/category-boundary-guard.js +30 -0
- package/scripts/lib/external-readiness/skills/pmm-positioning-guard.js +69 -0
- package/scripts/lib/external-readiness/skills/safe-fix-policy.js +35 -0
- package/scripts/lib/external-user-simulation.js +166 -0
- package/scripts/lib/failure-recovery-readiness.js +81 -0
- package/scripts/lib/failure-recovery.js +419 -0
- package/scripts/lib/feedback-intelligence.js +537 -0
- package/scripts/lib/feedback-signals.js +205 -0
- package/scripts/lib/file-integrity.js +68 -0
- package/scripts/lib/fsx.js +129 -0
- package/scripts/lib/full-readiness-gate.js +451 -0
- package/scripts/lib/governed-action-exposure-primitives.js +1514 -0
- package/scripts/lib/governed-exposure-planner.js +186 -0
- package/scripts/lib/governed-workspace-hygiene.js +946 -0
- package/scripts/lib/guard-suite-common.js +412 -0
- package/scripts/lib/guidance-builder.js +174 -0
- package/scripts/lib/hook-apply.js +1075 -0
- package/scripts/lib/hook-baseline.js +310 -0
- package/scripts/lib/hook-config-preview.js +275 -0
- package/scripts/lib/hook-contracts.js +290 -0
- package/scripts/lib/hook-safety-boundary-readiness.js +80 -0
- package/scripts/lib/host-capability-matrix.js +351 -0
- package/scripts/lib/host-support-context.js +254 -0
- package/scripts/lib/http-hook-action.js +538 -0
- package/scripts/lib/install-ai-readiness.js +84 -0
- package/scripts/lib/install-intake-risk.js +1051 -0
- package/scripts/lib/install-journey-intelligence.js +329 -0
- package/scripts/lib/intervention-guidance.js +57 -0
- package/scripts/lib/known-limitations.js +115 -0
- package/scripts/lib/l8-path-truth.js +146 -0
- package/scripts/lib/launch-hardening-gate.js +436 -0
- package/scripts/lib/launch-readiness.js +635 -0
- package/scripts/lib/learning-experimentation-foundation.js +1484 -0
- package/scripts/lib/learning-memory.js +686 -0
- package/scripts/lib/lifecycle-hooks.js +982 -0
- package/scripts/lib/local-package-smoke.js +436 -0
- package/scripts/lib/local-pricing.js +299 -0
- package/scripts/lib/mcp-enforcement.js +311 -0
- package/scripts/lib/mcp-least-privilege-policy.js +303 -0
- package/scripts/lib/mcp-tool-inventory.js +388 -0
- package/scripts/lib/mcp-tool-risk.js +0 -0
- package/scripts/lib/memory.js +335 -0
- package/scripts/lib/metrics.js +699 -0
- package/scripts/lib/micro-proof.js +133 -0
- package/scripts/lib/model-work-class-routing.js +79 -0
- package/scripts/lib/next-run-context.js +436 -0
- package/scripts/lib/next-run-continuity.js +1207 -0
- package/scripts/lib/observability-recovery-guard.js +1030 -0
- package/scripts/lib/operating-value.js +1662 -0
- package/scripts/lib/optimization-v3.js +122 -0
- package/scripts/lib/orchestration/adapters/_shared.js +49 -0
- package/scripts/lib/orchestration/adapters/aider.js +18 -0
- package/scripts/lib/orchestration/adapters/claude-code.js +35 -0
- package/scripts/lib/orchestration/adapters/codex.js +35 -0
- package/scripts/lib/orchestration/adapters/gemini-cli.js +18 -0
- package/scripts/lib/orchestration/adapters/git.js +25 -0
- package/scripts/lib/orchestration/adapters/index.js +31 -0
- package/scripts/lib/orchestration/adapters/lm-studio.js +18 -0
- package/scripts/lib/orchestration/adapters/ollama.js +18 -0
- package/scripts/lib/orchestration/adapters/opencode.js +18 -0
- package/scripts/lib/orchestration/adapters/openrouter.js +18 -0
- package/scripts/lib/orchestration/adapters/test-runner.js +25 -0
- package/scripts/lib/orchestration/cli.js +438 -0
- package/scripts/lib/orchestration/execution-manager.js +279 -0
- package/scripts/lib/orchestration/handoff.js +314 -0
- package/scripts/lib/orchestration/index.js +456 -0
- package/scripts/lib/orchestration/inventory.js +47 -0
- package/scripts/lib/orchestration/model-discovery.js +498 -0
- package/scripts/lib/orchestration/model-profiler.js +170 -0
- package/scripts/lib/orchestration/model-profiles.js +252 -0
- package/scripts/lib/orchestration/model-refresh-policy.js +72 -0
- package/scripts/lib/orchestration/proof-writer.js +349 -0
- package/scripts/lib/orchestration/provider-discovery/aider.js +49 -0
- package/scripts/lib/orchestration/provider-discovery/claude-code.js +56 -0
- package/scripts/lib/orchestration/provider-discovery/codex.js +49 -0
- package/scripts/lib/orchestration/provider-discovery/common.js +186 -0
- package/scripts/lib/orchestration/provider-discovery/gemini.js +106 -0
- package/scripts/lib/orchestration/provider-discovery/lm-studio.js +118 -0
- package/scripts/lib/orchestration/provider-discovery/models-dev.js +12 -0
- package/scripts/lib/orchestration/provider-discovery/ollama.js +100 -0
- package/scripts/lib/orchestration/provider-discovery/opencode.js +47 -0
- package/scripts/lib/orchestration/provider-discovery/openrouter.js +44 -0
- package/scripts/lib/orchestration/risk-classifier.js +130 -0
- package/scripts/lib/orchestration/routing-policy.js +486 -0
- package/scripts/lib/orchestration/settings.js +95 -0
- package/scripts/lib/orchestration/state.js +165 -0
- package/scripts/lib/orchestration/verification-manager.js +138 -0
- package/scripts/lib/outcome-evidence-stack.js +1083 -0
- package/scripts/lib/output-profiles.js +146 -0
- package/scripts/lib/package-content-audit.js +368 -0
- package/scripts/lib/package-runtime.js +278 -0
- package/scripts/lib/plan-surface.js +53 -0
- package/scripts/lib/plans.js +2327 -0
- package/scripts/lib/policy-provider.js +27 -0
- package/scripts/lib/prelaunch-activation-readiness.js +409 -0
- package/scripts/lib/prelaunch-evidence-store.js +816 -0
- package/scripts/lib/prelaunch-intelligence.js +869 -0
- package/scripts/lib/pricing-experiment.js +118 -0
- package/scripts/lib/pro-moment-events.js +77 -0
- package/scripts/lib/pro-moment-state.js +227 -0
- package/scripts/lib/pro-moments.js +1216 -0
- package/scripts/lib/product-home-receipt.js +1790 -0
- package/scripts/lib/product-learning-events.js +696 -0
- package/scripts/lib/production-confidence-control-tower.js +1209 -0
- package/scripts/lib/production-confidence.js +1858 -0
- package/scripts/lib/project-profile.js +555 -0
- package/scripts/lib/prompt-compiler-plan.js +94 -0
- package/scripts/lib/prompt-compiler.js +280 -0
- package/scripts/lib/prompt-lint.js +32 -0
- package/scripts/lib/prompt-suggestions.js +52 -0
- package/scripts/lib/proof-canonical.js +398 -0
- package/scripts/lib/proof-drilldown.js +383 -0
- package/scripts/lib/proof-e2e/promise-completion.js +141 -0
- package/scripts/lib/proof-e2e/promise-dashboard-claims.js +135 -0
- package/scripts/lib/proof-e2e/promise-local-proof.js +156 -0
- package/scripts/lib/proof-e2e/promise-provider-neutral.js +136 -0
- package/scripts/lib/proof-e2e/promise-registry.js +219 -0
- package/scripts/lib/proof-e2e/promise-security-trust.js +141 -0
- package/scripts/lib/proof-e2e/promise-skills-risk.js +163 -0
- package/scripts/lib/proof-e2e/promise-token-savings.js +112 -0
- package/scripts/lib/proof-e2e/promise-work-management.js +126 -0
- package/scripts/lib/proof-events.js +342 -0
- package/scripts/lib/proof-history.js +243 -0
- package/scripts/lib/proof-metrics.js +296 -0
- package/scripts/lib/proof-outcome-evidence.js +134 -0
- package/scripts/lib/proof-receipt.js +335 -0
- package/scripts/lib/proof-record.js +461 -0
- package/scripts/lib/proof-savings-report.js +1549 -0
- package/scripts/lib/public-activation-distribution-gate.js +266 -0
- package/scripts/lib/public-cli.js +5631 -0
- package/scripts/lib/public-distribution-truth.js +211 -0
- package/scripts/lib/public-distribution.js +73 -0
- package/scripts/lib/public-install-claim-checker.js +300 -0
- package/scripts/lib/publish-provenance-readiness.js +287 -0
- package/scripts/lib/readiness-delta.js +218 -0
- package/scripts/lib/readiness-evidence-closure.js +196 -0
- package/scripts/lib/reentry-memory-capture.js +241 -0
- package/scripts/lib/reentry-memory-retrieval.js +302 -0
- package/scripts/lib/reentry-memory-status.js +147 -0
- package/scripts/lib/reentry-memory-store.js +183 -0
- package/scripts/lib/reentry-state.js +66 -0
- package/scripts/lib/release-candidate-bundle.js +166 -0
- package/scripts/lib/remediation.js +81 -0
- package/scripts/lib/repo-map.js +391 -0
- package/scripts/lib/run-action-policy.js +104 -0
- package/scripts/lib/run-contract-receipt.js +48 -0
- package/scripts/lib/run-contract.js +288 -0
- package/scripts/lib/run-cost-to-verified-outcome.js +87 -0
- package/scripts/lib/run-improvements-lifecycle.js +330 -0
- package/scripts/lib/run-improvements.js +789 -0
- package/scripts/lib/run-proof-contract.js +116 -0
- package/scripts/lib/run-risk-classifier.js +131 -0
- package/scripts/lib/run-task-classifier.js +216 -0
- package/scripts/lib/runtime-decision-policy.js +387 -0
- package/scripts/lib/safe-path-engine.js +705 -0
- package/scripts/lib/safe-repair.js +877 -0
- package/scripts/lib/safe-run-controller.js +887 -0
- package/scripts/lib/scope-repair-before-approval.js +865 -0
- package/scripts/lib/score.js +262 -0
- package/scripts/lib/seamless-enforcement.js +329 -0
- package/scripts/lib/seamless-outcome.js +689 -0
- package/scripts/lib/seamless-reality-gate.js +5053 -0
- package/scripts/lib/security-confidence/activation-safety.js +78 -0
- package/scripts/lib/security-confidence/adapters/adapter-contract.js +125 -0
- package/scripts/lib/security-confidence/adapters/mock-claude-bughunter-adapter.js +36 -0
- package/scripts/lib/security-confidence/adapters/mock-decepticon-adapter.js +34 -0
- package/scripts/lib/security-confidence/adapters/mock-mcp-scan-adapter.js +35 -0
- package/scripts/lib/security-confidence/adapters/mock-snyk-agent-scan-adapter.js +35 -0
- package/scripts/lib/security-confidence/adapters/mock-tank-adapter.js +34 -0
- package/scripts/lib/security-confidence/adapters/reference-registry.js +63 -0
- package/scripts/lib/security-confidence/auth-rbac-plan.js +39 -0
- package/scripts/lib/security-confidence/component-inventory.js +151 -0
- package/scripts/lib/security-confidence/constants.js +191 -0
- package/scripts/lib/security-confidence/dependency-script-risk.js +95 -0
- package/scripts/lib/security-confidence/evidence-hygiene.js +127 -0
- package/scripts/lib/security-confidence/feature-impact-classifier.js +80 -0
- package/scripts/lib/security-confidence/file-utils.js +161 -0
- package/scripts/lib/security-confidence/finding-triage.js +90 -0
- package/scripts/lib/security-confidence/findings.js +115 -0
- package/scripts/lib/security-confidence/index.js +29 -0
- package/scripts/lib/security-confidence/permission-budget.js +93 -0
- package/scripts/lib/security-confidence/redaction.js +82 -0
- package/scripts/lib/security-confidence/redteam-fixtures.js +53 -0
- package/scripts/lib/security-confidence/reference-adoption.js +229 -0
- package/scripts/lib/security-confidence/reference-taxonomy.js +155 -0
- package/scripts/lib/security-confidence/report-quality.js +99 -0
- package/scripts/lib/security-confidence/report-writer.js +79 -0
- package/scripts/lib/security-confidence/risk-classifier.js +187 -0
- package/scripts/lib/security-confidence/runner.js +179 -0
- package/scripts/lib/security-confidence/schema.js +188 -0
- package/scripts/lib/security-confidence/secret-safety.js +74 -0
- package/scripts/lib/security-confidence/security-capability-router.js +98 -0
- package/scripts/lib/security-confidence/web-security-smoke-plan.js +46 -0
- package/scripts/lib/security-risk-classifier.js +511 -0
- package/scripts/lib/security-scan.js +396 -0
- package/scripts/lib/session-context-optimizer.js +1211 -0
- package/scripts/lib/session-timing.js +322 -0
- package/scripts/lib/skill-hygiene.js +805 -0
- package/scripts/lib/skill-packs.js +161 -0
- package/scripts/lib/skills-operating-layer-v1.js +1023 -0
- package/scripts/lib/skills-operating-layer.js +629 -0
- package/scripts/lib/smallest-safe-plan.js +214 -0
- package/scripts/lib/smart-routing-plan.js +115 -0
- package/scripts/lib/smart-work-routing.js +768 -0
- package/scripts/lib/source-catalog.js +1022 -0
- package/scripts/lib/status-value-summary.js +32 -0
- package/scripts/lib/supply-chain-dependency-guard.js +1333 -0
- package/scripts/lib/supply-chain-guard.js +219 -0
- package/scripts/lib/support-bundle.js +561 -0
- package/scripts/lib/support-redaction.js +66 -0
- package/scripts/lib/task-continuation.js +440 -0
- package/scripts/lib/test-helpers.js +15 -0
- package/scripts/lib/tier.js +38 -0
- package/scripts/lib/token-context-quality-gate.js +370 -0
- package/scripts/lib/token-cost-capture.js +187 -0
- package/scripts/lib/token-cost-evidence.js +862 -0
- package/scripts/lib/token-cost-intelligence.js +358 -0
- package/scripts/lib/token-efficiency-evidence.js +213 -0
- package/scripts/lib/token-efficiency-map.js +110 -0
- package/scripts/lib/token-evidence.js +703 -0
- package/scripts/lib/tokenish.js +17 -0
- package/scripts/lib/tool-output-sandbox.js +559 -0
- package/scripts/lib/trust-audit.js +136 -0
- package/scripts/lib/unified-events.js +396 -0
- package/scripts/lib/upgrade-interruption-recovery.js +407 -0
- package/scripts/lib/usage-ledger.js +201 -0
- package/scripts/lib/value-ledger.js +130 -0
- package/scripts/lib/value-proof-calibration.js +531 -0
- package/scripts/lib/visual-qa.js +231 -0
- package/scripts/lib/voice-alpha.js +29 -0
- package/scripts/lib/webhook-idempotency-guard.js +990 -0
- package/scripts/lib/work-aware-orchestration.js +976 -0
- package/scripts/lib/work-control-receipts.js +577 -0
- package/scripts/lib/work-ledger.js +1123 -0
- package/scripts/lib/work-panel-preview.js +352 -0
- package/scripts/lib/workflow-discipline.js +280 -0
- package/scripts/lib/workflow-intelligence-radar.js +804 -0
- package/scripts/lib/workflow-signals.js +419 -0
- package/scripts/lib/workspace-map.js +281 -0
- package/scripts/lib/workspace-registry.js +1367 -0
- package/scripts/lib/workspace-resolver.js +542 -0
- package/scripts/wuz-doctor.js +315 -0
- package/bin/avorelo.mjs +0 -7
- package/dist/avorelo.mjs +0 -24678
|
@@ -0,0 +1,789 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const crypto = require("crypto");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
|
|
7
|
+
const { ensureCcoDirs, nowIso, safeReadJson, safeWriteJson } = require("./fsx");
|
|
8
|
+
|
|
9
|
+
const CONTRACT = "avorelo.capabilityIntakeQuarantine.v1";
|
|
10
|
+
const REPORT_DIR_REL = ".claude/cco/security/capability-intake";
|
|
11
|
+
const LATEST_REPORT_REL = `${REPORT_DIR_REL}/latest-report.json`;
|
|
12
|
+
|
|
13
|
+
const SOURCE_REPORT_REL = ".claude/cco/skills/latest-report.json";
|
|
14
|
+
const BOUNDARY_REPORT_REL = ".claude/cco/security/governed-action-exposure/latest-report.json";
|
|
15
|
+
const AGENT_READINESS_REPORT_REL = ".claude/cco/orchestration/agent-readiness/latest-readiness.json";
|
|
16
|
+
const PRODUCT_HOME_REPORT_REL = ".claude/cco/orchestration/product-home/latest-receipt.json";
|
|
17
|
+
const RADAR_REPORT_REL = ".claude/cco/orchestration/workflow-radar/latest-report.json";
|
|
18
|
+
|
|
19
|
+
const VALID_TYPES = new Set(["skill", "mcp", "tool", "adapter", "prompt_pack", "unknown"]);
|
|
20
|
+
const VALID_PROVENANCE = new Set(["local", "repo", "package", "external_reference", "unknown"]);
|
|
21
|
+
const VALID_PERMISSIONS = new Set([
|
|
22
|
+
"read_only",
|
|
23
|
+
"writes_files",
|
|
24
|
+
"executes_commands",
|
|
25
|
+
"network_access",
|
|
26
|
+
"browser_access",
|
|
27
|
+
"secrets_or_env",
|
|
28
|
+
"credentials",
|
|
29
|
+
"package_install",
|
|
30
|
+
"production_or_deploy",
|
|
31
|
+
"unknown",
|
|
32
|
+
]);
|
|
33
|
+
const VALID_INSTRUCTION_RISKS = new Set([
|
|
34
|
+
"safe_pointer",
|
|
35
|
+
"broad_agent_instruction",
|
|
36
|
+
"hidden_automation",
|
|
37
|
+
"prompt_injection_like",
|
|
38
|
+
"chain_of_thought_request",
|
|
39
|
+
"secret_exfiltration_risk",
|
|
40
|
+
"unsafe_external_action",
|
|
41
|
+
"unknown",
|
|
42
|
+
]);
|
|
43
|
+
const VALID_DECISIONS = new Set(["allow_local_reference", "allow_prepare_only", "quarantine", "manual_review", "block"]);
|
|
44
|
+
|
|
45
|
+
const SKIP_DIRS = new Set([
|
|
46
|
+
".git",
|
|
47
|
+
".hg",
|
|
48
|
+
".svn",
|
|
49
|
+
"node_modules",
|
|
50
|
+
".next",
|
|
51
|
+
".turbo",
|
|
52
|
+
".cache",
|
|
53
|
+
"dist",
|
|
54
|
+
"build",
|
|
55
|
+
"coverage",
|
|
56
|
+
".claude",
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
const ADAPTER_CANDIDATES = new Set([
|
|
60
|
+
"AGENTS.md",
|
|
61
|
+
"CLAUDE.md",
|
|
62
|
+
"GEMINI.md",
|
|
63
|
+
".github/copilot-instructions.md",
|
|
64
|
+
".codex/config.toml",
|
|
65
|
+
".cursor/rules/wuz-project.mdc",
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
function unique(values) {
|
|
69
|
+
return [...new Set((values || []).filter(Boolean))];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function sha256(value) {
|
|
73
|
+
return crypto.createHash("sha256").update(String(value || "")).digest("hex");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function hashId(prefix, value) {
|
|
77
|
+
return `${prefix}-${sha256(value).slice(0, 12)}`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function compactText(value, maxChars = 220) {
|
|
81
|
+
const text = String(value || "").replace(/\s+/g, " ").trim();
|
|
82
|
+
if (!text) return null;
|
|
83
|
+
if (text.length <= maxChars) return text;
|
|
84
|
+
return `${text.slice(0, maxChars - 3).trimEnd()}...`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function sanitizeText(value, maxChars = 220) {
|
|
88
|
+
return compactText(
|
|
89
|
+
String(value || "")
|
|
90
|
+
.replace(/sk-[A-Za-z0-9_-]{16,}/g, "[redacted-openai-key]")
|
|
91
|
+
.replace(/gh[pousr]_[A-Za-z0-9]{12,}/g, "[redacted-github-token]")
|
|
92
|
+
.replace(/AKIA[0-9A-Z]{16}/g, "[redacted-aws-key]")
|
|
93
|
+
.replace(/(bearer\s+)[A-Za-z0-9._-]{8,}/ig, "$1[redacted]")
|
|
94
|
+
.replace(/((?:api[_ -]?key|token|password|secret|authorization)\s*[:=]\s*)([^\s'"]+)/ig, "$1[redacted]"),
|
|
95
|
+
maxChars
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function normalizePathValue(value) {
|
|
100
|
+
return String(value || "").replace(/\\/g, "/").replace(/^\.\/+/, "").trim();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function toRedactedRef(cwd, value) {
|
|
104
|
+
const raw = String(value || "").trim();
|
|
105
|
+
if (!raw) return null;
|
|
106
|
+
if (/^https?:\/\//i.test(raw)) {
|
|
107
|
+
try {
|
|
108
|
+
return new URL(raw).hostname.toLowerCase();
|
|
109
|
+
} catch {
|
|
110
|
+
return "[redacted-url]";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const absolute = path.isAbsolute(raw) ? raw : path.resolve(cwd, raw);
|
|
114
|
+
const relative = normalizePathValue(path.relative(cwd, absolute));
|
|
115
|
+
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) return null;
|
|
116
|
+
return relative;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function normalizeEnum(value, allowed, fallback) {
|
|
120
|
+
const normalized = String(value || "").trim().toLowerCase();
|
|
121
|
+
return allowed.has(normalized) ? normalized : fallback;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function safeReadText(absPath) {
|
|
125
|
+
try {
|
|
126
|
+
return fs.readFileSync(absPath, "utf8").replace(/^\uFEFF/, "");
|
|
127
|
+
} catch {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function safeReadJsonAbs(absPath) {
|
|
133
|
+
try {
|
|
134
|
+
return JSON.parse(fs.readFileSync(absPath, "utf8").replace(/^\uFEFF/, ""));
|
|
135
|
+
} catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function walkRepo(cwd, visitor, options = {}) {
|
|
141
|
+
const maxDepth = Number.isFinite(Number(options.maxDepth)) ? Number(options.maxDepth) : 7;
|
|
142
|
+
function visit(absPath, depth) {
|
|
143
|
+
if (depth > maxDepth) return;
|
|
144
|
+
let stat;
|
|
145
|
+
try {
|
|
146
|
+
stat = fs.statSync(absPath);
|
|
147
|
+
} catch {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (stat.isDirectory()) {
|
|
151
|
+
const base = path.basename(absPath);
|
|
152
|
+
if (SKIP_DIRS.has(base)) return;
|
|
153
|
+
let entries = [];
|
|
154
|
+
try {
|
|
155
|
+
entries = fs.readdirSync(absPath, { withFileTypes: true });
|
|
156
|
+
} catch {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
for (const entry of entries) {
|
|
160
|
+
visit(path.join(absPath, entry.name), depth + 1);
|
|
161
|
+
}
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const relPath = normalizePathValue(path.relative(cwd, absPath));
|
|
165
|
+
visitor(absPath, relPath);
|
|
166
|
+
}
|
|
167
|
+
visit(cwd, 0);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function buildSourceMetadataMap(cwd) {
|
|
171
|
+
const metadata = new Map();
|
|
172
|
+
walkRepo(cwd, (absPath, relPath) => {
|
|
173
|
+
if (!/\/SOURCE\.json$/i.test(`/${relPath}`)) return;
|
|
174
|
+
const payload = safeReadJsonAbs(absPath);
|
|
175
|
+
if (!payload) return;
|
|
176
|
+
metadata.set(path.posix.dirname(relPath), payload);
|
|
177
|
+
});
|
|
178
|
+
return metadata;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function hasFrontMatter(text) {
|
|
182
|
+
const value = String(text || "");
|
|
183
|
+
return /^---\s*\r?\n[\s\S]+?\r?\n---(?:\r?\n|$)/.test(value);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function hasExternalUrl(text) {
|
|
187
|
+
return /https?:\/\/(?!localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\]|::1)[^\s)'"]+/i.test(String(text || ""));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function detectCandidateType(relPath, manifest) {
|
|
191
|
+
const normalized = normalizePathValue(relPath);
|
|
192
|
+
if (manifest && manifest.type) {
|
|
193
|
+
return normalizeEnum(manifest.type, VALID_TYPES, "unknown");
|
|
194
|
+
}
|
|
195
|
+
if (normalized.endsWith("SKILL.md")) return "skill";
|
|
196
|
+
if (/\.capability\.json$/i.test(normalized)) return "unknown";
|
|
197
|
+
if (/(^|\/)(mcp|mcp-config|mcp-servers?)(\/|[-_.])/.test(normalized) || /(^|[-_.])mcp\.(json|ya?ml|md)$/i.test(normalized)) {
|
|
198
|
+
return "mcp";
|
|
199
|
+
}
|
|
200
|
+
if (/(^|\/)(prompt-packs?|prompts?)(\/|$)/i.test(normalized)) return "prompt_pack";
|
|
201
|
+
if (/(^|\/)(tools?|capabilities|fixtures\/capabilities|tests\/fixtures\/capabilities)(\/|$)/i.test(normalized)) return "tool";
|
|
202
|
+
return "unknown";
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function detectCandidateName(relPath, manifest, type) {
|
|
206
|
+
if (manifest && typeof manifest.name === "string" && manifest.name.trim()) {
|
|
207
|
+
return sanitizeText(manifest.name.trim(), 120);
|
|
208
|
+
}
|
|
209
|
+
const normalized = normalizePathValue(relPath);
|
|
210
|
+
if (type === "skill") {
|
|
211
|
+
const segments = normalized.split("/");
|
|
212
|
+
return sanitizeText(segments[segments.length - 2] || "skill", 120);
|
|
213
|
+
}
|
|
214
|
+
return sanitizeText(path.basename(normalized), 120);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function sourceMetadataForCandidate(metadataMap, relPath) {
|
|
218
|
+
const normalized = normalizePathValue(relPath);
|
|
219
|
+
const vendorMatch = normalized.match(/^(vendor\/skillpacks\/[^/]+)/);
|
|
220
|
+
if (vendorMatch) {
|
|
221
|
+
return metadataMap.get(vendorMatch[1]) || null;
|
|
222
|
+
}
|
|
223
|
+
const skillMatch = normalized.match(/^(skills\/[^/]+)/);
|
|
224
|
+
if (skillMatch) {
|
|
225
|
+
return metadataMap.get(skillMatch[1]) || null;
|
|
226
|
+
}
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function detectProvenance(relPath, manifest, sourceMetadata, text) {
|
|
231
|
+
if (manifest && manifest.provenance) {
|
|
232
|
+
return normalizeEnum(manifest.provenance, VALID_PROVENANCE, "unknown");
|
|
233
|
+
}
|
|
234
|
+
if (manifest && manifest.packageRef) return "package";
|
|
235
|
+
const normalized = normalizePathValue(relPath);
|
|
236
|
+
if (normalized.startsWith("skills/")) return "local";
|
|
237
|
+
if (normalized.startsWith("vendor/")) return "repo";
|
|
238
|
+
if (normalized.startsWith("prompts/") || normalized.startsWith("prompt-packs/")) return "local";
|
|
239
|
+
if (normalized.startsWith("mcp/") || normalized.startsWith("tools/") || normalized.startsWith("capabilities/")) return "repo";
|
|
240
|
+
if (normalized.startsWith("fixtures/capabilities/") || normalized.startsWith("tests/fixtures/capabilities/")) return "unknown";
|
|
241
|
+
if (sourceMetadata && sourceMetadata.packageName) return "package";
|
|
242
|
+
if (sourceMetadata && sourceMetadata.sourceUrl && !normalized.startsWith("vendor/")) return "external_reference";
|
|
243
|
+
if (hasExternalUrl(text)) return "external_reference";
|
|
244
|
+
return "unknown";
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function detectPermissions(text, manifest) {
|
|
248
|
+
const permissions = [];
|
|
249
|
+
const reasonCodes = [];
|
|
250
|
+
const value = String(text || "");
|
|
251
|
+
const manifestPermissions = Array.isArray(manifest?.permissions) ? manifest.permissions : [];
|
|
252
|
+
for (const entry of manifestPermissions) {
|
|
253
|
+
const normalized = normalizeEnum(entry, VALID_PERMISSIONS, null);
|
|
254
|
+
if (normalized) permissions.push(normalized);
|
|
255
|
+
}
|
|
256
|
+
const patterns = [
|
|
257
|
+
{ permission: "writes_files", pattern: /\b(write|writes|modify|modifies|edit|edits|create|creates|delete|deletes|patch|overwrite|rename|move)\b[^\n]{0,80}\b(file|files|config|configs|hook|hooks)\b/i, reasonCode: "write_permission_requested" },
|
|
258
|
+
{ permission: "executes_commands", pattern: /\b(command|commands|shell|terminal|powershell|bash|spawn|exec|git |npm run|node )/i, reasonCode: "command_execution_requested" },
|
|
259
|
+
{ permission: "network_access", pattern: /\b(fetch|http|https|api|curl|wget|invoke-webrequest|invoke-restmethod|network)\b/i, reasonCode: "network_access_requested" },
|
|
260
|
+
{ permission: "browser_access", pattern: /\b(browser|playwright|chrome|edge|devtools|open page|visit url)\b/i, reasonCode: "browser_access_requested" },
|
|
261
|
+
{ permission: "secrets_or_env", pattern: /\b(secret|secrets|token|tokens|api[_ -]?key|password|passwords|authorization|\.env|process\.env|env vars?)\b/i, reasonCode: "secrets_or_env_risk" },
|
|
262
|
+
{ permission: "credentials", pattern: /\b(credentials?|cookie|cookies|session|oauth|login|auth token)\b/i, reasonCode: "credential_risk" },
|
|
263
|
+
{ permission: "package_install", pattern: /\b(npm install|pnpm add|pnpm install|yarn add|pip install|brew install|apt-get install)\b/i, reasonCode: "package_install_requested" },
|
|
264
|
+
{ permission: "production_or_deploy", pattern: /\b(deploy|deployment|production|prod\b|publish|release|ship to prod|npm publish|gh release)\b/i, reasonCode: "production_or_deploy_risk" },
|
|
265
|
+
];
|
|
266
|
+
|
|
267
|
+
for (const rule of patterns) {
|
|
268
|
+
if (rule.pattern.test(value)) {
|
|
269
|
+
permissions.push(rule.permission);
|
|
270
|
+
reasonCodes.push(rule.reasonCode);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (permissions.length === 0) {
|
|
275
|
+
permissions.push("read_only");
|
|
276
|
+
reasonCodes.push("read_only_candidate");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return {
|
|
280
|
+
permissions: unique(permissions).map((permission) => normalizeEnum(permission, VALID_PERMISSIONS, "unknown")),
|
|
281
|
+
reasonCodes: unique(reasonCodes),
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function detectInstructionRisks(text, manifest) {
|
|
286
|
+
const risks = [];
|
|
287
|
+
const reasonCodes = [];
|
|
288
|
+
const value = String(text || "");
|
|
289
|
+
const manifestRisks = Array.isArray(manifest?.instructionRisks) ? manifest.instructionRisks : [];
|
|
290
|
+
for (const entry of manifestRisks) {
|
|
291
|
+
const normalized = normalizeEnum(entry, VALID_INSTRUCTION_RISKS, null);
|
|
292
|
+
if (normalized) risks.push(normalized);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const patterns = [
|
|
296
|
+
{ risk: "broad_agent_instruction", pattern: /\b(do anything|take over|full autonomy|entire repo|across the whole workspace|all files)\b/i, reasonCode: "broad_agent_instruction" },
|
|
297
|
+
{ risk: "hidden_automation", pattern: /\b(automatically|auto-run|autorun|without asking|silently|hidden background|background runtime)\b/i, reasonCode: "hidden_automation_risk" },
|
|
298
|
+
{ risk: "prompt_injection_like", pattern: /\b(ignore previous|ignore above|bypass policy|override policy|disable guard|skip verification|do not mention)\b/i, reasonCode: "prompt_injection_like_instruction" },
|
|
299
|
+
{ risk: "chain_of_thought_request", pattern: /\b(chain of thought|show your reasoning|reveal hidden reasoning|think step by step verbosely)\b/i, reasonCode: "chain_of_thought_request_detected" },
|
|
300
|
+
{ risk: "secret_exfiltration_risk", pattern: /\b(upload|print|send|exfiltrate|paste)\b[^\n]{0,120}\b(secret|token|credential|password|cookie|session|env)\b/i, reasonCode: "secret_exfiltration_risk" },
|
|
301
|
+
{ risk: "unsafe_external_action", pattern: /\b(download from|open external|visit external|deploy now|publish now|call external api|push directly to production)\b/i, reasonCode: "unsafe_external_action" },
|
|
302
|
+
];
|
|
303
|
+
|
|
304
|
+
for (const rule of patterns) {
|
|
305
|
+
if (rule.pattern.test(value)) {
|
|
306
|
+
risks.push(rule.risk);
|
|
307
|
+
reasonCodes.push(rule.reasonCode);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (risks.length === 0) {
|
|
312
|
+
risks.push("safe_pointer");
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
instructionRisks: unique(risks).map((risk) => normalizeEnum(risk, VALID_INSTRUCTION_RISKS, "unknown")),
|
|
317
|
+
reasonCodes: unique(reasonCodes),
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function inferSideEffectLevel(permissions) {
|
|
322
|
+
const set = new Set(permissions || []);
|
|
323
|
+
if (set.has("production_or_deploy")) return "network";
|
|
324
|
+
if (set.has("network_access") || set.has("browser_access")) return "network";
|
|
325
|
+
if (set.has("executes_commands")) return "execute";
|
|
326
|
+
if (set.has("writes_files") || set.has("package_install")) return "write";
|
|
327
|
+
if (set.has("read_only")) return "read";
|
|
328
|
+
return "unknown";
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function inferRiskTier(permissions, instructionRisks, provenance, missingManifest) {
|
|
332
|
+
const permissionSet = new Set(permissions || []);
|
|
333
|
+
const instructionSet = new Set(instructionRisks || []);
|
|
334
|
+
if (
|
|
335
|
+
permissionSet.has("secrets_or_env")
|
|
336
|
+
|| permissionSet.has("credentials")
|
|
337
|
+
|| permissionSet.has("production_or_deploy")
|
|
338
|
+
|| instructionSet.has("prompt_injection_like")
|
|
339
|
+
|| instructionSet.has("hidden_automation")
|
|
340
|
+
|| instructionSet.has("secret_exfiltration_risk")
|
|
341
|
+
|| instructionSet.has("unsafe_external_action")
|
|
342
|
+
) {
|
|
343
|
+
return "blocked";
|
|
344
|
+
}
|
|
345
|
+
if (
|
|
346
|
+
permissionSet.has("writes_files")
|
|
347
|
+
|| permissionSet.has("executes_commands")
|
|
348
|
+
|| permissionSet.has("network_access")
|
|
349
|
+
|| permissionSet.has("browser_access")
|
|
350
|
+
|| permissionSet.has("package_install")
|
|
351
|
+
|| instructionSet.has("chain_of_thought_request")
|
|
352
|
+
) {
|
|
353
|
+
return "high";
|
|
354
|
+
}
|
|
355
|
+
if (missingManifest || provenance === "external_reference" || provenance === "unknown") return "medium";
|
|
356
|
+
if (permissionSet.has("read_only") && instructionSet.has("safe_pointer")) return "low";
|
|
357
|
+
return "unknown";
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function classifyDecision(input) {
|
|
361
|
+
const permissionSet = new Set(input.permissions || []);
|
|
362
|
+
const instructionSet = new Set(input.instructionRisks || []);
|
|
363
|
+
const reasonCodes = ["candidate_detected"];
|
|
364
|
+
|
|
365
|
+
if (input.provenance === "local") reasonCodes.push("local_source_detected");
|
|
366
|
+
if (input.provenance === "repo") reasonCodes.push("repo_source_detected");
|
|
367
|
+
if (input.provenance === "external_reference") reasonCodes.push("external_reference_detected");
|
|
368
|
+
if (input.provenance === "unknown") reasonCodes.push("unknown_provenance");
|
|
369
|
+
if (input.missingManifest) reasonCodes.push("missing_manifest");
|
|
370
|
+
if (input.missingPermissions) reasonCodes.push("missing_permissions");
|
|
371
|
+
if (input.sideEffectUnknown) reasonCodes.push("side_effect_unknown");
|
|
372
|
+
|
|
373
|
+
if (
|
|
374
|
+
permissionSet.has("secrets_or_env")
|
|
375
|
+
|| permissionSet.has("credentials")
|
|
376
|
+
|| permissionSet.has("production_or_deploy")
|
|
377
|
+
|| instructionSet.has("prompt_injection_like")
|
|
378
|
+
|| instructionSet.has("hidden_automation")
|
|
379
|
+
|| instructionSet.has("secret_exfiltration_risk")
|
|
380
|
+
|| instructionSet.has("unsafe_external_action")
|
|
381
|
+
|| instructionSet.has("chain_of_thought_request")
|
|
382
|
+
) {
|
|
383
|
+
return {
|
|
384
|
+
state: "block",
|
|
385
|
+
reasonCodes: unique([...reasonCodes, "blocked_unsafe_capability"]),
|
|
386
|
+
safeNextAction: "Keep this capability blocked and review the unsafe instruction or secret-sensitive behavior before any use.",
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (
|
|
391
|
+
permissionSet.has("writes_files")
|
|
392
|
+
|| permissionSet.has("executes_commands")
|
|
393
|
+
|| permissionSet.has("network_access")
|
|
394
|
+
|| permissionSet.has("browser_access")
|
|
395
|
+
|| permissionSet.has("package_install")
|
|
396
|
+
|| input.adapterOrConfigSensitive
|
|
397
|
+
) {
|
|
398
|
+
return {
|
|
399
|
+
state: "manual_review",
|
|
400
|
+
reasonCodes: unique([...reasonCodes, "manual_review_required"]),
|
|
401
|
+
safeNextAction: "Review the requested side effects and keep this capability in manual-review mode before trusting it.",
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (
|
|
406
|
+
input.provenance === "external_reference"
|
|
407
|
+
|| input.provenance === "unknown"
|
|
408
|
+
|| input.missingManifest
|
|
409
|
+
|| input.sideEffectUnknown
|
|
410
|
+
) {
|
|
411
|
+
return {
|
|
412
|
+
state: "quarantine",
|
|
413
|
+
reasonCodes: unique([...reasonCodes, "quarantined_for_review"]),
|
|
414
|
+
safeNextAction: "Keep this capability quarantined until provenance and permission evidence are complete.",
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (
|
|
419
|
+
permissionSet.has("read_only")
|
|
420
|
+
&& instructionSet.size === 1
|
|
421
|
+
&& instructionSet.has("safe_pointer")
|
|
422
|
+
&& (input.provenance === "local" || input.provenance === "repo")
|
|
423
|
+
) {
|
|
424
|
+
return {
|
|
425
|
+
state: "allow_local_reference",
|
|
426
|
+
reasonCodes: unique([...reasonCodes, "allowed_local_reference"]),
|
|
427
|
+
safeNextAction: "Keep this capability available as a local reference only and do not treat it as trusted runtime execution.",
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
return {
|
|
432
|
+
state: "allow_prepare_only",
|
|
433
|
+
reasonCodes: unique([...reasonCodes, "allowed_prepare_only"]),
|
|
434
|
+
safeNextAction: "Prepare documentation or evidence for this capability, but do not promote it automatically.",
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function candidateShouldBeScanned(relPath) {
|
|
439
|
+
const normalized = normalizePathValue(relPath);
|
|
440
|
+
if (normalized.endsWith("SKILL.md")) return true;
|
|
441
|
+
if (/\.capability\.json$/i.test(normalized)) return true;
|
|
442
|
+
if (/(^|\/)(mcp|mcp-config|mcp-servers?|prompts?|prompt-packs?|tools?|capabilities|fixtures\/capabilities|tests\/fixtures\/capabilities)(\/|$)/i.test(normalized)) {
|
|
443
|
+
return /\.(md|json|ya?ml|toml)$/i.test(normalized);
|
|
444
|
+
}
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function readManifestForCandidate(absPath, relPath, type) {
|
|
449
|
+
const normalized = normalizePathValue(relPath);
|
|
450
|
+
if (/\.json$/i.test(normalized)) {
|
|
451
|
+
return safeReadJsonAbs(absPath);
|
|
452
|
+
}
|
|
453
|
+
if (type === "skill" || type === "prompt_pack") {
|
|
454
|
+
const text = safeReadText(absPath) || "";
|
|
455
|
+
const match = text.match(/^---\s*\r?\n([\s\S]+?)\r?\n---(?:\r?\n|$)/);
|
|
456
|
+
if (!match) return null;
|
|
457
|
+
const lines = match[1].split(/\r?\n/);
|
|
458
|
+
const manifest = {};
|
|
459
|
+
for (const line of lines) {
|
|
460
|
+
const split = line.match(/^([A-Za-z0-9_-]+)\s*:\s*(.+)$/);
|
|
461
|
+
if (!split) continue;
|
|
462
|
+
manifest[split[1]] = split[2].replace(/^['"]|['"]$/g, "").trim();
|
|
463
|
+
}
|
|
464
|
+
return manifest;
|
|
465
|
+
}
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function buildCandidate(cwd, absPath, relPath, sourceMetadataMap) {
|
|
470
|
+
const detectedType = detectCandidateType(relPath, null);
|
|
471
|
+
const text = safeReadText(absPath) || "";
|
|
472
|
+
const manifest = readManifestForCandidate(absPath, relPath, detectedType);
|
|
473
|
+
const type = detectCandidateType(relPath, manifest);
|
|
474
|
+
const sourceMetadata = sourceMetadataForCandidate(sourceMetadataMap, relPath);
|
|
475
|
+
const provenance = detectProvenance(relPath, manifest, sourceMetadata, text);
|
|
476
|
+
const permissionInfo = detectPermissions(text, manifest);
|
|
477
|
+
const instructionInfo = detectInstructionRisks(text, manifest);
|
|
478
|
+
const missingManifest = Boolean(
|
|
479
|
+
(type === "skill" || type === "prompt_pack")
|
|
480
|
+
&& !hasFrontMatter(text)
|
|
481
|
+
&& !(manifest && typeof manifest === "object")
|
|
482
|
+
);
|
|
483
|
+
const missingPermissions = !Array.isArray(manifest?.permissions)
|
|
484
|
+
&& permissionInfo.permissions.length === 1
|
|
485
|
+
&& permissionInfo.permissions[0] === "read_only"
|
|
486
|
+
&& (type === "mcp" || type === "tool" || type === "adapter");
|
|
487
|
+
const sideEffectUnknown = permissionInfo.permissions.includes("unknown");
|
|
488
|
+
const adapterOrConfigSensitive = type === "adapter"
|
|
489
|
+
|| /\b(hook|config|settings\.json|\.codex|adapter)\b/i.test(text)
|
|
490
|
+
|| /\.codex\/config\.toml$/i.test(normalizePathValue(relPath));
|
|
491
|
+
const decision = classifyDecision({
|
|
492
|
+
provenance,
|
|
493
|
+
permissions: permissionInfo.permissions,
|
|
494
|
+
instructionRisks: instructionInfo.instructionRisks,
|
|
495
|
+
missingManifest,
|
|
496
|
+
missingPermissions,
|
|
497
|
+
sideEffectUnknown,
|
|
498
|
+
adapterOrConfigSensitive,
|
|
499
|
+
});
|
|
500
|
+
const riskTier = inferRiskTier(permissionInfo.permissions, instructionInfo.instructionRisks, provenance, missingManifest);
|
|
501
|
+
const name = detectCandidateName(relPath, manifest, type);
|
|
502
|
+
const sourceUrl = sanitizeText(manifest?.urlRef || manifest?.sourceUrl || sourceMetadata?.sourceUrl || null, 160);
|
|
503
|
+
const packageRef = sanitizeText(manifest?.packageRef || sourceMetadata?.packageName || null, 120);
|
|
504
|
+
const evidenceRefs = unique([
|
|
505
|
+
toRedactedRef(cwd, relPath),
|
|
506
|
+
sourceUrl ? toRedactedRef(cwd, sourceUrl) : null,
|
|
507
|
+
]).slice(0, 4);
|
|
508
|
+
|
|
509
|
+
return {
|
|
510
|
+
id: hashId("cap", `${relPath}|${type}|${name}`),
|
|
511
|
+
name,
|
|
512
|
+
type,
|
|
513
|
+
source: {
|
|
514
|
+
provenance,
|
|
515
|
+
pathRef: toRedactedRef(cwd, relPath),
|
|
516
|
+
packageRef,
|
|
517
|
+
urlRef: sourceUrl ? toRedactedRef(cwd, sourceUrl) : null,
|
|
518
|
+
redacted: true,
|
|
519
|
+
},
|
|
520
|
+
risk: {
|
|
521
|
+
tier: riskTier,
|
|
522
|
+
permissions: permissionInfo.permissions,
|
|
523
|
+
instructionRisks: instructionInfo.instructionRisks,
|
|
524
|
+
sideEffectLevel: inferSideEffectLevel(permissionInfo.permissions),
|
|
525
|
+
secretsRisk: permissionInfo.permissions.includes("secrets_or_env") || permissionInfo.permissions.includes("credentials"),
|
|
526
|
+
networkRisk: permissionInfo.permissions.includes("network_access") || permissionInfo.permissions.includes("browser_access"),
|
|
527
|
+
productionRisk: permissionInfo.permissions.includes("production_or_deploy"),
|
|
528
|
+
},
|
|
529
|
+
decision: {
|
|
530
|
+
state: normalizeEnum(decision.state, VALID_DECISIONS, "quarantine"),
|
|
531
|
+
reasonCodes: unique([
|
|
532
|
+
...decision.reasonCodes,
|
|
533
|
+
...permissionInfo.reasonCodes,
|
|
534
|
+
...instructionInfo.reasonCodes,
|
|
535
|
+
]),
|
|
536
|
+
safeNextAction: decision.safeNextAction,
|
|
537
|
+
},
|
|
538
|
+
evidenceRefs,
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function collectCandidates(cwd) {
|
|
543
|
+
const candidates = [];
|
|
544
|
+
const sourceMetadataMap = buildSourceMetadataMap(cwd);
|
|
545
|
+
walkRepo(cwd, (absPath, relPath) => {
|
|
546
|
+
if (!candidateShouldBeScanned(relPath)) return;
|
|
547
|
+
const candidate = buildCandidate(cwd, absPath, relPath, sourceMetadataMap);
|
|
548
|
+
candidates.push(candidate);
|
|
549
|
+
});
|
|
550
|
+
return candidates.sort((left, right) => left.name.localeCompare(right.name));
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
function summarizeCandidates(candidates) {
|
|
554
|
+
const counts = {
|
|
555
|
+
allow_local_reference: 0,
|
|
556
|
+
allow_prepare_only: 0,
|
|
557
|
+
quarantine: 0,
|
|
558
|
+
manual_review: 0,
|
|
559
|
+
block: 0,
|
|
560
|
+
};
|
|
561
|
+
for (const candidate of candidates) {
|
|
562
|
+
counts[candidate.decision.state] += 1;
|
|
563
|
+
}
|
|
564
|
+
return counts;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
function buildRollup(candidates) {
|
|
568
|
+
return {
|
|
569
|
+
safeLocalReferences: candidates.filter((candidate) => candidate.decision.state === "allow_local_reference").map((candidate) => candidate.id),
|
|
570
|
+
quarantineQueue: candidates.filter((candidate) => candidate.decision.state === "quarantine").map((candidate) => candidate.id),
|
|
571
|
+
manualReviewQueue: candidates.filter((candidate) => candidate.decision.state === "manual_review").map((candidate) => candidate.id),
|
|
572
|
+
blockedItems: candidates.filter((candidate) => candidate.decision.state === "block").map((candidate) => candidate.id),
|
|
573
|
+
notEnoughEvidence: candidates
|
|
574
|
+
.filter((candidate) =>
|
|
575
|
+
candidate.decision.reasonCodes.includes("missing_manifest")
|
|
576
|
+
|| candidate.decision.reasonCodes.includes("unknown_provenance")
|
|
577
|
+
|| candidate.decision.reasonCodes.includes("side_effect_unknown")
|
|
578
|
+
)
|
|
579
|
+
.map((candidate) => candidate.id),
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
function buildIntegrationRefs(candidates) {
|
|
584
|
+
const hasCandidates = candidates.length > 0;
|
|
585
|
+
const hasSkillCandidates = candidates.some((candidate) => candidate.type === "skill" && candidate.decision.state === "allow_local_reference");
|
|
586
|
+
const hasBoundaryRisk = candidates.some((candidate) =>
|
|
587
|
+
candidate.risk.permissions.some((permission) =>
|
|
588
|
+
["writes_files", "executes_commands", "network_access", "browser_access", "package_install", "production_or_deploy"].includes(permission)
|
|
589
|
+
)
|
|
590
|
+
);
|
|
591
|
+
const hasAgentReadinessRisk = candidates.some((candidate) =>
|
|
592
|
+
candidate.type === "adapter"
|
|
593
|
+
|| candidate.decision.reasonCodes.some((code) => ["write_permission_requested", "browser_access_requested"].includes(code))
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
return {
|
|
597
|
+
skills: hasSkillCandidates ? [LATEST_REPORT_REL, SOURCE_REPORT_REL] : [],
|
|
598
|
+
boundary: hasBoundaryRisk ? [LATEST_REPORT_REL, BOUNDARY_REPORT_REL] : [],
|
|
599
|
+
agentReadiness: hasAgentReadinessRisk ? [LATEST_REPORT_REL, AGENT_READINESS_REPORT_REL] : [],
|
|
600
|
+
productHome: hasCandidates ? [LATEST_REPORT_REL, PRODUCT_HOME_REPORT_REL] : [],
|
|
601
|
+
radar: hasCandidates ? [LATEST_REPORT_REL, RADAR_REPORT_REL] : [],
|
|
602
|
+
status: hasCandidates ? [LATEST_REPORT_REL, "scripts/cco-status.js"] : [],
|
|
603
|
+
dashboard: hasCandidates ? [LATEST_REPORT_REL, "scripts/cco-dashboard.js"] : [],
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
function buildSafeNextAction(summary) {
|
|
608
|
+
if (summary.block > 0) {
|
|
609
|
+
return "Keep blocked capability candidates out of use and review the unsafe instruction or secret-sensitive behavior first.";
|
|
610
|
+
}
|
|
611
|
+
if (summary.manual_review > 0) {
|
|
612
|
+
return "Review the requested writes, command, browser, network, or package side effects before trusting these capabilities.";
|
|
613
|
+
}
|
|
614
|
+
if (summary.quarantine > 0) {
|
|
615
|
+
return "Add provenance and permission evidence before promoting quarantined capability candidates.";
|
|
616
|
+
}
|
|
617
|
+
if (summary.allow_prepare_only > 0) {
|
|
618
|
+
return "Prepare documentation and evidence for these candidates, but keep them out of trusted runtime use.";
|
|
619
|
+
}
|
|
620
|
+
if (summary.allow_local_reference > 0) {
|
|
621
|
+
return "Keep allowed capability candidates as local references only and avoid auto-install or auto-execution claims.";
|
|
622
|
+
}
|
|
623
|
+
return "Add a local capability manifest, skill, or MCP fixture and rerun `avorelo capability-intake --json`.";
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function determineStatus(candidates, summary) {
|
|
627
|
+
if (candidates.length === 0) return "no_data";
|
|
628
|
+
if (summary.block > 0 && summary.manual_review === 0 && summary.quarantine === 0 && summary.allow_prepare_only === 0 && summary.allow_local_reference === 0) {
|
|
629
|
+
return "blocked";
|
|
630
|
+
}
|
|
631
|
+
if (summary.block > 0 || summary.manual_review > 0 || summary.quarantine > 0 || summary.allow_prepare_only > 0) {
|
|
632
|
+
return "needs_attention";
|
|
633
|
+
}
|
|
634
|
+
return "ready";
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
function buildPrivacySection() {
|
|
638
|
+
return {
|
|
639
|
+
localOnly: true,
|
|
640
|
+
remoteFetch: false,
|
|
641
|
+
remoteTelemetry: false,
|
|
642
|
+
rawPromptStored: false,
|
|
643
|
+
rawCodeStored: false,
|
|
644
|
+
secretsStored: false,
|
|
645
|
+
envStored: false,
|
|
646
|
+
fullLogsStored: false,
|
|
647
|
+
privatePathsStored: false,
|
|
648
|
+
redacted: true,
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function buildClaimSafetySection() {
|
|
653
|
+
return {
|
|
654
|
+
marketplaceClaim: false,
|
|
655
|
+
autoInstallClaim: false,
|
|
656
|
+
autoExecutionClaim: false,
|
|
657
|
+
trustedByDefault: false,
|
|
658
|
+
guaranteedSafe: false,
|
|
659
|
+
universalMcpSupport: false,
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
function buildCapabilityIntakeQuarantineReport(cwd = process.cwd(), options = {}) {
|
|
664
|
+
const candidates = collectCandidates(cwd);
|
|
665
|
+
const summaryByDecision = summarizeCandidates(candidates);
|
|
666
|
+
const safeNextAction = buildSafeNextAction(summaryByDecision);
|
|
667
|
+
const status = determineStatus(candidates, summaryByDecision);
|
|
668
|
+
const report = {
|
|
669
|
+
schemaVersion: CONTRACT,
|
|
670
|
+
generatedAt: nowIso(),
|
|
671
|
+
status,
|
|
672
|
+
redacted: true,
|
|
673
|
+
summary: {
|
|
674
|
+
candidatesInspected: candidates.length,
|
|
675
|
+
allowed: summaryByDecision.allow_local_reference,
|
|
676
|
+
quarantined: summaryByDecision.quarantine,
|
|
677
|
+
manualReview: summaryByDecision.manual_review,
|
|
678
|
+
blocked: summaryByDecision.block,
|
|
679
|
+
safeNextAction,
|
|
680
|
+
},
|
|
681
|
+
candidates,
|
|
682
|
+
rollup: buildRollup(candidates),
|
|
683
|
+
integrationRefs: buildIntegrationRefs(candidates),
|
|
684
|
+
privacy: buildPrivacySection(),
|
|
685
|
+
claimSafety: buildClaimSafetySection(),
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
if (candidates.length === 0) {
|
|
689
|
+
report.rollup.notEnoughEvidence = ["no_candidates_found"];
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
return report;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
function writeCapabilityIntakeQuarantineReport(cwd, report) {
|
|
696
|
+
ensureCcoDirs(cwd);
|
|
697
|
+
safeWriteJson(cwd, LATEST_REPORT_REL, report);
|
|
698
|
+
return LATEST_REPORT_REL;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
function generateCapabilityIntakeQuarantine(cwd = process.cwd(), options = {}) {
|
|
702
|
+
const report = buildCapabilityIntakeQuarantineReport(cwd, options);
|
|
703
|
+
const writtenPath = options.write === false ? null : writeCapabilityIntakeQuarantineReport(cwd, report);
|
|
704
|
+
return {
|
|
705
|
+
report,
|
|
706
|
+
writtenPath,
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
function readLatestCapabilityIntakeQuarantineReport(cwd = process.cwd()) {
|
|
711
|
+
return safeReadJson(cwd, LATEST_REPORT_REL, null);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
function buildCapabilityIntakeQuarantineSurface(cwd = process.cwd(), options = {}) {
|
|
715
|
+
const report = options.report
|
|
716
|
+
|| readLatestCapabilityIntakeQuarantineReport(cwd)
|
|
717
|
+
|| (options.buildIfMissing ? buildCapabilityIntakeQuarantineReport(cwd, { write: false }) : null);
|
|
718
|
+
|
|
719
|
+
if (!report || report.schemaVersion !== CONTRACT) {
|
|
720
|
+
return {
|
|
721
|
+
status: "not_run",
|
|
722
|
+
totalCandidates: 0,
|
|
723
|
+
allowed: 0,
|
|
724
|
+
quarantined: 0,
|
|
725
|
+
manualReview: 0,
|
|
726
|
+
blocked: 0,
|
|
727
|
+
nextAction: "Run `node bin/avorelo capability-intake --json` to inspect local capability candidates.",
|
|
728
|
+
latestReportPath: null,
|
|
729
|
+
showInStatus: false,
|
|
730
|
+
showInDashboard: false,
|
|
731
|
+
statusLine: "Capability intake: NOT RUN",
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
return {
|
|
736
|
+
status: report.status,
|
|
737
|
+
totalCandidates: Number(report.summary?.candidatesInspected || 0),
|
|
738
|
+
allowed: Number(report.summary?.allowed || 0),
|
|
739
|
+
quarantined: Number(report.summary?.quarantined || 0),
|
|
740
|
+
manualReview: Number(report.summary?.manualReview || 0),
|
|
741
|
+
blocked: Number(report.summary?.blocked || 0),
|
|
742
|
+
nextAction: report.summary?.safeNextAction || "Review capability candidates before trusting them.",
|
|
743
|
+
latestReportPath: LATEST_REPORT_REL,
|
|
744
|
+
showInStatus: true,
|
|
745
|
+
showInDashboard: true,
|
|
746
|
+
statusLine: `Capability intake: ${String(report.status || "no_data").replace(/_/g, " ").toUpperCase()} · inspected=${Number(report.summary?.candidatesInspected || 0)} · allowed=${Number(report.summary?.allowed || 0)} · quarantine=${Number(report.summary?.quarantined || 0)} · manual=${Number(report.summary?.manualReview || 0)} · blocked=${Number(report.summary?.blocked || 0)}`,
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
function formatCapabilityIntakeQuarantineText(report) {
|
|
751
|
+
if (!report || report.schemaVersion !== CONTRACT) {
|
|
752
|
+
return [
|
|
753
|
+
"Avorelo Capability Intake",
|
|
754
|
+
"Status: NO DATA",
|
|
755
|
+
"Candidates: 0",
|
|
756
|
+
"Next: Add a local capability manifest, skill, or MCP fixture and rerun `avorelo capability-intake --json`.",
|
|
757
|
+
].join("\n");
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
const lines = [
|
|
761
|
+
"Avorelo Capability Intake",
|
|
762
|
+
`Status: ${String(report.status || "no_data").replace(/_/g, " ").toUpperCase()}`,
|
|
763
|
+
`Candidates: ${Number(report.summary?.candidatesInspected || 0)} inspected`,
|
|
764
|
+
`Allowed: ${Number(report.summary?.allowed || 0)} · Quarantine: ${Number(report.summary?.quarantined || 0)} · Manual review: ${Number(report.summary?.manualReview || 0)} · Blocked: ${Number(report.summary?.blocked || 0)}`,
|
|
765
|
+
];
|
|
766
|
+
|
|
767
|
+
const topCandidate = (report.candidates || []).find((candidate) => candidate.decision?.state !== "allow_local_reference")
|
|
768
|
+
|| (report.candidates || [])[0];
|
|
769
|
+
if (topCandidate) {
|
|
770
|
+
lines.push(
|
|
771
|
+
`Top candidate: ${topCandidate.name} (${topCandidate.type}) · ${topCandidate.decision.state} · ${topCandidate.risk.tier}`
|
|
772
|
+
);
|
|
773
|
+
lines.push(`Reason codes: ${(topCandidate.decision.reasonCodes || []).slice(0, 5).join(", ") || "none"}`);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
lines.push(`Next: ${report.summary?.safeNextAction || "Review the latest capability intake report."}`);
|
|
777
|
+
return lines.join("\n");
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
module.exports = {
|
|
781
|
+
CONTRACT,
|
|
782
|
+
LATEST_REPORT_REL,
|
|
783
|
+
buildCapabilityIntakeQuarantineReport,
|
|
784
|
+
buildCapabilityIntakeQuarantineSurface,
|
|
785
|
+
formatCapabilityIntakeQuarantineText,
|
|
786
|
+
generateCapabilityIntakeQuarantine,
|
|
787
|
+
readLatestCapabilityIntakeQuarantineReport,
|
|
788
|
+
writeCapabilityIntakeQuarantineReport,
|
|
789
|
+
};
|