avorelo 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +56 -0
  3. package/bin/avorelo +9 -0
  4. package/package.json +135 -0
  5. package/scripts/README.md +40 -0
  6. package/scripts/cco-dashboard.js +252 -0
  7. package/scripts/cco-status.js +430 -0
  8. package/scripts/lib/activation/account-state.js +37 -0
  9. package/scripts/lib/activation/activation-runner.js +546 -0
  10. package/scripts/lib/activation/activation-self-healing.js +480 -0
  11. package/scripts/lib/activation/activation-state.js +83 -0
  12. package/scripts/lib/activation/activation-summary.js +191 -0
  13. package/scripts/lib/activation/adapters/claude-code.js +77 -0
  14. package/scripts/lib/activation/adapters/codex-cli.js +52 -0
  15. package/scripts/lib/activation/adapters/cursor.js +37 -0
  16. package/scripts/lib/activation/adapters/github-agent.js +39 -0
  17. package/scripts/lib/activation/adapters/terminal.js +42 -0
  18. package/scripts/lib/activation/adapters/vscode.js +39 -0
  19. package/scripts/lib/activation/adapters/windsurf.js +37 -0
  20. package/scripts/lib/activation/ai-surface-detector.js +151 -0
  21. package/scripts/lib/activation/connect-account.js +145 -0
  22. package/scripts/lib/activation/detect-environment.js +75 -0
  23. package/scripts/lib/activation/detect-hosts.js +62 -0
  24. package/scripts/lib/activation/format-activation-output.js +109 -0
  25. package/scripts/lib/activation/next-action.js +43 -0
  26. package/scripts/lib/activation/repair-engine.js +219 -0
  27. package/scripts/lib/activation-distribution-readiness.js +507 -0
  28. package/scripts/lib/adapter-conformance.js +176 -0
  29. package/scripts/lib/adapter-readiness.js +417 -0
  30. package/scripts/lib/adapter-safety-boundaries.js +335 -0
  31. package/scripts/lib/adapter-technical-readiness-gate.js +205 -0
  32. package/scripts/lib/agent-access-governance.js +455 -0
  33. package/scripts/lib/agent-enforcement.js +765 -0
  34. package/scripts/lib/agent-policy-profile.js +210 -0
  35. package/scripts/lib/agent-security/action-evaluator.js +507 -0
  36. package/scripts/lib/agent-security/adapter-registry.js +98 -0
  37. package/scripts/lib/agent-security/auto-policy.js +139 -0
  38. package/scripts/lib/agent-security/bounded-scan.js +93 -0
  39. package/scripts/lib/agent-security/enforcement-adapter.js +174 -0
  40. package/scripts/lib/agent-security/enforcement-engine.js +1129 -0
  41. package/scripts/lib/agent-security/file-write-adapter.js +183 -0
  42. package/scripts/lib/agent-security/file-write-rules.js +178 -0
  43. package/scripts/lib/agent-security/index.js +3342 -0
  44. package/scripts/lib/agent-security/instruction-risk.js +181 -0
  45. package/scripts/lib/agent-security/mcp-action-adapter.js +185 -0
  46. package/scripts/lib/agent-security/mcp-action-rules.js +184 -0
  47. package/scripts/lib/agent-security/package-action-adapter.js +175 -0
  48. package/scripts/lib/agent-security/package-action-rules.js +233 -0
  49. package/scripts/lib/agent-security/performance.js +148 -0
  50. package/scripts/lib/agent-security/permission-minimizer.js +403 -0
  51. package/scripts/lib/agent-security/scan-cache.js +74 -0
  52. package/scripts/lib/agent-security/source-trust.js +146 -0
  53. package/scripts/lib/ai-install-prompt.js +288 -0
  54. package/scripts/lib/ai-workspace-hygiene.js +1499 -0
  55. package/scripts/lib/alpha-activation.js +520 -0
  56. package/scripts/lib/alpha-feedback.js +263 -0
  57. package/scripts/lib/alpha-readiness-gate.js +332 -0
  58. package/scripts/lib/anti-gaming.js +169 -0
  59. package/scripts/lib/artifact-health.js +431 -0
  60. package/scripts/lib/attribution.js +180 -0
  61. package/scripts/lib/audit.js +289 -0
  62. package/scripts/lib/avorelo-skill-registry.js +810 -0
  63. package/scripts/lib/batch-jobs.js +71 -0
  64. package/scripts/lib/brain-pack.js +578 -0
  65. package/scripts/lib/brand-boundary.js +424 -0
  66. package/scripts/lib/brand.js +74 -0
  67. package/scripts/lib/browser-capability.js +1048 -0
  68. package/scripts/lib/browser-proof-preflight.js +321 -0
  69. package/scripts/lib/cache-readiness.js +187 -0
  70. package/scripts/lib/canonical-reentry.js +162 -0
  71. package/scripts/lib/capability-packs.js +314 -0
  72. package/scripts/lib/capability-recommender.js +512 -0
  73. package/scripts/lib/capability-registry.js +1059 -0
  74. package/scripts/lib/carry-forward-surfacing.js +194 -0
  75. package/scripts/lib/ccusage-adapter.js +188 -0
  76. package/scripts/lib/company-loop.js +1149 -0
  77. package/scripts/lib/config.js +637 -0
  78. package/scripts/lib/context-acquisition-plan.js +287 -0
  79. package/scripts/lib/context-budget-guard.js +170 -0
  80. package/scripts/lib/context-budget-scanner.js +257 -0
  81. package/scripts/lib/context-optimizer.js +715 -0
  82. package/scripts/lib/context-reduction-plan.js +178 -0
  83. package/scripts/lib/context-safety.js +88 -0
  84. package/scripts/lib/context-savings-engine.js +158 -0
  85. package/scripts/lib/cost-evidence.js +254 -0
  86. package/scripts/lib/cross-host-install-plan.js +308 -0
  87. package/scripts/lib/cross-host-install-readiness.js +237 -0
  88. package/scripts/lib/cross-host-value-flow.js +268 -0
  89. package/scripts/lib/dashboard.js +900 -0
  90. package/scripts/lib/design-partner-feedback.js +346 -0
  91. package/scripts/lib/entitlements.js +100 -0
  92. package/scripts/lib/execution-packet.js +559 -0
  93. package/scripts/lib/experimentation-events.js +547 -0
  94. package/scripts/lib/external-capability-compliance.js +107 -0
  95. package/scripts/lib/external-user-simulation.js +166 -0
  96. package/scripts/lib/failure-recovery-readiness.js +81 -0
  97. package/scripts/lib/failure-recovery.js +419 -0
  98. package/scripts/lib/feedback-intelligence.js +537 -0
  99. package/scripts/lib/feedback-signals.js +205 -0
  100. package/scripts/lib/file-integrity.js +68 -0
  101. package/scripts/lib/fsx.js +127 -0
  102. package/scripts/lib/full-readiness-gate.js +451 -0
  103. package/scripts/lib/guidance-builder.js +174 -0
  104. package/scripts/lib/hook-apply.js +1019 -0
  105. package/scripts/lib/hook-baseline.js +310 -0
  106. package/scripts/lib/hook-config-preview.js +275 -0
  107. package/scripts/lib/hook-contracts.js +290 -0
  108. package/scripts/lib/hook-safety-boundary-readiness.js +80 -0
  109. package/scripts/lib/host-capability-matrix.js +351 -0
  110. package/scripts/lib/host-support-context.js +254 -0
  111. package/scripts/lib/http-hook-action.js +538 -0
  112. package/scripts/lib/install-ai-readiness.js +84 -0
  113. package/scripts/lib/install-intake-risk.js +1037 -0
  114. package/scripts/lib/install-journey-intelligence.js +329 -0
  115. package/scripts/lib/intervention-guidance.js +57 -0
  116. package/scripts/lib/known-limitations.js +115 -0
  117. package/scripts/lib/l8-path-truth.js +146 -0
  118. package/scripts/lib/launch-hardening-gate.js +436 -0
  119. package/scripts/lib/launch-readiness.js +628 -0
  120. package/scripts/lib/learning-memory.js +686 -0
  121. package/scripts/lib/lifecycle-hooks.js +802 -0
  122. package/scripts/lib/local-package-smoke.js +423 -0
  123. package/scripts/lib/local-pricing.js +299 -0
  124. package/scripts/lib/mcp-enforcement.js +311 -0
  125. package/scripts/lib/mcp-least-privilege-policy.js +303 -0
  126. package/scripts/lib/mcp-tool-inventory.js +388 -0
  127. package/scripts/lib/mcp-tool-risk.js +0 -0
  128. package/scripts/lib/memory.js +335 -0
  129. package/scripts/lib/metrics.js +699 -0
  130. package/scripts/lib/micro-proof.js +133 -0
  131. package/scripts/lib/next-run-context.js +436 -0
  132. package/scripts/lib/operating-value.js +1648 -0
  133. package/scripts/lib/optimization-v3.js +122 -0
  134. package/scripts/lib/orchestration/adapters/_shared.js +49 -0
  135. package/scripts/lib/orchestration/adapters/aider.js +18 -0
  136. package/scripts/lib/orchestration/adapters/claude-code.js +35 -0
  137. package/scripts/lib/orchestration/adapters/codex.js +35 -0
  138. package/scripts/lib/orchestration/adapters/gemini-cli.js +18 -0
  139. package/scripts/lib/orchestration/adapters/git.js +25 -0
  140. package/scripts/lib/orchestration/adapters/index.js +31 -0
  141. package/scripts/lib/orchestration/adapters/lm-studio.js +18 -0
  142. package/scripts/lib/orchestration/adapters/ollama.js +18 -0
  143. package/scripts/lib/orchestration/adapters/opencode.js +18 -0
  144. package/scripts/lib/orchestration/adapters/openrouter.js +18 -0
  145. package/scripts/lib/orchestration/adapters/test-runner.js +25 -0
  146. package/scripts/lib/orchestration/cli.js +438 -0
  147. package/scripts/lib/orchestration/execution-manager.js +279 -0
  148. package/scripts/lib/orchestration/handoff.js +314 -0
  149. package/scripts/lib/orchestration/index.js +456 -0
  150. package/scripts/lib/orchestration/inventory.js +47 -0
  151. package/scripts/lib/orchestration/model-discovery.js +498 -0
  152. package/scripts/lib/orchestration/model-profiler.js +170 -0
  153. package/scripts/lib/orchestration/model-profiles.js +252 -0
  154. package/scripts/lib/orchestration/model-refresh-policy.js +72 -0
  155. package/scripts/lib/orchestration/proof-writer.js +349 -0
  156. package/scripts/lib/orchestration/provider-discovery/aider.js +49 -0
  157. package/scripts/lib/orchestration/provider-discovery/claude-code.js +56 -0
  158. package/scripts/lib/orchestration/provider-discovery/codex.js +49 -0
  159. package/scripts/lib/orchestration/provider-discovery/common.js +186 -0
  160. package/scripts/lib/orchestration/provider-discovery/gemini.js +106 -0
  161. package/scripts/lib/orchestration/provider-discovery/lm-studio.js +118 -0
  162. package/scripts/lib/orchestration/provider-discovery/models-dev.js +12 -0
  163. package/scripts/lib/orchestration/provider-discovery/ollama.js +100 -0
  164. package/scripts/lib/orchestration/provider-discovery/opencode.js +47 -0
  165. package/scripts/lib/orchestration/provider-discovery/openrouter.js +44 -0
  166. package/scripts/lib/orchestration/risk-classifier.js +130 -0
  167. package/scripts/lib/orchestration/routing-policy.js +486 -0
  168. package/scripts/lib/orchestration/settings.js +112 -0
  169. package/scripts/lib/orchestration/state.js +165 -0
  170. package/scripts/lib/orchestration/verification-manager.js +138 -0
  171. package/scripts/lib/output-profiles.js +146 -0
  172. package/scripts/lib/package-content-audit.js +368 -0
  173. package/scripts/lib/package-runtime.js +278 -0
  174. package/scripts/lib/plan-surface.js +53 -0
  175. package/scripts/lib/plans.js +2318 -0
  176. package/scripts/lib/policy-provider.js +27 -0
  177. package/scripts/lib/prelaunch-activation-readiness.js +409 -0
  178. package/scripts/lib/prelaunch-evidence-store.js +816 -0
  179. package/scripts/lib/prelaunch-intelligence.js +869 -0
  180. package/scripts/lib/pricing-experiment.js +118 -0
  181. package/scripts/lib/pro-moment-events.js +77 -0
  182. package/scripts/lib/pro-moment-state.js +227 -0
  183. package/scripts/lib/pro-moments.js +1216 -0
  184. package/scripts/lib/product-learning-events.js +629 -0
  185. package/scripts/lib/project-profile.js +555 -0
  186. package/scripts/lib/prompt-compiler.js +280 -0
  187. package/scripts/lib/prompt-lint.js +32 -0
  188. package/scripts/lib/prompt-suggestions.js +52 -0
  189. package/scripts/lib/proof-canonical.js +398 -0
  190. package/scripts/lib/proof-drilldown.js +383 -0
  191. package/scripts/lib/proof-events.js +342 -0
  192. package/scripts/lib/proof-history.js +243 -0
  193. package/scripts/lib/proof-metrics.js +296 -0
  194. package/scripts/lib/proof-outcome-evidence.js +134 -0
  195. package/scripts/lib/proof-receipt.js +335 -0
  196. package/scripts/lib/proof-record.js +461 -0
  197. package/scripts/lib/public-activation-distribution-gate.js +258 -0
  198. package/scripts/lib/public-cli.js +3891 -0
  199. package/scripts/lib/public-distribution-truth.js +211 -0
  200. package/scripts/lib/public-install-claim-checker.js +294 -0
  201. package/scripts/lib/publish-provenance-readiness.js +283 -0
  202. package/scripts/lib/readiness-delta.js +218 -0
  203. package/scripts/lib/readiness-evidence-closure.js +196 -0
  204. package/scripts/lib/reentry-memory-capture.js +241 -0
  205. package/scripts/lib/reentry-memory-retrieval.js +302 -0
  206. package/scripts/lib/reentry-memory-status.js +146 -0
  207. package/scripts/lib/reentry-memory-store.js +178 -0
  208. package/scripts/lib/reentry-state.js +66 -0
  209. package/scripts/lib/release-candidate-bundle.js +166 -0
  210. package/scripts/lib/remediation.js +81 -0
  211. package/scripts/lib/repo-map.js +391 -0
  212. package/scripts/lib/run-improvements-lifecycle.js +330 -0
  213. package/scripts/lib/run-improvements.js +789 -0
  214. package/scripts/lib/runtime-decision-policy.js +387 -0
  215. package/scripts/lib/safe-path-engine.js +705 -0
  216. package/scripts/lib/safe-run-controller.js +887 -0
  217. package/scripts/lib/score.js +262 -0
  218. package/scripts/lib/seamless-enforcement.js +329 -0
  219. package/scripts/lib/seamless-outcome.js +689 -0
  220. package/scripts/lib/seamless-reality-gate.js +5043 -0
  221. package/scripts/lib/security-risk-classifier.js +511 -0
  222. package/scripts/lib/security-scan.js +384 -0
  223. package/scripts/lib/session-context-optimizer.js +1211 -0
  224. package/scripts/lib/session-timing.js +315 -0
  225. package/scripts/lib/skill-hygiene.js +805 -0
  226. package/scripts/lib/skill-packs.js +161 -0
  227. package/scripts/lib/skills-operating-layer.js +580 -0
  228. package/scripts/lib/smart-work-routing.js +768 -0
  229. package/scripts/lib/source-catalog.js +700 -0
  230. package/scripts/lib/status-value-summary.js +32 -0
  231. package/scripts/lib/support-bundle.js +578 -0
  232. package/scripts/lib/task-continuation.js +440 -0
  233. package/scripts/lib/test-helpers.js +15 -0
  234. package/scripts/lib/tier.js +38 -0
  235. package/scripts/lib/token-context-quality-gate.js +370 -0
  236. package/scripts/lib/token-cost-capture.js +187 -0
  237. package/scripts/lib/token-cost-intelligence.js +358 -0
  238. package/scripts/lib/token-efficiency-evidence.js +213 -0
  239. package/scripts/lib/token-evidence.js +699 -0
  240. package/scripts/lib/tokenish.js +17 -0
  241. package/scripts/lib/tool-output-sandbox.js +304 -0
  242. package/scripts/lib/trust-audit.js +136 -0
  243. package/scripts/lib/unified-events.js +396 -0
  244. package/scripts/lib/upgrade-interruption-recovery.js +407 -0
  245. package/scripts/lib/usage-ledger.js +201 -0
  246. package/scripts/lib/value-ledger.js +130 -0
  247. package/scripts/lib/value-proof-calibration.js +531 -0
  248. package/scripts/lib/visual-qa.js +231 -0
  249. package/scripts/lib/voice-alpha.js +29 -0
  250. package/scripts/lib/work-aware-orchestration.js +976 -0
  251. package/scripts/lib/work-control-receipts.js +577 -0
  252. package/scripts/lib/work-ledger.js +1123 -0
  253. package/scripts/lib/work-panel-preview.js +352 -0
  254. package/scripts/lib/workflow-discipline.js +280 -0
  255. package/scripts/lib/workflow-signals.js +419 -0
  256. package/scripts/lib/workspace-map.js +281 -0
  257. package/scripts/lib/workspace-registry.js +1367 -0
  258. package/scripts/lib/workspace-resolver.js +480 -0
