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,194 @@
1
+ // Thin carry-forward surfacing utilities for wrappers
2
+ // Local-first, deterministic, bounded
3
+ const path = require("path");
4
+ const fs = require("fs");
5
+
6
+ const CARRY_FORWARD_PATH = ".claude/cco/state/reentry-carry-forward.json";
7
+ const CARRY_FORWARD_TTL_MS = 10 * 60 * 1000; // 10 minutes
8
+ const MAX_HISTORY_DEPTH = 3; // Last 3 tool calls
9
+
10
+ /**
11
+ * Capture bounded carry-forward state at session_end
12
+ * Minimal JavaScript implementation for sessionend.js
13
+ */
14
+ function captureCarryForward(cwd, sessionId, toolHistory) {
15
+ try {
16
+ // Build state object
17
+ const state = {
18
+ capturedAt: new Date().toISOString(),
19
+ sessionId,
20
+ ttlMs: CARRY_FORWARD_TTL_MS,
21
+ };
22
+
23
+ // Store bounded tool history if provided
24
+ if (toolHistory && toolHistory.length > 0) {
25
+ state.toolHistory = {
26
+ toolNames: toolHistory.slice(-MAX_HISTORY_DEPTH),
27
+ lastRunAt: new Date().toISOString(),
28
+ };
29
+ }
30
+
31
+ // Persist to disk
32
+ const fullPath = path.join(cwd, CARRY_FORWARD_PATH);
33
+ const dir = path.dirname(fullPath);
34
+ if (!fs.existsSync(dir)) {
35
+ fs.mkdirSync(dir, { recursive: true });
36
+ }
37
+ fs.writeFileSync(fullPath, JSON.stringify(state, null, 2));
38
+
39
+ return state;
40
+ } catch (err) {
41
+ // Fail open - log error but don't break session end
42
+ console.error(`[carry-forward] Failed to capture: ${err.message}`);
43
+ return null;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Load carry-forward state from disk if it exists and is valid (within TTL)
49
+ * Returns null if no valid state, preserving fail-open contract
50
+ */
51
+ function loadCarryForward(cwd) {
52
+ try {
53
+ const fullPath = path.join(cwd, ".claude", "cco", "state", "reentry-carry-forward.json");
54
+ const fs = require("fs");
55
+ if (!fs.existsSync(fullPath)) {
56
+ return null;
57
+ }
58
+ const state = JSON.parse(fs.readFileSync(fullPath, "utf8"));
59
+
60
+ // Simple TTL check: if TTL expired (10 minutes), return null
61
+ const capturedAt = new Date(state.capturedAt).getTime();
62
+ const age = Date.now() - capturedAt;
63
+ const TTL = state.ttlMs || (10 * 60 * 1000); // 10 minutes default
64
+ if (age > TTL) {
65
+ // Expired: clear and return null
66
+ try {
67
+ fs.unlinkSync(fullPath);
68
+ } catch {}
69
+ return null;
70
+ }
71
+ return state;
72
+ } catch (err) {
73
+ return null;
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Build human-readable continuity message from carry-forward state
79
+ * Bounded, explicit, non-magical
80
+ *
81
+ * @returns {string} message suitable for console or UI
82
+ */
83
+ function buildContinuityMessage(state, opts = {}) {
84
+ const compact = opts.compact || false;
85
+
86
+ if (!state) {
87
+ return compact ? "" : "Fresh start";
88
+ }
89
+
90
+ // Calculate simple human-friendly time (e.g., "3 minutes ago")
91
+ const capturedAt = new Date(state.capturedAt).getTime();
92
+ const age = Date.now() - capturedAt;
93
+ const ageMinutes = Math.floor(age / (1000 * 60));
94
+ const ageText = ageMinutes <= 0 ? "just now" : `${ageMinutes} min ago`;
95
+
96
+ // If tool history available
97
+ if (state.toolHistory && state.toolHistory.toolNames && state.toolHistory.toolNames.length > 0) {
98
+ const lastTool = state.toolHistory.toolNames[state.toolHistory.toolNames.length - 1];
99
+ const count = state.toolHistory.toolNames.length;
100
+ if (compact) {
101
+ return `[resume: ${lastTool}, ${ageText}]`;
102
+ }
103
+ return `Resume context available (${ageText}). Last: ${lastTool} (${count} tool${count > 1 ? "s" : ""})`;
104
+ }
105
+
106
+ // Fallback if only loop summary
107
+ if (compact) {
108
+ return "[resume available]";
109
+ }
110
+ return `Resume context available (${ageText})`;
111
+ }
112
+
113
+ /**
114
+ * Build structured output for wrappers to use
115
+ *
116
+ * Input example: { cwd, sessionId }
117
+ * Output shape:
118
+ * {
119
+ * reentryStatus: "fresh_start" | "resume_available",
120
+ * continuityMessage: string (human-facing),
121
+ * carryForward?: object (for wrappers with more complex needs)
122
+ * }
123
+ */
124
+ function buildReentryOutput(input) {
125
+ const state = loadCarryForward(input.cwd);
126
+
127
+ if (!state) {
128
+ return {
129
+ reentryStatus: "fresh_start",
130
+ continuityMessage: "Fresh start",
131
+ carryForward: null,
132
+ };
133
+ }
134
+
135
+ return {
136
+ reentryStatus: "resume_available",
137
+ continuityMessage: buildContinuityMessage(state),
138
+ carryForward: state,
139
+ };
140
+ }
141
+
142
+ /**
143
+ * Validates consistency between carry-forward and continuity.json
144
+ * Ensures they don't give conflicting resume signals
145
+ * Returns any inconsistencies found (empty array if consistent)
146
+ */
147
+ function validateCarryForwardContinuityConsistency(cwd) {
148
+ const inconsistencies = [];
149
+
150
+ try {
151
+ // Check continuity state
152
+ const continuityPath = path.join(cwd, ".claude", "cco", "state", "continuity.json");
153
+ let hasContinuity = false;
154
+ let continuityState = null;
155
+
156
+ if (fs.existsSync(continuityPath)) {
157
+ try {
158
+ continuityState = JSON.parse(fs.readFileSync(continuityPath, "utf8"));
159
+ hasContinuity = continuityState.sessionId && continuityState.reEntryCount > 0;
160
+ } catch {
161
+ // Invalid continuity.json - ignore for consistency check
162
+ }
163
+ }
164
+
165
+ // Check carry-forward state
166
+ const carryForward = loadCarryForward(cwd);
167
+ const hasValidCarryForward = carryForward !== null;
168
+
169
+ // Consistency rule: If carry-forward is available, consistency state should be re-entry
170
+ if (hasValidCarryForward && !hasContinuity) {
171
+ // Edge case: carry-forward exists but continuity doesn't (first session with carry-forward)
172
+ // This can happen on first session after carry-forward capture
173
+ // Not technically inconsistent, but good to know about
174
+ console.error("[consistency] Note: carry-forward exists but no continuity state");
175
+ }
176
+
177
+ // If continuity says re-entry but carry-forward is expired, that's consistent
178
+ // (we prefer carry-forward over continuity due to more specific context)
179
+
180
+ } catch (err) {
181
+ // Failed to check consistency - log but don't fail
182
+ console.error(`[consistency] Failed to validate consistency: ${err.message}`);
183
+ }
184
+
185
+ return inconsistencies;
186
+ }
187
+
188
+ module.exports = {
189
+ captureCarryForward,
190
+ loadCarryForward,
191
+ buildContinuityMessage,
192
+ buildReentryOutput,
193
+ validateCarryForwardContinuityConsistency
194
+ };
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+
3
+ const { spawnSync } = require("child_process");
4
+ const path = require("path");
5
+ const { nowIso, safeWriteJson, safeReadJson } = require("./fsx");
6
+ const { buildOutcomeEvent, appendOutcomeEvents } = require("./unified-events");
7
+
8
+ function run(command, args, cwd) {
9
+ return spawnSync(command, args, {
10
+ cwd,
11
+ encoding: "utf8",
12
+ timeout: 30000,
13
+ });
14
+ }
15
+
16
+ function parseJsonMaybe(text) {
17
+ try {
18
+ return JSON.parse(text || "{}");
19
+ } catch {
20
+ return null;
21
+ }
22
+ }
23
+
24
+ function normalizeCcusageRows(payload) {
25
+ if (!payload) return [];
26
+ if (Array.isArray(payload)) return payload;
27
+ if (Array.isArray(payload.data)) return payload.data;
28
+ if (Array.isArray(payload.rows)) return payload.rows;
29
+ if (Array.isArray(payload.daily)) return payload.daily;
30
+ if (Array.isArray(payload.result)) return payload.result;
31
+ return [];
32
+ }
33
+
34
+ function numeric(row, keys) {
35
+ for (const k of keys) {
36
+ const v = Number(row?.[k]);
37
+ if (Number.isFinite(v)) return v;
38
+ }
39
+ return 0;
40
+ }
41
+
42
+ function rowToMetric(row, sessionId) {
43
+ const date = String(row.date || row.day || row.bucket || nowIso().slice(0, 10));
44
+ const totalCost = numeric(row, ["cost", "totalCost", "total_cost", "usd", "costUsd"]);
45
+ const totalTokens = numeric(row, ["tokens", "totalTokens", "total_tokens", "inputTokens", "outputTokens"]);
46
+
47
+ return {
48
+ ts: `${date}T00:00:00.000Z`,
49
+ sessionId,
50
+ event: "CcusageImport",
51
+ tool: "ccusage",
52
+ action: "import",
53
+ reasonCodes: ["CCUSAGE_IMPORT"],
54
+ meta: {
55
+ measured_value: totalCost > 0 ? totalCost : totalTokens,
56
+ estimated_counterfactual_value: totalCost > 0 ? Math.round(totalCost * 0.12 * 100) / 100 : Math.round(totalTokens * 0.08),
57
+ date,
58
+ totalCost,
59
+ totalTokens,
60
+ provider: row.provider || null,
61
+ model: row.model || null,
62
+ },
63
+ };
64
+ }
65
+
66
+ function buildImportSummary(rows) {
67
+ const totalCost = rows.reduce((acc, row) => acc + numeric(row, ["cost", "totalCost", "total_cost", "usd", "costUsd"]), 0);
68
+ const totalTokens = rows.reduce((acc, row) => acc + numeric(row, ["tokens", "totalTokens", "total_tokens", "inputTokens", "outputTokens"]), 0);
69
+ return {
70
+ rows: rows.length,
71
+ totalCost: Math.round(totalCost * 100) / 100,
72
+ totalTokens: Math.round(totalTokens),
73
+ };
74
+ }
75
+
76
+ function fixtureRows() {
77
+ const now = new Date();
78
+ const day1 = new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
79
+ const day2 = new Date(now.getTime() - 1 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
80
+ return [
81
+ { date: day1, cost: 4.25, tokens: 125000, provider: "claude", model: "sonnet" },
82
+ { date: day2, cost: 2.75, tokens: 93000, provider: "claude", model: "haiku" },
83
+ ];
84
+ }
85
+
86
+ function runCcusageCommand(cwd, flavor) {
87
+ const cmd = "npx";
88
+ const pkg = flavor === "codex" ? "@ccusage/codex@latest" : "ccusage@latest";
89
+ const args = ["--yes", pkg, "daily", "--json"];
90
+ return run(cmd, args, cwd);
91
+ }
92
+
93
+ function importCcusageSignals(cwd, options = {}) {
94
+ const flavor = options.flavor || "claude";
95
+ const projectId = options.projectId || path.basename(cwd).toLowerCase();
96
+ const userId = options.userId || process.env.CCO_USER_ID || "local-user";
97
+ const sessionId = `ccusage-${Date.now()}`;
98
+
99
+ if (options?.fixture || process.env.CCO_CCUSAGE_FIXTURE === "1") {
100
+ const rows = fixtureRows();
101
+ const summary = buildImportSummary(rows);
102
+ const metrics = rows.map((row) => rowToMetric(row, sessionId));
103
+ const outcomes = metrics.map((metric) =>
104
+ buildOutcomeEvent({
105
+ metric,
106
+ platform: flavor === "codex" ? "codex" : "claude",
107
+ projectId,
108
+ repoId: projectId,
109
+ userId,
110
+ })
111
+ );
112
+ appendOutcomeEvents(cwd, outcomes);
113
+ const ts = nowIso().replace(/[:.]/g, "-");
114
+ const rel = `.claude/cco/events/ccusage-import-${flavor}-${ts}.json`;
115
+ safeWriteJson(cwd, rel, { importedAt: nowIso(), flavor, summary, rows, outcomes, fixture: true });
116
+ safeWriteJson(cwd, ".claude/cco/events/ccusage-latest.json", { importedAt: nowIso(), flavor, summary, artifact: rel, fixture: true });
117
+ return { ok: true, flavor, summary, artifact: rel, eventsWritten: outcomes.length, fixture: true };
118
+ }
119
+
120
+ const proc = runCcusageCommand(cwd, flavor);
121
+ if (proc.status !== 0) {
122
+ return {
123
+ ok: false,
124
+ reason: "ccusage-unavailable",
125
+ stderr: String(proc.stderr || "").slice(0, 1000),
126
+ stdout: String(proc.stdout || "").slice(0, 1000),
127
+ };
128
+ }
129
+
130
+ const payload = parseJsonMaybe(proc.stdout);
131
+ if (!payload) {
132
+ return {
133
+ ok: false,
134
+ reason: "ccusage-invalid-json",
135
+ stdout: String(proc.stdout || "").slice(0, 1000),
136
+ };
137
+ }
138
+
139
+ const rows = normalizeCcusageRows(payload);
140
+ const summary = buildImportSummary(rows);
141
+
142
+ const metrics = rows.map((row) => rowToMetric(row, sessionId));
143
+ const outcomes = metrics.map((metric) =>
144
+ buildOutcomeEvent({
145
+ metric,
146
+ platform: flavor === "codex" ? "codex" : "claude",
147
+ projectId,
148
+ repoId: projectId,
149
+ userId,
150
+ })
151
+ );
152
+ appendOutcomeEvents(cwd, outcomes);
153
+
154
+ const ts = nowIso().replace(/[:.]/g, "-");
155
+ const rel = `.claude/cco/events/ccusage-import-${flavor}-${ts}.json`;
156
+ safeWriteJson(cwd, rel, {
157
+ importedAt: nowIso(),
158
+ flavor,
159
+ summary,
160
+ rows,
161
+ outcomes,
162
+ });
163
+
164
+ safeWriteJson(cwd, ".claude/cco/events/ccusage-latest.json", {
165
+ importedAt: nowIso(),
166
+ flavor,
167
+ summary,
168
+ artifact: rel,
169
+ });
170
+
171
+ return {
172
+ ok: true,
173
+ flavor,
174
+ summary,
175
+ artifact: rel,
176
+ eventsWritten: outcomes.length,
177
+ };
178
+ }
179
+
180
+ function readLatestCcusageImport(cwd) {
181
+ return safeReadJson(cwd, ".claude/cco/events/ccusage-latest.json", null);
182
+ }
183
+
184
+ module.exports = {
185
+ importCcusageSignals,
186
+ readLatestCcusageImport,
187
+ normalizeCcusageRows,
188
+ };