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,133 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Inline Micro-Proof System (Surface 1).
5
+ *
6
+ * Shows small, calm, contextual proof moments inside the workflow
7
+ * only when a material value event actually happened.
8
+ *
9
+ * Rules:
10
+ * - Must not be modal
11
+ * - Must not spam the user
12
+ * - Must deduplicate repeated proof types per session
13
+ * - Must show at most top 1-2 meaningful proofs at a moment
14
+ * - Must map directly to real telemetry/proof data
15
+ * - Must use calm factual copy
16
+ */
17
+
18
+ const fs = require("fs");
19
+ const path = require("path");
20
+ const { REASON_CODE_PROOF_MAP } = require("./proof-events");
21
+
22
+ const MAX_PROOFS_PER_HOOK = 2;
23
+ const MAX_PROOFS_PER_TYPE_PER_SESSION = 3;
24
+
25
+ /**
26
+ * Load the micro-proof dedup state for a session.
27
+ */
28
+ function loadMicroProofState(cwd, sessionId) {
29
+ const p = path.join(cwd, ".claude", "cco", "state", `micro-proof-${sessionId}.json`);
30
+ try {
31
+ return JSON.parse(fs.readFileSync(p, "utf8"));
32
+ } catch {
33
+ return { shown: {} };
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Save the micro-proof dedup state for a session.
39
+ */
40
+ function saveMicroProofState(cwd, sessionId, state) {
41
+ const p = path.join(cwd, ".claude", "cco", "state", `micro-proof-${sessionId}.json`);
42
+ fs.mkdirSync(path.dirname(p), { recursive: true });
43
+ fs.writeFileSync(p, JSON.stringify(state, null, 2), "utf8");
44
+ }
45
+
46
+ /**
47
+ * Select proof-worthy micro-proofs from a set of reason codes.
48
+ *
49
+ * Returns up to MAX_PROOFS_PER_HOOK calm one-liners, deduplicated
50
+ * against what was already shown in this session.
51
+ *
52
+ * @param {string[]} reasonCodes - reason codes from the current hook metric
53
+ * @param {string} cwd - workspace root
54
+ * @param {string} sessionId - session identifier
55
+ * @param {object} options - { proofEnabled?: boolean }
56
+ * @returns {{ proofs: string[], updated: boolean }}
57
+ */
58
+ function selectMicroProofs(reasonCodes, cwd, sessionId, options = {}) {
59
+ if (options.proofEnabled === false) {
60
+ return { proofs: [], updated: false };
61
+ }
62
+
63
+ const state = loadMicroProofState(cwd, sessionId);
64
+ const candidates = [];
65
+
66
+ for (const code of reasonCodes || []) {
67
+ const mapping = REASON_CODE_PROOF_MAP[code];
68
+ if (!mapping || !mapping.proofWorthy || !mapping.calmCopy) continue;
69
+
70
+ // Dedup: skip if this proof type has been shown too many times
71
+ const shown = state.shown[code] || 0;
72
+ if (shown >= MAX_PROOFS_PER_TYPE_PER_SESSION) continue;
73
+
74
+ candidates.push({
75
+ code,
76
+ copy: mapping.calmCopy,
77
+ dimension: mapping.dimension,
78
+ family: mapping.family,
79
+ });
80
+ }
81
+
82
+ if (candidates.length === 0) {
83
+ return { proofs: [], updated: false };
84
+ }
85
+
86
+ // Prioritize by dimension diversity: show one from each dimension if possible
87
+ const selected = [];
88
+ const seenDimensions = new Set();
89
+
90
+ for (const c of candidates) {
91
+ if (selected.length >= MAX_PROOFS_PER_HOOK) break;
92
+ if (!seenDimensions.has(c.dimension)) {
93
+ selected.push(c);
94
+ seenDimensions.add(c.dimension);
95
+ }
96
+ }
97
+
98
+ // Fill remaining slots if we haven't hit the cap
99
+ for (const c of candidates) {
100
+ if (selected.length >= MAX_PROOFS_PER_HOOK) break;
101
+ if (!selected.includes(c)) {
102
+ selected.push(c);
103
+ }
104
+ }
105
+
106
+ // Update dedup state
107
+ for (const s of selected) {
108
+ state.shown[s.code] = (state.shown[s.code] || 0) + 1;
109
+ }
110
+ saveMicroProofState(cwd, sessionId, state);
111
+
112
+ return {
113
+ proofs: selected.map((s) => s.copy),
114
+ updated: true,
115
+ };
116
+ }
117
+
118
+ /**
119
+ * Format micro-proofs as additional context for hook output.
120
+ * Returns a single string to be injected via outAdditional, or null if no proofs.
121
+ */
122
+ function formatMicroProofContext(proofs) {
123
+ if (!proofs || proofs.length === 0) return null;
124
+ return proofs.join(" ");
125
+ }
126
+
127
+ module.exports = {
128
+ selectMicroProofs,
129
+ formatMicroProofContext,
130
+ loadMicroProofState,
131
+ MAX_PROOFS_PER_HOOK,
132
+ MAX_PROOFS_PER_TYPE_PER_SESSION,
133
+ };
@@ -0,0 +1,436 @@
1
+ "use strict";
2
+
3
+ // Next-Run Context — auto-injection of evidence-backed learning into the next AI coding run.
4
+ // Builds a compact, bounded artifact from prepared run improvements and learning summary.
5
+ // No cloud calls, no LLM, no daemon. Deterministic, local-first, honest.
6
+ //
7
+ // Artifact path: .claude/cco/state/next-run-context.json
8
+ // Schema: avorelo.nextRunContext.v1
9
+ //
10
+ // Lifecycle:
11
+ // not_available — run improvements not prepared
12
+ // prepared — artifact built, waiting for session to consume
13
+ // injected — session-start hook read and embedded it
14
+ // applied — artifact written and pointed to by lifecycle receipt
15
+ // expired — TTL exceeded
16
+ // stale — source fingerprint no longer matches run improvements
17
+ // insufficient_evidence — no actionable defaults to inject
18
+ // skipped — injection explicitly skipped
19
+ // error — unexpected error
20
+
21
+ const fs = require("fs");
22
+ const path = require("path");
23
+
24
+ const NEXT_RUN_CONTEXT_REL = ".claude/cco/state/next-run-context.json";
25
+ const SCHEMA_VERSION = "avorelo.nextRunContext.v1";
26
+
27
+ // 4-hour TTL: this is a "current-handoff" artifact, shorter than run-improvements (24h)
28
+ const TTL_MS = 4 * 60 * 60 * 1000;
29
+
30
+ const NEXT_RUN_STATUSES = [
31
+ "not_available",
32
+ "prepared",
33
+ "injected",
34
+ "applied",
35
+ "expired",
36
+ "stale",
37
+ "insufficient_evidence",
38
+ "skipped",
39
+ "error",
40
+ ];
41
+
42
+ function nowIso() {
43
+ return new Date().toISOString();
44
+ }
45
+
46
+ function expiresAtFromNow(fromIso) {
47
+ const base = fromIso ? new Date(fromIso) : new Date();
48
+ return new Date(base.getTime() + TTL_MS).toISOString();
49
+ }
50
+
51
+ function isExpired(artifact) {
52
+ if (!artifact || !artifact.expiresAt) return true;
53
+ return Date.now() > new Date(artifact.expiresAt).getTime();
54
+ }
55
+
56
+ function isStale(artifact, runImprovementsArtifact) {
57
+ if (!artifact || !runImprovementsArtifact) return false;
58
+ return artifact.sourceRunFingerprint !== runImprovementsArtifact.sourceRunFingerprint;
59
+ }
60
+
61
+ // ── Bounded payload selection ─────────────────────────────────────────────────
62
+
63
+ // Top 1–3 defaults from run improvements (evidence-backed only)
64
+ function selectBoundedDefaults(runImprovements) {
65
+ if (!runImprovements || !Array.isArray(runImprovements.nextRunDefaults)) return [];
66
+ return runImprovements.nextRunDefaults.slice(0, 3);
67
+ }
68
+
69
+ // Top 1–3 active decisions from learning summary
70
+ function selectActiveDecisions(learningSummary) {
71
+ if (!learningSummary || !Array.isArray(learningSummary.topSignals)) return [];
72
+ return learningSummary.topSignals
73
+ .filter((s) => s.type === "decision")
74
+ .slice(0, 3)
75
+ .map((s) => ({
76
+ summary: s.summary,
77
+ confidence: s.confidence,
78
+ reasonCodes: s.reasonCodes || [],
79
+ }));
80
+ }
81
+
82
+ // Top 1–3 active risks from learning summary
83
+ function selectActiveRisks(learningSummary) {
84
+ if (!learningSummary || !Array.isArray(learningSummary.topRisks)) return [];
85
+ return learningSummary.topRisks
86
+ .filter((r) => r.status === "active")
87
+ .slice(0, 3)
88
+ .map((r) => ({
89
+ title: r.title,
90
+ severity: r.severity,
91
+ mitigation: r.mitigation,
92
+ reasonCodes: r.reasonCodes || [],
93
+ }));
94
+ }
95
+
96
+ // Evidence-backed capability recommendation
97
+ function selectCapabilityRecommendation(learningSummary) {
98
+ if (!learningSummary || !learningSummary.capabilityRecommendation) return null;
99
+ const rec = learningSummary.capabilityRecommendation;
100
+ if (!rec.id) return null;
101
+ return {
102
+ id: rec.id,
103
+ whenToUse: rec.whenToUse || null,
104
+ whenNotToUse: rec.whenNotToUse || null,
105
+ evidenceBacked: Boolean(rec.evidenceRefs && rec.evidenceRefs.length > 0),
106
+ };
107
+ }
108
+
109
+ // Build the human-readable context blocks for session injection
110
+ function buildContextBlocks(appliedDefaults, activeDecisions, activeRisks, capabilityRec) {
111
+ const blocks = [];
112
+
113
+ if (appliedDefaults.length > 0) {
114
+ const lines = appliedDefaults.map((d) => `- ${d.text}`).join("\n");
115
+ blocks.push({
116
+ type: "next_run_defaults",
117
+ heading: "Next-run defaults (evidence-backed):",
118
+ text: lines,
119
+ });
120
+ }
121
+
122
+ if (activeDecisions.length > 0) {
123
+ const lines = activeDecisions.map((d) => `- ${d.summary}`).join("\n");
124
+ blocks.push({
125
+ type: "active_decisions",
126
+ heading: "Active decisions for this run:",
127
+ text: lines,
128
+ });
129
+ }
130
+
131
+ if (activeRisks.length > 0) {
132
+ const lines = activeRisks.map((r) => `- [${r.severity}] ${r.title}: ${r.mitigation}`).join("\n");
133
+ blocks.push({
134
+ type: "active_risks",
135
+ heading: "Active risks to carry forward:",
136
+ text: lines,
137
+ });
138
+ }
139
+
140
+ if (capabilityRec && capabilityRec.evidenceBacked) {
141
+ blocks.push({
142
+ type: "capability_recommendation",
143
+ heading: "Capability recommendation:",
144
+ text: `Use: ${capabilityRec.id}. ${capabilityRec.whenToUse || ""}`,
145
+ });
146
+ }
147
+
148
+ return blocks;
149
+ }
150
+
151
+ // Produce a compact human-readable text block suitable for session injection
152
+ function buildCompactContextText(artifact) {
153
+ if (!artifact || !Array.isArray(artifact.contextBlocks) || artifact.contextBlocks.length === 0) {
154
+ return null;
155
+ }
156
+
157
+ const lines = ["Next-run context from Avorelo:"];
158
+ for (const block of artifact.contextBlocks) {
159
+ for (const line of block.text.split("\n")) {
160
+ lines.push(` ${line}`);
161
+ }
162
+ }
163
+ if (artifact.limitations && artifact.limitations.length > 0) {
164
+ lines.push(` Limitations: ${artifact.limitations[0]}`);
165
+ }
166
+ return lines.join("\n");
167
+ }
168
+
169
+ // ── Core builder ──────────────────────────────────────────────────────────────
170
+
171
+ function buildNextRunContext(cwd) {
172
+ const generatedAt = nowIso();
173
+
174
+ // Load run improvements
175
+ let runImprovements = null;
176
+ try {
177
+ const { loadRunImprovements } = require("./run-improvements");
178
+ runImprovements = loadRunImprovements(cwd);
179
+ } catch {}
180
+
181
+ if (!runImprovements || runImprovements.status === "not_available" || runImprovements.status === "expired") {
182
+ return {
183
+ schemaVersion: SCHEMA_VERSION,
184
+ generatedAt,
185
+ expiresAt: expiresAtFromNow(generatedAt),
186
+ sourceRunFingerprint: runImprovements?.sourceRunFingerprint || "none",
187
+ sourceArtifacts: {
188
+ runImprovementsRef: null,
189
+ learningSummaryRef: null,
190
+ },
191
+ appliedDefaults: [],
192
+ contextBlocks: [],
193
+ reasonCodes: ["NO_RUN_IMPROVEMENTS"],
194
+ redactionStatus: "redacted",
195
+ limitations: ["No prepared run improvements found. Run `avorelo run-improvements --generate` first."],
196
+ status: "not_available",
197
+ };
198
+ }
199
+
200
+ // Load learning summary (optional)
201
+ let learningSummary = null;
202
+ try {
203
+ const { loadLearningSummary } = require("./learning-memory");
204
+ learningSummary = loadLearningSummary(cwd);
205
+ } catch {}
206
+
207
+ const fingerprint = runImprovements.sourceRunFingerprint;
208
+ const appliedDefaults = selectBoundedDefaults(runImprovements);
209
+ const activeDecisions = selectActiveDecisions(learningSummary);
210
+ const activeRisks = selectActiveRisks(learningSummary);
211
+ const capabilityRec = selectCapabilityRecommendation(learningSummary);
212
+
213
+ if (appliedDefaults.length === 0 && activeDecisions.length === 0) {
214
+ return {
215
+ schemaVersion: SCHEMA_VERSION,
216
+ generatedAt,
217
+ expiresAt: expiresAtFromNow(generatedAt),
218
+ sourceRunFingerprint: fingerprint,
219
+ sourceArtifacts: {
220
+ runImprovementsRef: ".claude/cco/state/run-improvements.json",
221
+ learningSummaryRef: learningSummary ? ".claude/cco/state/learning-summary.json" : null,
222
+ },
223
+ appliedDefaults: [],
224
+ contextBlocks: [],
225
+ reasonCodes: ["INSUFFICIENT_DEFAULTS"],
226
+ redactionStatus: "redacted",
227
+ limitations: [
228
+ "No actionable defaults or decisions found to inject.",
229
+ "Run `avorelo learning --generate` to refresh learning artifacts.",
230
+ ],
231
+ status: "insufficient_evidence",
232
+ };
233
+ }
234
+
235
+ const contextBlocks = buildContextBlocks(appliedDefaults, activeDecisions, activeRisks, capabilityRec);
236
+ const reasonCodes = [
237
+ ...new Set([
238
+ ...(runImprovements.reasonCodes || []),
239
+ ...(learningSummary ? ["LEARNING_SUMMARY_INCLUDED"] : []),
240
+ ]),
241
+ ];
242
+
243
+ const limitations = [
244
+ "Defaults are bounded to top 3 from evidence — full register is not included.",
245
+ "Decisions are active-only — stale/superseded items are excluded.",
246
+ "Run improvements lifecycle: applied only when this artifact is written and receipt exists.",
247
+ ...(runImprovements.limitations || []).slice(0, 2),
248
+ ];
249
+
250
+ // Never include raw transcripts, secrets, env dumps, or absolute local paths
251
+ return {
252
+ schemaVersion: SCHEMA_VERSION,
253
+ generatedAt,
254
+ expiresAt: expiresAtFromNow(generatedAt),
255
+ sourceRunFingerprint: fingerprint,
256
+ sourceArtifacts: {
257
+ runImprovementsRef: ".claude/cco/state/run-improvements.json",
258
+ learningSummaryRef: learningSummary ? ".claude/cco/state/learning-summary.json" : null,
259
+ },
260
+ appliedDefaults,
261
+ activeDecisionCount: activeDecisions.length,
262
+ activeRiskCount: activeRisks.length,
263
+ capabilityRecommendation: capabilityRec,
264
+ contextBlocks,
265
+ reasonCodes,
266
+ redactionStatus: "redacted",
267
+ limitations,
268
+ status: "prepared",
269
+ };
270
+ }
271
+
272
+ // ── Write / load ──────────────────────────────────────────────────────────────
273
+
274
+ function generateNextRunContextArtifact(cwd, options = {}) {
275
+ const artifact = buildNextRunContext(cwd);
276
+
277
+ // Idempotency: same fingerprint + prepared/applied + not expired → skip rewrite
278
+ const existing = loadNextRunContext(cwd);
279
+ if (
280
+ existing &&
281
+ !isExpired(existing) &&
282
+ existing.sourceRunFingerprint === artifact.sourceRunFingerprint &&
283
+ (existing.status === "prepared" || existing.status === "applied" || existing.status === "injected") &&
284
+ !options.force
285
+ ) {
286
+ return { artifact: existing, written: false, reason: "same_fingerprint_not_expired" };
287
+ }
288
+
289
+ const absPath = path.join(cwd, NEXT_RUN_CONTEXT_REL);
290
+ fs.mkdirSync(path.dirname(absPath), { recursive: true });
291
+ fs.writeFileSync(absPath, JSON.stringify(artifact, null, 2), "utf8");
292
+
293
+ _emitAuditEvent(cwd, artifact, "next_run_context.prepared");
294
+
295
+ return { artifact, written: true, reason: "generated" };
296
+ }
297
+
298
+ function loadNextRunContext(cwd) {
299
+ try {
300
+ const absPath = path.join(cwd, NEXT_RUN_CONTEXT_REL);
301
+ const raw = JSON.parse(fs.readFileSync(absPath, "utf8"));
302
+ if (raw.schemaVersion !== SCHEMA_VERSION) return null;
303
+ if (isExpired(raw)) {
304
+ raw.status = "expired";
305
+ }
306
+ return raw;
307
+ } catch {
308
+ return null;
309
+ }
310
+ }
311
+
312
+ // Update the artifact's status in-place (used by session-start injection)
313
+ function updateNextRunContextStatus(cwd, newStatus, options = {}) {
314
+ try {
315
+ const absPath = path.join(cwd, NEXT_RUN_CONTEXT_REL);
316
+ if (!fs.existsSync(absPath)) return false;
317
+ const stored = JSON.parse(fs.readFileSync(absPath, "utf8"));
318
+ if (stored.schemaVersion !== SCHEMA_VERSION) return false;
319
+ stored.status = newStatus;
320
+ if (options.injectedAt) stored.injectedAt = options.injectedAt;
321
+ fs.writeFileSync(absPath, JSON.stringify(stored, null, 2), "utf8");
322
+ return true;
323
+ } catch {
324
+ return false;
325
+ }
326
+ }
327
+
328
+ // ── Audit events ──────────────────────────────────────────────────────────────
329
+
330
+ function _emitAuditEvent(cwd, artifact, eventName) {
331
+ try {
332
+ const eventsPath = path.join(cwd, ".claude/cco/events/outcome-events.jsonl");
333
+ fs.mkdirSync(path.dirname(eventsPath), { recursive: true });
334
+ const safeEventName = eventName.replace(/\./g, "_");
335
+ const event = JSON.stringify({
336
+ event_id: `nrc_${safeEventName}_${artifact.sourceRunFingerprint}`,
337
+ session_id: "avorelo-next-run-context",
338
+ timestamp: nowIso(),
339
+ category: "next_run_context",
340
+ event_name: safeEventName,
341
+ reason_code: "NEXT_RUN_CONTEXT_LIFECYCLE",
342
+ confidence_score: 1.0,
343
+ platform: "avorelo",
344
+ metadata: {
345
+ schemaVersion: artifact.schemaVersion,
346
+ status: artifact.status,
347
+ defaultsCount: (artifact.appliedDefaults || []).length,
348
+ decisionsCount: artifact.activeDecisionCount || 0,
349
+ risksCount: artifact.activeRiskCount || 0,
350
+ capabilityCount: artifact.capabilityRecommendation ? 1 : 0,
351
+ sourceRunFingerprint: artifact.sourceRunFingerprint,
352
+ surface: artifact.injectedSurface || null,
353
+ redactionStatus: artifact.redactionStatus || "redacted",
354
+ reasonCodes: (artifact.reasonCodes || []).slice(0, 5),
355
+ },
356
+ });
357
+ fs.appendFileSync(eventsPath, event + "\n", "utf8");
358
+ } catch {}
359
+ }
360
+
361
+ function emitNextRunContextEvent(cwd, artifact, eventName) {
362
+ _emitAuditEvent(cwd, artifact, eventName);
363
+ }
364
+
365
+ // ── Status/dashboard surface ──────────────────────────────────────────────────
366
+
367
+ function buildNextRunContextSurface(cwd) {
368
+ const artifact = loadNextRunContext(cwd);
369
+ if (!artifact || artifact.status === "not_available") {
370
+ return {
371
+ showInStatus: false,
372
+ statusLine: null,
373
+ artifact: null,
374
+ };
375
+ }
376
+
377
+ const statusText = {
378
+ prepared: "prepared",
379
+ injected: "injected",
380
+ applied: "applied",
381
+ expired: "expired",
382
+ stale: "stale",
383
+ insufficient_evidence: "no actionable context",
384
+ skipped: "skipped",
385
+ error: "error",
386
+ }[artifact.status] || artifact.status;
387
+
388
+ const defaultsCount = (artifact.appliedDefaults || []).length;
389
+ const expiresIn = artifact.expiresAt
390
+ ? Math.max(0, Math.round((new Date(artifact.expiresAt).getTime() - Date.now()) / 60000))
391
+ : null;
392
+
393
+ const expiryNote = expiresIn !== null && artifact.status !== "expired"
394
+ ? ` · expires in ${expiresIn}m`
395
+ : "";
396
+
397
+ const statusLine =
398
+ artifact.status === "expired"
399
+ ? "Next-run context: expired — run `avorelo run-improvements --apply` to refresh"
400
+ : artifact.status === "insufficient_evidence"
401
+ ? "Next-run context: no actionable context"
402
+ : `Next-run context: ${statusText} · ${defaultsCount} default(s)${expiryNote}`;
403
+
404
+ return {
405
+ showInStatus: true,
406
+ statusLine,
407
+ artifact,
408
+ };
409
+ }
410
+
411
+ function formatNextRunContextText(cwd) {
412
+ const artifact = loadNextRunContext(cwd);
413
+ if (!artifact) return null;
414
+ if (artifact.status === "not_available" || artifact.status === "expired") return null;
415
+ return buildCompactContextText(artifact);
416
+ }
417
+
418
+ module.exports = {
419
+ SCHEMA_VERSION,
420
+ NEXT_RUN_CONTEXT_REL,
421
+ NEXT_RUN_STATUSES,
422
+ TTL_MS,
423
+ buildNextRunContext,
424
+ generateNextRunContextArtifact,
425
+ loadNextRunContext,
426
+ updateNextRunContextStatus,
427
+ buildNextRunContextSurface,
428
+ buildCompactContextText,
429
+ formatNextRunContextText,
430
+ emitNextRunContextEvent,
431
+ isExpired,
432
+ isStale,
433
+ selectBoundedDefaults,
434
+ selectActiveDecisions,
435
+ selectActiveRisks,
436
+ };