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.
- package/LICENSE +21 -0
- package/README.md +56 -0
- package/bin/avorelo +9 -0
- package/package.json +135 -0
- package/scripts/README.md +40 -0
- package/scripts/cco-dashboard.js +252 -0
- package/scripts/cco-status.js +430 -0
- package/scripts/lib/activation/account-state.js +37 -0
- package/scripts/lib/activation/activation-runner.js +546 -0
- package/scripts/lib/activation/activation-self-healing.js +480 -0
- package/scripts/lib/activation/activation-state.js +83 -0
- package/scripts/lib/activation/activation-summary.js +191 -0
- package/scripts/lib/activation/adapters/claude-code.js +77 -0
- package/scripts/lib/activation/adapters/codex-cli.js +52 -0
- package/scripts/lib/activation/adapters/cursor.js +37 -0
- package/scripts/lib/activation/adapters/github-agent.js +39 -0
- package/scripts/lib/activation/adapters/terminal.js +42 -0
- package/scripts/lib/activation/adapters/vscode.js +39 -0
- package/scripts/lib/activation/adapters/windsurf.js +37 -0
- package/scripts/lib/activation/ai-surface-detector.js +151 -0
- package/scripts/lib/activation/connect-account.js +145 -0
- package/scripts/lib/activation/detect-environment.js +75 -0
- package/scripts/lib/activation/detect-hosts.js +62 -0
- package/scripts/lib/activation/format-activation-output.js +109 -0
- package/scripts/lib/activation/next-action.js +43 -0
- package/scripts/lib/activation/repair-engine.js +219 -0
- package/scripts/lib/activation-distribution-readiness.js +507 -0
- package/scripts/lib/adapter-conformance.js +176 -0
- package/scripts/lib/adapter-readiness.js +417 -0
- package/scripts/lib/adapter-safety-boundaries.js +335 -0
- package/scripts/lib/adapter-technical-readiness-gate.js +205 -0
- package/scripts/lib/agent-access-governance.js +455 -0
- package/scripts/lib/agent-enforcement.js +765 -0
- package/scripts/lib/agent-policy-profile.js +210 -0
- package/scripts/lib/agent-security/action-evaluator.js +507 -0
- package/scripts/lib/agent-security/adapter-registry.js +98 -0
- package/scripts/lib/agent-security/auto-policy.js +139 -0
- package/scripts/lib/agent-security/bounded-scan.js +93 -0
- package/scripts/lib/agent-security/enforcement-adapter.js +174 -0
- package/scripts/lib/agent-security/enforcement-engine.js +1129 -0
- package/scripts/lib/agent-security/file-write-adapter.js +183 -0
- package/scripts/lib/agent-security/file-write-rules.js +178 -0
- package/scripts/lib/agent-security/index.js +3342 -0
- package/scripts/lib/agent-security/instruction-risk.js +181 -0
- package/scripts/lib/agent-security/mcp-action-adapter.js +185 -0
- package/scripts/lib/agent-security/mcp-action-rules.js +184 -0
- package/scripts/lib/agent-security/package-action-adapter.js +175 -0
- package/scripts/lib/agent-security/package-action-rules.js +233 -0
- package/scripts/lib/agent-security/performance.js +148 -0
- package/scripts/lib/agent-security/permission-minimizer.js +403 -0
- package/scripts/lib/agent-security/scan-cache.js +74 -0
- package/scripts/lib/agent-security/source-trust.js +146 -0
- package/scripts/lib/ai-install-prompt.js +288 -0
- package/scripts/lib/ai-workspace-hygiene.js +1499 -0
- package/scripts/lib/alpha-activation.js +520 -0
- package/scripts/lib/alpha-feedback.js +263 -0
- package/scripts/lib/alpha-readiness-gate.js +332 -0
- package/scripts/lib/anti-gaming.js +169 -0
- package/scripts/lib/artifact-health.js +431 -0
- package/scripts/lib/attribution.js +180 -0
- package/scripts/lib/audit.js +289 -0
- package/scripts/lib/avorelo-skill-registry.js +810 -0
- package/scripts/lib/batch-jobs.js +71 -0
- package/scripts/lib/brain-pack.js +578 -0
- package/scripts/lib/brand-boundary.js +424 -0
- package/scripts/lib/brand.js +74 -0
- package/scripts/lib/browser-capability.js +1048 -0
- package/scripts/lib/browser-proof-preflight.js +321 -0
- package/scripts/lib/cache-readiness.js +187 -0
- package/scripts/lib/canonical-reentry.js +162 -0
- package/scripts/lib/capability-packs.js +314 -0
- package/scripts/lib/capability-recommender.js +512 -0
- package/scripts/lib/capability-registry.js +1059 -0
- package/scripts/lib/carry-forward-surfacing.js +194 -0
- package/scripts/lib/ccusage-adapter.js +188 -0
- package/scripts/lib/company-loop.js +1149 -0
- package/scripts/lib/config.js +637 -0
- package/scripts/lib/context-acquisition-plan.js +287 -0
- package/scripts/lib/context-budget-guard.js +170 -0
- package/scripts/lib/context-budget-scanner.js +257 -0
- package/scripts/lib/context-optimizer.js +715 -0
- package/scripts/lib/context-reduction-plan.js +178 -0
- package/scripts/lib/context-safety.js +88 -0
- package/scripts/lib/context-savings-engine.js +158 -0
- package/scripts/lib/cost-evidence.js +254 -0
- package/scripts/lib/cross-host-install-plan.js +308 -0
- package/scripts/lib/cross-host-install-readiness.js +237 -0
- package/scripts/lib/cross-host-value-flow.js +268 -0
- package/scripts/lib/dashboard.js +900 -0
- package/scripts/lib/design-partner-feedback.js +346 -0
- package/scripts/lib/entitlements.js +100 -0
- package/scripts/lib/execution-packet.js +559 -0
- package/scripts/lib/experimentation-events.js +547 -0
- package/scripts/lib/external-capability-compliance.js +107 -0
- package/scripts/lib/external-user-simulation.js +166 -0
- package/scripts/lib/failure-recovery-readiness.js +81 -0
- package/scripts/lib/failure-recovery.js +419 -0
- package/scripts/lib/feedback-intelligence.js +537 -0
- package/scripts/lib/feedback-signals.js +205 -0
- package/scripts/lib/file-integrity.js +68 -0
- package/scripts/lib/fsx.js +127 -0
- package/scripts/lib/full-readiness-gate.js +451 -0
- package/scripts/lib/guidance-builder.js +174 -0
- package/scripts/lib/hook-apply.js +1019 -0
- package/scripts/lib/hook-baseline.js +310 -0
- package/scripts/lib/hook-config-preview.js +275 -0
- package/scripts/lib/hook-contracts.js +290 -0
- package/scripts/lib/hook-safety-boundary-readiness.js +80 -0
- package/scripts/lib/host-capability-matrix.js +351 -0
- package/scripts/lib/host-support-context.js +254 -0
- package/scripts/lib/http-hook-action.js +538 -0
- package/scripts/lib/install-ai-readiness.js +84 -0
- package/scripts/lib/install-intake-risk.js +1037 -0
- package/scripts/lib/install-journey-intelligence.js +329 -0
- package/scripts/lib/intervention-guidance.js +57 -0
- package/scripts/lib/known-limitations.js +115 -0
- package/scripts/lib/l8-path-truth.js +146 -0
- package/scripts/lib/launch-hardening-gate.js +436 -0
- package/scripts/lib/launch-readiness.js +628 -0
- package/scripts/lib/learning-memory.js +686 -0
- package/scripts/lib/lifecycle-hooks.js +802 -0
- package/scripts/lib/local-package-smoke.js +423 -0
- package/scripts/lib/local-pricing.js +299 -0
- package/scripts/lib/mcp-enforcement.js +311 -0
- package/scripts/lib/mcp-least-privilege-policy.js +303 -0
- package/scripts/lib/mcp-tool-inventory.js +388 -0
- package/scripts/lib/mcp-tool-risk.js +0 -0
- package/scripts/lib/memory.js +335 -0
- package/scripts/lib/metrics.js +699 -0
- package/scripts/lib/micro-proof.js +133 -0
- package/scripts/lib/next-run-context.js +436 -0
- package/scripts/lib/operating-value.js +1648 -0
- package/scripts/lib/optimization-v3.js +122 -0
- package/scripts/lib/orchestration/adapters/_shared.js +49 -0
- package/scripts/lib/orchestration/adapters/aider.js +18 -0
- package/scripts/lib/orchestration/adapters/claude-code.js +35 -0
- package/scripts/lib/orchestration/adapters/codex.js +35 -0
- package/scripts/lib/orchestration/adapters/gemini-cli.js +18 -0
- package/scripts/lib/orchestration/adapters/git.js +25 -0
- package/scripts/lib/orchestration/adapters/index.js +31 -0
- package/scripts/lib/orchestration/adapters/lm-studio.js +18 -0
- package/scripts/lib/orchestration/adapters/ollama.js +18 -0
- package/scripts/lib/orchestration/adapters/opencode.js +18 -0
- package/scripts/lib/orchestration/adapters/openrouter.js +18 -0
- package/scripts/lib/orchestration/adapters/test-runner.js +25 -0
- package/scripts/lib/orchestration/cli.js +438 -0
- package/scripts/lib/orchestration/execution-manager.js +279 -0
- package/scripts/lib/orchestration/handoff.js +314 -0
- package/scripts/lib/orchestration/index.js +456 -0
- package/scripts/lib/orchestration/inventory.js +47 -0
- package/scripts/lib/orchestration/model-discovery.js +498 -0
- package/scripts/lib/orchestration/model-profiler.js +170 -0
- package/scripts/lib/orchestration/model-profiles.js +252 -0
- package/scripts/lib/orchestration/model-refresh-policy.js +72 -0
- package/scripts/lib/orchestration/proof-writer.js +349 -0
- package/scripts/lib/orchestration/provider-discovery/aider.js +49 -0
- package/scripts/lib/orchestration/provider-discovery/claude-code.js +56 -0
- package/scripts/lib/orchestration/provider-discovery/codex.js +49 -0
- package/scripts/lib/orchestration/provider-discovery/common.js +186 -0
- package/scripts/lib/orchestration/provider-discovery/gemini.js +106 -0
- package/scripts/lib/orchestration/provider-discovery/lm-studio.js +118 -0
- package/scripts/lib/orchestration/provider-discovery/models-dev.js +12 -0
- package/scripts/lib/orchestration/provider-discovery/ollama.js +100 -0
- package/scripts/lib/orchestration/provider-discovery/opencode.js +47 -0
- package/scripts/lib/orchestration/provider-discovery/openrouter.js +44 -0
- package/scripts/lib/orchestration/risk-classifier.js +130 -0
- package/scripts/lib/orchestration/routing-policy.js +486 -0
- package/scripts/lib/orchestration/settings.js +112 -0
- package/scripts/lib/orchestration/state.js +165 -0
- package/scripts/lib/orchestration/verification-manager.js +138 -0
- package/scripts/lib/output-profiles.js +146 -0
- package/scripts/lib/package-content-audit.js +368 -0
- package/scripts/lib/package-runtime.js +278 -0
- package/scripts/lib/plan-surface.js +53 -0
- package/scripts/lib/plans.js +2318 -0
- package/scripts/lib/policy-provider.js +27 -0
- package/scripts/lib/prelaunch-activation-readiness.js +409 -0
- package/scripts/lib/prelaunch-evidence-store.js +816 -0
- package/scripts/lib/prelaunch-intelligence.js +869 -0
- package/scripts/lib/pricing-experiment.js +118 -0
- package/scripts/lib/pro-moment-events.js +77 -0
- package/scripts/lib/pro-moment-state.js +227 -0
- package/scripts/lib/pro-moments.js +1216 -0
- package/scripts/lib/product-learning-events.js +629 -0
- package/scripts/lib/project-profile.js +555 -0
- package/scripts/lib/prompt-compiler.js +280 -0
- package/scripts/lib/prompt-lint.js +32 -0
- package/scripts/lib/prompt-suggestions.js +52 -0
- package/scripts/lib/proof-canonical.js +398 -0
- package/scripts/lib/proof-drilldown.js +383 -0
- package/scripts/lib/proof-events.js +342 -0
- package/scripts/lib/proof-history.js +243 -0
- package/scripts/lib/proof-metrics.js +296 -0
- package/scripts/lib/proof-outcome-evidence.js +134 -0
- package/scripts/lib/proof-receipt.js +335 -0
- package/scripts/lib/proof-record.js +461 -0
- package/scripts/lib/public-activation-distribution-gate.js +258 -0
- package/scripts/lib/public-cli.js +3891 -0
- package/scripts/lib/public-distribution-truth.js +211 -0
- package/scripts/lib/public-install-claim-checker.js +294 -0
- package/scripts/lib/publish-provenance-readiness.js +283 -0
- package/scripts/lib/readiness-delta.js +218 -0
- package/scripts/lib/readiness-evidence-closure.js +196 -0
- package/scripts/lib/reentry-memory-capture.js +241 -0
- package/scripts/lib/reentry-memory-retrieval.js +302 -0
- package/scripts/lib/reentry-memory-status.js +146 -0
- package/scripts/lib/reentry-memory-store.js +178 -0
- package/scripts/lib/reentry-state.js +66 -0
- package/scripts/lib/release-candidate-bundle.js +166 -0
- package/scripts/lib/remediation.js +81 -0
- package/scripts/lib/repo-map.js +391 -0
- package/scripts/lib/run-improvements-lifecycle.js +330 -0
- package/scripts/lib/run-improvements.js +789 -0
- package/scripts/lib/runtime-decision-policy.js +387 -0
- package/scripts/lib/safe-path-engine.js +705 -0
- package/scripts/lib/safe-run-controller.js +887 -0
- package/scripts/lib/score.js +262 -0
- package/scripts/lib/seamless-enforcement.js +329 -0
- package/scripts/lib/seamless-outcome.js +689 -0
- package/scripts/lib/seamless-reality-gate.js +5043 -0
- package/scripts/lib/security-risk-classifier.js +511 -0
- package/scripts/lib/security-scan.js +384 -0
- package/scripts/lib/session-context-optimizer.js +1211 -0
- package/scripts/lib/session-timing.js +315 -0
- package/scripts/lib/skill-hygiene.js +805 -0
- package/scripts/lib/skill-packs.js +161 -0
- package/scripts/lib/skills-operating-layer.js +580 -0
- package/scripts/lib/smart-work-routing.js +768 -0
- package/scripts/lib/source-catalog.js +700 -0
- package/scripts/lib/status-value-summary.js +32 -0
- package/scripts/lib/support-bundle.js +578 -0
- package/scripts/lib/task-continuation.js +440 -0
- package/scripts/lib/test-helpers.js +15 -0
- package/scripts/lib/tier.js +38 -0
- package/scripts/lib/token-context-quality-gate.js +370 -0
- package/scripts/lib/token-cost-capture.js +187 -0
- package/scripts/lib/token-cost-intelligence.js +358 -0
- package/scripts/lib/token-efficiency-evidence.js +213 -0
- package/scripts/lib/token-evidence.js +699 -0
- package/scripts/lib/tokenish.js +17 -0
- package/scripts/lib/tool-output-sandbox.js +304 -0
- package/scripts/lib/trust-audit.js +136 -0
- package/scripts/lib/unified-events.js +396 -0
- package/scripts/lib/upgrade-interruption-recovery.js +407 -0
- package/scripts/lib/usage-ledger.js +201 -0
- package/scripts/lib/value-ledger.js +130 -0
- package/scripts/lib/value-proof-calibration.js +531 -0
- package/scripts/lib/visual-qa.js +231 -0
- package/scripts/lib/voice-alpha.js +29 -0
- package/scripts/lib/work-aware-orchestration.js +976 -0
- package/scripts/lib/work-control-receipts.js +577 -0
- package/scripts/lib/work-ledger.js +1123 -0
- package/scripts/lib/work-panel-preview.js +352 -0
- package/scripts/lib/workflow-discipline.js +280 -0
- package/scripts/lib/workflow-signals.js +419 -0
- package/scripts/lib/workspace-map.js +281 -0
- package/scripts/lib/workspace-registry.js +1367 -0
- package/scripts/lib/workspace-resolver.js +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
|
+
};
|