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.
Files changed (394) hide show
  1. package/LICENSE +16 -23
  2. package/README.md +62 -72
  3. package/bin/avorelo +9 -0
  4. package/package.json +147 -139
  5. package/scripts/README.md +40 -0
  6. package/scripts/avorelo-session-collision-guard.js +540 -0
  7. package/scripts/avorelo-workstream-preflight.js +918 -0
  8. package/scripts/cco-dashboard.js +346 -0
  9. package/scripts/cco-posttooluse.js +504 -0
  10. package/scripts/cco-pretooluse.js +381 -0
  11. package/scripts/cco-status.js +540 -0
  12. package/scripts/cco-stop.js +77 -0
  13. package/scripts/cco-userprompt-submit.js +83 -0
  14. package/scripts/lib/activation/account-state.js +37 -0
  15. package/scripts/lib/activation/activate-command.js +114 -0
  16. package/scripts/lib/activation/activation-runner.js +607 -0
  17. package/scripts/lib/activation/activation-self-healing.js +481 -0
  18. package/scripts/lib/activation/activation-state.js +96 -0
  19. package/scripts/lib/activation/activation-summary.js +241 -0
  20. package/scripts/lib/activation/adapters/claude-code.js +77 -0
  21. package/scripts/lib/activation/adapters/codex-cli.js +52 -0
  22. package/scripts/lib/activation/adapters/cursor.js +37 -0
  23. package/scripts/lib/activation/adapters/github-agent.js +39 -0
  24. package/scripts/lib/activation/adapters/terminal.js +42 -0
  25. package/scripts/lib/activation/adapters/vscode.js +39 -0
  26. package/scripts/lib/activation/adapters/windsurf.js +37 -0
  27. package/scripts/lib/activation/ai-surface-detector.js +151 -0
  28. package/scripts/lib/activation/connect-account.js +145 -0
  29. package/scripts/lib/activation/detect-environment.js +75 -0
  30. package/scripts/lib/activation/detect-hosts.js +62 -0
  31. package/scripts/lib/activation/format-activation-output.js +109 -0
  32. package/scripts/lib/activation/next-action.js +43 -0
  33. package/scripts/lib/activation/repair-engine.js +219 -0
  34. package/scripts/lib/activation/run-entry.js +346 -0
  35. package/scripts/lib/activation-distribution-readiness.js +507 -0
  36. package/scripts/lib/adapter-conformance.js +176 -0
  37. package/scripts/lib/adapter-readiness.js +428 -0
  38. package/scripts/lib/adapter-safety-boundaries.js +335 -0
  39. package/scripts/lib/adapter-technical-readiness-gate.js +205 -0
  40. package/scripts/lib/agent-access-governance.js +455 -0
  41. package/scripts/lib/agent-activation-readiness.js +878 -0
  42. package/scripts/lib/agent-enforcement.js +765 -0
  43. package/scripts/lib/agent-evolution-loop.js +479 -0
  44. package/scripts/lib/agent-policy-profile.js +210 -0
  45. package/scripts/lib/agent-security/action-evaluator.js +507 -0
  46. package/scripts/lib/agent-security/adapter-registry.js +98 -0
  47. package/scripts/lib/agent-security/auto-policy.js +139 -0
  48. package/scripts/lib/agent-security/bounded-scan.js +93 -0
  49. package/scripts/lib/agent-security/enforcement-adapter.js +174 -0
  50. package/scripts/lib/agent-security/enforcement-engine.js +1129 -0
  51. package/scripts/lib/agent-security/file-write-adapter.js +183 -0
  52. package/scripts/lib/agent-security/file-write-rules.js +178 -0
  53. package/scripts/lib/agent-security/index.js +3342 -0
  54. package/scripts/lib/agent-security/instruction-risk.js +181 -0
  55. package/scripts/lib/agent-security/mcp-action-adapter.js +185 -0
  56. package/scripts/lib/agent-security/mcp-action-rules.js +184 -0
  57. package/scripts/lib/agent-security/package-action-adapter.js +175 -0
  58. package/scripts/lib/agent-security/package-action-rules.js +233 -0
  59. package/scripts/lib/agent-security/performance.js +148 -0
  60. package/scripts/lib/agent-security/permission-minimizer.js +403 -0
  61. package/scripts/lib/agent-security/scan-cache.js +74 -0
  62. package/scripts/lib/agent-security/source-trust.js +146 -0
  63. package/scripts/lib/ai-efficiency-dogfood-pack.js +437 -0
  64. package/scripts/lib/ai-efficiency-eval.js +207 -0
  65. package/scripts/lib/ai-efficiency-guard-contract.js +209 -0
  66. package/scripts/lib/ai-efficiency-measured-value.js +106 -0
  67. package/scripts/lib/ai-install-prompt.js +293 -0
  68. package/scripts/lib/ai-task-inference.js +155 -0
  69. package/scripts/lib/ai-value-ledger.js +121 -0
  70. package/scripts/lib/ai-value-proof-table.js +151 -0
  71. package/scripts/lib/ai-work-efficiency-routing.js +623 -0
  72. package/scripts/lib/ai-workspace-hygiene.js +1499 -0
  73. package/scripts/lib/alpha-activation.js +520 -0
  74. package/scripts/lib/alpha-feedback.js +263 -0
  75. package/scripts/lib/alpha-readiness-gate.js +332 -0
  76. package/scripts/lib/anti-gaming.js +169 -0
  77. package/scripts/lib/artifact-health.js +431 -0
  78. package/scripts/lib/artifact-receipt-hygiene.js +619 -0
  79. package/scripts/lib/attribution.js +180 -0
  80. package/scripts/lib/audit.js +289 -0
  81. package/scripts/lib/avorelo-skill-registry.js +810 -0
  82. package/scripts/lib/batch-jobs.js +71 -0
  83. package/scripts/lib/brain-pack.js +578 -0
  84. package/scripts/lib/brand-boundary.js +424 -0
  85. package/scripts/lib/brand.js +74 -0
  86. package/scripts/lib/browser-capability.js +1048 -0
  87. package/scripts/lib/browser-proof-governed-workflow.js +1020 -0
  88. package/scripts/lib/browser-proof-preflight.js +321 -0
  89. package/scripts/lib/cache-readiness.js +296 -0
  90. package/scripts/lib/canonical-reentry.js +162 -0
  91. package/scripts/lib/capability-contract-validator.js +177 -0
  92. package/scripts/lib/capability-hygiene.js +504 -0
  93. package/scripts/lib/capability-intake-quarantine.js +789 -0
  94. package/scripts/lib/capability-kernel-registry.js +566 -0
  95. package/scripts/lib/capability-kernel.js +202 -0
  96. package/scripts/lib/capability-manifest.js +255 -0
  97. package/scripts/lib/capability-outcome-normalizer.js +104 -0
  98. package/scripts/lib/capability-packs.js +314 -0
  99. package/scripts/lib/capability-recommender.js +513 -0
  100. package/scripts/lib/capability-registry.js +1062 -0
  101. package/scripts/lib/carry-forward-surfacing.js +194 -0
  102. package/scripts/lib/ccusage-adapter.js +188 -0
  103. package/scripts/lib/claude-session-evidence/index.js +1027 -0
  104. package/scripts/lib/cli-output-sanitizer.js +118 -0
  105. package/scripts/lib/company-loop.js +1149 -0
  106. package/scripts/lib/config.js +641 -0
  107. package/scripts/lib/context-acquisition-plan.js +359 -0
  108. package/scripts/lib/context-authority-rules.js +138 -0
  109. package/scripts/lib/context-budget-guard.js +170 -0
  110. package/scripts/lib/context-budget-scanner.js +257 -0
  111. package/scripts/lib/context-budget.js +167 -0
  112. package/scripts/lib/context-claim-safety.js +116 -0
  113. package/scripts/lib/context-compiler.js +236 -0
  114. package/scripts/lib/context-optimizer.js +715 -0
  115. package/scripts/lib/context-packet.js +121 -0
  116. package/scripts/lib/context-receipt.js +57 -0
  117. package/scripts/lib/context-reduction-plan.js +179 -0
  118. package/scripts/lib/context-safety.js +88 -0
  119. package/scripts/lib/context-savings-engine.js +158 -0
  120. package/scripts/lib/context-source-registry.js +393 -0
  121. package/scripts/lib/context-task-profiles.js +147 -0
  122. package/scripts/lib/cost-abuse-guard.js +975 -0
  123. package/scripts/lib/cost-evidence.js +287 -0
  124. package/scripts/lib/cost-to-outcome-signals.js +639 -0
  125. package/scripts/lib/cross-host-install-plan.js +308 -0
  126. package/scripts/lib/cross-host-install-readiness.js +242 -0
  127. package/scripts/lib/cross-host-value-flow.js +268 -0
  128. package/scripts/lib/dashboard.js +1056 -0
  129. package/scripts/lib/data-permissions-guard.js +1187 -0
  130. package/scripts/lib/deployment-environment-guard.js +1236 -0
  131. package/scripts/lib/design-partner-feedback.js +346 -0
  132. package/scripts/lib/dogfood-evidence-freshness.js +567 -0
  133. package/scripts/lib/efficiency-receipt.js +354 -0
  134. package/scripts/lib/entitlements.js +100 -0
  135. package/scripts/lib/execution-packet.js +559 -0
  136. package/scripts/lib/execution-route-governor.js +179 -0
  137. package/scripts/lib/experimentation-events.js +547 -0
  138. package/scripts/lib/external-capability-compliance.js +107 -0
  139. package/scripts/lib/external-readiness/ai-visibility/ai-visibility-runner.js +322 -0
  140. package/scripts/lib/external-readiness/calibration/benchmark-site-catalog.js +121 -0
  141. package/scripts/lib/external-readiness/calibration/completion-gate.js +112 -0
  142. package/scripts/lib/external-readiness/calibration/real-site-benchmark-runner.js +284 -0
  143. package/scripts/lib/external-readiness/drift-detector.js +100 -0
  144. package/scripts/lib/external-readiness/endpoint-prober.js +332 -0
  145. package/scripts/lib/external-readiness/external-readiness-runner.js +112 -0
  146. package/scripts/lib/external-readiness/full-agent-readiness-scorer.js +220 -0
  147. package/scripts/lib/external-readiness/golden-path-runner.js +333 -0
  148. package/scripts/lib/external-readiness/inside-out-runner.js +118 -0
  149. package/scripts/lib/external-readiness/proof-receipt-writer.js +112 -0
  150. package/scripts/lib/external-readiness/safe-fix-executor.js +117 -0
  151. package/scripts/lib/external-readiness/skills/category-boundary-guard.js +30 -0
  152. package/scripts/lib/external-readiness/skills/pmm-positioning-guard.js +69 -0
  153. package/scripts/lib/external-readiness/skills/safe-fix-policy.js +35 -0
  154. package/scripts/lib/external-user-simulation.js +166 -0
  155. package/scripts/lib/failure-recovery-readiness.js +81 -0
  156. package/scripts/lib/failure-recovery.js +419 -0
  157. package/scripts/lib/feedback-intelligence.js +537 -0
  158. package/scripts/lib/feedback-signals.js +205 -0
  159. package/scripts/lib/file-integrity.js +68 -0
  160. package/scripts/lib/fsx.js +129 -0
  161. package/scripts/lib/full-readiness-gate.js +451 -0
  162. package/scripts/lib/governed-action-exposure-primitives.js +1514 -0
  163. package/scripts/lib/governed-exposure-planner.js +186 -0
  164. package/scripts/lib/governed-workspace-hygiene.js +946 -0
  165. package/scripts/lib/guard-suite-common.js +412 -0
  166. package/scripts/lib/guidance-builder.js +174 -0
  167. package/scripts/lib/hook-apply.js +1075 -0
  168. package/scripts/lib/hook-baseline.js +310 -0
  169. package/scripts/lib/hook-config-preview.js +275 -0
  170. package/scripts/lib/hook-contracts.js +290 -0
  171. package/scripts/lib/hook-safety-boundary-readiness.js +80 -0
  172. package/scripts/lib/host-capability-matrix.js +351 -0
  173. package/scripts/lib/host-support-context.js +254 -0
  174. package/scripts/lib/http-hook-action.js +538 -0
  175. package/scripts/lib/install-ai-readiness.js +84 -0
  176. package/scripts/lib/install-intake-risk.js +1051 -0
  177. package/scripts/lib/install-journey-intelligence.js +329 -0
  178. package/scripts/lib/intervention-guidance.js +57 -0
  179. package/scripts/lib/known-limitations.js +115 -0
  180. package/scripts/lib/l8-path-truth.js +146 -0
  181. package/scripts/lib/launch-hardening-gate.js +436 -0
  182. package/scripts/lib/launch-readiness.js +635 -0
  183. package/scripts/lib/learning-experimentation-foundation.js +1484 -0
  184. package/scripts/lib/learning-memory.js +686 -0
  185. package/scripts/lib/lifecycle-hooks.js +982 -0
  186. package/scripts/lib/local-package-smoke.js +436 -0
  187. package/scripts/lib/local-pricing.js +299 -0
  188. package/scripts/lib/mcp-enforcement.js +311 -0
  189. package/scripts/lib/mcp-least-privilege-policy.js +303 -0
  190. package/scripts/lib/mcp-tool-inventory.js +388 -0
  191. package/scripts/lib/mcp-tool-risk.js +0 -0
  192. package/scripts/lib/memory.js +335 -0
  193. package/scripts/lib/metrics.js +699 -0
  194. package/scripts/lib/micro-proof.js +133 -0
  195. package/scripts/lib/model-work-class-routing.js +79 -0
  196. package/scripts/lib/next-run-context.js +436 -0
  197. package/scripts/lib/next-run-continuity.js +1207 -0
  198. package/scripts/lib/observability-recovery-guard.js +1030 -0
  199. package/scripts/lib/operating-value.js +1662 -0
  200. package/scripts/lib/optimization-v3.js +122 -0
  201. package/scripts/lib/orchestration/adapters/_shared.js +49 -0
  202. package/scripts/lib/orchestration/adapters/aider.js +18 -0
  203. package/scripts/lib/orchestration/adapters/claude-code.js +35 -0
  204. package/scripts/lib/orchestration/adapters/codex.js +35 -0
  205. package/scripts/lib/orchestration/adapters/gemini-cli.js +18 -0
  206. package/scripts/lib/orchestration/adapters/git.js +25 -0
  207. package/scripts/lib/orchestration/adapters/index.js +31 -0
  208. package/scripts/lib/orchestration/adapters/lm-studio.js +18 -0
  209. package/scripts/lib/orchestration/adapters/ollama.js +18 -0
  210. package/scripts/lib/orchestration/adapters/opencode.js +18 -0
  211. package/scripts/lib/orchestration/adapters/openrouter.js +18 -0
  212. package/scripts/lib/orchestration/adapters/test-runner.js +25 -0
  213. package/scripts/lib/orchestration/cli.js +438 -0
  214. package/scripts/lib/orchestration/execution-manager.js +279 -0
  215. package/scripts/lib/orchestration/handoff.js +314 -0
  216. package/scripts/lib/orchestration/index.js +456 -0
  217. package/scripts/lib/orchestration/inventory.js +47 -0
  218. package/scripts/lib/orchestration/model-discovery.js +498 -0
  219. package/scripts/lib/orchestration/model-profiler.js +170 -0
  220. package/scripts/lib/orchestration/model-profiles.js +252 -0
  221. package/scripts/lib/orchestration/model-refresh-policy.js +72 -0
  222. package/scripts/lib/orchestration/proof-writer.js +349 -0
  223. package/scripts/lib/orchestration/provider-discovery/aider.js +49 -0
  224. package/scripts/lib/orchestration/provider-discovery/claude-code.js +56 -0
  225. package/scripts/lib/orchestration/provider-discovery/codex.js +49 -0
  226. package/scripts/lib/orchestration/provider-discovery/common.js +186 -0
  227. package/scripts/lib/orchestration/provider-discovery/gemini.js +106 -0
  228. package/scripts/lib/orchestration/provider-discovery/lm-studio.js +118 -0
  229. package/scripts/lib/orchestration/provider-discovery/models-dev.js +12 -0
  230. package/scripts/lib/orchestration/provider-discovery/ollama.js +100 -0
  231. package/scripts/lib/orchestration/provider-discovery/opencode.js +47 -0
  232. package/scripts/lib/orchestration/provider-discovery/openrouter.js +44 -0
  233. package/scripts/lib/orchestration/risk-classifier.js +130 -0
  234. package/scripts/lib/orchestration/routing-policy.js +486 -0
  235. package/scripts/lib/orchestration/settings.js +95 -0
  236. package/scripts/lib/orchestration/state.js +165 -0
  237. package/scripts/lib/orchestration/verification-manager.js +138 -0
  238. package/scripts/lib/outcome-evidence-stack.js +1083 -0
  239. package/scripts/lib/output-profiles.js +146 -0
  240. package/scripts/lib/package-content-audit.js +368 -0
  241. package/scripts/lib/package-runtime.js +278 -0
  242. package/scripts/lib/plan-surface.js +53 -0
  243. package/scripts/lib/plans.js +2327 -0
  244. package/scripts/lib/policy-provider.js +27 -0
  245. package/scripts/lib/prelaunch-activation-readiness.js +409 -0
  246. package/scripts/lib/prelaunch-evidence-store.js +816 -0
  247. package/scripts/lib/prelaunch-intelligence.js +869 -0
  248. package/scripts/lib/pricing-experiment.js +118 -0
  249. package/scripts/lib/pro-moment-events.js +77 -0
  250. package/scripts/lib/pro-moment-state.js +227 -0
  251. package/scripts/lib/pro-moments.js +1216 -0
  252. package/scripts/lib/product-home-receipt.js +1790 -0
  253. package/scripts/lib/product-learning-events.js +696 -0
  254. package/scripts/lib/production-confidence-control-tower.js +1209 -0
  255. package/scripts/lib/production-confidence.js +1858 -0
  256. package/scripts/lib/project-profile.js +555 -0
  257. package/scripts/lib/prompt-compiler-plan.js +94 -0
  258. package/scripts/lib/prompt-compiler.js +280 -0
  259. package/scripts/lib/prompt-lint.js +32 -0
  260. package/scripts/lib/prompt-suggestions.js +52 -0
  261. package/scripts/lib/proof-canonical.js +398 -0
  262. package/scripts/lib/proof-drilldown.js +383 -0
  263. package/scripts/lib/proof-e2e/promise-completion.js +141 -0
  264. package/scripts/lib/proof-e2e/promise-dashboard-claims.js +135 -0
  265. package/scripts/lib/proof-e2e/promise-local-proof.js +156 -0
  266. package/scripts/lib/proof-e2e/promise-provider-neutral.js +136 -0
  267. package/scripts/lib/proof-e2e/promise-registry.js +219 -0
  268. package/scripts/lib/proof-e2e/promise-security-trust.js +141 -0
  269. package/scripts/lib/proof-e2e/promise-skills-risk.js +163 -0
  270. package/scripts/lib/proof-e2e/promise-token-savings.js +112 -0
  271. package/scripts/lib/proof-e2e/promise-work-management.js +126 -0
  272. package/scripts/lib/proof-events.js +342 -0
  273. package/scripts/lib/proof-history.js +243 -0
  274. package/scripts/lib/proof-metrics.js +296 -0
  275. package/scripts/lib/proof-outcome-evidence.js +134 -0
  276. package/scripts/lib/proof-receipt.js +335 -0
  277. package/scripts/lib/proof-record.js +461 -0
  278. package/scripts/lib/proof-savings-report.js +1549 -0
  279. package/scripts/lib/public-activation-distribution-gate.js +266 -0
  280. package/scripts/lib/public-cli.js +5631 -0
  281. package/scripts/lib/public-distribution-truth.js +211 -0
  282. package/scripts/lib/public-distribution.js +73 -0
  283. package/scripts/lib/public-install-claim-checker.js +300 -0
  284. package/scripts/lib/publish-provenance-readiness.js +287 -0
  285. package/scripts/lib/readiness-delta.js +218 -0
  286. package/scripts/lib/readiness-evidence-closure.js +196 -0
  287. package/scripts/lib/reentry-memory-capture.js +241 -0
  288. package/scripts/lib/reentry-memory-retrieval.js +302 -0
  289. package/scripts/lib/reentry-memory-status.js +147 -0
  290. package/scripts/lib/reentry-memory-store.js +183 -0
  291. package/scripts/lib/reentry-state.js +66 -0
  292. package/scripts/lib/release-candidate-bundle.js +166 -0
  293. package/scripts/lib/remediation.js +81 -0
  294. package/scripts/lib/repo-map.js +391 -0
  295. package/scripts/lib/run-action-policy.js +104 -0
  296. package/scripts/lib/run-contract-receipt.js +48 -0
  297. package/scripts/lib/run-contract.js +288 -0
  298. package/scripts/lib/run-cost-to-verified-outcome.js +87 -0
  299. package/scripts/lib/run-improvements-lifecycle.js +330 -0
  300. package/scripts/lib/run-improvements.js +789 -0
  301. package/scripts/lib/run-proof-contract.js +116 -0
  302. package/scripts/lib/run-risk-classifier.js +131 -0
  303. package/scripts/lib/run-task-classifier.js +216 -0
  304. package/scripts/lib/runtime-decision-policy.js +387 -0
  305. package/scripts/lib/safe-path-engine.js +705 -0
  306. package/scripts/lib/safe-repair.js +877 -0
  307. package/scripts/lib/safe-run-controller.js +887 -0
  308. package/scripts/lib/scope-repair-before-approval.js +865 -0
  309. package/scripts/lib/score.js +262 -0
  310. package/scripts/lib/seamless-enforcement.js +329 -0
  311. package/scripts/lib/seamless-outcome.js +689 -0
  312. package/scripts/lib/seamless-reality-gate.js +5053 -0
  313. package/scripts/lib/security-confidence/activation-safety.js +78 -0
  314. package/scripts/lib/security-confidence/adapters/adapter-contract.js +125 -0
  315. package/scripts/lib/security-confidence/adapters/mock-claude-bughunter-adapter.js +36 -0
  316. package/scripts/lib/security-confidence/adapters/mock-decepticon-adapter.js +34 -0
  317. package/scripts/lib/security-confidence/adapters/mock-mcp-scan-adapter.js +35 -0
  318. package/scripts/lib/security-confidence/adapters/mock-snyk-agent-scan-adapter.js +35 -0
  319. package/scripts/lib/security-confidence/adapters/mock-tank-adapter.js +34 -0
  320. package/scripts/lib/security-confidence/adapters/reference-registry.js +63 -0
  321. package/scripts/lib/security-confidence/auth-rbac-plan.js +39 -0
  322. package/scripts/lib/security-confidence/component-inventory.js +151 -0
  323. package/scripts/lib/security-confidence/constants.js +191 -0
  324. package/scripts/lib/security-confidence/dependency-script-risk.js +95 -0
  325. package/scripts/lib/security-confidence/evidence-hygiene.js +127 -0
  326. package/scripts/lib/security-confidence/feature-impact-classifier.js +80 -0
  327. package/scripts/lib/security-confidence/file-utils.js +161 -0
  328. package/scripts/lib/security-confidence/finding-triage.js +90 -0
  329. package/scripts/lib/security-confidence/findings.js +115 -0
  330. package/scripts/lib/security-confidence/index.js +29 -0
  331. package/scripts/lib/security-confidence/permission-budget.js +93 -0
  332. package/scripts/lib/security-confidence/redaction.js +82 -0
  333. package/scripts/lib/security-confidence/redteam-fixtures.js +53 -0
  334. package/scripts/lib/security-confidence/reference-adoption.js +229 -0
  335. package/scripts/lib/security-confidence/reference-taxonomy.js +155 -0
  336. package/scripts/lib/security-confidence/report-quality.js +99 -0
  337. package/scripts/lib/security-confidence/report-writer.js +79 -0
  338. package/scripts/lib/security-confidence/risk-classifier.js +187 -0
  339. package/scripts/lib/security-confidence/runner.js +179 -0
  340. package/scripts/lib/security-confidence/schema.js +188 -0
  341. package/scripts/lib/security-confidence/secret-safety.js +74 -0
  342. package/scripts/lib/security-confidence/security-capability-router.js +98 -0
  343. package/scripts/lib/security-confidence/web-security-smoke-plan.js +46 -0
  344. package/scripts/lib/security-risk-classifier.js +511 -0
  345. package/scripts/lib/security-scan.js +396 -0
  346. package/scripts/lib/session-context-optimizer.js +1211 -0
  347. package/scripts/lib/session-timing.js +322 -0
  348. package/scripts/lib/skill-hygiene.js +805 -0
  349. package/scripts/lib/skill-packs.js +161 -0
  350. package/scripts/lib/skills-operating-layer-v1.js +1023 -0
  351. package/scripts/lib/skills-operating-layer.js +629 -0
  352. package/scripts/lib/smallest-safe-plan.js +214 -0
  353. package/scripts/lib/smart-routing-plan.js +115 -0
  354. package/scripts/lib/smart-work-routing.js +768 -0
  355. package/scripts/lib/source-catalog.js +1022 -0
  356. package/scripts/lib/status-value-summary.js +32 -0
  357. package/scripts/lib/supply-chain-dependency-guard.js +1333 -0
  358. package/scripts/lib/supply-chain-guard.js +219 -0
  359. package/scripts/lib/support-bundle.js +561 -0
  360. package/scripts/lib/support-redaction.js +66 -0
  361. package/scripts/lib/task-continuation.js +440 -0
  362. package/scripts/lib/test-helpers.js +15 -0
  363. package/scripts/lib/tier.js +38 -0
  364. package/scripts/lib/token-context-quality-gate.js +370 -0
  365. package/scripts/lib/token-cost-capture.js +187 -0
  366. package/scripts/lib/token-cost-evidence.js +862 -0
  367. package/scripts/lib/token-cost-intelligence.js +358 -0
  368. package/scripts/lib/token-efficiency-evidence.js +213 -0
  369. package/scripts/lib/token-efficiency-map.js +110 -0
  370. package/scripts/lib/token-evidence.js +703 -0
  371. package/scripts/lib/tokenish.js +17 -0
  372. package/scripts/lib/tool-output-sandbox.js +559 -0
  373. package/scripts/lib/trust-audit.js +136 -0
  374. package/scripts/lib/unified-events.js +396 -0
  375. package/scripts/lib/upgrade-interruption-recovery.js +407 -0
  376. package/scripts/lib/usage-ledger.js +201 -0
  377. package/scripts/lib/value-ledger.js +130 -0
  378. package/scripts/lib/value-proof-calibration.js +531 -0
  379. package/scripts/lib/visual-qa.js +231 -0
  380. package/scripts/lib/voice-alpha.js +29 -0
  381. package/scripts/lib/webhook-idempotency-guard.js +990 -0
  382. package/scripts/lib/work-aware-orchestration.js +976 -0
  383. package/scripts/lib/work-control-receipts.js +577 -0
  384. package/scripts/lib/work-ledger.js +1123 -0
  385. package/scripts/lib/work-panel-preview.js +352 -0
  386. package/scripts/lib/workflow-discipline.js +280 -0
  387. package/scripts/lib/workflow-intelligence-radar.js +804 -0
  388. package/scripts/lib/workflow-signals.js +419 -0
  389. package/scripts/lib/workspace-map.js +281 -0
  390. package/scripts/lib/workspace-registry.js +1367 -0
  391. package/scripts/lib/workspace-resolver.js +542 -0
  392. package/scripts/wuz-doctor.js +315 -0
  393. package/bin/avorelo.mjs +0 -7
  394. package/dist/avorelo.mjs +0 -24678
