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,71 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const { nowIso } = require("./fsx");
6
+
7
+ const BATCH_DIR = ".claude/cco/batch/jobs";
8
+
9
+ function batchPath(cwd, jobId) {
10
+ return path.join(cwd, BATCH_DIR, `${jobId}.json`);
11
+ }
12
+
13
+ function createBatchJob(cwd, input) {
14
+ const ts = Date.now();
15
+ const jobId = String(input?.jobId || `batch-${ts}`);
16
+ const job = {
17
+ version: 1,
18
+ jobId,
19
+ provider: input?.provider || "claude",
20
+ mode: input?.mode || "headless",
21
+ taskType: input?.taskType || "general",
22
+ inputRef: input?.inputRef || null,
23
+ status: "queued",
24
+ costEstimate: Number(input?.costEstimate || 0),
25
+ resultRef: null,
26
+ createdAt: nowIso(),
27
+ updatedAt: nowIso(),
28
+ };
29
+
30
+ const abs = batchPath(cwd, jobId);
31
+ fs.mkdirSync(path.dirname(abs), { recursive: true });
32
+ fs.writeFileSync(abs, JSON.stringify(job, null, 2), "utf8");
33
+ return job;
34
+ }
35
+
36
+ function updateBatchJob(cwd, jobId, patch) {
37
+ const abs = batchPath(cwd, jobId);
38
+ if (!fs.existsSync(abs)) return null;
39
+ const current = JSON.parse(fs.readFileSync(abs, "utf8"));
40
+ const next = {
41
+ ...current,
42
+ ...(patch || {}),
43
+ updatedAt: nowIso(),
44
+ };
45
+ fs.writeFileSync(abs, JSON.stringify(next, null, 2), "utf8");
46
+ return next;
47
+ }
48
+
49
+ function listBatchJobs(cwd) {
50
+ const dir = path.join(cwd, BATCH_DIR);
51
+ if (!fs.existsSync(dir)) return [];
52
+ return fs
53
+ .readdirSync(dir)
54
+ .filter((f) => f.endsWith(".json"))
55
+ .map((f) => {
56
+ try {
57
+ return JSON.parse(fs.readFileSync(path.join(dir, f), "utf8"));
58
+ } catch {
59
+ return null;
60
+ }
61
+ })
62
+ .filter(Boolean)
63
+ .sort((a, b) => Date.parse(b.updatedAt || 0) - Date.parse(a.updatedAt || 0));
64
+ }
65
+
66
+ module.exports = {
67
+ BATCH_DIR,
68
+ createBatchJob,
69
+ updateBatchJob,
70
+ listBatchJobs,
71
+ };
@@ -0,0 +1,578 @@
1
+ "use strict";
2
+
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const crypto = require("crypto");
6
+ const { ensureCcoDirs, nowIso, safeReadJson, safeWriteJson, safeWriteText } = require("./fsx");
7
+ const { appendProductLearningEvent } = require("./product-learning-events");
8
+
9
+ const BRAIN_PACK_CONTRACT = "avorelo.brainPack.v1";
10
+ const BRAIN_PACK_SCHEMA_VERSION = 1;
11
+ const BRAIN_PACK_LATEST_JSON = ".claude/cco/context/brain-pack/latest.json";
12
+ const BRAIN_PACK_LATEST_MD = ".claude/cco/context/brain-pack/latest.md";
13
+ const BRAIN_PACK_EVENT_LOG = ".claude/cco/events/brain-pack.jsonl";
14
+
15
+ const SECRET_PATTERN = /(?:sk-[A-Za-z0-9_-]{16,}|ghp_[A-Za-z0-9]{20,}|AKIA[0-9A-Z]{16}|(?:api[_ -]?key|token|password|secret|authorization)\s*[:=]\s*\S+)/i;
16
+
17
+ function redactIfSecret(text) {
18
+ if (!text) return text;
19
+ const s = String(text);
20
+ return SECRET_PATTERN.test(s) ? "[REDACTED]" : s;
21
+ }
22
+
23
+ function createBrainPackId() {
24
+ return `bp-${Date.now()}-${crypto.randomBytes(4).toString("hex")}`;
25
+ }
26
+
27
+ // ── Package.json reader ───────────────────────────────────────────────────────
28
+
29
+ function readPackageJson(cwd) {
30
+ try {
31
+ return JSON.parse(fs.readFileSync(path.join(cwd, "package.json"), "utf8"));
32
+ } catch {
33
+ return null;
34
+ }
35
+ }
36
+
37
+ // ── Work-Control reader (safe) ────────────────────────────────────────────────
38
+
39
+ function readWorkControlForBrainPack(cwd) {
40
+ try {
41
+ const { readLatestWorkControlReceipt } = require("./work-control-receipts");
42
+ return readLatestWorkControlReceipt(cwd);
43
+ } catch {
44
+ return null;
45
+ }
46
+ }
47
+
48
+ // ── Session Context reader (safe) ─────────────────────────────────────────────
49
+
50
+ function readSessionContextForBrainPack(cwd) {
51
+ try {
52
+ const { readLatestSessionContext } = require("./session-context-optimizer");
53
+ return readLatestSessionContext(cwd);
54
+ } catch {
55
+ return null;
56
+ }
57
+ }
58
+
59
+ // ── Dogfood doc scanner (safe, compact) ───────────────────────────────────────
60
+
61
+ function readLatestDogfoodSignals(cwd) {
62
+ const signals = { gaps: [], nextCandidates: [] };
63
+ try {
64
+ const dogfoodDir = path.join(cwd, "docs", "dogfood");
65
+ if (!fs.existsSync(dogfoodDir)) return signals;
66
+ const files = fs.readdirSync(dogfoodDir).filter((f) => f.endsWith(".md"));
67
+ // Read only the most recent dogfood doc (compact, safe)
68
+ if (!files.length) return signals;
69
+ const latest = files.sort().pop();
70
+ const content = fs.readFileSync(path.join(dogfoodDir, latest), "utf8");
71
+ // Extract deferred sections compactly (just headings)
72
+ const lines = content.split("\n").filter((l) => l.startsWith("## Deferred") || l.startsWith("13. Deferred") || l.includes("deferred") || l.includes("gap"));
73
+ signals.gaps = lines.slice(0, 5).map((l) => l.replace(/^#+\s*/, "").trim()).filter(Boolean);
74
+ signals.nextCandidates = [];
75
+ } catch {
76
+ // safe fail
77
+ }
78
+ return signals;
79
+ }
80
+
81
+ // ── Project builder ───────────────────────────────────────────────────────────
82
+
83
+ function buildProject(cwd, pkg) {
84
+ const name = pkg?.name || path.basename(cwd);
85
+ const productName = pkg?.productName || pkg?.name || name;
86
+
87
+ // Try to read CLAUDE.md for product direction hints
88
+ let productDirection = "Local AI coding optimization platform.";
89
+ let architecturePrinciples = [
90
+ "local-first, no mandatory cloud",
91
+ "deterministic, no LLM calls in core logic",
92
+ "compact receipts, not huge JSON",
93
+ "capability-router pattern: one router, no duplicates",
94
+ "evidence-backed decisions",
95
+ ];
96
+ let nonGoals = [
97
+ "AI Workspace Registry (deferred)",
98
+ "Browser Proof (deferred)",
99
+ "Workflow Intelligence Radar (deferred)",
100
+ "Full model gateway (deferred)",
101
+ "Pricing / website (deferred)",
102
+ ];
103
+
104
+ try {
105
+ const claudeMdPath = path.join(cwd, "CLAUDE.md");
106
+ if (fs.existsSync(claudeMdPath)) {
107
+ const content = fs.readFileSync(claudeMdPath, "utf8");
108
+ // Extract first non-empty line after # heading as direction hint
109
+ const lines = content.split("\n").filter((l) => l.trim() && !l.startsWith("#")).slice(0, 3);
110
+ if (lines.length) productDirection = lines[0].slice(0, 200);
111
+ }
112
+ } catch {}
113
+
114
+ // Detect current roadmap stage from work-control or package version
115
+ const wcReceipt = readWorkControlForBrainPack(cwd);
116
+ const currentRoadmapStage = wcReceipt?.task?.text
117
+ ? String(wcReceipt.task.text).slice(0, 100)
118
+ : "Context Intelligence Completion v1";
119
+
120
+ return {
121
+ name: redactIfSecret(name),
122
+ productName: redactIfSecret(productName),
123
+ repoPath: redactIfSecret(cwd),
124
+ currentRoadmapStage,
125
+ productDirection,
126
+ nonGoals,
127
+ architecturePrinciples,
128
+ };
129
+ }
130
+
131
+ // ── Repo conventions builder ──────────────────────────────────────────────────
132
+
133
+ function buildRepoConventions(cwd, pkg) {
134
+ const scripts = pkg?.scripts || {};
135
+ const testCommands = ["node --test tests/*.test.js", "cmd /c npm test"];
136
+ const buildCommands = [];
137
+ const validationCommands = ["node scripts/validate-operating-layer.js"];
138
+
139
+ if (scripts.test) buildCommands.push(`npm test`);
140
+ if (scripts.build) buildCommands.push(`npm run build`);
141
+ if (scripts["test:brand"]) testCommands.push("npm run test:brand");
142
+
143
+ const packageManager = fs.existsSync(path.join(cwd, "yarn.lock")) ? "yarn"
144
+ : fs.existsSync(path.join(cwd, "pnpm-lock.yaml")) ? "pnpm"
145
+ : "npm";
146
+
147
+ return {
148
+ packageManager,
149
+ testCommands,
150
+ buildCommands,
151
+ validationCommands,
152
+ branchPrConventions: "kebab-case, feature branches, PR per bounded task",
153
+ runtimeArtifactRules: "do not commit .claude/cco/ runtime receipts; do not commit .avorelo/ artifacts",
154
+ };
155
+ }
156
+
157
+ // ── Context rules builder ─────────────────────────────────────────────────────
158
+
159
+ function buildContextRules() {
160
+ return {
161
+ doNotRediscover: true,
162
+ avoidHugeJson: true,
163
+ preferNamedFiles: true,
164
+ useAvoreloFirst: true,
165
+ useWorkControl: true,
166
+ useSessionContext: true,
167
+ useCapabilityRecommender: true,
168
+ note: "Start from Work-Control receipt and Session Context, not broad repo scans.",
169
+ };
170
+ }
171
+
172
+ // ── User preferences builder ──────────────────────────────────────────────────
173
+
174
+ function buildUserPreferences() {
175
+ return {
176
+ preferredWorkflow: "bounded-implementation-first",
177
+ promptStyle: "short, direct, no trailing summaries",
178
+ dogfoodExpectations: "structured feedback with frictionObserved, missingContext, capabilityThatShouldHaveHandledIt",
179
+ safetyExpectations: "no bypassing guards, no destructive ops without confirmation, preserve blocks",
180
+ };
181
+ }
182
+
183
+ // ── Recipe detection ──────────────────────────────────────────────────────────
184
+
185
+ const RECIPE_SIGNALS = [
186
+ {
187
+ name: "pr_continuation_or_merge",
188
+ signals: ["pr", "merge", "ci", "branch", "validation", "pull request", "commit"],
189
+ recommendedCapabilityPack: "release_readiness",
190
+ firstCommand: "node bin/avorelo work-control --handoff",
191
+ doNotRepeat: ["Do not rewrite commit history without explicit approval.", "Do not push --force without user confirmation."],
192
+ deferredCapabilities: [],
193
+ },
194
+ {
195
+ name: "security_or_intake_review",
196
+ signals: ["mcp", "package", "install", "unknown tool", "dependency", "risk", "intake", "guard"],
197
+ recommendedCapabilityPack: "install_intake_risk",
198
+ firstCommand: "node bin/avorelo intake --json",
199
+ doNotRepeat: ["Do not execute unknown-source tools before intake review.", "Do not skip guard evaluation for MCP tool calls."],
200
+ deferredCapabilities: [],
201
+ },
202
+ {
203
+ name: "context_or_token_optimization",
204
+ signals: ["context", "token", "session", "handoff", "rediscovery", "continuation", "brain pack", "brain-pack"],
205
+ recommendedCapabilityPack: "workflow_efficiency",
206
+ firstCommand: "node bin/avorelo session-context --handoff",
207
+ doNotRepeat: ["Do not paste huge JSON into context.", "Do not broad-scan repo before reading named files."],
208
+ deferredCapabilities: [],
209
+ },
210
+ {
211
+ name: "skills_or_source_backed_workflow",
212
+ signals: ["skill", "recipe", "workflow", "reference", "source-backed", "source backed"],
213
+ recommendedCapabilityPack: "source_backed_skills",
214
+ firstCommand: "node bin/avorelo skills route --task \"<task>\"",
215
+ doNotRepeat: ["Do not use skill sources before intake review.", "Do not duplicate skill routing logic in session context."],
216
+ deferredCapabilities: [],
217
+ },
218
+ {
219
+ name: "frontend_or_browser_evidence",
220
+ signals: ["browser", "screenshot", "visual", "frontend", "playwright", "ui", "landing page"],
221
+ recommendedCapabilityPack: "frontend_readiness",
222
+ firstCommand: "node bin/avorelo visual-qa --dry-run",
223
+ doNotRepeat: ["Browser Proof remains deferred.", "Do not implement visual QA infrastructure in this session."],
224
+ deferredCapabilities: ["browser_proof_evidence", "full_visual_qa"],
225
+ },
226
+ {
227
+ name: "launch_pricing_site",
228
+ signals: ["pricing", "website", "landing page", "launch", "plugin", "marketplace"],
229
+ recommendedCapabilityPack: null,
230
+ firstCommand: null,
231
+ doNotRepeat: ["Pricing/website/plugin launch is deferred.", "Do not start public-web work in this session."],
232
+ deferredCapabilities: ["pricing_website_plugin_launch"],
233
+ },
234
+ ];
235
+
236
+ function detectRecipe(task, options = {}) {
237
+ if (!task || typeof task !== "string") {
238
+ return {
239
+ detectedRecipe: null,
240
+ confidence: 0,
241
+ reason: "No task provided — recipe detection skipped.",
242
+ recommendedCapabilityPack: null,
243
+ firstCommand: null,
244
+ doNotRepeat: [],
245
+ deferredCapabilities: [],
246
+ };
247
+ }
248
+
249
+ const taskLower = task.toLowerCase();
250
+
251
+ // Score each recipe by signal matches
252
+ const scored = RECIPE_SIGNALS.map((recipe) => {
253
+ const matches = recipe.signals.filter((signal) => taskLower.includes(signal));
254
+ return { recipe, matches, score: matches.length };
255
+ }).filter((s) => s.score > 0).sort((a, b) => b.score - a.score);
256
+
257
+ if (!scored.length) {
258
+ return {
259
+ detectedRecipe: null,
260
+ confidence: 0,
261
+ reason: "No matching recipe signals found.",
262
+ recommendedCapabilityPack: null,
263
+ firstCommand: null,
264
+ doNotRepeat: [],
265
+ deferredCapabilities: [],
266
+ };
267
+ }
268
+
269
+ const best = scored[0];
270
+ const confidence = Math.min(1, best.score / 3);
271
+
272
+ // Note: recipe detection augments, does not replace, capability recommender
273
+ // The capability recommender is the authoritative router
274
+
275
+ return {
276
+ detectedRecipe: best.recipe.name,
277
+ confidence: parseFloat(confidence.toFixed(2)),
278
+ reason: `Matched signals: ${best.matches.join(", ")}`,
279
+ recommendedCapabilityPack: best.recipe.recommendedCapabilityPack,
280
+ firstCommand: best.recipe.firstCommand
281
+ ? best.recipe.firstCommand.replace("<task>", task.slice(0, 60))
282
+ : null,
283
+ doNotRepeat: best.recipe.doNotRepeat,
284
+ deferredCapabilities: best.recipe.deferredCapabilities,
285
+ note: "Recipe detection augments capability-recommender output. Use recommendCapabilities() as the authoritative router.",
286
+ };
287
+ }
288
+
289
+ // ── Signals reader ────────────────────────────────────────────────────────────
290
+
291
+ function buildSignals(cwd, wcReceipt, sessionContext) {
292
+ const signals = {
293
+ lastWorkControlFinalState: wcReceipt?.workControl?.finalState || null,
294
+ latestSessionContextPath: ".claude/cco/orchestration/session-context/latest-context.json",
295
+ knownGaps: [],
296
+ nextRoadmapCandidates: [],
297
+ };
298
+
299
+ // Pull next safest action from work-control
300
+ if (wcReceipt?.workControl?.nextSafestAction) {
301
+ signals.nextSafestAction = String(wcReceipt.workControl.nextSafestAction).slice(0, 200);
302
+ }
303
+
304
+ // Pull known gaps from dogfood docs
305
+ const dogfoodSignals = readLatestDogfoodSignals(cwd);
306
+ signals.knownGaps = dogfoodSignals.gaps.slice(0, 5);
307
+
308
+ // Next roadmap candidates from brief's deferred list
309
+ signals.nextRoadmapCandidates = [
310
+ "AI Workspace Registry / Asset Inventory Foundation",
311
+ "Browser Proof / Evidence",
312
+ "Workflow Intelligence Radar",
313
+ "Full Brain Pack UI / management",
314
+ "Full recipe library",
315
+ ];
316
+
317
+ return signals;
318
+ }
319
+
320
+ // ── Main build function ───────────────────────────────────────────────────────
321
+
322
+ function buildBrainPack(cwd, options = {}) {
323
+ const pkg = readPackageJson(cwd);
324
+ const wcReceipt = readWorkControlForBrainPack(cwd);
325
+ const sessionContext = readSessionContextForBrainPack(cwd);
326
+
327
+ const brainPackId = createBrainPackId();
328
+ const createdAt = nowIso();
329
+
330
+ const project = buildProject(cwd, pkg);
331
+ const userPreferences = buildUserPreferences();
332
+ const repoConventions = buildRepoConventions(cwd, pkg);
333
+ const contextRules = buildContextRules();
334
+ const signals = buildSignals(cwd, wcReceipt, sessionContext);
335
+
336
+ // Capability recommender integration (read-only, no new router)
337
+ let capabilityRecommendation = null;
338
+ try {
339
+ const { recommendCapabilities } = require("./capability-recommender");
340
+ const rec = recommendCapabilities({ cwd, signals: {}, plan: "free" });
341
+ capabilityRecommendation = {
342
+ recommendedPackId: rec.recommendedPack?.id || null,
343
+ recommendedPackName: rec.recommendedPack?.name || null,
344
+ reason: rec.reason || null,
345
+ nextAction: rec.nextAction || null,
346
+ };
347
+ } catch {
348
+ capabilityRecommendation = null;
349
+ }
350
+
351
+ // Recipe detection (based on last task)
352
+ const lastTask = wcReceipt?.task?.text || options.task || null;
353
+ const recipe = lastTask ? detectRecipe(lastTask, { cwd }) : null;
354
+
355
+ const brainPack = {
356
+ schemaVersion: BRAIN_PACK_SCHEMA_VERSION,
357
+ contract: BRAIN_PACK_CONTRACT,
358
+ brainPackId,
359
+ createdAt,
360
+ project,
361
+ userPreferences,
362
+ repoConventions,
363
+ contextRules,
364
+ recipes: recipe ? [recipe] : [],
365
+ signals,
366
+ capabilityRecommendation,
367
+ redacted: true,
368
+ };
369
+
370
+ return brainPack;
371
+ }
372
+
373
+ // ── Markdown builder ──────────────────────────────────────────────────────────
374
+
375
+ function buildBrainPackMarkdown(brainPack) {
376
+ const p = brainPack.project || {};
377
+ const r = brainPack.repoConventions || {};
378
+ const s = brainPack.signals || {};
379
+ const cr = brainPack.contextRules || {};
380
+ const cap = brainPack.capabilityRecommendation;
381
+
382
+ const lines = [
383
+ `# Avorelo Brain Pack — ${p.name || "project"}`,
384
+ `> ${p.productName || ""} | Generated: ${brainPack.createdAt}`,
385
+ "",
386
+ "## Project",
387
+ `- **Product direction:** ${p.productDirection || ""}`,
388
+ `- **Current roadmap stage:** ${p.currentRoadmapStage || ""}`,
389
+ "",
390
+ "## Architecture Principles",
391
+ ...(p.architecturePrinciples || []).map((a) => `- ${a}`),
392
+ "",
393
+ "## Non-Goals (this session)",
394
+ ...(p.nonGoals || []).map((n) => `- ${n}`),
395
+ "",
396
+ "## Repo Conventions",
397
+ `- Package manager: ${r.packageManager || "npm"}`,
398
+ `- Tests: ${(r.testCommands || []).join(", ")}`,
399
+ `- Validation: ${(r.validationCommands || []).join(", ")}`,
400
+ `- Artifacts: ${r.runtimeArtifactRules || ""}`,
401
+ "",
402
+ "## Context Rules",
403
+ `- Do not rediscover repo: ${cr.doNotRediscover}`,
404
+ `- Avoid huge JSON: ${cr.avoidHugeJson}`,
405
+ `- Prefer named files: ${cr.preferNamedFiles}`,
406
+ `- ${cr.note || ""}`,
407
+ "",
408
+ ];
409
+
410
+ if (cap) {
411
+ lines.push("## Recommended Capability");
412
+ lines.push(`- Pack: ${cap.recommendedPackName || cap.recommendedPackId || "none"}`);
413
+ lines.push(`- Why: ${cap.reason || ""}`);
414
+ lines.push(`- Next: ${cap.nextAction || ""}`);
415
+ lines.push("");
416
+ }
417
+
418
+ if (brainPack.recipes?.length) {
419
+ const rec = brainPack.recipes[0];
420
+ lines.push("## Detected Recipe");
421
+ lines.push(`- Recipe: ${rec.detectedRecipe}`);
422
+ lines.push(`- Confidence: ${rec.confidence}`);
423
+ lines.push(`- First command: \`${rec.firstCommand || ""}\``);
424
+ lines.push("");
425
+ }
426
+
427
+ lines.push("## Signals");
428
+ lines.push(`- Last work-control state: ${s.lastWorkControlFinalState || "missing"}`);
429
+ if (s.nextSafestAction) lines.push(`- Next safest action: ${s.nextSafestAction}`);
430
+ lines.push("");
431
+
432
+ if (s.knownGaps?.length) {
433
+ lines.push("## Known Gaps");
434
+ s.knownGaps.forEach((g) => lines.push(`- ${g}`));
435
+ lines.push("");
436
+ }
437
+
438
+ lines.push("## Deferred Capabilities");
439
+ (s.nextRoadmapCandidates || []).forEach((c) => lines.push(`- ${c}`));
440
+ lines.push("");
441
+
442
+ lines.push("---");
443
+ lines.push("*Generated by `avorelo brain-pack`. Do not paste raw — use `avorelo brain-pack --json` for compact output.*");
444
+
445
+ return lines.join("\n");
446
+ }
447
+
448
+ // ── Write function ────────────────────────────────────────────────────────────
449
+
450
+ function writeBrainPack(cwd, brainPack) {
451
+ ensureCcoDirs(cwd);
452
+
453
+ const brainPackDir = path.join(cwd, ".claude", "cco", "context", "brain-pack");
454
+ fs.mkdirSync(brainPackDir, { recursive: true });
455
+
456
+ safeWriteJson(cwd, BRAIN_PACK_LATEST_JSON, brainPack);
457
+
458
+ const md = buildBrainPackMarkdown(brainPack);
459
+ safeWriteText(cwd, BRAIN_PACK_LATEST_MD, md);
460
+
461
+ // Append event log (compact)
462
+ try {
463
+ const logAbs = path.join(cwd, BRAIN_PACK_EVENT_LOG);
464
+ fs.mkdirSync(path.dirname(logAbs), { recursive: true });
465
+ const logEntry = JSON.stringify({
466
+ brainPackId: brainPack.brainPackId,
467
+ createdAt: brainPack.createdAt,
468
+ projectName: brainPack.project?.name || null,
469
+ recipesCount: (brainPack.recipes || []).length,
470
+ capabilityRecommended: brainPack.capabilityRecommendation?.recommendedPackId || null,
471
+ });
472
+ fs.appendFileSync(logAbs, `${logEntry}\n`, "utf8");
473
+ } catch {}
474
+
475
+ // Product learning events
476
+ try {
477
+ appendProductLearningEvent(cwd, {
478
+ eventName: "brain_pack_generated",
479
+ category: "brain_pack",
480
+ status: "completed",
481
+ payload: {
482
+ brainPackId: brainPack.brainPackId,
483
+ hasCapabilityRecommendation: Boolean(brainPack.capabilityRecommendation),
484
+ recipesCount: (brainPack.recipes || []).length,
485
+ signalsCount: Object.keys(brainPack.signals || {}).length,
486
+ },
487
+ });
488
+ } catch {}
489
+
490
+ return {
491
+ jsonPath: BRAIN_PACK_LATEST_JSON,
492
+ mdPath: BRAIN_PACK_LATEST_MD,
493
+ };
494
+ }
495
+
496
+ // ── Read latest ───────────────────────────────────────────────────────────────
497
+
498
+ function readLatestBrainPack(cwd) {
499
+ return safeReadJson(cwd, BRAIN_PACK_LATEST_JSON, null);
500
+ }
501
+
502
+ // ── Surface builder (for dashboard/status) ────────────────────────────────────
503
+
504
+ function buildBrainPackSurface(cwd) {
505
+ const latest = readLatestBrainPack(cwd);
506
+ if (!latest) {
507
+ return {
508
+ status: "missing",
509
+ latestBrainPackPath: null,
510
+ productDirectionAvailable: false,
511
+ repoConventionsAvailable: false,
512
+ recipesAvailable: false,
513
+ recommendedRecipe: null,
514
+ nextAction: "Run `node bin/avorelo brain-pack --init` to create the first brain pack.",
515
+ };
516
+ }
517
+
518
+ const recipe = (latest.recipes || [])[0] || null;
519
+
520
+ return {
521
+ status: "available",
522
+ latestBrainPackPath: BRAIN_PACK_LATEST_JSON,
523
+ latestMarkdownPath: BRAIN_PACK_LATEST_MD,
524
+ productDirectionAvailable: Boolean(latest.project?.productDirection),
525
+ repoConventionsAvailable: Boolean(latest.repoConventions?.packageManager),
526
+ recipesAvailable: (latest.recipes || []).length > 0,
527
+ recommendedRecipe: recipe?.detectedRecipe || null,
528
+ capabilityRecommended: latest.capabilityRecommendation?.recommendedPackId || null,
529
+ nextAction: latest.signals?.nextSafestAction
530
+ || "Run `node bin/avorelo brain-pack --json` to refresh.",
531
+ brainPackId: latest.brainPackId,
532
+ };
533
+ }
534
+
535
+ // ── Summary text ──────────────────────────────────────────────────────────────
536
+
537
+ function formatBrainPackText(brainPackOrSurface, options = {}) {
538
+ if (!brainPackOrSurface) {
539
+ return "Brain Pack: MISSING · run `avorelo brain-pack --init` to create.\n";
540
+ }
541
+
542
+ if (brainPackOrSurface.contract === BRAIN_PACK_CONTRACT) {
543
+ const bp = brainPackOrSurface;
544
+ const lines = [
545
+ `Brain Pack: ${bp.brainPackId}`,
546
+ `Project: ${bp.project?.name || "unknown"}`,
547
+ `Stage: ${bp.project?.currentRoadmapStage || "unknown"}`,
548
+ `Capability: ${bp.capabilityRecommendation?.recommendedPackName || "none"}`,
549
+ `Recipe: ${(bp.recipes || [])[0]?.detectedRecipe || "none"}`,
550
+ `State: ${bp.signals?.lastWorkControlFinalState || "missing"}`,
551
+ `JSON: ${BRAIN_PACK_LATEST_JSON}`,
552
+ ];
553
+ return lines.join("\n") + "\n";
554
+ }
555
+
556
+ const surface = brainPackOrSurface;
557
+ const lines = [
558
+ `Brain Pack: ${surface.status?.toUpperCase() || "MISSING"}`,
559
+ surface.recommendedRecipe ? `Recipe: ${surface.recommendedRecipe}` : null,
560
+ surface.nextAction ? `Next: ${surface.nextAction}` : null,
561
+ surface.latestBrainPackPath ? `Path: ${surface.latestBrainPackPath}` : null,
562
+ ].filter(Boolean);
563
+ return lines.join("\n") + "\n";
564
+ }
565
+
566
+ module.exports = {
567
+ BRAIN_PACK_CONTRACT,
568
+ BRAIN_PACK_SCHEMA_VERSION,
569
+ BRAIN_PACK_LATEST_JSON,
570
+ BRAIN_PACK_LATEST_MD,
571
+ buildBrainPack,
572
+ writeBrainPack,
573
+ readLatestBrainPack,
574
+ buildBrainPackSurface,
575
+ buildBrainPackMarkdown,
576
+ formatBrainPackText,
577
+ detectRecipe,
578
+ };