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,332 @@
1
+ 'use strict';
2
+
3
+ const https = require('https');
4
+ const http = require('http');
5
+
6
+ const DEFAULTS = {
7
+ perProbeTimeoutMs: 2500,
8
+ siteBudgetMs: 35000,
9
+ maxConcurrencyPerHost: 4,
10
+ maxConcurrencyPerSite: 8,
11
+ maxRedirects: 3,
12
+ maxSnippetBytes: 16384,
13
+ };
14
+
15
+ // Probe definitions in priority order
16
+ const MACHINE_READABLE = [
17
+ { key: 'openapi', path: '/openapi.json' },
18
+ { key: 'openapi', path: '/openapi.yaml' },
19
+ { key: 'swagger', path: '/swagger.json' },
20
+ { key: 'llmsTxt', path: '/llms.txt' },
21
+ { key: 'llmsTxtFull', path: '/llms-full.txt' },
22
+ ];
23
+ const HIGH_SIGNAL_DOCS = [
24
+ { key: 'docs', path: '/docs' },
25
+ { key: 'developerDocs', path: '/developers' },
26
+ { key: 'developerDocs', path: '/developer' },
27
+ { key: 'apiDocs', path: '/api' },
28
+ { key: 'apiDocs', path: '/api-reference' },
29
+ { key: 'apiDocs', path: '/api/docs' },
30
+ ];
31
+ const AUTH_PROBES = [
32
+ { key: 'oauthDiscovery', path: '/.well-known/oauth-authorization-server' },
33
+ { key: 'oauth', path: '/oauth' },
34
+ { key: 'authMd', path: '/auth.md' },
35
+ ];
36
+ const LOWER_PRIORITY = [
37
+ { key: 'mcp', path: '/mcp' },
38
+ { key: 'mcpServerCard', path: '/.well-known/mcp/server-card.json' },
39
+ { key: 'agentSkills', path: '/.well-known/agent-skills/index.json' },
40
+ { key: 'apiCatalog', path: '/.well-known/api-catalog' },
41
+ { key: 'swagger', path: '/swagger-ui' },
42
+ ];
43
+
44
+ async function probeEndpoints(baseUrl, opts = {}) {
45
+ const cfg = { ...DEFAULTS, ...opts };
46
+ const relatedDomains = opts.relatedDomains || [];
47
+ const docsCandidates = opts.docsCandidates || [];
48
+ const allBases = [baseUrl, ...relatedDomains];
49
+
50
+ const signals = {};
51
+ const details = {};
52
+ const softFalse = [];
53
+ const blocked = [];
54
+ let timedOut = false;
55
+
56
+ const siteDeadline = Date.now() + cfg.siteBudgetMs;
57
+
58
+ // Build prioritized probe list
59
+ const probes = [];
60
+
61
+ // Priority 1: Exact docs candidates
62
+ for (const url of docsCandidates) {
63
+ const key = url.match(/api|swagger|openapi/i) ? 'apiDocs' : 'developerDocs';
64
+ probes.push({ key, url, priority: 1, isDocsCandidate: true });
65
+ }
66
+
67
+ // Priority 2-4: Standard probes across all base domains
68
+ for (const base of allBases) {
69
+ const b = base.replace(/\/+$/, '');
70
+ for (const p of MACHINE_READABLE) probes.push({ ...p, url: b + p.path, priority: 2 });
71
+ for (const p of HIGH_SIGNAL_DOCS) probes.push({ ...p, url: b + p.path, priority: 3 });
72
+ for (const p of AUTH_PROBES) probes.push({ ...p, url: b + p.path, priority: 3 });
73
+ for (const p of LOWER_PRIORITY) probes.push({ ...p, url: b + p.path, priority: 4 });
74
+ }
75
+
76
+ // Sort by priority
77
+ probes.sort((a, b) => a.priority - b.priority);
78
+
79
+ // Execute with bounded concurrency and site budget
80
+ let strongSignalFound = false;
81
+ const batchSize = cfg.maxConcurrencyPerSite;
82
+
83
+ for (let i = 0; i < probes.length; i += batchSize) {
84
+ if (Date.now() >= siteDeadline) { timedOut = true; break; }
85
+
86
+ // If we found strong docs candidates, skip lower-priority probes
87
+ if (strongSignalFound && probes[i].priority >= 4) break;
88
+
89
+ const batch = probes.slice(i, i + batchSize);
90
+ const remaining = siteDeadline - Date.now();
91
+ if (remaining <= 0) { timedOut = true; break; }
92
+
93
+ const batchTimeout = Math.min(remaining, cfg.perProbeTimeoutMs + 1000);
94
+ const batchResults = await Promise.allSettled(
95
+ batch.map(p => withTimeout(
96
+ probeUrlWithContent(p.url, cfg.perProbeTimeoutMs, cfg.maxSnippetBytes),
97
+ batchTimeout
98
+ ).then(r => ({ ...p, ...r })))
99
+ );
100
+
101
+ const followUpProbes = [];
102
+
103
+ for (const r of batchResults) {
104
+ if (r.status !== 'fulfilled') continue;
105
+ const probe = r.value;
106
+
107
+ if (probe.httpStatus >= 200 && probe.httpStatus < 400) {
108
+ const relevant = validateProbeContent(probe.key, probe.snippet, probe.contentType);
109
+ if (relevant) {
110
+ signals[probe.key] = true;
111
+ if (!details[probe.key]) details[probe.key] = [];
112
+ details[probe.key].push({ path: probe.url, status: probe.httpStatus, strength: relevant, isDocsCandidate: !!probe.isDocsCandidate });
113
+ if (relevant === 'strong' && probe.priority <= 2) strongSignalFound = true;
114
+
115
+ // Follow up to 2 high-signal links discovered in docs content
116
+ if (probe.isDocsCandidate && probe.snippet && followUpProbes.length < 4) {
117
+ const discovered = extractHighSignalLinks(probe.snippet, probe.url);
118
+ for (const link of discovered.slice(0, 2)) {
119
+ followUpProbes.push({ key: 'apiDocs', url: link, priority: 1, isDocsCandidate: true, isFollowUp: true });
120
+ }
121
+ }
122
+ } else {
123
+ // Even non-relevant pages may contain useful links (e.g., 404 pages listing related docs)
124
+ if (probe.isDocsCandidate && probe.snippet && followUpProbes.length < 4) {
125
+ const discovered = extractHighSignalLinks(probe.snippet, probe.url);
126
+ for (const link of discovered.slice(0, 2)) {
127
+ followUpProbes.push({ key: 'apiDocs', url: link, priority: 1, isDocsCandidate: true, isFollowUp: true });
128
+ }
129
+ }
130
+ const isJsShell = detectJsShell(probe.snippet, probe.contentType);
131
+ if (isJsShell) {
132
+ softFalse.push({ key: probe.key, path: probe.url, status: probe.httpStatus, reason: 'JS_RENDER_REQUIRED' });
133
+ } else {
134
+ softFalse.push({ key: probe.key, path: probe.url, status: probe.httpStatus, reason: 'content_not_relevant' });
135
+ }
136
+ }
137
+ } else if (probe.httpStatus === 403 || probe.httpStatus === 401) {
138
+ blocked.push({ key: probe.key, path: probe.url, status: probe.httpStatus, reason: 'blocked' });
139
+ } else if (probe.httpStatus === 999) {
140
+ blocked.push({ key: probe.key, path: probe.url, status: 999, reason: 'timeout' });
141
+ }
142
+ }
143
+
144
+ // Execute follow-up probes from discovered links (max 4, within site budget)
145
+ if (followUpProbes.length > 0 && Date.now() < siteDeadline) {
146
+ const remaining = siteDeadline - Date.now();
147
+ const fuResults = await Promise.allSettled(
148
+ followUpProbes.slice(0, 4).map(p => withTimeout(
149
+ probeUrlWithContent(p.url, cfg.perProbeTimeoutMs, cfg.maxSnippetBytes),
150
+ Math.min(remaining, cfg.perProbeTimeoutMs + 1000)
151
+ ).then(r => ({ ...p, ...r })))
152
+ );
153
+ for (const r of fuResults) {
154
+ if (r.status !== 'fulfilled') continue;
155
+ const probe = r.value;
156
+ if (probe.httpStatus >= 200 && probe.httpStatus < 400) {
157
+ const relevant = validateProbeContent(probe.key, probe.snippet, probe.contentType);
158
+ if (relevant) {
159
+ signals[probe.key] = true;
160
+ if (!details[probe.key]) details[probe.key] = [];
161
+ details[probe.key].push({ path: probe.url, status: probe.httpStatus, strength: relevant, isFollowUp: true });
162
+ }
163
+ }
164
+ }
165
+ }
166
+ }
167
+
168
+ // Score
169
+ let score = 0;
170
+ if (signals.openapi || signals.swagger) score += 25;
171
+ if (signals.apiDocs) score += 10;
172
+ if (signals.apiCatalog) score += 5;
173
+ if (signals.mcp || signals.mcpServerCard) score += 20;
174
+ if (signals.agentSkills) score += 5;
175
+ if (signals.developerDocs || signals.docs) score += 10;
176
+ if (signals.oauth || signals.oauthDiscovery) score += 10;
177
+ if (signals.authMd) score += 5;
178
+ if (signals.llmsTxt) score += 5;
179
+ if (signals.llmsTxtFull) score += 2;
180
+ score = Math.min(100, score);
181
+
182
+ const hasAnySignal = Object.values(signals).some(v => v);
183
+ const jsRenderRequired = softFalse.some(sf => sf.reason === 'JS_RENDER_REQUIRED');
184
+
185
+ let evidenceStatus = 'scored';
186
+ if (timedOut) evidenceStatus = 'timeout';
187
+ else if (!hasAnySignal && blocked.length > 5) evidenceStatus = 'evidence_unavailable';
188
+ else if (!hasAnySignal && jsRenderRequired) evidenceStatus = 'js_render_required';
189
+ else if (!hasAnySignal && blocked.length > 0) evidenceStatus = 'partial_evidence';
190
+
191
+ return { score, signals, details, softFalse, blocked, evidenceStatus, timedOut, jsRenderRequired, probeCount: probes.length, blockedCount: blocked.length };
192
+ }
193
+
194
+ function detectJsShell(snippet, contentType) {
195
+ if (!snippet || !contentType) return false;
196
+ if (!contentType.includes('html')) return false;
197
+ const s = snippet.toLowerCase();
198
+ // JS shell: has <script> but very little text content, or has __NEXT_DATA__ / react-root / app-root
199
+ const textContent = s.replace(/<[^>]*>/g, '').replace(/\s+/g, ' ').trim();
200
+ const hasScripts = (s.match(/<script/g) || []).length;
201
+ const hasReactRoot = s.includes('__next') || s.includes('react-root') || s.includes('id="app"') || s.includes('id="root"');
202
+ if (hasScripts >= 2 && textContent.length < 200 && hasReactRoot) return true;
203
+ if (hasScripts >= 3 && textContent.length < 100) return true;
204
+ return false;
205
+ }
206
+
207
+ function validateProbeContent(key, snippet, contentType) {
208
+ if (!snippet || snippet.length < 5) return false;
209
+ const s = snippet.toLowerCase();
210
+ const ct = (contentType || '').toLowerCase();
211
+
212
+ switch (key) {
213
+ case 'openapi':
214
+ if (ct.includes('json') || ct.includes('yaml')) return (s.includes('"openapi"') || s.includes('"swagger"') || s.includes('"paths"') || s.includes('openapi:')) ? 'strong' : false;
215
+ return false;
216
+ case 'swagger':
217
+ if (ct.includes('json')) return s.includes('"swagger"') || s.includes('"paths"') ? 'strong' : false;
218
+ if (ct.includes('html')) return s.includes('swagger-ui') ? 'present' : false;
219
+ return false;
220
+ case 'apiDocs': {
221
+ const apiTerms = ['endpoint', 'api reference', 'authentication', 'request', 'response', 'sdk', 'webhook', 'rate limit', 'api key', 'curl', 'authorization', 'openapi', 'rest api'];
222
+ if (ct.includes('html') || ct.includes('markdown')) {
223
+ const hits = apiTerms.filter(t => s.includes(t)).length;
224
+ return hits >= 2 ? 'strong' : hits >= 1 ? 'present' : false;
225
+ }
226
+ if (ct.includes('json')) return s.includes('"endpoint') || s.includes('"paths"') ? 'strong' : false;
227
+ return false;
228
+ }
229
+ case 'apiCatalog':
230
+ if (ct.includes('json')) return s.includes('"apis"') ? 'strong' : false;
231
+ return false;
232
+ case 'mcp': case 'mcpServerCard':
233
+ if (ct.includes('json')) return (s.includes('"tools"') || s.includes('"resources"') || s.includes('"capabilities"')) ? 'strong' : false;
234
+ if (ct.includes('html')) return s.includes('model context protocol') || s.includes('mcp server') ? 'present' : false;
235
+ return false;
236
+ case 'agentSkills':
237
+ if (ct.includes('json')) return s.includes('"skills"') || s.includes('"actions"') ? 'strong' : false;
238
+ return false;
239
+ case 'developerDocs': case 'docs':
240
+ if (ct.includes('html') || ct.includes('markdown')) {
241
+ const terms = ['documentation', 'guide', 'reference', 'api', 'sdk', 'getting started', 'quickstart', 'install', 'authentication', 'endpoint', 'example', 'webhook', 'cli'];
242
+ const hits = terms.filter(t => s.includes(t)).length;
243
+ return hits >= 3 ? 'strong' : hits >= 1 ? 'present' : false;
244
+ }
245
+ return false;
246
+ case 'oauth': case 'oauthDiscovery':
247
+ if (ct.includes('json')) return (s.includes('authorization_endpoint') || s.includes('token_endpoint')) ? 'strong' : false;
248
+ if (ct.includes('html')) return (s.includes('oauth') || s.includes('authorize') || s.includes('client_id')) ? 'present' : false;
249
+ return false;
250
+ case 'authMd':
251
+ if (ct.includes('text') || ct.includes('markdown')) return (s.includes('auth') && s.length > 100) ? 'strong' : false;
252
+ if (ct.includes('html')) return false;
253
+ return false;
254
+ case 'llmsTxt': case 'llmsTxtFull':
255
+ if (ct.includes('html')) return false;
256
+ const lines = snippet.split('\n').filter(l => l.trim().length > 0);
257
+ return lines.length >= 3 ? 'strong' : lines.length >= 1 ? 'present' : false;
258
+ default:
259
+ return snippet.length > 50 ? 'present' : false;
260
+ }
261
+ }
262
+
263
+ function probeUrlWithContent(url, timeoutMs, maxBytes) {
264
+ return new Promise((resolve) => {
265
+ const mod = url.startsWith('https') ? https : http;
266
+ const req = mod.get(url, {
267
+ timeout: timeoutMs,
268
+ headers: { 'User-Agent': 'AvoreloBotReadinessCheck/1.0 (+https://avorelo.com/tools/agent-readiness)' },
269
+ }, (res) => {
270
+ // Follow redirects (max 3)
271
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
272
+ res.resume();
273
+ resolve({ httpStatus: res.statusCode, contentType: '', snippet: '', redirectedTo: res.headers.location });
274
+ return;
275
+ }
276
+ const contentType = res.headers['content-type'] || '';
277
+ let body = '';
278
+ let bytes = 0;
279
+ res.on('data', (chunk) => {
280
+ if (bytes < maxBytes) { body += chunk.toString('utf8').slice(0, maxBytes - bytes); bytes += chunk.length; }
281
+ if (bytes >= maxBytes) res.destroy();
282
+ });
283
+ res.on('end', () => resolve({ httpStatus: res.statusCode, contentType, snippet: body }));
284
+ res.on('error', () => resolve({ httpStatus: res.statusCode, contentType, snippet: body }));
285
+ });
286
+ req.on('error', () => resolve({ httpStatus: 999, contentType: '', snippet: '' }));
287
+ req.on('timeout', () => { req.destroy(); resolve({ httpStatus: 999, contentType: '', snippet: '' }); });
288
+ });
289
+ }
290
+
291
+ function extractHighSignalLinks(snippet, sourceUrl) {
292
+ const links = [];
293
+ const lower = snippet.toLowerCase();
294
+
295
+ // Extract absolute URLs that look like API/docs content
296
+ const absMatches = snippet.match(/https?:\/\/[^\s"'<>)]+/g) || [];
297
+ for (const l of absMatches) {
298
+ if (l.match(/rest-api|api-reference|openapi|swagger|authentication|webhook|endpoint/i) && !links.includes(l)) {
299
+ links.push(l);
300
+ }
301
+ }
302
+
303
+ // Extract relative links (markdown-style or bare paths) and make absolute
304
+ let baseUrl;
305
+ try { baseUrl = new URL(sourceUrl); } catch { return links; }
306
+ const relPatterns = [
307
+ /\(\/[^\s"'<>)]+\.md\)/g,
308
+ /\(\/docs\/[^\s"'<>)]+\)/g,
309
+ /href="(\/[^"]+)"/g,
310
+ ];
311
+ for (const pattern of relPatterns) {
312
+ const matches = snippet.matchAll(pattern);
313
+ for (const m of matches) {
314
+ const path = (m[1] || m[0]).replace(/[()]/g, '');
315
+ if (path.match(/rest-api|api-reference|authentication|webhook|endpoint/i)) {
316
+ const absUrl = baseUrl.origin + path;
317
+ if (!links.includes(absUrl)) links.push(absUrl);
318
+ }
319
+ }
320
+ }
321
+
322
+ return links.slice(0, 4);
323
+ }
324
+
325
+ function withTimeout(promise, ms) {
326
+ return Promise.race([
327
+ promise,
328
+ new Promise(resolve => setTimeout(() => resolve({ httpStatus: 999, contentType: '', snippet: '' }), ms)),
329
+ ]);
330
+ }
331
+
332
+ module.exports = { probeEndpoints, validateProbeContent, detectJsShell };
@@ -0,0 +1,112 @@
1
+ 'use strict';
2
+
3
+ const https = require('https');
4
+ const http = require('http');
5
+ const { URL } = require('url');
6
+
7
+ const PRIVATE_RANGES = [
8
+ /^10\./, /^172\.(1[6-9]|2\d|3[01])\./, /^192\.168\./, /^127\./,
9
+ /^0\./, /^169\.254\./, /^fc00:/i, /^fd/i, /^fe80:/i, /^::1$/,
10
+ ];
11
+
12
+ function isPrivateIP(hostname) {
13
+ return PRIVATE_RANGES.some(re => re.test(hostname));
14
+ }
15
+
16
+ function normalizeUrl(raw) {
17
+ const trimmed = (raw || '').trim();
18
+ if (!trimmed) return { ok: false, error: 'URL is required.' };
19
+ let withProto = trimmed;
20
+ if (!/^https?:\/\//i.test(withProto)) withProto = 'https://' + withProto;
21
+ let parsed;
22
+ try { parsed = new URL(withProto); } catch { return { ok: false, error: 'Invalid URL.' }; }
23
+ if (!['http:', 'https:'].includes(parsed.protocol)) return { ok: false, error: 'Only http/https supported.' };
24
+ if (['localhost', '127.0.0.1', '::1'].includes(parsed.hostname)) {
25
+ return { ok: false, error: 'Localhost not allowed in public mode.' };
26
+ }
27
+ if (isPrivateIP(parsed.hostname)) return { ok: false, error: 'Private IPs not allowed.' };
28
+ return { ok: true, url: parsed.origin + parsed.pathname.replace(/\/+$/, '') };
29
+ }
30
+
31
+ function fetchUrl(url, timeoutMs = 15000) {
32
+ return new Promise((resolve, reject) => {
33
+ const mod = url.startsWith('https') ? https : http;
34
+ const req = mod.get(url, { headers: { 'User-Agent': 'AvoreloBotReadinessCheck/1.0' }, timeout: timeoutMs }, (res) => {
35
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
36
+ return fetchUrl(res.headers.location, timeoutMs).then(resolve, reject);
37
+ }
38
+ let body = '';
39
+ res.on('data', chunk => { body += chunk; if (body.length > 2_000_000) req.destroy(); });
40
+ res.on('end', () => resolve({ status: res.statusCode, headers: res.headers, body }));
41
+ });
42
+ req.on('error', reject);
43
+ req.on('timeout', () => { req.destroy(); reject(new Error('Timeout')); });
44
+ });
45
+ }
46
+
47
+ async function runReadiness(rawUrl, opts = {}) {
48
+ const norm = normalizeUrl(rawUrl);
49
+ if (!norm.ok) return { url: rawUrl, error: norm.error, findings: [], score: 0 };
50
+
51
+ const url = norm.url;
52
+ const findings = [];
53
+ const errors = [];
54
+
55
+ let html = '', headers = {};
56
+ try {
57
+ const page = await fetchUrl(url);
58
+ html = page.body;
59
+ headers = page.headers || {};
60
+ if (page.status >= 400) errors.push(`HTTP ${page.status}`);
61
+ } catch (err) {
62
+ return { url, error: err.message, findings: [], score: 0, errors: [err.message] };
63
+ }
64
+
65
+ // Metadata
66
+ const title = (html.match(/<title[^>]*>([\s\S]*?)<\/title>/i) || [])[1];
67
+ if (!title) findings.push({ id: 'meta-no-title', severity: 'blocking', title: 'Missing page title' });
68
+ const desc = html.match(/<meta\s+name=["']description["']\s+content=["']([^"']*)["']/i);
69
+ if (!desc) findings.push({ id: 'meta-no-description', severity: 'important', title: 'Missing meta description' });
70
+ if (!html.match(/<link[^>]*rel=["']canonical["']/i)) findings.push({ id: 'meta-no-canonical', severity: 'advisory', title: 'Missing canonical URL' });
71
+
72
+ // OG
73
+ if (!html.match(/<meta\s+property=["']og:title["']/i)) findings.push({ id: 'meta-no-og-title', severity: 'advisory', title: 'Missing og:title' });
74
+
75
+ // Schema
76
+ if (!html.match(/<script\s+type=["']application\/ld\+json["']/i)) {
77
+ findings.push({ id: 'schema-no-jsonld', severity: 'important', title: 'No JSON-LD structured data' });
78
+ }
79
+
80
+ // Robots/sitemap/llms with content snippets
81
+ const contentSnippets = { robotsTxt: null, sitemapXml: null, llmsTxt: null };
82
+ try {
83
+ const r = await fetchUrl(url + '/robots.txt', 8000);
84
+ if (r.status >= 400) findings.push({ id: 'crawl-no-robots', severity: 'advisory', title: 'No robots.txt' });
85
+ else contentSnippets.robotsTxt = r.body.slice(0, 8000);
86
+ } catch { findings.push({ id: 'crawl-no-robots', severity: 'advisory', title: 'No robots.txt' }); }
87
+
88
+ try {
89
+ const s = await fetchUrl(url + '/sitemap.xml', 8000);
90
+ if (s.status >= 400) findings.push({ id: 'crawl-no-sitemap', severity: 'advisory', title: 'No sitemap.xml' });
91
+ else contentSnippets.sitemapXml = s.body.slice(0, 8000);
92
+ } catch { findings.push({ id: 'crawl-no-sitemap', severity: 'advisory', title: 'No sitemap.xml' }); }
93
+
94
+ try {
95
+ const l = await fetchUrl(url + '/llms.txt', 8000);
96
+ if (l.status >= 400) findings.push({ id: 'docs-no-llms-txt', severity: 'advisory', title: 'No llms.txt' });
97
+ else contentSnippets.llmsTxt = l.body.slice(0, 8000);
98
+ } catch { findings.push({ id: 'docs-no-llms-txt', severity: 'advisory', title: 'No llms.txt' }); }
99
+
100
+ // Security headers
101
+ if (!headers['strict-transport-security']) findings.push({ id: 'sec-no-hsts', severity: 'important', title: 'Missing HSTS header' });
102
+ if (!headers['x-content-type-options']) findings.push({ id: 'sec-no-xcto', severity: 'advisory', title: 'Missing X-Content-Type-Options' });
103
+
104
+ const blocking = findings.filter(f => f.severity === 'blocking').length;
105
+ const important = findings.filter(f => f.severity === 'important').length;
106
+ const advisory = findings.filter(f => f.severity === 'advisory').length;
107
+ const score = Math.max(0, 100 - blocking * 25 - important * 10 - advisory * 3);
108
+
109
+ return { url, scannedAt: new Date().toISOString(), score, findings, errors, html, headers, contentSnippets };
110
+ }
111
+
112
+ module.exports = { runReadiness, normalizeUrl };
@@ -0,0 +1,220 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ /**
7
+ * Full Agent Readiness: evidence-based, capped.
8
+ * No subscore can be 100 without measured evidence.
9
+ * Missing API/MCP/tool docs = cannot be strong.
10
+ * Missing runtime verification = handoff/UX capped.
11
+ * Missing live visibility = AI Visibility must be evidence-readiness only.
12
+ */
13
+
14
+ // Weights calibrated against Ora layers (Discovery 20, Identity 20, Auth 30, Integration 20, UX 10)
15
+ // Avorelo adds AEO evidence and manual visibility as separate surfaces
16
+ const SURFACES = [
17
+ { id: 'discovery', label: 'Discovery', weight: 12, check: checkDiscovery },
18
+ { id: 'identity', label: 'Identity clarity', weight: 8, check: checkIdentity },
19
+ { id: 'auth', label: 'Auth & Access', weight: 15, check: checkAuth },
20
+ { id: 'agent_integration', label: 'Agent Integration (API/MCP)', weight: 22, check: checkAgentIntegration },
21
+ { id: 'agent_ux', label: 'Agent-Friendly UX', weight: 8, check: checkAgentUX },
22
+ { id: 'handoff', label: 'Handoff', weight: 7, check: checkHandoff },
23
+ { id: 'aeo_evidence', label: 'AI Visibility Readiness Signals', weight: 10, check: checkAeoEvidence },
24
+ { id: 'manual_visibility', label: 'Manual-Live Visibility', weight: 3, check: checkManualVisibility },
25
+ ];
26
+
27
+ function scoreFullAgentReadiness(opts) {
28
+ const { html, headers, repoRoot, aeoEvidence, manualVisibility, externalImport, runtimeVerified, endpointProbe } = opts;
29
+ const results = [];
30
+ const findings = [];
31
+
32
+ for (const surface of SURFACES) {
33
+ const r = surface.check({ html, headers, repoRoot, aeoEvidence, manualVisibility, externalImport, runtimeVerified, endpointProbe });
34
+ results.push({ id: surface.id, label: surface.label, weight: surface.weight, score: r.score, evidenceBasis: r.evidenceBasis || 'estimated', ...r });
35
+ findings.push(...(r.findings || []));
36
+ }
37
+
38
+ const totalWeight = SURFACES.reduce((s, a) => s + a.weight, 0);
39
+ const scored = results.reduce((s, r) => s + (r.score / 100) * r.weight, 0);
40
+ const overall = Math.round((scored / totalWeight) * 100);
41
+ const level = overall >= 85 ? 'strong' : overall >= 65 ? 'good' : overall >= 40 ? 'needs work' : 'low';
42
+
43
+ return { overall, level, surfaces: results, findings };
44
+ }
45
+
46
+ function checkDiscovery({ html, aeoEvidence, manualVisibility }) {
47
+ const findings = [];
48
+ let score = 0;
49
+ let basis = 'estimated';
50
+
51
+ // Primary: AEO evidence readiness (deterministic)
52
+ if (aeoEvidence) {
53
+ score = Math.min(80, aeoEvidence.overall); // Capped at 80 without live evidence
54
+ basis = 'measured';
55
+ }
56
+
57
+ // Boost with manual-live data
58
+ if (manualVisibility?.measured) {
59
+ const mentionBoost = Math.min(20, Math.round(manualVisibility.summary.mentionRate / 5));
60
+ score = Math.min(100, score + mentionBoost);
61
+ basis = 'measured';
62
+ }
63
+
64
+ if (score < 30) {
65
+ findings.push({ id: 'far-low-discovery', category: 'full_agent_readiness', severity: 'blocking', confidence: basis, title: `Discovery weak (${score}/100)`, detail: 'AI systems may not find or recommend this product.', autoFixEligible: false, requiresApproval: false });
66
+ }
67
+
68
+ return { score, evidenceBasis: basis, findings };
69
+ }
70
+
71
+ function checkIdentity({ html }) {
72
+ let score = 0;
73
+ const findings = [];
74
+ const h = html || '';
75
+
76
+ if (h.match(/<title[^>]*>.{10,}<\/title>/i)) score += 25;
77
+ if (h.match(/<meta\s+name=["']description["']/i)) score += 20;
78
+ if (h.match(/application\/ld\+json/i)) score += 25;
79
+ if (h.match(/og:title/i) && h.match(/og:description/i)) score += 20;
80
+ // Cap: never 100 without measured evidence of what AI engines actually see
81
+ score = Math.min(90, score);
82
+
83
+ if (score < 50) {
84
+ findings.push({ id: 'far-weak-identity', category: 'full_agent_readiness', severity: 'important', title: 'Product identity not clear enough for agents', autoFixEligible: false, requiresApproval: false });
85
+ }
86
+ return { score, evidenceBasis: 'measured', findings };
87
+ }
88
+
89
+ function checkAuth({ html, repoRoot, endpointProbe }) {
90
+ let score = 0;
91
+ const findings = [];
92
+ const h = html || '';
93
+
94
+ // Basic auth surface from HTML
95
+ if (h.match(/login|sign.?in|sign.?up/i)) score += 15;
96
+ if (h.match(/google|github|discord|slack/i)) score += 10;
97
+
98
+ // Endpoint probe signals (much more valuable)
99
+ if (endpointProbe) {
100
+ if (endpointProbe.signals.oauth || endpointProbe.signals.oauthDiscovery) score += 25;
101
+ if (endpointProbe.signals.authMd) score += 20;
102
+ }
103
+
104
+ // Local source check
105
+ if (repoRoot && fs.existsSync(path.join(repoRoot, 'src', 'auth'))) score += 10;
106
+
107
+ if (score < 25) {
108
+ findings.push({ id: 'far-weak-auth', category: 'full_agent_readiness', severity: 'important', title: 'No agent-accessible auth surface', detail: 'No OAuth discovery, auth.md, or documented auth flow for agents.', autoFixEligible: false, requiresApproval: true });
109
+ }
110
+
111
+ score = Math.min(90, score);
112
+ return { score, evidenceBasis: endpointProbe ? 'measured' : 'estimated', findings };
113
+ }
114
+
115
+ function checkAgentIntegration({ html, repoRoot, endpointProbe }) {
116
+ let score = 0;
117
+ const findings = [];
118
+ const h = html || '';
119
+
120
+ let hasOpenAPI = false;
121
+ let hasMCP = false;
122
+ let hasDocs = false;
123
+
124
+ // Primary: use endpoint probe data (real HTTP probes)
125
+ if (endpointProbe) {
126
+ if (endpointProbe.signals.openapi || endpointProbe.signals.swagger) { score += 30; hasOpenAPI = true; }
127
+ if (endpointProbe.signals.apiDocs) { score += 10; hasDocs = true; }
128
+ if (endpointProbe.signals.mcp || endpointProbe.signals.mcpWellKnown) { score += 25; hasMCP = true; }
129
+ if (endpointProbe.signals.developerDocs || endpointProbe.signals.docs) { score += 10; hasDocs = true; }
130
+ if (endpointProbe.signals.oauth || endpointProbe.signals.oauthDocs) score += 10;
131
+ if (endpointProbe.signals.llmsTxt) score += 5;
132
+ } else {
133
+ // Fallback: HTML inspection + local file checks
134
+ if (h.match(/openapi|swagger|\/api\/docs/i)) { score += 20; hasOpenAPI = true; }
135
+ if (h.match(/mcp|model.context.protocol/i)) { score += 15; hasMCP = true; }
136
+ if (h.match(/sdk|npm install|npx/i)) score += 10;
137
+ }
138
+
139
+ // Local file checks
140
+ if (repoRoot) {
141
+ for (const c of ['openapi.json', 'openapi.yaml', 'swagger.json']) {
142
+ if (fs.existsSync(path.join(repoRoot, c))) { score += 10; hasOpenAPI = true; break; }
143
+ }
144
+ for (const c of ['mcp.json', '.mcp', 'docs/mcp']) {
145
+ if (fs.existsSync(path.join(repoRoot, c))) { score += 5; hasMCP = true; break; }
146
+ }
147
+ if (fs.existsSync(path.join(repoRoot, 'docs', 'INSTALL.md'))) score += 5;
148
+ }
149
+
150
+ if (!hasOpenAPI) {
151
+ findings.push({ id: 'far-no-openapi', category: 'full_agent_readiness', severity: 'important', title: 'No public API / OpenAPI spec', detail: 'Agents cannot discover or use APIs without documentation.', autoFixEligible: false, requiresApproval: true });
152
+ }
153
+ if (!hasMCP) {
154
+ findings.push({ id: 'far-no-mcp', category: 'full_agent_readiness', severity: 'important', title: 'No MCP readiness visible', detail: 'Agents using MCP cannot discover this product as a tool server.', autoFixEligible: false, requiresApproval: true });
155
+ }
156
+
157
+ // Hard cap: without API and MCP, max 25
158
+ if (!hasOpenAPI && !hasMCP) score = Math.min(score, 25);
159
+ // Without either: max 50
160
+ else if (!hasOpenAPI || !hasMCP) score = Math.min(score, 50);
161
+
162
+ return { score: Math.min(90, score), evidenceBasis: endpointProbe ? 'measured' : 'estimated', findings };
163
+ }
164
+
165
+ function checkAgentUX({ html, runtimeVerified }) {
166
+ let score = 0;
167
+ const findings = [];
168
+ const h = html || '';
169
+
170
+ if (h.match(/<button/i)) score += 20;
171
+ if (h.match(/<a\s+href/i)) score += 20;
172
+ if (h.match(/aria-label/i)) score += 20;
173
+ if (h.match(/npx|npm install/i)) score += 20;
174
+
175
+ // Cap without runtime verification
176
+ if (!runtimeVerified) {
177
+ score = Math.min(70, score);
178
+ findings.push({ id: 'far-ux-not-runtime-verified', category: 'full_agent_readiness', severity: 'advisory', confidence: 'estimated', title: 'Agent UX not runtime-verified', detail: 'Run Wasp/browser to verify the full interaction flow.', autoFixEligible: false, requiresApproval: false });
179
+ }
180
+
181
+ return { score: Math.min(90, score), evidenceBasis: runtimeVerified ? 'measured' : 'estimated', findings };
182
+ }
183
+
184
+ function checkHandoff({ html, runtimeVerified }) {
185
+ let score = 0;
186
+ const findings = [];
187
+ const h = html || '';
188
+
189
+ if (h.match(/<title/i) && h.match(/<meta\s+name=["']description["']/i)) score += 20;
190
+ if (h.match(/application\/ld\+json/i)) score += 20;
191
+ if (h.match(/npx|npm install/i)) score += 20;
192
+ if (h.match(/login|sign.?up/i)) score += 20;
193
+ if (h.match(/api|docs|sdk/i)) score += 20;
194
+
195
+ if (!runtimeVerified) score = Math.min(70, score);
196
+
197
+ return { score: Math.min(90, score), evidenceBasis: runtimeVerified ? 'measured' : 'estimated', findings };
198
+ }
199
+
200
+ function checkAeoEvidence({ aeoEvidence }) {
201
+ const findings = [];
202
+ if (!aeoEvidence) {
203
+ findings.push({ id: 'far-aeo-not-checked', category: 'full_agent_readiness', severity: 'advisory', title: 'AEO evidence readiness not checked', detail: 'Run with --aeo-readiness to measure.', autoFixEligible: false, requiresApproval: false });
204
+ return { score: 0, evidenceBasis: 'not_measured', findings };
205
+ }
206
+ return { score: Math.min(90, aeoEvidence.overall), evidenceBasis: 'measured', findings };
207
+ }
208
+
209
+ function checkManualVisibility({ manualVisibility }) {
210
+ const findings = [];
211
+ if (!manualVisibility?.measured) {
212
+ return { score: 0, evidenceBasis: 'not_provided', findings: [
213
+ { id: 'far-manual-not-provided', category: 'full_agent_readiness', severity: 'advisory', title: 'Manual-live AI visibility not provided', detail: 'Import manual results from ChatGPT/Gemini/Perplexity for live evidence.', autoFixEligible: false, requiresApproval: false }
214
+ ] };
215
+ }
216
+ const rate = manualVisibility.summary.mentionRate || 0;
217
+ return { score: Math.min(90, rate), evidenceBasis: 'measured', findings };
218
+ }
219
+
220
+ module.exports = { scoreFullAgentReadiness, SURFACES };