@@ -0,0 +1,1020 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const crypto = require("crypto");
6
+
7
+ const { ensureCcoDirs, nowIso, safeReadJson, safeWriteJson } = require("./fsx");
8
+ const {
9
+ buildGovernedActionExposureReport,
10
+ LATEST_REPORT_REL: BOUNDARY_REPORT_REL,
11
+ } = require("./governed-action-exposure-primitives");
12
+ const { buildBrowserCapabilitySurface } = require("./browser-capability");
13
+ const { VISUAL_QA_REPORT_REL_PATH } = require("./visual-qa");
14
+ const { appendProductLearningEvent } = require("./product-learning-events");
15
+
16
+ const CONTRACT = "avorelo.browserProofWorkflow.v1";
17
+ const SCHEMA_VERSION = 1;
18
+ const REPORT_DIR_REL = ".claude/cco/reports/browser-proof";
19
+ const REPORT_JSON_REL = `${REPORT_DIR_REL}/latest-report.json`;
20
+ const RECEIPT_REL = ".claude/cco/evidence/browser-proof/latest-receipt.json";
21
+ const SKILLS_REPORT_REL = ".claude/cco/skills/latest-report.json";
22
+ const WORKSPACE_REPORT_REL = ".claude/cco/orchestration/governed-workspace-hygiene/latest-report.json";
23
+ const LEARNING_REPORT_REL = ".claude/cco/learning-experimentation/latest-report.json";
24
+ const PRODUCTION_CONFIDENCE_REPORT_REL = ".claude/cco/reports/production-confidence/latest-report.json";
25
+ const PROOF_OUTCOME_REL = ".claude/cco/orchestration/seamless-outcome/latest-proof-outcome-evidence.json";
26
+ const DOGFOOD_COMMANDS = Object.freeze([
27
+ "node bin/avorelo support --json",
28
+ "node bin/avorelo support --text",
29
+ "node bin/avorelo outcome-evidence --json",
30
+ "node bin/avorelo outcome-evidence --text",
31
+ "node bin/avorelo workspace-hygiene --json",
32
+ "node bin/avorelo workspace-hygiene --text",
33
+ "node bin/avorelo learning --json",
34
+ "node bin/avorelo learning --text",
35
+ "node bin/avorelo production-confidence --json",
36
+ "node bin/avorelo production-confidence --text",
37
+ "node bin/avorelo skills --json",
38
+ "node bin/avorelo skills --text",
39
+ "node bin/avorelo boundary --json",
40
+ "node bin/avorelo boundary --text",
41
+ "node bin/avorelo browser-proof --json",
42
+ "node bin/avorelo browser-proof --text",
43
+ "node bin/avorelo status --text",
44
+ "node bin/avorelo open --json",
45
+ "node bin/avorelo package-audit --json",
46
+ "node bin/avorelo package-smoke --json",
47
+ "node bin/avorelo install-claims --json",
48
+ "node bin/avorelo public-distribution --json",
49
+ ]);
50
+
51
+ const PRODUCTION_HOST_SUFFIXES = [
52
+ ".vercel.app",
53
+ ".netlify.app",
54
+ ".onrender.com",
55
+ ".railway.app",
56
+ ".herokuapp.com",
57
+ ".fly.dev",
58
+ ".pages.dev",
59
+ ".firebaseapp.com",
60
+ ".web.app",
61
+ ];
62
+
63
+ function stableStringify(value) {
64
+ if (Array.isArray(value)) {
65
+ return `[${value.map((item) => stableStringify(item)).join(",")}]`;
66
+ }
67
+ if (value && typeof value === "object") {
68
+ return `{${Object.keys(value)
69
+ .sort((left, right) => left.localeCompare(right))
70
+ .map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`)
71
+ .join(",")}}`;
72
+ }
73
+ return JSON.stringify(value);
74
+ }
75
+
76
+ function sha256(value) {
77
+ return crypto.createHash("sha256").update(String(value || "")).digest("hex");
78
+ }
79
+
80
+ function hashId(prefix, payload) {
81
+ return `${prefix}-${sha256(stableStringify(payload)).slice(0, 12)}`;
82
+ }
83
+
84
+ function unique(values) {
85
+ return [...new Set((values || []).filter(Boolean))];
86
+ }
87
+
88
+ function sanitizeText(value, maxChars = 180) {
89
+ const text = String(value || "")
90
+ .replace(/\s+/g, " ")
91
+ .replace(/sk-[A-Za-z0-9_-]{16,}/g, "[redacted-openai-key]")
92
+ .replace(/gh[ps]_[A-Za-z0-9]{20,}/g, "[redacted-github-token]")
93
+ .replace(/AKIA[0-9A-Z]{16}/g, "[redacted-aws-key]")
94
+ .replace(/(bearer\s+)[A-Za-z0-9._-]{8,}/ig, "$1[redacted]")
95
+ .trim();
96
+ if (!text) return null;
97
+ if (text.length <= maxChars) return text;
98
+ return `${text.slice(0, maxChars - 3).trimEnd()}...`;
99
+ }
100
+
101
+ function toRelativePath(cwd, value) {
102
+ if (!value) return null;
103
+ const absolute = path.isAbsolute(value) ? value : path.resolve(cwd, value);
104
+ const relative = path.relative(cwd, absolute).replace(/\\/g, "/");
105
+ if (!relative || relative === "") return ".";
106
+ if (relative.startsWith("..") || path.isAbsolute(relative)) return "<outside-repo>";
107
+ return relative;
108
+ }
109
+
110
+ function redactUrl(value) {
111
+ if (!value) return null;
112
+ const raw = String(value || "").trim();
113
+ if (!raw) return null;
114
+ if (raw.startsWith("file://")) {
115
+ return "file://<redacted-local-file>";
116
+ }
117
+ const candidate = /^https?:\/\//i.test(raw) ? raw : `http://${raw}`;
118
+ try {
119
+ const parsed = new URL(candidate);
120
+ if (isLocalHostname(parsed.hostname)) {
121
+ const port = parsed.port ? `:${parsed.port}` : "";
122
+ return `${parsed.protocol}//${parsed.hostname}${port}/<redacted>`;
123
+ }
124
+ return `${parsed.protocol}//${parsed.hostname}/<redacted>`;
125
+ } catch {
126
+ return sanitizeText(raw, 80) || "<redacted-target>";
127
+ }
128
+ }
129
+
130
+ function redactScreenshotPath(relPath) {
131
+ if (!relPath || relPath === "<outside-repo>") return "<redacted-local-screenshot>";
132
+ const normalized = relPath.replace(/\\/g, "/");
133
+ const ext = path.extname(normalized) || ".png";
134
+ const dir = path.posix.dirname(normalized);
135
+ return dir && dir !== "."
136
+ ? `${dir}/<redacted-screenshot>${ext}`
137
+ : `<redacted-screenshot>${ext}`;
138
+ }
139
+
140
+ function isLocalHostname(hostname) {
141
+ const value = String(hostname || "").toLowerCase().replace(/^\[|\]$/g, "");
142
+ return value === "localhost"
143
+ || value === "127.0.0.1"
144
+ || value === "0.0.0.0"
145
+ || value === "::1";
146
+ }
147
+
148
+ function isProductionHostname(hostname) {
149
+ const value = String(hostname || "").toLowerCase();
150
+ if (!value || isLocalHostname(value)) return false;
151
+ if (PRODUCTION_HOST_SUFFIXES.some((suffix) => value.endsWith(suffix))) return true;
152
+ if (/^(prod|production)[.-]/i.test(value)) return true;
153
+ if (/[.-](prod|production)(?:[.-]|$)/i.test(value)) return true;
154
+ return false;
155
+ }
156
+
157
+ function fileUrlToPath(value) {
158
+ const trimmed = String(value || "").trim();
159
+ if (!trimmed.startsWith("file://")) return null;
160
+ try {
161
+ return decodeURIComponent(trimmed.replace(/^file:\/\//i, ""));
162
+ } catch {
163
+ return trimmed.replace(/^file:\/\//i, "");
164
+ }
165
+ }
166
+
167
+ function classifyBrowserTarget(cwd, targetInput) {
168
+ const raw = String(targetInput || "").trim();
169
+ if (!raw) {
170
+ return {
171
+ targetType: "unknown",
172
+ urlRedacted: null,
173
+ sourceTrust: "unknown",
174
+ boundaryDecision: "warn",
175
+ reasonCodes: ["NO_TARGET_PROVIDED"],
176
+ hostname: null,
177
+ localPath: null,
178
+ };
179
+ }
180
+
181
+ const filePathFromUrl = fileUrlToPath(raw);
182
+ if (filePathFromUrl) {
183
+ const localPath = toRelativePath(cwd, filePathFromUrl);
184
+ return {
185
+ targetType: "local_file",
186
+ urlRedacted: "file://<redacted-local-file>",
187
+ sourceTrust: "trusted",
188
+ boundaryDecision: "warn",
189
+ reasonCodes: ["LOCAL_FILE_TARGET"],
190
+ hostname: null,
191
+ localPath,
192
+ };
193
+ }
194
+
195
+ const directLocalPath = (() => {
196
+ const maybePath = path.isAbsolute(raw)
197
+ || raw.startsWith(".")
198
+ || raw.startsWith("/")
199
+ || /^[A-Za-z]:[\\/]/.test(raw);
200
+ if (!maybePath) return null;
201
+ const resolved = path.isAbsolute(raw) ? raw : path.resolve(cwd, raw);
202
+ return fs.existsSync(resolved) ? resolved : null;
203
+ })();
204
+ if (directLocalPath) {
205
+ return {
206
+ targetType: "local_file",
207
+ urlRedacted: "file://<redacted-local-file>",
208
+ sourceTrust: "trusted",
209
+ boundaryDecision: "warn",
210
+ reasonCodes: ["LOCAL_FILE_TARGET"],
211
+ hostname: null,
212
+ localPath: toRelativePath(cwd, directLocalPath),
213
+ };
214
+ }
215
+
216
+ const candidate = /^https?:\/\//i.test(raw)
217
+ ? raw
218
+ : /^(localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\]|::1)(:\d+)?(\/|$)/i.test(raw)
219
+ ? `http://${raw}`
220
+ : raw;
221
+
222
+ try {
223
+ const parsed = new URL(candidate);
224
+ const hostname = String(parsed.hostname || "").toLowerCase();
225
+ if (isLocalHostname(hostname)) {
226
+ return {
227
+ targetType: "localhost",
228
+ urlRedacted: redactUrl(candidate),
229
+ sourceTrust: "trusted",
230
+ boundaryDecision: "warn",
231
+ reasonCodes: ["LOCALHOST_TARGET"],
232
+ hostname,
233
+ localPath: null,
234
+ };
235
+ }
236
+ if (isProductionHostname(hostname)) {
237
+ return {
238
+ targetType: "production_url",
239
+ urlRedacted: redactUrl(candidate),
240
+ sourceTrust: "unknown",
241
+ boundaryDecision: "block",
242
+ reasonCodes: ["PRODUCTION_URL_DETECTED"],
243
+ hostname,
244
+ localPath: null,
245
+ };
246
+ }
247
+ return {
248
+ targetType: "external_url",
249
+ urlRedacted: redactUrl(candidate),
250
+ sourceTrust: "unknown",
251
+ boundaryDecision: "approval_required",
252
+ reasonCodes: ["EXTERNAL_URL_TARGET"],
253
+ hostname,
254
+ localPath: null,
255
+ };
256
+ } catch {
257
+ return {
258
+ targetType: "unknown",
259
+ urlRedacted: sanitizeText(raw, 80) || "<redacted-target>",
260
+ sourceTrust: "unknown",
261
+ boundaryDecision: "warn",
262
+ reasonCodes: ["TARGET_CLASSIFICATION_UNKNOWN"],
263
+ hostname: null,
264
+ localPath: null,
265
+ };
266
+ }
267
+ }
268
+
269
+ function readEvidenceFile(evidenceFile) {
270
+ try {
271
+ if (!evidenceFile) return null;
272
+ const raw = fs.readFileSync(evidenceFile, "utf8").replace(/^\uFEFF/, "");
273
+ return JSON.parse(raw);
274
+ } catch {
275
+ return null;
276
+ }
277
+ }
278
+
279
+ function normalizeEvidence(cwd, options = {}) {
280
+ const fileEvidence = readEvidenceFile(options.evidenceFile);
281
+ const inline = options.evidence && typeof options.evidence === "object" ? options.evidence : {};
282
+ const visualQa = safeReadJson(cwd, VISUAL_QA_REPORT_REL_PATH, null);
283
+ const merged = {
284
+ ...(fileEvidence && typeof fileEvidence === "object" ? fileEvidence : {}),
285
+ ...inline,
286
+ };
287
+
288
+ const target = String(options.target || merged.target || merged.url || visualQa?.target || "").trim() || null;
289
+ const screenshot = merged.screenshot && typeof merged.screenshot === "object"
290
+ ? merged.screenshot
291
+ : visualQa?.screenshotsCaptured
292
+ ? {
293
+ path: visualQa.evidenceStoredAt || null,
294
+ localOnly: true,
295
+ capturedAt: visualQa.generatedAt || null,
296
+ }
297
+ : null;
298
+ const visualHint = merged.visualHint && typeof merged.visualHint === "object"
299
+ ? merged.visualHint
300
+ : visualQa
301
+ ? {
302
+ checked: true,
303
+ pageRendered: visualQa.screenshotsCaptured === true,
304
+ obviousFailure: Array.isArray(visualQa.lookedBrokenOrRisky) && visualQa.lookedBrokenOrRisky.length > 0,
305
+ summary: Array.isArray(visualQa.lookedBrokenOrRisky) && visualQa.lookedBrokenOrRisky.length > 0
306
+ ? visualQa.lookedBrokenOrRisky[0]
307
+ : visualQa.screenshotsCaptured
308
+ ? "Local screenshot-backed visual hint is available."
309
+ : "Visual QA runner metadata exists, but no screenshot proof was captured.",
310
+ }
311
+ : null;
312
+
313
+ return {
314
+ target,
315
+ reachability: merged.reachability && typeof merged.reachability === "object" ? merged.reachability : null,
316
+ dom: merged.dom && typeof merged.dom === "object" ? merged.dom : null,
317
+ console: merged.console && typeof merged.console === "object" ? merged.console : null,
318
+ network: merged.network && typeof merged.network === "object" ? merged.network : null,
319
+ screenshot,
320
+ visualHint,
321
+ workflowIntent: merged.workflowIntent && typeof merged.workflowIntent === "object" ? merged.workflowIntent : {},
322
+ evidenceFileUsed: options.evidenceFile ? toRelativePath(cwd, options.evidenceFile) : null,
323
+ visualQaUsed: visualQa ? VISUAL_QA_REPORT_REL_PATH : null,
324
+ };
325
+ }
326
+
327
+ function detectSkillsBrowserGate(skillsReport) {
328
+ const selected = Array.isArray(skillsReport?.routing?.selected) ? skillsReport.routing.selected : [];
329
+ const phrases = selected.flatMap((item) => [
330
+ item?.id,
331
+ ...(Array.isArray(item?.verificationGates) ? item.verificationGates : []),
332
+ ...(Array.isArray(item?.evidenceRequirements) ? item.evidenceRequirements : []),
333
+ ]).filter(Boolean).join(" \n ");
334
+ const required = /\b(browser|runtime|frontend|ui|dom|console|network|screenshot|visual)\b/i.test(phrases);
335
+ return {
336
+ required,
337
+ reasonCodes: required ? ["SKILL_BROWSER_VERIFICATION_GATE"] : [],
338
+ refs: skillsReport ? [SKILLS_REPORT_REL] : [],
339
+ };
340
+ }
341
+
342
+ function loadIntegrationReports(cwd) {
343
+ return {
344
+ skillsReport: safeReadJson(cwd, SKILLS_REPORT_REL, null),
345
+ workspaceReport: safeReadJson(cwd, WORKSPACE_REPORT_REL, null),
346
+ learningReport: safeReadJson(cwd, LEARNING_REPORT_REL, null),
347
+ productionReport: safeReadJson(cwd, PRODUCTION_CONFIDENCE_REPORT_REL, null),
348
+ boundaryReport: safeReadJson(cwd, BOUNDARY_REPORT_REL, null),
349
+ };
350
+ }
351
+
352
+ function buildBrowserCapabilityRisk(cwd) {
353
+ try {
354
+ const surface = buildBrowserCapabilitySurface(cwd);
355
+ return surface || null;
356
+ } catch {
357
+ return null;
358
+ }
359
+ }
360
+
361
+ function buildBoundaryCandidates(classification, evidence, skillsGate) {
362
+ const baseScope = classification.targetType === "local_file"
363
+ ? {
364
+ paths: classification.localPath ? [classification.localPath] : [],
365
+ visibility: "repo_internal",
366
+ }
367
+ : classification.hostname
368
+ ? {
369
+ domains: [classification.hostname],
370
+ visibility: classification.targetType === "localhost"
371
+ ? "local_only"
372
+ : classification.targetType === "production_url"
373
+ ? "production_deploy"
374
+ : "browser_external",
375
+ }
376
+ : {};
377
+ const sourceTrust = classification.sourceTrust;
378
+ const candidates = [
379
+ {
380
+ id: "browser-reachability",
381
+ actionType: "browser_action",
382
+ browserActionCategory: "page_reachability_check",
383
+ browserTargetType: classification.targetType,
384
+ intent: "Review whether the local page can be reached.",
385
+ sourceTrust,
386
+ requestedScope: baseScope,
387
+ },
388
+ {
389
+ id: "browser-dom",
390
+ actionType: "browser_action",
391
+ browserActionCategory: "dom_presence_check",
392
+ browserTargetType: classification.targetType,
393
+ intent: "Review whether bounded DOM evidence is present.",
394
+ sourceTrust,
395
+ requestedScope: baseScope,
396
+ },
397
+ {
398
+ id: "browser-console",
399
+ actionType: "browser_action",
400
+ browserActionCategory: "console_summary_check",
401
+ browserTargetType: classification.targetType,
402
+ intent: "Review whether bounded browser console evidence is clean.",
403
+ sourceTrust,
404
+ requestedScope: baseScope,
405
+ },
406
+ {
407
+ id: "browser-network",
408
+ actionType: "browser_action",
409
+ browserActionCategory: "network_summary_check",
410
+ browserTargetType: classification.targetType,
411
+ intent: "Review whether bounded local network evidence is clean.",
412
+ sourceTrust,
413
+ requestedScope: baseScope,
414
+ },
415
+ {
416
+ id: "browser-screenshot",
417
+ actionType: "browser_action",
418
+ browserActionCategory: "screenshot_reference",
419
+ browserTargetType: classification.targetType,
420
+ intent: "Review whether a local redacted screenshot reference is safe to include.",
421
+ sourceTrust,
422
+ requestedScope: baseScope,
423
+ },
424
+ {
425
+ id: "browser-visual-hint",
426
+ actionType: "browser_action",
427
+ browserActionCategory: "visual_hint",
428
+ browserTargetType: classification.targetType,
429
+ intent: "Review whether a bounded local visual hint can be included without overclaiming.",
430
+ sourceTrust,
431
+ requestedScope: baseScope,
432
+ },
433
+ ];
434
+
435
+ if (classification.targetType === "external_url") {
436
+ candidates.push({
437
+ id: "browser-external-request",
438
+ actionType: "browser_action",
439
+ browserActionCategory: "external_browse_request",
440
+ browserTargetType: classification.targetType,
441
+ intent: "Model an external browser browse request only.",
442
+ sourceTrust,
443
+ requestedScope: baseScope,
444
+ });
445
+ }
446
+ if (classification.targetType === "production_url") {
447
+ candidates.push({
448
+ id: "browser-production-request",
449
+ actionType: "browser_action",
450
+ browserActionCategory: "production_browse",
451
+ browserTargetType: classification.targetType,
452
+ intent: "Model a production browser request only.",
453
+ sourceTrust,
454
+ requestedScope: baseScope,
455
+ });
456
+ }
457
+ if (evidence.workflowIntent?.credentialFlow === true || evidence.workflowIntent?.loginFlow === true) {
458
+ candidates.push({
459
+ id: "browser-credential-flow",
460
+ actionType: "browser_action",
461
+ browserActionCategory: "credential_flow",
462
+ browserTargetType: classification.targetType,
463
+ intent: "Model a credential or login flow only.",
464
+ sourceTrust,
465
+ requestedScope: baseScope,
466
+ skillBinding: skillsGate.required
467
+ ? { verificationGates: ["Browser verification gate is active."], sourceTrust }
468
+ : undefined,
469
+ });
470
+ }
471
+ if (evidence.workflowIntent?.formSubmit === true) {
472
+ candidates.push({
473
+ id: "browser-form-submit",
474
+ actionType: "browser_action",
475
+ browserActionCategory: "form_submit",
476
+ browserTargetType: classification.targetType,
477
+ intent: "Model a form submit flow only.",
478
+ sourceTrust,
479
+ requestedScope: baseScope,
480
+ });
481
+ }
482
+ return candidates;
483
+ }
484
+
485
+ function strongestDecision(decisions) {
486
+ const order = {
487
+ allow: 0,
488
+ warn: 1,
489
+ auto_limit: 2,
490
+ approval_required: 3,
491
+ block: 4,
492
+ };
493
+ return (decisions || []).reduce((current, next) =>
494
+ order[next] > order[current] ? next : current, "allow");
495
+ }
496
+
497
+ function summarizeTargetDecision(classification, boundaryDecisions) {
498
+ const relevantDecisions = (boundaryDecisions || []).filter((decision) =>
499
+ decision
500
+ && !["browser-screenshot", "browser-visual-hint"].includes(decision.id));
501
+ const strongest = strongestDecision(relevantDecisions.map((decision) => decision.decision));
502
+ if (strongest === "allow" && classification.boundaryDecision && classification.boundaryDecision !== "warn") {
503
+ return classification.boundaryDecision;
504
+ }
505
+ return strongest === "allow"
506
+ ? (classification.targetType === "unknown" ? "warn" : "allow")
507
+ : strongest;
508
+ }
509
+
510
+ function summarizeConsole(consoleEvidence) {
511
+ if (!consoleEvidence || consoleEvidence.checked !== true) {
512
+ return { checked: false, criticalCount: 0, warningCount: 0, headline: "No bounded console summary is available." };
513
+ }
514
+ const criticalCount = Number(consoleEvidence.criticalCount || consoleEvidence.errorCount || 0);
515
+ const warningCount = Number(consoleEvidence.warningCount || 0);
516
+ const headline = criticalCount > 0
517
+ ? `${criticalCount} critical console issue(s) detected.`
518
+ : warningCount > 0
519
+ ? `${warningCount} console warning(s) detected.`
520
+ : "No critical console issues detected.";
521
+ return { checked: true, criticalCount, warningCount, headline };
522
+ }
523
+
524
+ function summarizeNetwork(networkEvidence) {
525
+ if (!networkEvidence || networkEvidence.checked !== true) {
526
+ return { checked: false, criticalCount: 0, warningCount: 0, headline: "No bounded network summary is available." };
527
+ }
528
+ const criticalCount = Number(networkEvidence.criticalCount || networkEvidence.failureCount || 0);
529
+ const warningCount = Number(networkEvidence.warningCount || 0);
530
+ const headline = criticalCount > 0
531
+ ? `${criticalCount} critical network issue(s) detected.`
532
+ : warningCount > 0
533
+ ? `${warningCount} network warning(s) detected.`
534
+ : "No critical network issues detected.";
535
+ return { checked: true, criticalCount, warningCount, headline };
536
+ }
537
+
538
+ function summarizeDom(domEvidence) {
539
+ if (!domEvidence || domEvidence.checked !== true) {
540
+ return { checked: false, selector: null, found: false, headline: "No bounded DOM evidence is available." };
541
+ }
542
+ const selector = sanitizeText(domEvidence.selector || domEvidence.signal || "", 80);
543
+ const found = domEvidence.found === true || domEvidence.present === true;
544
+ const headline = found
545
+ ? selector ? `DOM signal found for ${selector}.` : "DOM signal found."
546
+ : selector ? `DOM signal missing for ${selector}.` : "DOM signal is missing.";
547
+ return { checked: true, selector, found, headline };
548
+ }
549
+
550
+ function buildScreenshotRef(cwd, screenshot) {
551
+ if (!screenshot || !screenshot.path) return null;
552
+ const relPath = toRelativePath(cwd, screenshot.path);
553
+ return {
554
+ pathRef: redactScreenshotPath(relPath),
555
+ localOnly: true,
556
+ capturedAt: sanitizeText(screenshot.capturedAt || null, 60),
557
+ redacted: true,
558
+ };
559
+ }
560
+
561
+ function buildCheck(checkType, state, confidence, evidenceRefs, reasonCodes) {
562
+ return {
563
+ id: hashId("browser-check", { checkType, state, evidenceRefs, reasonCodes }),
564
+ checkType,
565
+ state,
566
+ confidence,
567
+ evidenceRefs: unique(evidenceRefs),
568
+ reasonCodes: unique(reasonCodes),
569
+ redacted: true,
570
+ };
571
+ }
572
+
573
+ function stateFromBoundary(decision) {
574
+ if (decision === "block") return "blocked";
575
+ if (decision === "approval_required") return "approval_required";
576
+ return null;
577
+ }
578
+
579
+ function evaluateReachabilityCheck(classification, evidence, boundaryDecision, evidenceRefs, reasonCodes) {
580
+ const governed = stateFromBoundary(boundaryDecision);
581
+ if (governed) return buildCheck("reachability", governed, "none", evidenceRefs, reasonCodes);
582
+ if (!classification.targetType || classification.targetType === "unknown") {
583
+ return buildCheck("reachability", "not_enough_evidence", "none", evidenceRefs, [...reasonCodes, "TARGET_NOT_RESOLVED"]);
584
+ }
585
+ if (classification.targetType === "local_file") {
586
+ const exists = classification.localPath && classification.localPath !== "<outside-repo>";
587
+ return buildCheck("reachability", exists ? "pass" : "fail", exists ? "high" : "medium", evidenceRefs, [
588
+ ...reasonCodes,
589
+ exists ? "LOCAL_FILE_PRESENT" : "LOCAL_FILE_MISSING",
590
+ ]);
591
+ }
592
+ if (!evidence || evidence.checked !== true) {
593
+ return buildCheck("reachability", "not_enough_evidence", "none", evidenceRefs, [...reasonCodes, "REACHABILITY_NOT_CAPTURED"]);
594
+ }
595
+ if (evidence.reachable === true) {
596
+ return buildCheck("reachability", "pass", "high", evidenceRefs, [...reasonCodes, "TARGET_REACHABLE"]);
597
+ }
598
+ return buildCheck("reachability", "fail", "medium", evidenceRefs, [...reasonCodes, "TARGET_UNREACHABLE"]);
599
+ }
600
+
601
+ function evaluateDomCheck(domSummary, boundaryDecision, evidenceRefs, reasonCodes) {
602
+ const governed = stateFromBoundary(boundaryDecision);
603
+ if (governed) return buildCheck("dom", governed, "none", evidenceRefs, reasonCodes);
604
+ if (!domSummary.checked) {
605
+ return buildCheck("dom", "not_enough_evidence", "none", evidenceRefs, [...reasonCodes, "DOM_EVIDENCE_MISSING"]);
606
+ }
607
+ if (domSummary.found) {
608
+ return buildCheck("dom", "pass", "medium", evidenceRefs, [...reasonCodes, "DOM_SIGNAL_FOUND"]);
609
+ }
610
+ return buildCheck("dom", "warn", "low", evidenceRefs, [...reasonCodes, "DOM_SIGNAL_MISSING"]);
611
+ }
612
+
613
+ function evaluateConsoleCheck(consoleSummary, boundaryDecision, evidenceRefs, reasonCodes) {
614
+ const governed = stateFromBoundary(boundaryDecision);
615
+ if (governed) return buildCheck("console", governed, "none", evidenceRefs, reasonCodes);
616
+ if (!consoleSummary.checked) {
617
+ return buildCheck("console", "not_enough_evidence", "none", evidenceRefs, [...reasonCodes, "CONSOLE_EVIDENCE_MISSING"]);
618
+ }
619
+ if (consoleSummary.criticalCount > 0) {
620
+ return buildCheck("console", "fail", "high", evidenceRefs, [...reasonCodes, "CONSOLE_CRITICAL_ERRORS"]);
621
+ }
622
+ if (consoleSummary.warningCount > 0) {
623
+ return buildCheck("console", "warn", "medium", evidenceRefs, [...reasonCodes, "CONSOLE_WARNINGS_PRESENT"]);
624
+ }
625
+ return buildCheck("console", "pass", "high", evidenceRefs, [...reasonCodes, "CONSOLE_CLEAN"]);
626
+ }
627
+
628
+ function evaluateNetworkCheck(networkSummary, boundaryDecision, evidenceRefs, reasonCodes) {
629
+ const governed = stateFromBoundary(boundaryDecision);
630
+ if (governed) return buildCheck("network", governed, "none", evidenceRefs, reasonCodes);
631
+ if (!networkSummary.checked) {
632
+ return buildCheck("network", "not_enough_evidence", "none", evidenceRefs, [...reasonCodes, "NETWORK_EVIDENCE_MISSING"]);
633
+ }
634
+ if (networkSummary.criticalCount > 0) {
635
+ return buildCheck("network", "fail", "high", evidenceRefs, [...reasonCodes, "NETWORK_CRITICAL_FAILURES"]);
636
+ }
637
+ if (networkSummary.warningCount > 0) {
638
+ return buildCheck("network", "warn", "medium", evidenceRefs, [...reasonCodes, "NETWORK_WARNINGS_PRESENT"]);
639
+ }
640
+ return buildCheck("network", "pass", "high", evidenceRefs, [...reasonCodes, "NETWORK_CLEAN"]);
641
+ }
642
+
643
+ function evaluateScreenshotCheck(screenshotRef, boundaryDecision, evidenceRefs, reasonCodes) {
644
+ const governed = stateFromBoundary(boundaryDecision);
645
+ if (governed) return buildCheck("screenshot", governed, "none", evidenceRefs, reasonCodes);
646
+ if (!screenshotRef) {
647
+ return buildCheck("screenshot", "not_enough_evidence", "none", evidenceRefs, [...reasonCodes, "SCREENSHOT_REFERENCE_MISSING"]);
648
+ }
649
+ return buildCheck("screenshot", "pass", "low", evidenceRefs, [...reasonCodes, "LOCAL_SCREENSHOT_REFERENCE_REDACTED"]);
650
+ }
651
+
652
+ function evaluateVisualHintCheck(visualHint, boundaryDecision, evidenceRefs, reasonCodes) {
653
+ const governed = stateFromBoundary(boundaryDecision);
654
+ if (governed) return buildCheck("visual_hint", governed, "none", evidenceRefs, reasonCodes);
655
+ if (!visualHint || visualHint.checked !== true) {
656
+ return buildCheck("visual_hint", "not_enough_evidence", "none", evidenceRefs, [...reasonCodes, "VISUAL_HINT_MISSING"]);
657
+ }
658
+ if (visualHint.obviousFailure === true) {
659
+ return buildCheck("visual_hint", "warn", "low", evidenceRefs, [...reasonCodes, "VISUAL_HINT_FAILURE"]);
660
+ }
661
+ if (visualHint.pageRendered === true) {
662
+ return buildCheck("visual_hint", "pass", "low", evidenceRefs, [...reasonCodes, "VISUAL_HINT_RENDERED"]);
663
+ }
664
+ return buildCheck("visual_hint", "warn", "low", evidenceRefs, [...reasonCodes, "VISUAL_HINT_NEEDS_REVIEW"]);
665
+ }
666
+
667
+ function buildProofReceipt(cwd, classification, checks, screenshotRef, consoleSummary, networkSummary, domSummary) {
668
+ const receipt = {
669
+ receiptId: hashId("browser-proof-receipt", {
670
+ targetType: classification.targetType,
671
+ checks: checks.map((check) => [check.checkType, check.state, check.reasonCodes]),
672
+ }),
673
+ generatedAt: nowIso(),
674
+ targetType: classification.targetType,
675
+ checksIncluded: checks.map((check) => check.checkType),
676
+ screenshotRef,
677
+ consoleSummary: {
678
+ checked: consoleSummary.checked,
679
+ criticalCount: consoleSummary.criticalCount,
680
+ warningCount: consoleSummary.warningCount,
681
+ headline: consoleSummary.headline,
682
+ },
683
+ networkSummary: {
684
+ checked: networkSummary.checked,
685
+ criticalCount: networkSummary.criticalCount,
686
+ warningCount: networkSummary.warningCount,
687
+ headline: networkSummary.headline,
688
+ },
689
+ domSummary: {
690
+ checked: domSummary.checked,
691
+ selector: domSummary.selector,
692
+ found: domSummary.found,
693
+ headline: domSummary.headline,
694
+ },
695
+ redacted: true,
696
+ };
697
+ safeWriteJson(cwd, RECEIPT_REL, receipt);
698
+ return receipt;
699
+ }
700
+
701
+ function summarizeChecks(cwd, checks, targetType, targetDecision) {
702
+ const counts = {
703
+ allowedChecks: 0,
704
+ approvalRequired: 0,
705
+ blocked: 0,
706
+ proofsCreated: 0,
707
+ consoleIssues: 0,
708
+ networkIssues: 0,
709
+ domIssues: 0,
710
+ screenshotsCaptured: 0,
711
+ };
712
+
713
+ checks.forEach((check) => {
714
+ if (["pass", "warn", "fail", "not_enough_evidence"].includes(check.state)) counts.allowedChecks += 1;
715
+ if (check.state === "approval_required") counts.approvalRequired += 1;
716
+ if (check.state === "blocked") counts.blocked += 1;
717
+ if (check.checkType === "console" && ["warn", "fail"].includes(check.state)) counts.consoleIssues += 1;
718
+ if (check.checkType === "network" && ["warn", "fail"].includes(check.state)) counts.networkIssues += 1;
719
+ if (check.checkType === "dom" && ["warn", "fail", "not_enough_evidence"].includes(check.state)) counts.domIssues += 1;
720
+ if (check.checkType === "screenshot" && check.state === "pass") counts.screenshotsCaptured += 1;
721
+ });
722
+
723
+ counts.proofsCreated = fs.existsSync(path.join(cwd, RECEIPT_REL)) ? 1 : 0;
724
+ const passChecks = checks.filter((check) => check.state === "pass").length;
725
+ const hasIssues = checks.some((check) => ["warn", "fail", "approval_required", "blocked", "not_enough_evidence"].includes(check.state));
726
+ let safeNextAction = "Run `avorelo browser-proof --text` after collecting bounded local browser evidence.";
727
+ if (targetDecision === "block") {
728
+ safeNextAction = "Keep browser work local-only. Production browsing stays blocked in v1.";
729
+ } else if (targetDecision === "approval_required") {
730
+ safeNextAction = "Keep browser work local-first or request explicit approval before external browsing.";
731
+ } else if (checks.some((check) => check.checkType === "console" && check.state === "fail")) {
732
+ safeNextAction = "Fix the client-side console error and rerun `avorelo browser-proof --text`.";
733
+ } else if (checks.some((check) => check.checkType === "network" && check.state === "fail")) {
734
+ safeNextAction = "Fix the failing local network dependency and rerun `avorelo browser-proof --text`.";
735
+ } else if (checks.some((check) => check.checkType === "dom" && ["warn", "not_enough_evidence"].includes(check.state))) {
736
+ safeNextAction = "Capture bounded DOM evidence and rerun `avorelo browser-proof --text`.";
737
+ } else if (!hasIssues && passChecks >= 4) {
738
+ safeNextAction = "Keep the proof receipt linked with the UI change and continue the bounded local workflow.";
739
+ }
740
+
741
+ return {
742
+ browserChecksReviewed: checks.length,
743
+ localTargetsReviewed: ["localhost", "local_file"].includes(targetType) ? 1 : 0,
744
+ ...counts,
745
+ safeNextAction,
746
+ };
747
+ }
748
+
749
+ function computeWorkflowStatus(classification, checks, targetDecision) {
750
+ if (targetDecision === "block") return "fail";
751
+ if (checks.some((check) => check.state === "fail" || check.state === "blocked")) return "fail";
752
+ if (classification.targetType === "unknown") return "warn";
753
+ const required = ["reachability", "dom", "console", "network"];
754
+ const requiredChecks = required.map((type) => checks.find((check) => check.checkType === type)).filter(Boolean);
755
+ const allRequiredPass = requiredChecks.length === required.length
756
+ && requiredChecks.every((check) => check.state === "pass");
757
+ if (allRequiredPass && targetDecision === "allow") return "pass";
758
+ return "warn";
759
+ }
760
+
761
+ function buildIntegrations(cwd, reports, browserCapability) {
762
+ const refs = (relPath) => fs.existsSync(path.join(cwd, relPath)) ? [relPath] : [];
763
+ return {
764
+ boundaryRefs: refs(BOUNDARY_REPORT_REL),
765
+ skillsRefs: reports.skillsReport ? [SKILLS_REPORT_REL] : [],
766
+ productionConfidenceRefs: reports.productionReport ? [PRODUCTION_CONFIDENCE_REPORT_REL] : [],
767
+ workspaceHygieneRefs: unique([
768
+ ...refs(WORKSPACE_REPORT_REL),
769
+ browserCapability?.evidenceArtifact || null,
770
+ ]),
771
+ outcomeEvidenceRefs: unique([
772
+ ...refs(RECEIPT_REL),
773
+ ...refs(PROOF_OUTCOME_REL),
774
+ ]),
775
+ learningRefs: reports.learningReport ? [LEARNING_REPORT_REL] : [],
776
+ };
777
+ }
778
+
779
+ function buildBrowserProofWorkflow(cwd = process.cwd(), options = {}) {
780
+ const reports = loadIntegrationReports(cwd);
781
+ const browserCapability = buildBrowserCapabilityRisk(cwd);
782
+ const evidence = normalizeEvidence(cwd, options);
783
+ const classification = classifyBrowserTarget(cwd, evidence.target);
784
+ const skillsGate = detectSkillsBrowserGate(reports.skillsReport);
785
+ const boundaryCandidates = buildBoundaryCandidates(classification, evidence, skillsGate);
786
+ const boundaryReview = buildGovernedActionExposureReport(cwd, {
787
+ actions: boundaryCandidates,
788
+ exposures: [],
789
+ tools: [],
790
+ integrationOverrides: {
791
+ workspaceReport: reports.workspaceReport,
792
+ learningReport: reports.learningReport,
793
+ productionReport: reports.productionReport,
794
+ skillsReport: reports.skillsReport,
795
+ },
796
+ });
797
+ const decisionsById = new Map(boundaryReview.decisions.map((decision) => [decision.id, decision]));
798
+ const screenshotRef = buildScreenshotRef(cwd, evidence.screenshot);
799
+ const consoleSummary = summarizeConsole(evidence.console);
800
+ const networkSummary = summarizeNetwork(evidence.network);
801
+ const domSummary = summarizeDom(evidence.dom);
802
+
803
+ const evidenceRefs = unique([
804
+ evidence.evidenceFileUsed,
805
+ evidence.visualQaUsed,
806
+ screenshotRef ? RECEIPT_REL : null,
807
+ ]);
808
+ const browserRiskCodes = browserCapability && ["high", "critical"].includes(browserCapability.overallTier)
809
+ ? ["BROWSER_CAPABILITY_REVIEW_RECOMMENDED"]
810
+ : [];
811
+ const skillCodes = skillsGate.reasonCodes;
812
+ const baseReasonCodes = unique([
813
+ ...classification.reasonCodes,
814
+ ...browserRiskCodes,
815
+ ...skillCodes,
816
+ ]);
817
+
818
+ const checks = [
819
+ evaluateReachabilityCheck(classification, evidence.reachability, decisionsById.get("browser-reachability")?.decision || classification.boundaryDecision, evidenceRefs, baseReasonCodes),
820
+ evaluateDomCheck(domSummary, decisionsById.get("browser-dom")?.decision || classification.boundaryDecision, evidenceRefs, baseReasonCodes),
821
+ evaluateConsoleCheck(consoleSummary, decisionsById.get("browser-console")?.decision || classification.boundaryDecision, evidenceRefs, baseReasonCodes),
822
+ evaluateNetworkCheck(networkSummary, decisionsById.get("browser-network")?.decision || classification.boundaryDecision, evidenceRefs, baseReasonCodes),
823
+ evaluateScreenshotCheck(screenshotRef, decisionsById.get("browser-screenshot")?.decision || classification.boundaryDecision, evidenceRefs, baseReasonCodes),
824
+ evaluateVisualHintCheck(evidence.visualHint, decisionsById.get("browser-visual-hint")?.decision || classification.boundaryDecision, evidenceRefs, baseReasonCodes),
825
+ ];
826
+
827
+ const targetDecision = summarizeTargetDecision(classification, boundaryReview.decisions);
828
+ const proof = buildProofReceipt(cwd, classification, checks, screenshotRef, consoleSummary, networkSummary, domSummary);
829
+ const summary = summarizeChecks(cwd, checks, classification.targetType, targetDecision);
830
+
831
+ const report = {
832
+ contract: CONTRACT,
833
+ schemaVersion: SCHEMA_VERSION,
834
+ generatedAt: nowIso(),
835
+ status: computeWorkflowStatus(classification, checks, targetDecision),
836
+ redacted: true,
837
+ summary,
838
+ target: {
839
+ targetType: classification.targetType,
840
+ urlRedacted: classification.urlRedacted,
841
+ sourceTrust: classification.sourceTrust,
842
+ boundaryDecision: targetDecision,
843
+ reasonCodes: unique([
844
+ ...baseReasonCodes,
845
+ ...boundaryReview.decisions.flatMap((decision) => decision.reasonCodes || []),
846
+ ]),
847
+ },
848
+ checks,
849
+ proof: {
850
+ ...proof,
851
+ screenshotRef,
852
+ },
853
+ policy: {
854
+ localOnly: true,
855
+ externalBrowsingDefault: false,
856
+ productionBrowsingDefault: false,
857
+ formSubmissionDefault: false,
858
+ credentialUseDefault: false,
859
+ browserAutomationUnbounded: false,
860
+ providerApis: false,
861
+ upload: false,
862
+ },
863
+ integrations: buildIntegrations(cwd, reports, browserCapability),
864
+ claimSafety: {
865
+ fullQACertified: false,
866
+ productionVerified: false,
867
+ securityGuaranteed: false,
868
+ externalUserJourneyCompleted: false,
869
+ visualRegressionCertified: false,
870
+ },
871
+ dogfood: {
872
+ ranOnAvorelo: safeReadJson(cwd, "package.json", {}).name === "avorelo",
873
+ commands: DOGFOOD_COMMANDS.slice(),
874
+ summary: "Avorelo can convert bounded local browser evidence into a governed proof receipt without browsing external or production targets.",
875
+ },
876
+ };
877
+
878
+ return report;
879
+ }
880
+
881
+ function writeBrowserProofWorkflowReport(cwd, report) {
882
+ ensureCcoDirs(cwd);
883
+ safeWriteJson(cwd, REPORT_JSON_REL, report);
884
+ return { jsonPath: REPORT_JSON_REL, receiptPath: RECEIPT_REL };
885
+ }
886
+
887
+ function generateBrowserProofWorkflow(cwd = process.cwd(), options = {}) {
888
+ const report = buildBrowserProofWorkflow(cwd, options);
889
+ const written = writeBrowserProofWorkflowReport(cwd, report);
890
+ try {
891
+ appendProductLearningEvent(cwd, {
892
+ eventName: "browser_proof_workflow_run",
893
+ category: "browser_proof",
894
+ status: report.status,
895
+ targetType: report.target.targetType,
896
+ boundaryDecision: report.target.boundaryDecision,
897
+ proofsCreated: report.summary.proofsCreated,
898
+ redacted: true,
899
+ });
900
+ } catch {}
901
+ return {
902
+ report,
903
+ written: true,
904
+ jsonPath: written.jsonPath,
905
+ receiptPath: written.receiptPath,
906
+ };
907
+ }
908
+
909
+ function readLatestBrowserProofWorkflowReport(cwd = process.cwd()) {
910
+ return safeReadJson(cwd, REPORT_JSON_REL, null);
911
+ }
912
+
913
+ function summarizeFound(checks) {
914
+ const found = [];
915
+ if (checks.some((check) => check.checkType === "reachability" && check.state === "pass")) found.push("page reachable");
916
+ if (checks.some((check) => check.checkType === "dom" && check.state === "pass")) found.push("DOM signal found");
917
+ if (checks.some((check) => check.checkType === "console" && check.state === "pass")) found.push("console summary clean");
918
+ if (checks.some((check) => check.checkType === "network" && check.state === "pass")) found.push("network summary clean");
919
+ if (checks.some((check) => check.checkType === "screenshot" && check.state === "pass")) found.push("local screenshot reference recorded");
920
+ return found.length > 0 ? found.join(", ") : "no bounded local browser proof yet";
921
+ }
922
+
923
+ function summarizeNeedsAttention(checks, report) {
924
+ const consoleCheck = checks.find((item) => item.checkType === "console");
925
+ if (consoleCheck && ["warn", "fail"].includes(consoleCheck.state)) return "console issue detected";
926
+
927
+ const networkCheck = checks.find((item) => item.checkType === "network");
928
+ if (networkCheck && ["warn", "fail"].includes(networkCheck.state)) return "network issue detected";
929
+
930
+ const domCheck = checks.find((item) => item.checkType === "dom");
931
+ if (domCheck && ["warn", "fail", "not_enough_evidence"].includes(domCheck.state)) {
932
+ return "DOM evidence missing or incomplete";
933
+ }
934
+
935
+ const reachabilityCheck = checks.find((item) => item.checkType === "reachability");
936
+ if (reachabilityCheck && ["warn", "fail", "not_enough_evidence"].includes(reachabilityCheck.state)) {
937
+ return "page reachability still unproven";
938
+ }
939
+
940
+ const visualHintCheck = checks.find((item) => item.checkType === "visual_hint");
941
+ if (visualHintCheck && ["warn", "fail", "not_enough_evidence", "approval_required", "blocked"].includes(visualHintCheck.state)) {
942
+ return "visual hint still needs review";
943
+ }
944
+
945
+ const blockedCheck = checks.find((item) => ["approval_required", "blocked"].includes(item.state));
946
+ if (blockedCheck) {
947
+ return blockedCheck.state === "blocked"
948
+ ? "governed browser action remains blocked"
949
+ : "explicit approval is still required";
950
+ }
951
+
952
+ return report.summary.safeNextAction;
953
+ }
954
+
955
+ function formatBrowserProofWorkflowText(report) {
956
+ return [
957
+ "Avorelo Browser Proof",
958
+ `Status: ${String(report.status || "warn").toUpperCase()}`,
959
+ `Target: ${report.target.targetType}`,
960
+ `Found: ${summarizeFound(report.checks)}`,
961
+ `Needs attention: ${summarizeNeedsAttention(report.checks, report)}`,
962
+ `Proof: ${report.summary.proofsCreated > 0 ? "local receipt created" : "no receipt created"}`,
963
+ `Safe next action: ${report.summary.safeNextAction}`,
964
+ ].join("\n");
965
+ }
966
+
967
+ function buildBrowserProofWorkflowSurface(cwd = process.cwd(), options = {}) {
968
+ const report = readLatestBrowserProofWorkflowReport(cwd)
969
+ || (options.buildIfMissing === true ? buildBrowserProofWorkflow(cwd, options) : null);
970
+ if (!report) {
971
+ return {
972
+ status: "not_run",
973
+ showInStatus: true,
974
+ showInDashboard: true,
975
+ targetType: "unknown",
976
+ proofsCreated: 0,
977
+ browserChecksReviewed: 0,
978
+ approvalRequired: 0,
979
+ blocked: 0,
980
+ nextAction: "Run `avorelo browser-proof --text` to generate the first governed browser proof receipt.",
981
+ latestReportPath: null,
982
+ statusLine: "Browser proof: NOT RUN · run `avorelo browser-proof --text`",
983
+ };
984
+ }
985
+
986
+ const found = summarizeFound(report.checks);
987
+ const needsAttention = summarizeNeedsAttention(report.checks, report);
988
+ const headline = report.status === "pass"
989
+ ? `Browser proof: PASS · ${report.target.targetType} ${found} · proof receipt linked`
990
+ : `Browser proof: ${String(report.status || "warn").toUpperCase()} · ${report.target.targetType} ${found} · next: ${needsAttention}`;
991
+
992
+ return {
993
+ status: report.status,
994
+ showInStatus: true,
995
+ showInDashboard: true,
996
+ targetType: report.target.targetType,
997
+ proofsCreated: report.summary.proofsCreated,
998
+ browserChecksReviewed: report.summary.browserChecksReviewed,
999
+ approvalRequired: report.summary.approvalRequired,
1000
+ blocked: report.summary.blocked,
1001
+ nextAction: report.summary.safeNextAction,
1002
+ latestReportPath: REPORT_JSON_REL,
1003
+ statusLine: headline,
1004
+ };
1005
+ }
1006
+
1007
+ module.exports = {
1008
+ CONTRACT,
1009
+ SCHEMA_VERSION,
1010
+ REPORT_JSON_REL,
1011
+ RECEIPT_REL,
1012
+ DOGFOOD_COMMANDS,
1013
+ classifyBrowserTarget,
1014
+ buildBrowserProofWorkflow,
1015
+ writeBrowserProofWorkflowReport,
1016
+ generateBrowserProofWorkflow,
1017
+ readLatestBrowserProofWorkflowReport,
1018
+ buildBrowserProofWorkflowSurface,
1019
+ formatBrowserProofWorkflowText,
1020
+ };