@@ -0,0 +1,358 @@
1
+ "use strict";
2
+
3
+ // ── Token / Cost Intelligence ─────────────────────────────────────────────────
4
+ //
5
+ // Contract: avorelo.tokenCostIntelligence.v1
6
+ //
7
+ // Rolls up token/context evidence from existing artifacts.
8
+ // Always distinguishes: exact | estimated | not_available | mixed.
9
+ // Never claims dollar savings without exact source.
10
+ // Never claims guaranteed savings.
11
+
12
+ const fs = require("fs");
13
+ const path = require("path");
14
+ const { nowIso } = require("./fsx");
15
+ const { appendProductLearningEvent } = require("./product-learning-events");
16
+ const {
17
+ readImportedTokenCostEvidence,
18
+ readCapturedTokenCostEvidence,
19
+ buildTokenCostEvidenceSummary,
20
+ writeTokenCostEvidenceSummary,
21
+ } = require("./prelaunch-evidence-store");
22
+
23
+ const CONTRACT = "avorelo.tokenCostIntelligence.v1";
24
+ const SCHEMA_VERSION = 1;
25
+ const INTELLIGENCE_DIR_REL = ".claude/cco/orchestration/prelaunch-intelligence";
26
+ const ARTIFACT_REL = `${INTELLIGENCE_DIR_REL}/latest-token-cost-intelligence.json`;
27
+
28
+ const TOKEN_EVIDENCE_REL = ".claude/cco/orchestration/token-efficiency/latest-evidence.json";
29
+ const QUALITY_GATE_REL = ".claude/cco/orchestration/token-efficiency/latest-quality-gate.json";
30
+ const CACHE_READINESS_REL = ".claude/cco/orchestration/cache-readiness/latest-readiness.json";
31
+
32
+ function safeReadJson(absPath) {
33
+ try {
34
+ if (!fs.existsSync(absPath)) return null;
35
+ return JSON.parse(fs.readFileSync(absPath, "utf8").replace(/^/, ""));
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+
41
+ function classifyEvidenceLevel(evidence, options = {}) {
42
+ if (!evidence) return "not_available";
43
+
44
+ const levels = [];
45
+
46
+ // Check token efficiency evidence
47
+ if (evidence.tokenEvidence) {
48
+ const te = evidence.tokenEvidence;
49
+ if (te.evidenceLevel === "exact") levels.push("exact");
50
+ else if (te.evidenceLevel === "estimated") levels.push("estimated");
51
+ else levels.push("not_available");
52
+ }
53
+
54
+ // Check cache readiness
55
+ if (evidence.cacheReadiness && evidence.cacheReadiness.status) {
56
+ if (evidence.cacheReadiness.status === "ready") levels.push("estimated");
57
+ else levels.push("not_available");
58
+ }
59
+
60
+ if (evidence.tokenCostEvidenceSummary) {
61
+ if (evidence.tokenCostEvidenceSummary.evidenceMode === "measured") levels.push("exact");
62
+ else if (evidence.tokenCostEvidenceSummary.evidenceMode === "estimated") levels.push("estimated");
63
+ else if (evidence.tokenCostEvidenceSummary.evidenceMode === "heuristic") levels.push("estimated");
64
+ } else if (Array.isArray(evidence.importedUsage) && evidence.importedUsage.length > 0) {
65
+ const hasExact = evidence.importedUsage.some((item) =>
66
+ item &&
67
+ item.evidenceMode === "measured" &&
68
+ typeof item.totalTokens === "number" &&
69
+ (typeof item.measuredCostUsd === "number" || typeof item.costMicros === "number")
70
+ );
71
+ const hasEstimated = evidence.importedUsage.some((item) =>
72
+ item &&
73
+ typeof item.totalTokens === "number" &&
74
+ (typeof item.estimatedCostUsd === "number" || typeof item.measuredCostUsd === "number" || typeof item.costMicros === "number")
75
+ );
76
+ if (hasExact) levels.push("exact");
77
+ else if (hasEstimated) levels.push("estimated");
78
+ }
79
+
80
+ if (levels.length === 0) return "not_available";
81
+ if (levels.every((l) => l === "exact")) return "exact";
82
+ if (levels.every((l) => l === "not_available")) return "not_available";
83
+ if (levels.some((l) => l === "exact") && levels.some((l) => l !== "exact")) return "mixed";
84
+ if (levels.some((l) => l === "estimated")) return "estimated";
85
+ return "not_available";
86
+ }
87
+
88
+ function collectTokenCostEvidence(cwd, options = {}) {
89
+ const tokenEvidencePath = path.join(cwd, TOKEN_EVIDENCE_REL);
90
+ const qualityGatePath = path.join(cwd, QUALITY_GATE_REL);
91
+ const cacheReadinessPath = path.join(cwd, CACHE_READINESS_REL);
92
+
93
+ const tokenEvidence = safeReadJson(tokenEvidencePath);
94
+ const qualityGate = safeReadJson(qualityGatePath);
95
+ const cacheReadiness = safeReadJson(cacheReadinessPath);
96
+
97
+ const tokenCostEvidenceSummary = buildTokenCostEvidenceSummary(cwd);
98
+ writeTokenCostEvidenceSummary(cwd, tokenCostEvidenceSummary);
99
+
100
+ return {
101
+ tokenEvidence,
102
+ qualityGate,
103
+ cacheReadiness,
104
+ importedUsage: readImportedTokenCostEvidence(cwd),
105
+ capturedUsage: readCapturedTokenCostEvidence(cwd),
106
+ tokenCostEvidenceSummary,
107
+ refs: {
108
+ tokenEvidence: tokenEvidence ? TOKEN_EVIDENCE_REL : null,
109
+ qualityGate: qualityGate ? QUALITY_GATE_REL : null,
110
+ cacheReadiness: cacheReadiness ? CACHE_READINESS_REL : null,
111
+ importedUsage: fs.existsSync(path.join(cwd, ".claude/cco/evidence/token-cost/token-cost.jsonl"))
112
+ ? ".claude/cco/evidence/token-cost/token-cost.jsonl"
113
+ : null,
114
+ capturedUsage: fs.existsSync(path.join(cwd, ".claude/cco/evidence/token-cost/capture.jsonl"))
115
+ ? ".claude/cco/evidence/token-cost/capture.jsonl"
116
+ : null,
117
+ },
118
+ };
119
+ }
120
+
121
+ function buildTokenCostRollup(cwd, options = {}) {
122
+ const evidence = collectTokenCostEvidence(cwd, options);
123
+ const { tokenEvidence, qualityGate, cacheReadiness, importedUsage, capturedUsage, tokenCostEvidenceSummary } = evidence;
124
+ const usageRows = [...(capturedUsage || []), ...(importedUsage || [])];
125
+
126
+ const evidenceLevel = classifyEvidenceLevel(evidence, options);
127
+ const evidenceMode = tokenCostEvidenceSummary?.evidenceMode || "missing";
128
+
129
+ // Gather available refs
130
+ const tokenEvidenceRefs = Object.entries(evidence.refs)
131
+ .filter(([, v]) => v !== null)
132
+ .map(([k, v]) => ({ label: k, path: v }));
133
+
134
+ // Context avoided
135
+ const contextAvoidedEstimate = tokenEvidence?.contextAvoidedEstimate ?? null;
136
+ const outputAvoidedEstimate = tokenEvidence?.outputAvoidedEstimate ?? null;
137
+ const realUsageSamples = usageRows.filter((item) =>
138
+ item &&
139
+ item.redacted === true &&
140
+ typeof item.totalTokens === "number" &&
141
+ ((typeof item.measuredCostUsd === "number" || typeof item.costMicros === "number") && item.estimatedOnly !== true)
142
+ );
143
+ const tokenFieldSamples = usageRows.filter((item) => item && typeof item.totalTokens === "number");
144
+ const costFieldSamples = usageRows.filter((item) =>
145
+ item && (typeof item.estimatedCostUsd === "number" || typeof item.measuredCostUsd === "number" || typeof item.costMicros === "number")
146
+ );
147
+
148
+ // Cache readiness summary
149
+ const cacheReadinessSummary = cacheReadiness
150
+ ? { status: cacheReadiness.status, artifactPath: CACHE_READINESS_REL }
151
+ : { status: "not_available", artifactPath: null };
152
+
153
+ // Cost evidence from token efficiency
154
+ const costEvidence = tokenEvidence
155
+ ? {
156
+ evidenceLevel: tokenEvidence.evidenceLevel || "not_available",
157
+ rawRepoEstimateTokens: tokenEvidence.rawRepoEstimateTokens ?? null,
158
+ selectedContextTokens: tokenEvidence.selectedContextTokens ?? null,
159
+ rawToolOutputTokens: tokenEvidence.rawToolOutputTokens ?? null,
160
+ summarizedToolOutputTokens: tokenEvidence.summarizedToolOutputTokens ?? null,
161
+ noExactCostClaim: tokenEvidence.noExactCostClaim ?? true,
162
+ }
163
+ : null;
164
+
165
+ // Quality gate summary
166
+ const qualityGateSummary = qualityGate
167
+ ? {
168
+ status: qualityGate.status,
169
+ verdict: qualityGate.verdict,
170
+ checksPass: qualityGate.quality?.checksPass ?? null,
171
+ checksWarn: qualityGate.quality?.checksWarn ?? null,
172
+ checksFail: qualityGate.quality?.checksFail ?? null,
173
+ }
174
+ : null;
175
+
176
+ // Runs observed
177
+ const runsObserved = tokenEvidence ? 1 : (capturedUsage || []).length;
178
+
179
+ // Status
180
+ let status;
181
+ if (evidenceMode === "measured" || realUsageSamples.length > 0) {
182
+ status = "ready";
183
+ } else if (evidenceMode === "estimated" || evidenceMode === "heuristic") {
184
+ status = "partial";
185
+ } else if (evidenceLevel === "not_available" && runsObserved === 0) {
186
+ status = "not_available";
187
+ } else if (evidenceLevel === "exact") {
188
+ status = "ready";
189
+ } else if (evidenceLevel === "estimated" || evidenceLevel === "mixed") {
190
+ status = "partial";
191
+ } else {
192
+ status = "not_available";
193
+ }
194
+
195
+ // Build caveats
196
+ const caveats = [
197
+ "Token estimates are approximate and may vary from actual provider billing.",
198
+ "No exact dollar savings are claimed without a verified billing source.",
199
+ "Tokenizer mismatch between local estimates and actual API tokenization may cause variance.",
200
+ ];
201
+ if (evidenceLevel === "not_available") {
202
+ caveats.push("No token/cost evidence is currently available. Run avorelo token-efficiency --json to generate.");
203
+ }
204
+ if (contextAvoidedEstimate === null) {
205
+ caveats.push("Context avoided estimate not yet computed. Run a full task to populate.");
206
+ }
207
+ if (realUsageSamples.length === 0) {
208
+ caveats.push("No real measured token/cost usage samples are available yet.");
209
+ }
210
+
211
+ let confidence = tokenCostEvidenceSummary?.confidence || "missing";
212
+ if (confidence === "missing" && realUsageSamples.length > 0) confidence = "measured";
213
+ else if (confidence === "missing" && tokenFieldSamples.length > 0) confidence = "estimated";
214
+ else if (confidence === "missing" && (status === "partial" || evidenceLevel === "estimated" || evidenceLevel === "mixed")) confidence = "heuristic";
215
+
216
+ const tokenFieldsAvailable = tokenCostEvidenceSummary?.tokenFieldsAvailable || (tokenFieldSamples.length > 0
217
+ ? ["totalTokens", "promptTokens", "completionTokens"].filter((field) =>
218
+ importedUsage.some((item) => typeof item[field] === "number")
219
+ )
220
+ : []);
221
+ const costFieldsAvailable = tokenCostEvidenceSummary?.costFieldsAvailable || (costFieldSamples.length > 0
222
+ ? ["estimatedCostUsd", "measuredCostUsd", "costMicros", "currency"].filter((field) =>
223
+ importedUsage.some((item) => item[field] !== null && item[field] !== undefined && item[field] !== "")
224
+ )
225
+ : []);
226
+ const missingEvidence = [...(tokenCostEvidenceSummary?.missingEvidence || [])];
227
+ if (!tokenEvidence) missingEvidence.push("No local token-efficiency artifact available for heuristic comparison.");
228
+ const safeNextActions = [...(tokenCostEvidenceSummary?.safeNextActions || [])];
229
+ if ((capturedUsage || []).length === 0) {
230
+ safeNextActions.push("Run: node bin/avorelo token-cost capture --json");
231
+ }
232
+ if (!tokenEvidence) {
233
+ safeNextActions.push("Run: node bin/avorelo token-efficiency --json");
234
+ }
235
+ if (!safeNextActions.includes("Use imported real usage evidence only for measured cost claims.")) {
236
+ safeNextActions.push("Use imported real usage evidence only for measured cost claims.");
237
+ }
238
+
239
+ return {
240
+ contract: CONTRACT,
241
+ schemaVersion: SCHEMA_VERSION,
242
+ createdAt: nowIso(),
243
+ status,
244
+ readinessStatus: status === "ready" ? "pass" : status === "partial" ? "warn" : "info",
245
+ evidenceLevel,
246
+ evidenceMode,
247
+ evidenceAvailable: tokenCostEvidenceSummary?.evidenceAvailable === true || evidenceLevel !== "not_available",
248
+ runsObserved,
249
+ realUsageSamplesCount: realUsageSamples.length,
250
+ capturedUsageSamplesCount: tokenCostEvidenceSummary?.capturedUsageSamplesCount || 0,
251
+ importedUsageSamplesCount: tokenCostEvidenceSummary?.importedUsageSamplesCount || 0,
252
+ source: Object.assign({
253
+ heuristicArtifact: tokenEvidence ? TOKEN_EVIDENCE_REL : null,
254
+ importedEvidence: evidence.refs.importedUsage,
255
+ capturedEvidence: evidence.refs.capturedUsage,
256
+ }, tokenCostEvidenceSummary?.source || {}),
257
+ costFieldsAvailable,
258
+ tokenFieldsAvailable,
259
+ estimatedOnly: evidenceMode !== "measured",
260
+ confidence,
261
+ tokenEvidenceRefs,
262
+ contextAvoidedEstimate,
263
+ outputAvoidedEstimate,
264
+ cacheReadinessSummary,
265
+ costEvidence,
266
+ qualityGateSummary,
267
+ caveats,
268
+ missingEvidence,
269
+ safeNextActions,
270
+ noSavingsClaimUnlessMeasured: true,
271
+ noExactSavingsClaim: true,
272
+ redacted: true,
273
+ };
274
+ }
275
+
276
+ function writeTokenCostIntelligence(cwd, intelligence) {
277
+ const dirAbs = path.join(cwd, INTELLIGENCE_DIR_REL);
278
+ fs.mkdirSync(dirAbs, { recursive: true });
279
+ const absPath = path.join(cwd, ARTIFACT_REL);
280
+ fs.writeFileSync(absPath, JSON.stringify(intelligence, null, 2), "utf8");
281
+ return absPath;
282
+ }
283
+
284
+ function buildTokenCostIntelligenceSurface(cwd, options = {}) {
285
+ const absPath = path.join(cwd, ARTIFACT_REL);
286
+ const existing = safeReadJson(absPath);
287
+ if (existing) {
288
+ return {
289
+ status: existing.status,
290
+ readinessStatus: existing.readinessStatus,
291
+ evidenceLevel: existing.evidenceLevel,
292
+ runsObserved: existing.runsObserved,
293
+ realUsageSamplesCount: existing.realUsageSamplesCount || 0,
294
+ noExactSavingsClaim: true,
295
+ artifactPath: ARTIFACT_REL,
296
+ };
297
+ }
298
+ const intel = buildTokenCostRollup(cwd, options);
299
+ writeTokenCostIntelligence(cwd, intel);
300
+ return {
301
+ status: intel.status,
302
+ readinessStatus: intel.readinessStatus,
303
+ evidenceLevel: intel.evidenceLevel,
304
+ runsObserved: intel.runsObserved,
305
+ realUsageSamplesCount: intel.realUsageSamplesCount || 0,
306
+ noExactSavingsClaim: true,
307
+ artifactPath: ARTIFACT_REL,
308
+ };
309
+ }
310
+
311
+ function formatTokenCostIntelligenceText(intelligence, options = {}) {
312
+ const debug = options.debug === true;
313
+ const lines = [];
314
+
315
+ lines.push(`Token/cost intelligence: ${intelligence.status}`);
316
+ lines.push(` Evidence level: ${intelligence.evidenceLevel}`);
317
+ lines.push(` Evidence mode: ${intelligence.evidenceMode || "missing"}`);
318
+ lines.push(` Runs observed: ${intelligence.runsObserved}`);
319
+ lines.push(` Real usage samples: ${intelligence.realUsageSamplesCount || 0}`);
320
+ lines.push(` Confidence: ${intelligence.confidence || "missing"}`);
321
+
322
+ if (intelligence.contextAvoidedEstimate !== null) {
323
+ lines.push(` Context avoided (estimate): ${intelligence.contextAvoidedEstimate} tokens`);
324
+ }
325
+ if (intelligence.outputAvoidedEstimate !== null) {
326
+ lines.push(` Output avoided (estimate): ${intelligence.outputAvoidedEstimate} tokens`);
327
+ }
328
+ lines.push(` Cache readiness: ${intelligence.cacheReadinessSummary?.status || "not_available"}`);
329
+ lines.push(` No exact savings claim: ${intelligence.noExactSavingsClaim}`);
330
+
331
+ if (debug) {
332
+ lines.push("");
333
+ lines.push("Caveats:");
334
+ for (const caveat of intelligence.caveats || []) {
335
+ lines.push(` - ${caveat}`);
336
+ }
337
+ if (intelligence.qualityGateSummary) {
338
+ lines.push("");
339
+ lines.push(`Quality gate: ${intelligence.qualityGateSummary.status} (verdict: ${intelligence.qualityGateSummary.verdict})`);
340
+ lines.push(` Pass: ${intelligence.qualityGateSummary.checksPass}, Warn: ${intelligence.qualityGateSummary.checksWarn}, Fail: ${intelligence.qualityGateSummary.checksFail}`);
341
+ }
342
+ }
343
+
344
+ return lines.join("\n");
345
+ }
346
+
347
+ module.exports = {
348
+ CONTRACT,
349
+ SCHEMA_VERSION,
350
+ ARTIFACT_REL,
351
+ TOKEN_EVIDENCE_REL,
352
+ classifyEvidenceLevel,
353
+ collectTokenCostEvidence,
354
+ buildTokenCostRollup,
355
+ writeTokenCostIntelligence,
356
+ buildTokenCostIntelligenceSurface,
357
+ formatTokenCostIntelligenceText,
358
+ };
@@ -0,0 +1,213 @@
1
+ "use strict";
2
+
3
+ // ── Token Efficiency Evidence ─────────────────────────────────────────────────
4
+ //
5
+ // Builds deterministic, honest token efficiency evidence for Avorelo.
6
+ // Estimates input/context/tool-output token sizes locally.
7
+ // Does NOT claim exact dollar savings. Does NOT call external APIs.
8
+ //
9
+ // Contract: avorelo.tokenEfficiencyEvidence.v1
10
+ //
11
+ // Evidence levels:
12
+ // exact — from a real usage measurement source
13
+ // estimated — from counted text/context sizes (approximate)
14
+ // not_available — no evidence source available
15
+ //
16
+ // Non-goals: LLM calls, provider billing, guaranteed savings, external tokenizer.
17
+
18
+ const fs = require("node:fs");
19
+ const path = require("node:path");
20
+ const crypto = require("node:crypto");
21
+ const { ensureCcoDirs, nowIso } = require("./fsx");
22
+ const { appendProductLearningEvent } = require("./product-learning-events");
23
+
24
+ const CONTRACT = "avorelo.tokenEfficiencyEvidence.v1";
25
+ const SCHEMA_VERSION = 1;
26
+
27
+ const EVIDENCE_DIR_REL = ".claude/cco/orchestration/token-efficiency";
28
+ const LATEST_EVIDENCE_REL = `${EVIDENCE_DIR_REL}/latest-evidence.json`;
29
+
30
+ // ── Re-use estimateTokens from context-optimizer ──────────────────────────────
31
+
32
+ function estimateTextTokens(text, options = {}) {
33
+ if (!text) return { estimatedTokens: 0, estimatedChars: 0, estimateMethod: "heuristic" };
34
+ try {
35
+ const { estimateTokens } = require("./context-optimizer");
36
+ return estimateTokens(String(text));
37
+ } catch {
38
+ const s = String(text);
39
+ return {
40
+ estimatedTokens: Math.ceil(s.length / 4),
41
+ estimatedChars: s.length,
42
+ estimateMethod: "heuristic",
43
+ };
44
+ }
45
+ }
46
+
47
+ function estimateFileTokens(cwd, relPath, options = {}) {
48
+ try {
49
+ const abs = path.join(cwd, relPath);
50
+ if (!fs.existsSync(abs)) return { estimatedTokens: 0, estimatedChars: 0, estimateMethod: "heuristic", path: relPath, missing: true };
51
+ const stat = fs.statSync(abs);
52
+ if (stat.size > 1024 * 1024) {
53
+ // Large file: heuristic only
54
+ return { estimatedTokens: Math.ceil(stat.size / 4), estimatedChars: stat.size, estimateMethod: "heuristic", path: relPath, largeFile: true };
55
+ }
56
+ const content = fs.readFileSync(abs, "utf8");
57
+ const est = estimateTextTokens(content, options);
58
+ return { ...est, path: relPath };
59
+ } catch {
60
+ return { estimatedTokens: 0, estimatedChars: 0, estimateMethod: "heuristic", path: relPath, error: true };
61
+ }
62
+ }
63
+
64
+ // ── Build evidence ────────────────────────────────────────────────────────────
65
+
66
+ function buildTokenEfficiencyEvidence(cwd, input = {}, options = {}) {
67
+ const {
68
+ rawContextText,
69
+ selectedContextText,
70
+ rawToolOutputText,
71
+ summarizedToolOutputText,
72
+ exactUsageSource,
73
+ } = input;
74
+
75
+ const caveats = ["Token estimates are approximate and may vary from actual provider billing."];
76
+ let evidenceLevel = "not_available";
77
+ let status = "not_available";
78
+
79
+ let rawRepoEstimateTokens = null;
80
+ let selectedContextTokens = null;
81
+ let contextAvoidedEstimate = null;
82
+ let rawToolOutputTokens = null;
83
+ let summarizedToolOutputTokens = null;
84
+ let outputAvoidedEstimate = null;
85
+
86
+ if (exactUsageSource) {
87
+ evidenceLevel = "exact";
88
+ status = "available";
89
+ caveats.push("Exact usage from provided source; verify against provider billing.");
90
+ } else if (rawContextText || selectedContextText || rawToolOutputText || summarizedToolOutputText) {
91
+ evidenceLevel = "estimated";
92
+ status = "partial";
93
+ }
94
+
95
+ if (rawContextText) {
96
+ rawRepoEstimateTokens = estimateTextTokens(rawContextText).estimatedTokens;
97
+ }
98
+ if (selectedContextText) {
99
+ selectedContextTokens = estimateTextTokens(selectedContextText).estimatedTokens;
100
+ }
101
+ if (rawRepoEstimateTokens !== null && selectedContextTokens !== null) {
102
+ contextAvoidedEstimate = Math.max(0, rawRepoEstimateTokens - selectedContextTokens);
103
+ status = "available";
104
+ }
105
+ if (rawToolOutputText) {
106
+ rawToolOutputTokens = estimateTextTokens(rawToolOutputText).estimatedTokens;
107
+ }
108
+ if (summarizedToolOutputText) {
109
+ summarizedToolOutputTokens = estimateTextTokens(summarizedToolOutputText).estimatedTokens;
110
+ }
111
+ if (rawToolOutputTokens !== null && summarizedToolOutputTokens !== null) {
112
+ outputAvoidedEstimate = Math.max(0, rawToolOutputTokens - summarizedToolOutputTokens);
113
+ }
114
+
115
+ // Read context pack as an evidence source
116
+ try {
117
+ const packPath = path.join(cwd, ".claude/cco/orchestration/context-optimizer/latest-receipt.json");
118
+ if (fs.existsSync(packPath)) {
119
+ const receipt = JSON.parse(fs.readFileSync(packPath, "utf8"));
120
+ if (receipt.totalEstimatedTokens && selectedContextTokens === null) {
121
+ selectedContextTokens = receipt.totalEstimatedTokens;
122
+ evidenceLevel = evidenceLevel === "not_available" ? "estimated" : evidenceLevel;
123
+ status = status === "not_available" ? "partial" : status;
124
+ }
125
+ }
126
+ } catch {}
127
+
128
+ return {
129
+ contract: CONTRACT,
130
+ schemaVersion: SCHEMA_VERSION,
131
+ createdAt: nowIso(),
132
+ status,
133
+ evidenceLevel,
134
+ rawRepoEstimateTokens,
135
+ selectedContextTokens,
136
+ contextAvoidedEstimate,
137
+ rawToolOutputTokens,
138
+ summarizedToolOutputTokens,
139
+ outputAvoidedEstimate,
140
+ cacheReadinessRef: `.claude/cco/orchestration/cache-readiness/latest-readiness.json`,
141
+ contextQualityGateRef: `.claude/cco/orchestration/token-efficiency/latest-quality-gate.json`,
142
+ caveats,
143
+ noExactCostClaim: true,
144
+ redacted: true,
145
+ };
146
+ }
147
+
148
+ function writeTokenEfficiencyEvidence(cwd, evidence) {
149
+ const dir = path.join(cwd, EVIDENCE_DIR_REL);
150
+ fs.mkdirSync(dir, { recursive: true });
151
+ const abs = path.join(cwd, LATEST_EVIDENCE_REL);
152
+ fs.writeFileSync(abs, JSON.stringify(evidence, null, 2), "utf8");
153
+ try {
154
+ appendProductLearningEvent(cwd, "token_efficiency_evidence_generated", {
155
+ status: evidence.status,
156
+ evidenceLevel: evidence.evidenceLevel,
157
+ contextAvoidedEstimate: evidence.contextAvoidedEstimate,
158
+ outputAvoidedEstimate: evidence.outputAvoidedEstimate,
159
+ });
160
+ } catch {}
161
+ return abs;
162
+ }
163
+
164
+ function buildTokenEfficiencySurface(cwd, options = {}) {
165
+ const abs = path.join(cwd, LATEST_EVIDENCE_REL);
166
+ if (!fs.existsSync(abs)) {
167
+ return { status: "not_available", artifactPath: LATEST_EVIDENCE_REL };
168
+ }
169
+ try {
170
+ const evidence = JSON.parse(fs.readFileSync(abs, "utf8"));
171
+ return {
172
+ status: evidence.status || "not_available",
173
+ evidenceLevel: evidence.evidenceLevel,
174
+ contextAvoidedEstimate: evidence.contextAvoidedEstimate,
175
+ outputAvoidedEstimate: evidence.outputAvoidedEstimate,
176
+ artifactPath: LATEST_EVIDENCE_REL,
177
+ };
178
+ } catch {
179
+ return { status: "error", artifactPath: LATEST_EVIDENCE_REL };
180
+ }
181
+ }
182
+
183
+ function formatTokenEfficiencyText(evidence, options = {}) {
184
+ const lines = [];
185
+ lines.push(`Token Efficiency Evidence (${evidence.evidenceLevel || "not_available"})`);
186
+ if (evidence.selectedContextTokens != null) {
187
+ lines.push(` Context selected: ~${evidence.selectedContextTokens} tokens`);
188
+ }
189
+ if (evidence.contextAvoidedEstimate != null) {
190
+ lines.push(` Context avoided (est.): ~${evidence.contextAvoidedEstimate} tokens`);
191
+ }
192
+ if (evidence.outputAvoidedEstimate != null) {
193
+ lines.push(` Tool output avoided (est.): ~${evidence.outputAvoidedEstimate} tokens`);
194
+ }
195
+ if (evidence.caveats && evidence.caveats.length > 0) {
196
+ lines.push(` Caveats: ${evidence.caveats[0]}`);
197
+ }
198
+ lines.push(` noExactCostClaim: ${evidence.noExactCostClaim}`);
199
+ return lines.join("\n");
200
+ }
201
+
202
+ module.exports = {
203
+ CONTRACT,
204
+ SCHEMA_VERSION,
205
+ LATEST_EVIDENCE_REL,
206
+ EVIDENCE_DIR_REL,
207
+ estimateTextTokens,
208
+ estimateFileTokens,
209
+ buildTokenEfficiencyEvidence,
210
+ writeTokenEfficiencyEvidence,
211
+ buildTokenEfficiencySurface,
212
+ formatTokenEfficiencyText,
213
+ };