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,619 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
|
|
6
|
+
const { nowIso, safeReadJson, safeWriteJson } = require("./fsx");
|
|
7
|
+
|
|
8
|
+
const CONTRACT = "avorelo.artifactReceiptHygiene.v1";
|
|
9
|
+
const REPORT_DIR_REL = ".claude/cco/reports/artifact-receipt-hygiene";
|
|
10
|
+
const REPORT_JSON_REL = `${REPORT_DIR_REL}/latest-report.json`;
|
|
11
|
+
|
|
12
|
+
const MAX_FILES = 1500;
|
|
13
|
+
const MAX_FINDINGS = 25;
|
|
14
|
+
const MAX_EVIDENCE_REFS_PER_FINDING = 3;
|
|
15
|
+
const MAX_ARTIFACT_SIZE = 256 * 1024; // 256KB
|
|
16
|
+
const OVERSIZED_THRESHOLD = 128 * 1024; // 128KB considered oversized for a single artifact
|
|
17
|
+
const STALE_DAYS = 90;
|
|
18
|
+
|
|
19
|
+
const SKIP_DIRS = new Set([
|
|
20
|
+
".git", "node_modules", "dist", "build", "coverage", ".next", ".nuxt", ".turbo", ".wasp", "temp",
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
// Matches a Windows drive path (C:\ or C:/dir) but NOT a URL scheme like
|
|
24
|
+
// http://, https://, postgresql://, wuz:// — a URL has `://` (two slashes after
|
|
25
|
+
// the colon) and is never an absolute LOCAL path. Excluding it removes a
|
|
26
|
+
// false-positive class without weakening local-path detection.
|
|
27
|
+
const ABSOLUTE_WINDOWS_PATH_RE = /[A-Za-z]:(?:\\|\/(?!\/))/;
|
|
28
|
+
const ABSOLUTE_UNIX_PATH_RE = /(?:^|\s|")\/(?:Users|home|tmp|var|etc)\//;
|
|
29
|
+
// `sk-` requires a leading non-alphanumeric boundary so it matches real API
|
|
30
|
+
// keys (e.g. "sk-ant-...") but NOT the "sk-" buried inside ordinary words like
|
|
31
|
+
// "ri[sk-]governance" or "ta[sk-]specific". Without the boundary, hyphenated
|
|
32
|
+
// English phrases were flagged as secrets — a false-positive class.
|
|
33
|
+
const SECRET_PATTERN_RE = /(?:(?<![A-Za-z0-9])sk-[A-Za-z0-9_-]{16,}|gh[ps]_[A-Za-z0-9]{12,}|npm_[A-Za-z0-9]{12,}|AKIA[0-9A-Z]{16})/;
|
|
34
|
+
const SECRET_ASSIGNMENT_RE = /(?:api[_ -]?key|token|password|secret|authorization|credentials?)\s*[:=]\s*["']?[^\s'"]{8,}/i;
|
|
35
|
+
const RAW_LOG_RE = /(?:\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}[.\d]*Z?\s+(?:ERROR|WARN|INFO|DEBUG|TRACE)\b|\[(?:error|warn|info|debug)\])/i;
|
|
36
|
+
const RAW_PROMPT_RE = /(?:system\s*:\s*(?:you are|as an|act as)|<system>|<human>|<assistant>|Human:|Assistant:|<<SYS>>)/i;
|
|
37
|
+
const RAW_TRANSCRIPT_RE = /(?:^\s*(?:Human|Assistant|User|System)\s*:\s*.{20,}$)/m;
|
|
38
|
+
const RAW_CODE_DUMP_RE = /(?:"(?:sourceCode|rawCode|codeContent|fullSource)"\s*:\s*"[\s\S]{500,}")/;
|
|
39
|
+
const PUBLIC_CLAIM_RE = /(?:"publicClaimAllowed"\s*:\s*true)/;
|
|
40
|
+
const VALUE_FIELDS = ["measured", "estimated", "heuristic", "unavailable"];
|
|
41
|
+
const UNSAFE_PUBLIC_CLAIM_RE = /(?:guaranteed|production.ready|guaranteed.secure|guaranteed.savings|launch.ready|published.verified|certified|marketplace|auto.install)/i;
|
|
42
|
+
|
|
43
|
+
// A claim term is only an UNSUPPORTED public claim when it is asserted as TRUE.
|
|
44
|
+
// The same vocabulary appears constantly in HONEST evidence that DISCLAIMS the
|
|
45
|
+
// claim ("No guaranteed savings claimed", "Does not claim production certified",
|
|
46
|
+
// "Not a marketplace", "Do NOT claim published_verified"), in detection-term
|
|
47
|
+
// lists, and as snake_case enum/identifier values (e.g. `published_verified`,
|
|
48
|
+
// `noGuaranteedRecallClaim`). Flagging those is a false positive — and rewording
|
|
49
|
+
// honest disclaimers to dodge the regex would REDUCE honesty. This context check
|
|
50
|
+
// preserves the original intent (catch positive overclaims) while skipping
|
|
51
|
+
// negated / disclaimed / technical-identifier usages.
|
|
52
|
+
// Disclaimer / detection / exclusion / technical-identifier cues. When any of
|
|
53
|
+
// these share the claim term's line (or nearby context), the term is being
|
|
54
|
+
// disclaimed, screened, deferred, or used as an enum — not asserted.
|
|
55
|
+
const CLAIM_DISCLAIMER_RE = /(?:\bno\b|\bnot\b|\bnon\b|\bnever\b|\bwithout\b|\bcannot\b|can't|won't|don't|doesn't|do not|does not|\bavoid(?:ed|s)?\b|deferred|\bdefer\b|\bfalse\b|premature|absent|\bnone\b|forbidden|disallow|blocked|terms ?checked|unsafeterms|screened|blocked copy|\bexamples?\b|not claim|cannot claim|requires?|ready_to_publish|not_available|not included|out of scope|excluded|non-goals?|separate track|no local|do not say|never say|→ ?never|❌)/i;
|
|
56
|
+
|
|
57
|
+
function hasUnsupportedPublicClaim(text) {
|
|
58
|
+
if (!text) return false;
|
|
59
|
+
const re = new RegExp(UNSAFE_PUBLIC_CLAIM_RE.source, "gi");
|
|
60
|
+
let m;
|
|
61
|
+
while ((m = re.exec(text)) !== null) {
|
|
62
|
+
const tok = m[0];
|
|
63
|
+
const start = m.index;
|
|
64
|
+
const end = start + tok.length;
|
|
65
|
+
if (tok.includes("_")) continue; // snake_case enum/identifier
|
|
66
|
+
if (/[A-Za-z0-9_]/.test(text[start - 1] || "")) continue; // embedded in a larger word/identifier
|
|
67
|
+
if (/[A-Za-z0-9_]/.test(text[end] || "")) continue; // embedded in a larger word/identifier
|
|
68
|
+
// Context = a bounded window before the match (catches a preceding section
|
|
69
|
+
// header such as "does not add:" / "What is not included") PLUS the rest of
|
|
70
|
+
// the current line (catches a same-line trailing qualifier such as
|
|
71
|
+
// "(no local evidence)" or "| No network |"). Markdown bullets/tables and
|
|
72
|
+
// exclusion lists carry the disclaimer in one of these two places.
|
|
73
|
+
let lineEnd = text.indexOf("\n", end);
|
|
74
|
+
if (lineEnd === -1) lineEnd = text.length;
|
|
75
|
+
const before = text.slice(Math.max(0, start - 160), start);
|
|
76
|
+
const restOfLine = text.slice(end, Math.min(lineEnd, end + 120));
|
|
77
|
+
if (CLAIM_DISCLAIMER_RE.test(before + " " + restOfLine)) continue; // disclaimed / screened / deferred / technical
|
|
78
|
+
return true; // a positive, asserted public claim
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function toPosix(value) {
|
|
84
|
+
return String(value || "").replace(/\\/g, "/");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function sanitizeText(value, max = 220) {
|
|
88
|
+
const text = String(value || "")
|
|
89
|
+
.replace(/\s+/g, " ")
|
|
90
|
+
.replace(/(?:(?<![A-Za-z0-9])sk-[A-Za-z0-9_-]{16,}|gh[ps]_[A-Za-z0-9]{12,}|npm_[A-Za-z0-9]{12,}|AKIA[0-9A-Z]{16})/g, "[redacted-token]")
|
|
91
|
+
.replace(/(bearer\s+)[A-Za-z0-9._-]{8,}/ig, "$1[redacted]")
|
|
92
|
+
.replace(/((?:api[_ -]?key|token|password|secret|authorization)\s*[:=]\s*)([^\s'"]+)/ig, "$1[redacted]")
|
|
93
|
+
.trim();
|
|
94
|
+
if (!text) return null;
|
|
95
|
+
return text.length > max ? `${text.slice(0, max - 3).trimEnd()}...` : text;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function sanitizeRef(ref) {
|
|
99
|
+
const text = toPosix(String(ref || "").trim());
|
|
100
|
+
if (!text || text.startsWith("..")) return null;
|
|
101
|
+
return text;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function makeEvidenceRef(relPath, label) {
|
|
105
|
+
const base = sanitizeRef(relPath);
|
|
106
|
+
if (!base) return null;
|
|
107
|
+
const note = label ? ` (${sanitizeText(label, 80)})` : "";
|
|
108
|
+
return `${base}${note}`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function severityRank(severity) {
|
|
112
|
+
if (severity === "block") return 3;
|
|
113
|
+
if (severity === "warn") return 2;
|
|
114
|
+
if (severity === "info") return 1;
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function isStaleDate(isoString) {
|
|
119
|
+
if (!isoString) return false;
|
|
120
|
+
try {
|
|
121
|
+
const d = new Date(isoString);
|
|
122
|
+
if (isNaN(d.getTime())) return false;
|
|
123
|
+
return (Date.now() - d.getTime()) > (STALE_DAYS * 24 * 60 * 60 * 1000);
|
|
124
|
+
} catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ── Walk artifact directories ───────────────────────────────────────────────
|
|
130
|
+
|
|
131
|
+
function walkArtifactDirs(cwd) {
|
|
132
|
+
const roots = [
|
|
133
|
+
"artifacts",
|
|
134
|
+
".claude/cco/reports",
|
|
135
|
+
".claude/cco/state",
|
|
136
|
+
"docs/dogfood",
|
|
137
|
+
"docs/releases",
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
const files = [];
|
|
141
|
+
for (const root of roots) {
|
|
142
|
+
const absRoot = path.join(cwd, root);
|
|
143
|
+
if (!fs.existsSync(absRoot)) continue;
|
|
144
|
+
walkDir(absRoot, cwd, files, 5);
|
|
145
|
+
}
|
|
146
|
+
return files;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function walkDir(dirPath, cwd, files, maxDepth) {
|
|
150
|
+
if (maxDepth <= 0 || files.length >= MAX_FILES) return;
|
|
151
|
+
try {
|
|
152
|
+
for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) {
|
|
153
|
+
if (files.length >= MAX_FILES) return;
|
|
154
|
+
const absPath = path.join(dirPath, entry.name);
|
|
155
|
+
if (entry.isDirectory()) {
|
|
156
|
+
if (SKIP_DIRS.has(entry.name)) continue;
|
|
157
|
+
walkDir(absPath, cwd, files, maxDepth - 1);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (!entry.isFile()) continue;
|
|
161
|
+
if (!entry.name.endsWith(".json") && !entry.name.endsWith(".md")) continue;
|
|
162
|
+
const relPath = toPosix(path.relative(cwd, absPath));
|
|
163
|
+
try {
|
|
164
|
+
const stat = fs.statSync(absPath);
|
|
165
|
+
files.push({ absPath, relPath, size: stat.size });
|
|
166
|
+
} catch {
|
|
167
|
+
files.push({ absPath, relPath, size: 0 });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
} catch {}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// ── Core analysis ───────────────────────────────────────────────────────────
|
|
174
|
+
|
|
175
|
+
function buildArtifactReceiptHygieneReport(cwd = process.cwd(), options = {}) {
|
|
176
|
+
const limitsApplied = [];
|
|
177
|
+
const findings = [];
|
|
178
|
+
const seenCodes = new Map();
|
|
179
|
+
|
|
180
|
+
function addFinding(severity, reasonCode, title, safeNextAction, evidenceRefs) {
|
|
181
|
+
if (findings.length >= MAX_FINDINGS) {
|
|
182
|
+
if (!limitsApplied.includes("MAX_FINDINGS_REACHED")) limitsApplied.push("MAX_FINDINGS_REACHED");
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const key = `${reasonCode}:${(evidenceRefs || [])[0] || ""}`;
|
|
186
|
+
if (seenCodes.has(key)) return;
|
|
187
|
+
seenCodes.set(key, true);
|
|
188
|
+
findings.push({
|
|
189
|
+
severity,
|
|
190
|
+
reasonCode,
|
|
191
|
+
title: sanitizeText(title, 220),
|
|
192
|
+
safeNextAction: sanitizeText(safeNextAction, 220),
|
|
193
|
+
evidenceRefs: (evidenceRefs || []).slice(0, MAX_EVIDENCE_REFS_PER_FINDING).filter(Boolean),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const files = walkArtifactDirs(cwd);
|
|
198
|
+
|
|
199
|
+
if (files.length === 0) {
|
|
200
|
+
const emptyReport = buildEmptyReport(limitsApplied);
|
|
201
|
+
if (options.write !== false) {
|
|
202
|
+
safeWriteJson(cwd, REPORT_JSON_REL, emptyReport);
|
|
203
|
+
}
|
|
204
|
+
return emptyReport;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (files.length >= MAX_FILES) {
|
|
208
|
+
limitsApplied.push("SCAN_LIMIT_APPLIED");
|
|
209
|
+
addFinding("warn", "ARTIFACT_HYGIENE_REVIEW_REQUIRED", `Artifact file count reached scan limit (${MAX_FILES})`, "Review artifact directories manually — some files were not inspected.", []);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
let staleCount = 0;
|
|
213
|
+
let missingSchemaCount = 0;
|
|
214
|
+
let unsafeCount = 0;
|
|
215
|
+
let oversizedCount = 0;
|
|
216
|
+
let brokenRefCount = 0;
|
|
217
|
+
let artifactsInspected = 0;
|
|
218
|
+
|
|
219
|
+
for (const file of files) {
|
|
220
|
+
// Skip very large files
|
|
221
|
+
if (file.size > MAX_ARTIFACT_SIZE) {
|
|
222
|
+
addFinding("warn", "ARTIFACT_OVERSIZED", `Artifact ${file.relPath} is ${Math.round(file.size / 1024)}KB — exceeds inspection limit`, "Consider splitting or compacting this artifact.", [makeEvidenceRef(file.relPath, "oversized")]);
|
|
223
|
+
oversizedCount++;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Skip non-JSON for structured checks (md files get text checks only)
|
|
228
|
+
if (file.relPath.endsWith(".md")) {
|
|
229
|
+
artifactsInspected++;
|
|
230
|
+
try {
|
|
231
|
+
const content = fs.readFileSync(file.absPath, "utf8");
|
|
232
|
+
|
|
233
|
+
// Check for absolute paths
|
|
234
|
+
if (ABSOLUTE_WINDOWS_PATH_RE.test(content) || ABSOLUTE_UNIX_PATH_RE.test(content)) {
|
|
235
|
+
addFinding("block", "ARTIFACT_ABSOLUTE_PATH_FOUND", `Absolute local path found in ${file.relPath}`, "Replace with repo-relative paths.", [makeEvidenceRef(file.relPath, "absolute path")]);
|
|
236
|
+
unsafeCount++;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Check for secret patterns
|
|
240
|
+
if (SECRET_PATTERN_RE.test(content) || SECRET_ASSIGNMENT_RE.test(content)) {
|
|
241
|
+
addFinding("block", "ARTIFACT_SECRET_PATTERN_FOUND", `Secret-like pattern found in ${file.relPath}`, "Remove or redact secret values.", [makeEvidenceRef(file.relPath, "secret")]);
|
|
242
|
+
unsafeCount++;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Check for unsafe public claims (asserted, not disclaimed)
|
|
246
|
+
if (hasUnsupportedPublicClaim(content)) {
|
|
247
|
+
addFinding("block", "ARTIFACT_PUBLIC_CLAIM_UNSUPPORTED", `Unsupported public claim found in ${file.relPath}`, "Remove or qualify the claim with evidence and caveats.", [makeEvidenceRef(file.relPath, "unsupported claim")]);
|
|
248
|
+
unsafeCount++;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Check for raw prompts
|
|
252
|
+
if (RAW_PROMPT_RE.test(content)) {
|
|
253
|
+
addFinding("block", "ARTIFACT_RAW_PROMPT_FOUND", `Raw prompt/system message found in ${file.relPath}`, "Remove raw prompts from artifacts.", [makeEvidenceRef(file.relPath, "raw prompt")]);
|
|
254
|
+
unsafeCount++;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Check for oversized threshold
|
|
258
|
+
if (file.size > OVERSIZED_THRESHOLD) {
|
|
259
|
+
addFinding("warn", "ARTIFACT_OVERSIZED", `Artifact ${file.relPath} is ${Math.round(file.size / 1024)}KB`, "Consider compacting this artifact.", [makeEvidenceRef(file.relPath, "large")]);
|
|
260
|
+
oversizedCount++;
|
|
261
|
+
}
|
|
262
|
+
} catch {}
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// JSON artifact checks
|
|
267
|
+
if (!file.relPath.endsWith(".json")) continue;
|
|
268
|
+
|
|
269
|
+
let data;
|
|
270
|
+
try {
|
|
271
|
+
const raw = fs.readFileSync(file.absPath, "utf8").replace(/^/, "");
|
|
272
|
+
data = JSON.parse(raw);
|
|
273
|
+
artifactsInspected++;
|
|
274
|
+
} catch {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Check schemaVersion
|
|
279
|
+
if (!data.schemaVersion) {
|
|
280
|
+
addFinding("warn", "ARTIFACT_SCHEMA_MISSING", `Artifact ${file.relPath} has no schemaVersion`, "Add schemaVersion to the artifact.", [makeEvidenceRef(file.relPath, "missing schema")]);
|
|
281
|
+
missingSchemaCount++;
|
|
282
|
+
} else {
|
|
283
|
+
addFinding("info", "ARTIFACT_SCHEMA_FOUND", `Schema '${data.schemaVersion}' found in ${file.relPath}`, "No action needed.", [makeEvidenceRef(file.relPath, data.schemaVersion)]);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Check generatedAt
|
|
287
|
+
if (data.generatedAt) {
|
|
288
|
+
addFinding("info", "ARTIFACT_GENERATED_AT_FOUND", `generatedAt present in ${file.relPath}`, "No action needed.", [makeEvidenceRef(file.relPath, "timestamp")]);
|
|
289
|
+
if (isStaleDate(data.generatedAt)) {
|
|
290
|
+
addFinding("warn", "ARTIFACT_STALE", `Artifact ${file.relPath} generatedAt is older than ${STALE_DAYS} days`, "Re-generate the artifact.", [makeEvidenceRef(file.relPath, "stale")]);
|
|
291
|
+
staleCount++;
|
|
292
|
+
}
|
|
293
|
+
} else if (data.schemaVersion) {
|
|
294
|
+
// Only warn about missing generatedAt on schema-versioned artifacts
|
|
295
|
+
addFinding("warn", "ARTIFACT_GENERATED_AT_MISSING", `Schema-versioned artifact ${file.relPath} has no generatedAt`, "Add generatedAt timestamp.", [makeEvidenceRef(file.relPath, "no timestamp")]);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Stringify and check content
|
|
299
|
+
const rawContent = JSON.stringify(data);
|
|
300
|
+
|
|
301
|
+
// Absolute paths
|
|
302
|
+
if (ABSOLUTE_WINDOWS_PATH_RE.test(rawContent) || ABSOLUTE_UNIX_PATH_RE.test(rawContent)) {
|
|
303
|
+
addFinding("block", "ARTIFACT_ABSOLUTE_PATH_FOUND", `Absolute local path found in ${file.relPath}`, "Replace with repo-relative paths.", [makeEvidenceRef(file.relPath, "absolute path")]);
|
|
304
|
+
unsafeCount++;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Secret patterns
|
|
308
|
+
if (SECRET_PATTERN_RE.test(rawContent)) {
|
|
309
|
+
addFinding("block", "ARTIFACT_SECRET_PATTERN_FOUND", `Secret-like token found in ${file.relPath}`, "Remove or redact secret values.", [makeEvidenceRef(file.relPath, "secret")]);
|
|
310
|
+
unsafeCount++;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Raw logs
|
|
314
|
+
if (RAW_LOG_RE.test(rawContent)) {
|
|
315
|
+
addFinding("block", "ARTIFACT_RAW_LOG_FOUND", `Raw log entries found in ${file.relPath}`, "Remove raw logs from artifacts.", [makeEvidenceRef(file.relPath, "raw log")]);
|
|
316
|
+
unsafeCount++;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Raw prompts
|
|
320
|
+
if (RAW_PROMPT_RE.test(rawContent)) {
|
|
321
|
+
addFinding("block", "ARTIFACT_RAW_PROMPT_FOUND", `Raw prompt/system message found in ${file.relPath}`, "Remove raw prompts from artifacts.", [makeEvidenceRef(file.relPath, "raw prompt")]);
|
|
322
|
+
unsafeCount++;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Raw transcript
|
|
326
|
+
if (RAW_TRANSCRIPT_RE.test(rawContent)) {
|
|
327
|
+
addFinding("block", "ARTIFACT_RAW_TRANSCRIPT_FOUND", `Raw transcript found in ${file.relPath}`, "Remove raw transcripts from artifacts.", [makeEvidenceRef(file.relPath, "raw transcript")]);
|
|
328
|
+
unsafeCount++;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Raw code dump
|
|
332
|
+
if (RAW_CODE_DUMP_RE.test(rawContent)) {
|
|
333
|
+
addFinding("block", "ARTIFACT_RAW_CODE_FOUND", `Raw source code dump found in ${file.relPath}`, "Remove raw code from artifacts.", [makeEvidenceRef(file.relPath, "raw code")]);
|
|
334
|
+
unsafeCount++;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Unsupported public claim
|
|
338
|
+
if (PUBLIC_CLAIM_RE.test(rawContent)) {
|
|
339
|
+
// Check if there's evidence backing it
|
|
340
|
+
const hasProof = data.valueProof && (data.valueProof.measured === true || data.valueProof.dogfooded === true);
|
|
341
|
+
if (!hasProof) {
|
|
342
|
+
addFinding("block", "ARTIFACT_PUBLIC_CLAIM_UNSUPPORTED", `publicClaimAllowed=true without proof support in ${file.relPath}`, "Set publicClaimAllowed to false or add proof evidence.", [makeEvidenceRef(file.relPath, "unsupported claim")]);
|
|
343
|
+
unsafeCount++;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Value label check
|
|
348
|
+
if (data.valueProof && typeof data.valueProof === "object") {
|
|
349
|
+
const mt = data.valueProof.measurementType;
|
|
350
|
+
if (!mt || !VALUE_FIELDS.includes(mt)) {
|
|
351
|
+
addFinding("warn", "ARTIFACT_VALUE_LABEL_MISSING", `Missing or unknown measurementType in ${file.relPath}`, "Add measurementType: measured|estimated|heuristic|unavailable.", [makeEvidenceRef(file.relPath, "value label")]);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Broken evidence refs
|
|
356
|
+
if (Array.isArray(data.valueProof?.evidenceRefs)) {
|
|
357
|
+
for (const ref of data.valueProof.evidenceRefs.slice(0, 5)) {
|
|
358
|
+
const refPath = String(ref || "").split(" (")[0].split(":")[0];
|
|
359
|
+
if (refPath && !refPath.startsWith("[") && !fs.existsSync(path.join(cwd, refPath))) {
|
|
360
|
+
addFinding("warn", "ARTIFACT_BROKEN_EVIDENCE_REF", `Broken evidence ref '${sanitizeText(refPath, 80)}' in ${file.relPath}`, "Update or remove the broken reference.", [makeEvidenceRef(file.relPath, `broken: ${refPath}`)]);
|
|
361
|
+
brokenRefCount++;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Redaction check
|
|
367
|
+
if (data.redacted === false || (data.privacy && data.privacy.redacted === false)) {
|
|
368
|
+
addFinding("warn", "ARTIFACT_REDACTION_MISSING", `Artifact ${file.relPath} is not marked as redacted`, "Set redacted: true or ensure content is redacted.", [makeEvidenceRef(file.relPath, "not redacted")]);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Oversized
|
|
372
|
+
if (file.size > OVERSIZED_THRESHOLD) {
|
|
373
|
+
addFinding("warn", "ARTIFACT_OVERSIZED", `Artifact ${file.relPath} is ${Math.round(file.size / 1024)}KB`, "Consider compacting this artifact.", [makeEvidenceRef(file.relPath, "large")]);
|
|
374
|
+
oversizedCount++;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Unsafe public text claim (asserted, not disclaimed)
|
|
378
|
+
if (hasUnsupportedPublicClaim(rawContent)) {
|
|
379
|
+
addFinding("block", "ARTIFACT_PUBLIC_CLAIM_UNSUPPORTED", `Unsupported public claim text found in ${file.relPath}`, "Remove or qualify the claim.", [makeEvidenceRef(file.relPath, "unsupported claim text")]);
|
|
380
|
+
unsafeCount++;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// ── Determine overall status ──
|
|
385
|
+
const hasBlock = findings.some(f => f.severity === "block");
|
|
386
|
+
const hasWarn = findings.some(f => f.severity === "warn");
|
|
387
|
+
const status = hasBlock ? "blocked" : hasWarn ? "warn" : "pass";
|
|
388
|
+
|
|
389
|
+
const warnCount = findings.filter(f => f.severity === "warn").length;
|
|
390
|
+
const blockCount = findings.filter(f => f.severity === "block").length;
|
|
391
|
+
const infoCount = findings.filter(f => f.severity === "info").length;
|
|
392
|
+
|
|
393
|
+
const safeNextAction = hasBlock
|
|
394
|
+
? "Remove raw secrets, prompts, logs, code dumps, or unsupported claims from artifacts before sharing."
|
|
395
|
+
: hasWarn
|
|
396
|
+
? "Review stale, oversized, or schema-missing artifacts and update accordingly."
|
|
397
|
+
: "Artifacts and receipts are clean. Safe to proceed.";
|
|
398
|
+
|
|
399
|
+
const report = {
|
|
400
|
+
schemaVersion: CONTRACT,
|
|
401
|
+
generatedAt: nowIso(),
|
|
402
|
+
status,
|
|
403
|
+
redacted: true,
|
|
404
|
+
summary: {
|
|
405
|
+
title: "Local Artifact & Receipt Hygiene Guard",
|
|
406
|
+
text: `${artifactsInspected} artifacts inspected. ${staleCount} stale, ${missingSchemaCount} missing schema, ${unsafeCount} unsafe, ${oversizedCount} oversized.`,
|
|
407
|
+
findingCounts: { info: infoCount, warn: warnCount, block: blockCount },
|
|
408
|
+
safeNextAction,
|
|
409
|
+
},
|
|
410
|
+
surfaceEvidence: {
|
|
411
|
+
filesInspected: files.length,
|
|
412
|
+
artifactsInspected,
|
|
413
|
+
capabilitiesInspected: 0,
|
|
414
|
+
limitsApplied,
|
|
415
|
+
},
|
|
416
|
+
hygieneCounts: {
|
|
417
|
+
artifactsInspected,
|
|
418
|
+
staleCount,
|
|
419
|
+
missingSchemaCount,
|
|
420
|
+
unsafeCount,
|
|
421
|
+
oversizedCount,
|
|
422
|
+
brokenRefCount,
|
|
423
|
+
},
|
|
424
|
+
findings: findings.sort((a, b) => severityRank(b.severity) - severityRank(a.severity)),
|
|
425
|
+
productHome: {
|
|
426
|
+
cardSource: "artifact-receipt-hygiene",
|
|
427
|
+
status,
|
|
428
|
+
found: findings.filter(f => f.severity === "warn" || f.severity === "block").map(f => sanitizeText(f.title, 120)).slice(0, 5),
|
|
429
|
+
fixedOrPrepared: [],
|
|
430
|
+
savedOrProved: unsafeCount === 0 && staleCount === 0 ? ["Artifacts and receipts are clean and redacted"] : [],
|
|
431
|
+
forReview: findings.filter(f => f.severity === "block").map(f => sanitizeText(f.title, 120)).slice(0, 3),
|
|
432
|
+
safeNextAction,
|
|
433
|
+
},
|
|
434
|
+
valueProof: {
|
|
435
|
+
implemented: true,
|
|
436
|
+
dogfooded: false,
|
|
437
|
+
measured: false,
|
|
438
|
+
measurementType: "heuristic",
|
|
439
|
+
publicClaimAllowed: false,
|
|
440
|
+
evidenceRefs: [makeEvidenceRef(REPORT_JSON_REL, "artifact hygiene report")].filter(Boolean),
|
|
441
|
+
caveat: "Hygiene checks are pattern-based. No exhaustive secret scanning or content validation performed.",
|
|
442
|
+
},
|
|
443
|
+
limits: {
|
|
444
|
+
localFirst: true,
|
|
445
|
+
deterministicFirst: true,
|
|
446
|
+
modelCalls: false,
|
|
447
|
+
networkCalls: false,
|
|
448
|
+
providerCalls: false,
|
|
449
|
+
registryCalls: false,
|
|
450
|
+
rawDump: false,
|
|
451
|
+
autoFix: false,
|
|
452
|
+
},
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
if (options.write !== false) {
|
|
456
|
+
safeWriteJson(cwd, REPORT_JSON_REL, report);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
return report;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function buildEmptyReport(limitsApplied = []) {
|
|
463
|
+
return {
|
|
464
|
+
schemaVersion: CONTRACT,
|
|
465
|
+
generatedAt: nowIso(),
|
|
466
|
+
status: "no_data",
|
|
467
|
+
redacted: true,
|
|
468
|
+
summary: {
|
|
469
|
+
title: "Local Artifact & Receipt Hygiene Guard",
|
|
470
|
+
text: "No artifacts or receipts found.",
|
|
471
|
+
findingCounts: { info: 0, warn: 0, block: 0 },
|
|
472
|
+
safeNextAction: "No artifacts available. Run commands that generate artifacts first.",
|
|
473
|
+
},
|
|
474
|
+
surfaceEvidence: {
|
|
475
|
+
filesInspected: 0,
|
|
476
|
+
artifactsInspected: 0,
|
|
477
|
+
capabilitiesInspected: 0,
|
|
478
|
+
limitsApplied,
|
|
479
|
+
},
|
|
480
|
+
hygieneCounts: {
|
|
481
|
+
artifactsInspected: 0,
|
|
482
|
+
staleCount: 0,
|
|
483
|
+
missingSchemaCount: 0,
|
|
484
|
+
unsafeCount: 0,
|
|
485
|
+
oversizedCount: 0,
|
|
486
|
+
brokenRefCount: 0,
|
|
487
|
+
},
|
|
488
|
+
findings: [],
|
|
489
|
+
productHome: {
|
|
490
|
+
cardSource: "artifact-receipt-hygiene",
|
|
491
|
+
status: "no_data",
|
|
492
|
+
found: [],
|
|
493
|
+
fixedOrPrepared: [],
|
|
494
|
+
savedOrProved: [],
|
|
495
|
+
forReview: [],
|
|
496
|
+
safeNextAction: "No artifacts available.",
|
|
497
|
+
},
|
|
498
|
+
valueProof: {
|
|
499
|
+
implemented: true,
|
|
500
|
+
dogfooded: false,
|
|
501
|
+
measured: false,
|
|
502
|
+
measurementType: "unavailable",
|
|
503
|
+
publicClaimAllowed: false,
|
|
504
|
+
evidenceRefs: [],
|
|
505
|
+
caveat: "No data to measure against.",
|
|
506
|
+
},
|
|
507
|
+
limits: {
|
|
508
|
+
localFirst: true,
|
|
509
|
+
deterministicFirst: true,
|
|
510
|
+
modelCalls: false,
|
|
511
|
+
networkCalls: false,
|
|
512
|
+
providerCalls: false,
|
|
513
|
+
registryCalls: false,
|
|
514
|
+
rawDump: false,
|
|
515
|
+
autoFix: false,
|
|
516
|
+
},
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// ── Generate / Load / Format / Surface ──────────────────────────────────────
|
|
521
|
+
|
|
522
|
+
function generateArtifactReceiptHygiene(cwd = process.cwd(), options = {}) {
|
|
523
|
+
const report = buildArtifactReceiptHygieneReport(cwd, options);
|
|
524
|
+
return { report, reportPath: path.join(cwd, REPORT_JSON_REL) };
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function loadArtifactReceiptHygiene(cwd = process.cwd()) {
|
|
528
|
+
return safeReadJson(cwd, REPORT_JSON_REL, null);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function formatArtifactReceiptHygieneText(report) {
|
|
532
|
+
if (!report || report.schemaVersion !== CONTRACT) {
|
|
533
|
+
return [
|
|
534
|
+
"Avorelo Local Artifact & Receipt Hygiene Guard",
|
|
535
|
+
"Status: NO DATA",
|
|
536
|
+
"No artifacts or receipts found yet.",
|
|
537
|
+
"Safe next action: Run commands that generate artifacts first.",
|
|
538
|
+
].join("\n");
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const hc = report.hygieneCounts || {};
|
|
542
|
+
const lines = [
|
|
543
|
+
"Avorelo Local Artifact & Receipt Hygiene Guard",
|
|
544
|
+
`Status: ${String(report.status || "no_data").toUpperCase()} · redacted=${report.redacted === true ? "yes" : "no"}`,
|
|
545
|
+
`Artifacts: ${hc.artifactsInspected || 0} · stale=${hc.staleCount || 0} · missing-schema=${hc.missingSchemaCount || 0} · unsafe=${hc.unsafeCount || 0} · oversized=${hc.oversizedCount || 0}`,
|
|
546
|
+
"Notes: local static scan only · no auto-fix · no raw dump",
|
|
547
|
+
];
|
|
548
|
+
|
|
549
|
+
if (Array.isArray(report.findings) && report.findings.length > 0) {
|
|
550
|
+
lines.push("");
|
|
551
|
+
lines.push("Findings:");
|
|
552
|
+
for (const finding of report.findings.slice(0, 5)) {
|
|
553
|
+
lines.push(`- [${finding.severity}] ${finding.title}${finding.evidenceRefs?.length ? ` · ${finding.evidenceRefs[0]}` : ""}`);
|
|
554
|
+
}
|
|
555
|
+
if (report.findings.length > 5) {
|
|
556
|
+
lines.push(` ... and ${report.findings.length - 5} more`);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
lines.push("");
|
|
561
|
+
lines.push(`Safe next action: ${report.summary?.safeNextAction || "Review artifact hygiene."}`);
|
|
562
|
+
return lines.join("\n");
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
function formatArtifactReceiptHygieneStatusLine(report) {
|
|
566
|
+
if (!report || report.schemaVersion !== CONTRACT) {
|
|
567
|
+
return "Artifact hygiene: NOT RUN · run `avorelo artifact-hygiene --text`";
|
|
568
|
+
}
|
|
569
|
+
const hc = report.hygieneCounts || {};
|
|
570
|
+
return `Artifact hygiene: ${String(report.status || "no_data").toUpperCase()}`
|
|
571
|
+
+ ` · artifacts=${hc.artifactsInspected || 0}`
|
|
572
|
+
+ ` · unsafe=${hc.unsafeCount || 0}`
|
|
573
|
+
+ ` · stale=${hc.staleCount || 0}`
|
|
574
|
+
+ ` · next: ${sanitizeText(report.summary?.safeNextAction, 140) || "Review artifact hygiene."}`;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
function buildArtifactReceiptHygieneSurface(cwd = process.cwd(), options = {}) {
|
|
578
|
+
const report = loadArtifactReceiptHygiene(cwd) || (options.buildIfMissing ? buildArtifactReceiptHygieneReport(cwd, { write: false }) : null);
|
|
579
|
+
if (!report) {
|
|
580
|
+
return {
|
|
581
|
+
status: "not_run",
|
|
582
|
+
artifactsInspected: 0,
|
|
583
|
+
unsafeCount: 0,
|
|
584
|
+
staleCount: 0,
|
|
585
|
+
nextBestAction: "Run `avorelo artifact-hygiene --text` to check artifact hygiene.",
|
|
586
|
+
statusLine: "Artifact hygiene: NOT RUN · run `avorelo artifact-hygiene --text`",
|
|
587
|
+
showInStatus: true,
|
|
588
|
+
showInDashboard: true,
|
|
589
|
+
evidenceRef: null,
|
|
590
|
+
limitations: ["Local pattern-based scan only. No exhaustive secret scanning."],
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
const hc = report.hygieneCounts || {};
|
|
595
|
+
return {
|
|
596
|
+
status: report.status,
|
|
597
|
+
artifactsInspected: hc.artifactsInspected || 0,
|
|
598
|
+
unsafeCount: hc.unsafeCount || 0,
|
|
599
|
+
staleCount: hc.staleCount || 0,
|
|
600
|
+
oversizedCount: hc.oversizedCount || 0,
|
|
601
|
+
nextBestAction: report.summary?.safeNextAction,
|
|
602
|
+
statusLine: formatArtifactReceiptHygieneStatusLine(report),
|
|
603
|
+
showInStatus: true,
|
|
604
|
+
showInDashboard: true,
|
|
605
|
+
evidenceRef: REPORT_JSON_REL,
|
|
606
|
+
limitations: ["Local pattern-based scan only. No exhaustive secret scanning."],
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
module.exports = {
|
|
611
|
+
CONTRACT,
|
|
612
|
+
REPORT_JSON_REL,
|
|
613
|
+
buildArtifactReceiptHygieneReport,
|
|
614
|
+
generateArtifactReceiptHygiene,
|
|
615
|
+
loadArtifactReceiptHygiene,
|
|
616
|
+
formatArtifactReceiptHygieneText,
|
|
617
|
+
formatArtifactReceiptHygieneStatusLine,
|
|
618
|
+
buildArtifactReceiptHygieneSurface,
|
|
619
|
+
};
|