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,166 @@
1
+ "use strict";
2
+
3
+ // ── Release Candidate Bundle ──────────────────────────────────────────────────
4
+ // Contract: avorelo.releaseCandidateBundle.v1
5
+ // Assembles a local release candidate bundle from summaries and refs only.
6
+ // No raw prompts, raw feedback, raw source code, secrets, or raw configs.
7
+
8
+ const fs = require("fs");
9
+ const path = require("path");
10
+ const { nowIso } = require("./fsx");
11
+ const { appendProductLearningEvent } = require("./product-learning-events");
12
+
13
+ const CONTRACT = "avorelo.releaseCandidateBundle.v1";
14
+ const SCHEMA_VERSION = 1;
15
+ const BUNDLE_DIR_REL = ".claude/cco/orchestration/full-readiness";
16
+ const ARTIFACT_REL = BUNDLE_DIR_REL + "/latest-release-candidate-bundle.json";
17
+
18
+ function safeReadJson(absPath) {
19
+ try {
20
+ if (!fs.existsSync(absPath)) return null;
21
+ return JSON.parse(fs.readFileSync(absPath, "utf8").replace(/^/, ""));
22
+ } catch { return null; }
23
+ }
24
+
25
+ function pick(obj, fields) {
26
+ if (!obj) return null;
27
+ var out = {};
28
+ fields.forEach(function(f) { if (obj[f] !== undefined) out[f] = obj[f]; });
29
+ return out;
30
+ }
31
+
32
+ function collectReleaseCandidateArtifacts(cwd, options) {
33
+ options = options || {};
34
+ function read(rel) { return safeReadJson(path.join(cwd, rel)); }
35
+ return {
36
+ gate: read(".claude/cco/orchestration/full-readiness/latest-gate.json"),
37
+ evidenceClosure: read(".claude/cco/orchestration/full-readiness/latest-evidence-closure.json"),
38
+ knownLimitations: read(".claude/cco/orchestration/full-readiness/latest-known-limitations.json"),
39
+ externalUserSim: read(".claude/cco/orchestration/full-readiness/latest-external-user-simulation.json"),
40
+ prelaunchIntel: read(".claude/cco/orchestration/prelaunch-intelligence/latest-intelligence.json"),
41
+ feedbackIntel: read(".claude/cco/orchestration/prelaunch-intelligence/latest-feedback-intelligence.json"),
42
+ installJourney: read(".claude/cco/orchestration/prelaunch-intelligence/latest-install-journey.json"),
43
+ tokenCost: read(".claude/cco/orchestration/prelaunch-intelligence/latest-token-cost-intelligence.json"),
44
+ tokenCostCapture: read(".claude/cco/evidence/token-cost/latest-capture.json"),
45
+ tokenCostEvidence: read(".claude/cco/evidence/token-cost/summary.json"),
46
+ proofOutcomeEvidence: read(".claude/cco/orchestration/seamless-outcome/latest-proof-outcome-evidence.json"),
47
+ mcpPolicy: read(".claude/cco/orchestration/mcp-tool-governance/latest-policy.json"),
48
+ launchHardening: read(".claude/cco/orchestration/launch-hardening/latest-gate.json"),
49
+ supportBundle: read(".claude/cco/support/latest-support-bundle.json"),
50
+ companyLoop: read(".claude/cco/orchestration/company-loop/latest-report.json"),
51
+ };
52
+ }
53
+
54
+ function buildReleaseCandidateBundle(cwd, options) {
55
+ options = options || {};
56
+ var a = collectReleaseCandidateArtifacts(cwd, options);
57
+
58
+ var gateSummary = pick(a.gate, ["contract", "status", "releaseCandidateStatus", "score", "decision", "recommendedNextPr", "safeNextAction", "noPublicLaunchClaim", "noReleaseReadyClaimUnlessPassed", "redacted"]);
59
+ if (gateSummary && a.gate) { gateSummary.blockerCount = (a.gate.blockers || []).length; gateSummary.warningCount = (a.gate.warnings || []).length; gateSummary.passCount = (a.gate.passes || []).length; }
60
+
61
+ var evidenceClosureSummary = pick(a.evidenceClosure, ["contract", "status", "evidencePresentCount", "evidenceMissingCount", "totalChecked", "nextAction", "redacted"]);
62
+ var knownLimitationsSummary = pick(a.knownLimitations, ["contract", "totalLimitations", "blockerLimitationsCount", "warnLimitationsCount", "infoLimitationsCount", "overallImpact", "redacted"]);
63
+ var externalUserSimSummary = pick(a.externalUserSim, ["contract", "status", "totalScenarios", "passed", "warned", "blocked", "redacted"]);
64
+
65
+ var prelaunchIntelSummary = pick(a.prelaunchIntel, ["contract", "status", "score", "noPublicLaunchClaim", "noReleaseReadyClaim", "redacted"]);
66
+ if (prelaunchIntelSummary && a.prelaunchIntel) {
67
+ prelaunchIntelSummary.recommendation = a.prelaunchIntel.recommendedNextPr && a.prelaunchIntel.recommendedNextPr.recommendation || null;
68
+ prelaunchIntelSummary.missingEvidenceCount = (a.prelaunchIntel.missingEvidence || []).length;
69
+ }
70
+
71
+ var feedbackIntelSummary = pick(a.feedbackIntel, ["contract", "status", "readinessStatus", "score", "redacted"]);
72
+ if (feedbackIntelSummary && a.feedbackIntel) {
73
+ feedbackIntelSummary.qualifiedFeedbackItemsCount = a.feedbackIntel.qualifiedFeedbackItemsCount || 0;
74
+ feedbackIntelSummary.topFriction = a.feedbackIntel.topFriction || null;
75
+ }
76
+
77
+ var installJourneySummary = pick(a.installJourney, ["contract", "status", "stepsComplete", "totalSteps", "redacted"]);
78
+ var tokenCostSummary = pick(a.tokenCost, ["contract", "status", "readinessStatus", "evidenceLevel", "evidenceMode", "noExactSavingsClaim", "redacted"]);
79
+ if (tokenCostSummary && a.tokenCost) {
80
+ tokenCostSummary.realUsageSamplesCount = a.tokenCost.realUsageSamplesCount || 0;
81
+ tokenCostSummary.capturedUsageSamplesCount = a.tokenCost.capturedUsageSamplesCount || a.tokenCostCapture && a.tokenCostCapture.realUsageSamplesCount || 0;
82
+ tokenCostSummary.confidence = a.tokenCost.confidence || "missing";
83
+ }
84
+ if (tokenCostSummary && a.tokenCostEvidence) {
85
+ tokenCostSummary.evidenceMode = a.tokenCostEvidence.evidenceMode || tokenCostSummary.evidenceMode || "missing";
86
+ tokenCostSummary.noSavingsClaimUnlessMeasured = a.tokenCostEvidence.noSavingsClaimUnlessMeasured === true;
87
+ }
88
+ var proofOutcomeSummary = pick(a.proofOutcomeEvidence, ["contract", "status", "latestProofAvailable", "realTaskProofCount", "proofQuality", "simulatedProofDetected", "redacted"]);
89
+ var mcpSummary = pick(a.mcpPolicy, ["contract", "status", "note", "redacted"]);
90
+ var hardeningSummary = pick(a.launchHardening, ["contract", "status", "redacted"]);
91
+ if (hardeningSummary && a.launchHardening) { hardeningSummary.pass = a.launchHardening.summary && a.launchHardening.summary.pass || 0; hardeningSummary.warn = a.launchHardening.summary && a.launchHardening.summary.warn || 0; hardeningSummary.fail = a.launchHardening.summary && a.launchHardening.summary.fail || 0; }
92
+
93
+ var supportSummary = pick(a.supportBundle, ["contract", "redacted", "artifactPath"]);
94
+ if (supportSummary && a.supportBundle) supportSummary.intelligenceSummaryStatus = a.supportBundle.intelligenceSummary && a.supportBundle.intelligenceSummary.status || null;
95
+
96
+ var failureRecoverySummary = a.supportBundle && a.supportBundle.failureRecoveryReadinessSummary || null;
97
+ var hookSafetyBoundarySummary = a.supportBundle && a.supportBundle.hookSafetyBoundarySummary || null;
98
+ var installAiReadinessSummary = a.supportBundle && a.supportBundle.installAiReadinessSummary || null;
99
+
100
+ var companyLoopSummary = pick(a.companyLoop, ["contract", "redacted"]);
101
+ if (companyLoopSummary && a.companyLoop) { companyLoopSummary.recommendedNextPr = (a.companyLoop.nextPrRecommendation && a.companyLoop.nextPrRecommendation.recommendedNextPr) || a.companyLoop.recommendedNextPr || null; companyLoopSummary.confidence = a.companyLoop.nextPrRecommendation && a.companyLoop.nextPrRecommendation.confidence || null; }
102
+
103
+ var bundleStatus = a.gate && a.gate.releaseCandidateStatus || "insufficient_data";
104
+ var overallStatus = a.gate && a.gate.status || "insufficient_data";
105
+
106
+ // Activation distribution readiness summary (PR #149)
107
+ var activationDistributionSummary = null;
108
+ try {
109
+ var adrMod = require("./activation-distribution-readiness");
110
+ var adrSurface = adrMod.buildActivationDistributionSurface(cwd, {});
111
+ if (adrSurface.status !== "not_available") {
112
+ activationDistributionSummary = { status: adrSurface.status, score: adrSurface.score, blockerCount: adrSurface.blockerCount, warningCount: adrSurface.warningCount, noPublicLaunchClaim: true, redacted: true };
113
+ }
114
+ } catch (e) {}
115
+
116
+ // Design partner feedback summary (PR #160)
117
+ var designPartnerFeedbackSummary = null;
118
+ try {
119
+ var dpMod = require("./design-partner-feedback");
120
+ var dpSummary = dpMod.buildDesignPartnerFeedbackSummary(cwd, {});
121
+ designPartnerFeedbackSummary = { status: dpSummary.status, qualifiedSessionCount: dpSummary.qualifiedSessionCount, blockerCount: dpSummary.blockerCount, partnerAliasCount: dpSummary.partnerAliasCount, noPublicLaunchClaim: true, noExternalFeedbackClaim: true, redacted: true };
122
+ } catch (e) {}
123
+
124
+ // Public distribution truth summary (PR #161)
125
+ var publicDistributionSummary = null;
126
+ try {
127
+ var pdGate = safeReadJson(path.join(cwd, ".claude/cco/orchestration/public-distribution/latest-gate.json"));
128
+ if (pdGate) {
129
+ publicDistributionSummary = { status: pdGate.status, score: pdGate.score, publicInstallStatus: pdGate.publicInstallStatus, localPackageStatus: pdGate.localPackageStatus, packageContentStatus: pdGate.packageContentStatus, claimSafetyStatus: pdGate.claimSafetyStatus, provenanceStatus: pdGate.provenanceStatus, blockerCount: (pdGate.blockers || []).length, warningCount: (pdGate.warnings || []).length, recommendedNextPr: pdGate.recommendedNextPr, noPublicLaunchClaim: true, redacted: true };
130
+ }
131
+ } catch (e) {}
132
+
133
+ // Adapter technical readiness summary (PR #162)
134
+ var adapterTechnicalReadinessSummary = null;
135
+ try {
136
+ var adapterGate = safeReadJson(path.join(cwd, ".claude/cco/orchestration/adapter-readiness/latest-technical-gate.json"));
137
+ if (adapterGate) {
138
+ adapterTechnicalReadinessSummary = { status: adapterGate.status, score: adapterGate.score, verdict: adapterGate.verdict, blockerCount: adapterGate.blockerCount || 0, warningCount: adapterGate.warningCount || 0, browserRequired: false, noBrowserLaunch: true, noPublicLaunchClaim: true, redacted: true };
139
+ }
140
+ } catch (e) {}
141
+
142
+ var bundle = { contract: CONTRACT, schemaVersion: SCHEMA_VERSION, createdAt: nowIso(), status: overallStatus, releaseCandidateStatus: bundleStatus, fullReadinessGate: gateSummary, evidenceClosure: evidenceClosureSummary, knownLimitations: knownLimitationsSummary, externalUserSimulation: externalUserSimSummary, prelaunchIntelligence: prelaunchIntelSummary, feedbackIntelligence: feedbackIntelSummary, installJourney: installJourneySummary, tokenCostIntelligence: tokenCostSummary, proofOutcomeEvidence: proofOutcomeSummary, failureRecoveryReadiness: failureRecoverySummary, hookSafetyBoundaryReadiness: hookSafetyBoundarySummary, installAiReadiness: installAiReadinessSummary, mcpGovernance: mcpSummary, launchHardening: hardeningSummary, supportBundle: supportSummary, companyLoop: companyLoopSummary, activationDistribution: activationDistributionSummary, designPartnerFeedback: designPartnerFeedbackSummary, publicDistribution: publicDistributionSummary, adapterTechnicalReadiness: adapterTechnicalReadinessSummary, noPublicLaunchClaim: true, noReleaseReadyClaimUnlessPassed: true, rawContentExcluded: true, redacted: true };
143
+ try { appendProductLearningEvent(cwd, { eventName: "release_candidate_bundle_built", category: "full_readiness", status: overallStatus, releaseCandidateStatus: bundleStatus }); } catch (e) {}
144
+ return bundle;
145
+ }
146
+
147
+ function writeReleaseCandidateBundle(cwd, bundle) {
148
+ var dir = path.join(cwd, BUNDLE_DIR_REL);
149
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
150
+ fs.writeFileSync(path.join(cwd, ARTIFACT_REL), JSON.stringify(bundle, null, 2));
151
+ return bundle;
152
+ }
153
+
154
+ function formatReleaseCandidateBundleText(bundle, options) {
155
+ options = options || {};
156
+ var lines = [];
157
+ lines.push("Release candidate bundle: " + bundle.releaseCandidateStatus);
158
+ lines.push("Gate status: " + bundle.status);
159
+ if (bundle.fullReadinessGate) { lines.push("Score: " + bundle.fullReadinessGate.score); lines.push("Blockers: " + bundle.fullReadinessGate.blockerCount + ", Warnings: " + bundle.fullReadinessGate.warningCount); }
160
+ if (bundle.knownLimitations) lines.push("Known limitations: " + bundle.knownLimitations.totalLimitations);
161
+ if (bundle.fullReadinessGate && bundle.fullReadinessGate.recommendedNextPr) lines.push("Next PR: " + bundle.fullReadinessGate.recommendedNextPr);
162
+ lines.push(""); lines.push("Bundle contains summaries and refs only. No raw content."); lines.push("No public launch claim.");
163
+ return lines.join("\n");
164
+ }
165
+
166
+ module.exports = { CONTRACT, SCHEMA_VERSION, ARTIFACT_REL, buildReleaseCandidateBundle, collectReleaseCandidateArtifacts, writeReleaseCandidateBundle, formatReleaseCandidateBundleText };
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+
3
+ const { safeWriteJson, safeWriteText, nowIso } = require("./fsx");
4
+
5
+ function toRiskClass(report) {
6
+ if ((report?.riskScore ?? 0) >= 80) return "high";
7
+ if ((report?.riskScore ?? 0) >= 45) return "medium";
8
+ return "low";
9
+ }
10
+
11
+ function buildPatchCandidates(report, filePath) {
12
+ const reasons = report?.topReasons || [];
13
+ if (!reasons.length) return [];
14
+
15
+ return reasons.map((reasonCode, idx) => {
16
+ const confidence = Math.max(0.3, 1 - idx * 0.2);
17
+ return {
18
+ patchId: `patch_${idx + 1}`,
19
+ reasonCode,
20
+ files: [filePath],
21
+ confidence,
22
+ rationale: `Suggested remediation for ${reasonCode}`,
23
+ recommendedOwnerAction: "Review finding, apply patch manually, and re-run /cco-audit.",
24
+ };
25
+ });
26
+ }
27
+
28
+ function validatePatchMetadata(patch) {
29
+ return Boolean(
30
+ patch &&
31
+ typeof patch.reasonCode === "string" &&
32
+ Array.isArray(patch.files) &&
33
+ patch.files.length > 0 &&
34
+ Number.isFinite(Number(patch.confidence))
35
+ );
36
+ }
37
+
38
+ function createRemediationJob(cwd, { sessionId, filePath, report }) {
39
+ const now = Date.now();
40
+ const jobId = `job_${now}`;
41
+ const riskClass = toRiskClass(report);
42
+ const patches = buildPatchCandidates(report, filePath).filter(validatePatchMetadata);
43
+
44
+ const patchPaths = patches.map((patch, idx) => {
45
+ const rel = `.claude/cco/patches/${jobId}-${idx + 1}.patch`;
46
+ const content = [
47
+ `# Patch suggestion ${idx + 1}`,
48
+ `# reasonCode: ${patch.reasonCode}`,
49
+ `# confidence: ${patch.confidence}`,
50
+ `# files: ${patch.files.join(",")}`,
51
+ `# recommendedOwnerAction: ${patch.recommendedOwnerAction}`,
52
+ "# TODO: apply manual remediation based on security guidance",
53
+ "",
54
+ ].join("\n");
55
+ safeWriteText(cwd, rel, content);
56
+ return rel;
57
+ });
58
+
59
+ const job = {
60
+ jobId,
61
+ sessionId,
62
+ findingIds: (report?.highlights || []).map((h) => h.id),
63
+ patches: patches.map((p, idx) => ({ ...p, path: patchPaths[idx] })),
64
+ approvalState: "suggested",
65
+ remediationState: "patch-suggested",
66
+ riskClass,
67
+ createdAt: nowIso(),
68
+ updatedAt: nowIso(),
69
+ };
70
+
71
+ const jobPath = `.claude/cco/patches/jobs/${jobId}.json`;
72
+ safeWriteJson(cwd, jobPath, job);
73
+
74
+ return { job, jobPath };
75
+ }
76
+
77
+ module.exports = {
78
+ createRemediationJob,
79
+ validatePatchMetadata,
80
+ toRiskClass,
81
+ };
@@ -0,0 +1,391 @@
1
+ "use strict";
2
+
3
+ // ── Repo Map / Symbol Map ─────────────────────────────────────────────────────
4
+ //
5
+ // Builds a concise, deterministic repo map from file metadata and safe parsing.
6
+ // No network, no LLM, no full code dumps.
7
+ //
8
+ // Contract: avorelo.repoMap.v1
9
+ //
10
+ // Non-goals: full AST parsing, external parser dependencies, code dumping,
11
+ // secret/env exposure, minified/binary files.
12
+
13
+ const fs = require("node:fs");
14
+ const path = require("node:path");
15
+ const { nowIso } = require("./fsx");
16
+ const { appendProductLearningEvent } = require("./product-learning-events");
17
+
18
+ const CONTRACT = "avorelo.repoMap.v1";
19
+ const SCHEMA_VERSION = 1;
20
+
21
+ const REPO_MAP_DIR_REL = ".claude/cco/orchestration/repo-map";
22
+ const LATEST_MAP_REL = `${REPO_MAP_DIR_REL}/latest-map.json`;
23
+
24
+ // ── Exclusion patterns ────────────────────────────────────────────────────────
25
+
26
+ const EXCLUDED_DIRS = new Set([
27
+ "node_modules", ".git", ".svn", "dist", "build", "out", ".next", ".nuxt",
28
+ "__pycache__", ".venv", "venv", "env", ".tox", "coverage", ".cache",
29
+ ".turbo", ".yarn", "vendor", "target", "bin", "obj", ".expo",
30
+ ]);
31
+
32
+ const EXCLUDED_EXTENSIONS = new Set([
33
+ ".map", ".min.js", ".min.css", ".bundle.js",
34
+ ".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".webp", ".avif",
35
+ ".woff", ".woff2", ".ttf", ".eot", ".otf",
36
+ ".pdf", ".zip", ".tar", ".gz", ".br", ".bz2",
37
+ ".exe", ".dll", ".so", ".dylib", ".bin",
38
+ ".lock",
39
+ ]);
40
+
41
+ const SENSITIVE_FILES = new Set([
42
+ ".env", ".env.local", ".env.production", ".env.staging", ".env.development",
43
+ ".env.test", "secrets.json", "credentials.json", ".npmrc", ".netrc",
44
+ ]);
45
+
46
+ const MAX_FILES = 2000;
47
+ const MAX_FILE_BYTES_FOR_SYMBOLS = 100 * 1024; // 100 KB
48
+ const MAX_SYMBOL_LINES = 5000;
49
+
50
+ // ── Helpers ───────────────────────────────────────────────────────────────────
51
+
52
+ function isExcludedDir(name) {
53
+ return EXCLUDED_DIRS.has(name) || name.startsWith(".");
54
+ }
55
+
56
+ function isExcludedFile(name) {
57
+ const lower = name.toLowerCase();
58
+ if (SENSITIVE_FILES.has(name) || SENSITIVE_FILES.has(lower)) return "sensitive";
59
+ const ext = path.extname(lower);
60
+ if (EXCLUDED_EXTENSIONS.has(ext)) return "excluded";
61
+ // Detect generated/minified by suffix pattern
62
+ if (lower.endsWith(".min.js") || lower.endsWith(".min.css") || lower.endsWith(".bundle.js") || lower.endsWith(".chunk.js")) return "excluded";
63
+ // Lock files
64
+ if (lower.endsWith(".lock") || lower === "package-lock.json" || lower === "pnpm-lock.yaml" || lower === "yarn.lock") return "excluded";
65
+ return false;
66
+ }
67
+
68
+ function isBinary(buffer) {
69
+ // Simple heuristic: check first 512 bytes for null bytes
70
+ const check = Math.min(buffer.length, 512);
71
+ for (let i = 0; i < check; i++) {
72
+ if (buffer[i] === 0) return true;
73
+ }
74
+ return false;
75
+ }
76
+
77
+ function detectWorkspaceType(cwd) {
78
+ try {
79
+ const pkg = JSON.parse(fs.readFileSync(path.join(cwd, "package.json"), "utf8"));
80
+ if (pkg.workspaces) return "npm_workspaces";
81
+ if (fs.existsSync(path.join(cwd, "pnpm-workspace.yaml"))) return "pnpm_workspaces";
82
+ if (fs.existsSync(path.join(cwd, "lerna.json"))) return "lerna";
83
+ return "single_package";
84
+ } catch {}
85
+ try {
86
+ if (fs.existsSync(path.join(cwd, "Cargo.toml"))) return "rust_cargo";
87
+ if (fs.existsSync(path.join(cwd, "go.mod"))) return "go_module";
88
+ if (fs.existsSync(path.join(cwd, "pyproject.toml")) || fs.existsSync(path.join(cwd, "setup.py"))) return "python";
89
+ } catch {}
90
+ return "unknown";
91
+ }
92
+
93
+ function detectPackageScopes(cwd) {
94
+ const scopes = [];
95
+ try {
96
+ const pkg = JSON.parse(fs.readFileSync(path.join(cwd, "package.json"), "utf8"));
97
+ if (pkg.workspaces) {
98
+ const ws = Array.isArray(pkg.workspaces) ? pkg.workspaces : (pkg.workspaces.packages || []);
99
+ for (const pattern of ws.slice(0, 10)) {
100
+ const p = pattern.replace(/\*$/, "").replace(/\/$/, "");
101
+ if (fs.existsSync(path.join(cwd, p))) scopes.push(p);
102
+ }
103
+ }
104
+ } catch {}
105
+ return scopes;
106
+ }
107
+
108
+ // ── Symbol extraction (safe heuristic, no AST) ───────────────────────────────
109
+
110
+ function extractSymbols(content, ext) {
111
+ const symbols = [];
112
+ const lines = content.split("\n");
113
+ if (lines.length > MAX_SYMBOL_LINES) return symbols;
114
+
115
+ const patterns = [];
116
+ if ([".js", ".mjs", ".cjs", ".ts", ".tsx", ".jsx"].includes(ext)) {
117
+ patterns.push(
118
+ /^(?:export\s+)?(?:async\s+)?function\s+(\w+)/,
119
+ /^(?:export\s+)?class\s+(\w+)/,
120
+ /^(?:export\s+)?const\s+(\w+)\s*=/,
121
+ /^module\.exports\s*=\s*\{([^}]{0,200})\}/,
122
+ /^exports\.(\w+)\s*=/,
123
+ );
124
+ } else if ([".py"].includes(ext)) {
125
+ patterns.push(/^def\s+(\w+)/, /^class\s+(\w+)/);
126
+ } else if ([".go"].includes(ext)) {
127
+ patterns.push(/^func\s+(\w+)/, /^type\s+(\w+)/);
128
+ }
129
+
130
+ for (const line of lines.slice(0, 200)) {
131
+ for (const re of patterns) {
132
+ const m = line.match(re);
133
+ if (m && m[1]) {
134
+ const sym = m[1].slice(0, 60);
135
+ if (sym && !symbols.includes(sym)) symbols.push(sym);
136
+ if (symbols.length >= 20) return symbols;
137
+ }
138
+ }
139
+ }
140
+ return symbols;
141
+ }
142
+
143
+ // ── File walker ───────────────────────────────────────────────────────────────
144
+
145
+ function walkFiles(cwd, dir, files, counts, depth = 0) {
146
+ if (depth > 8) return;
147
+ if (files.length >= MAX_FILES) return;
148
+ let entries;
149
+ try {
150
+ entries = fs.readdirSync(dir, { withFileTypes: true });
151
+ } catch {
152
+ return;
153
+ }
154
+ for (const entry of entries) {
155
+ if (files.length >= MAX_FILES) break;
156
+ if (entry.isSymbolicLink()) continue;
157
+ if (entry.isDirectory()) {
158
+ if (isExcludedDir(entry.name)) continue;
159
+ walkFiles(cwd, path.join(dir, entry.name), files, counts, depth + 1);
160
+ } else if (entry.isFile()) {
161
+ const abs = path.join(dir, entry.name);
162
+ const rel = path.relative(cwd, abs).replace(/\\/g, "/");
163
+ const exclusionReason = isExcludedFile(entry.name);
164
+
165
+ let stat;
166
+ try { stat = fs.statSync(abs); } catch { continue; }
167
+
168
+ if (exclusionReason === "sensitive") {
169
+ counts.sensitiveExcluded++;
170
+ continue;
171
+ }
172
+
173
+ const ext = path.extname(entry.name).toLowerCase();
174
+
175
+ // Check for binary
176
+ try {
177
+ const buf = Buffer.allocUnsafe(512);
178
+ const fd = fs.openSync(abs, "r");
179
+ const read = fs.readSync(fd, buf, 0, 512, 0);
180
+ fs.closeSync(fd);
181
+ if (isBinary(buf.slice(0, read))) {
182
+ counts.binaryExcluded++;
183
+ continue;
184
+ }
185
+ } catch { continue; }
186
+
187
+ if (exclusionReason === "excluded") {
188
+ counts.generatedExcluded++;
189
+ continue;
190
+ }
191
+
192
+ // Check for minified (line > 1000 chars)
193
+ let isMinified = false;
194
+ if (stat.size < 10 * 1024) {
195
+ try {
196
+ const content = fs.readFileSync(abs, "utf8");
197
+ const firstLine = content.split("\n")[0] || "";
198
+ if (firstLine.length > 1000) isMinified = true;
199
+ } catch {}
200
+ } else if (stat.size > 500 * 1024) {
201
+ isMinified = true; // large files treated as generated
202
+ }
203
+ if (isMinified) {
204
+ counts.minifiedExcluded++;
205
+ continue;
206
+ }
207
+
208
+ const fileEntry = {
209
+ path: rel,
210
+ ext,
211
+ bytes: stat.size,
212
+ estimatedTokens: Math.ceil(stat.size / 4),
213
+ };
214
+
215
+ // Extract symbols for source files under size limit
216
+ if (stat.size < MAX_FILE_BYTES_FOR_SYMBOLS && [".js", ".mjs", ".ts", ".tsx", ".jsx", ".py", ".go"].includes(ext)) {
217
+ try {
218
+ const content = fs.readFileSync(abs, "utf8");
219
+ const syms = extractSymbols(content, ext);
220
+ if (syms.length > 0) fileEntry.symbols = syms;
221
+ } catch {}
222
+ }
223
+
224
+ files.push(fileEntry);
225
+ }
226
+ }
227
+ }
228
+
229
+ // ── Token count tree ──────────────────────────────────────────────────────────
230
+
231
+ function buildTokenCountTree(files) {
232
+ const byDir = {};
233
+ for (const f of files) {
234
+ const dir = path.dirname(f.path) || ".";
235
+ byDir[dir] = (byDir[dir] || 0) + f.estimatedTokens;
236
+ }
237
+ return byDir;
238
+ }
239
+
240
+ // ── Main build ────────────────────────────────────────────────────────────────
241
+
242
+ function buildRepoMap(cwd, options = {}) {
243
+ const files = [];
244
+ const counts = { generatedExcluded: 0, binaryExcluded: 0, minifiedExcluded: 0, sensitiveExcluded: 0 };
245
+
246
+ let status = "ready";
247
+ let caveats = [];
248
+
249
+ try {
250
+ walkFiles(cwd, cwd, files, counts);
251
+ } catch (e) {
252
+ status = "partial";
253
+ caveats.push(`File walk error: ${e.message}`);
254
+ }
255
+
256
+ if (files.length >= MAX_FILES) {
257
+ status = "partial";
258
+ caveats.push(`File count capped at ${MAX_FILES}. Map may be incomplete for large repos.`);
259
+ }
260
+
261
+ const tokenCountTree = buildTokenCountTree(files);
262
+ const totalEstimatedTokens = files.reduce((s, f) => s + f.estimatedTokens, 0);
263
+ const workspaceType = detectWorkspaceType(cwd);
264
+ const packageScopes = detectPackageScopes(cwd);
265
+
266
+ caveats.push("Token estimates are approximate (chars/4 heuristic). Actual tokenization may differ.");
267
+
268
+ return {
269
+ contract: CONTRACT,
270
+ schemaVersion: SCHEMA_VERSION,
271
+ createdAt: nowIso(),
272
+ status,
273
+ root: cwd,
274
+ workspaceType,
275
+ packageScopes,
276
+ fileCount: files.length,
277
+ totalEstimatedTokens,
278
+ files,
279
+ symbols: files.filter((f) => f.symbols && f.symbols.length > 0).map((f) => ({ path: f.path, symbols: f.symbols })),
280
+ generatedExcluded: counts.generatedExcluded,
281
+ binaryExcluded: counts.binaryExcluded,
282
+ minifiedExcluded: counts.minifiedExcluded,
283
+ sensitiveExcluded: counts.sensitiveExcluded,
284
+ tokenCountTree,
285
+ caveats,
286
+ redacted: true,
287
+ };
288
+ }
289
+
290
+ function buildSymbolMap(cwd, options = {}) {
291
+ const map = buildRepoMap(cwd, options);
292
+ return {
293
+ contract: CONTRACT,
294
+ schemaVersion: SCHEMA_VERSION,
295
+ createdAt: map.createdAt,
296
+ status: map.status,
297
+ symbolCount: map.symbols.length,
298
+ symbols: map.symbols,
299
+ caveats: map.caveats,
300
+ redacted: true,
301
+ };
302
+ }
303
+
304
+ function selectLikelyRelevantFiles(cwd, taskText, repoMap, options = {}) {
305
+ if (!taskText || !repoMap || !repoMap.files) return [];
306
+ const words = taskText.toLowerCase().split(/\W+/).filter((w) => w.length > 3);
307
+ const scored = [];
308
+ for (const f of repoMap.files) {
309
+ let score = 0;
310
+ const fp = f.path.toLowerCase();
311
+ for (const w of words) {
312
+ if (fp.includes(w)) score += 2;
313
+ }
314
+ if (f.symbols) {
315
+ for (const sym of f.symbols) {
316
+ for (const w of words) {
317
+ if (sym.toLowerCase().includes(w)) score += 3;
318
+ }
319
+ }
320
+ }
321
+ if (score > 0) scored.push({ ...f, relevanceScore: score });
322
+ }
323
+ return scored.sort((a, b) => b.relevanceScore - a.relevanceScore).slice(0, 20);
324
+ }
325
+
326
+ function writeRepoMap(cwd, map) {
327
+ const dir = path.join(cwd, REPO_MAP_DIR_REL);
328
+ fs.mkdirSync(dir, { recursive: true });
329
+ const abs = path.join(cwd, LATEST_MAP_REL);
330
+ // Write without full file content — just metadata
331
+ const compact = {
332
+ ...map,
333
+ files: map.files.map((f) => ({ path: f.path, ext: f.ext, bytes: f.bytes, estimatedTokens: f.estimatedTokens, symbols: f.symbols })),
334
+ };
335
+ fs.writeFileSync(abs, JSON.stringify(compact, null, 2), "utf8");
336
+ try {
337
+ appendProductLearningEvent(cwd, "repo_map_generated", {
338
+ fileCount: map.fileCount,
339
+ totalEstimatedTokens: map.totalEstimatedTokens,
340
+ workspaceType: map.workspaceType,
341
+ status: map.status,
342
+ });
343
+ } catch {}
344
+ return abs;
345
+ }
346
+
347
+ function buildRepoMapSurface(cwd, options = {}) {
348
+ const abs = path.join(cwd, LATEST_MAP_REL);
349
+ if (!fs.existsSync(abs)) {
350
+ return { status: "not_available", artifactPath: LATEST_MAP_REL };
351
+ }
352
+ try {
353
+ const map = JSON.parse(fs.readFileSync(abs, "utf8"));
354
+ return {
355
+ status: map.status || "unknown",
356
+ fileCount: map.fileCount,
357
+ totalEstimatedTokens: map.totalEstimatedTokens,
358
+ workspaceType: map.workspaceType,
359
+ artifactPath: LATEST_MAP_REL,
360
+ };
361
+ } catch {
362
+ return { status: "error", artifactPath: LATEST_MAP_REL };
363
+ }
364
+ }
365
+
366
+ function formatRepoMapText(map, options = {}) {
367
+ const lines = [`Repo Map (${map.status})`];
368
+ lines.push(` Files: ${map.fileCount} | Tokens (est.): ~${map.totalEstimatedTokens}`);
369
+ lines.push(` Workspace: ${map.workspaceType}`);
370
+ if (map.packageScopes && map.packageScopes.length) {
371
+ lines.push(` Packages: ${map.packageScopes.join(", ")}`);
372
+ }
373
+ lines.push(` Excluded: ${map.generatedExcluded} generated, ${map.binaryExcluded} binary, ${map.minifiedExcluded} minified, ${map.sensitiveExcluded} sensitive`);
374
+ if (map.caveats && map.caveats.length) {
375
+ lines.push(` Caveat: ${map.caveats[0]}`);
376
+ }
377
+ return lines.join("\n");
378
+ }
379
+
380
+ module.exports = {
381
+ CONTRACT,
382
+ SCHEMA_VERSION,
383
+ REPO_MAP_DIR_REL,
384
+ LATEST_MAP_REL,
385
+ buildRepoMap,
386
+ buildSymbolMap,
387
+ selectLikelyRelevantFiles,
388
+ writeRepoMap,
389
+ buildRepoMapSurface,
390
+ formatRepoMapText,
391
+ };