@cleocode/core 2026.9.16 → 2026.9.18

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 (236) hide show
  1. package/dist/changesets/parser.d.ts.map +1 -1
  2. package/dist/changesets/parser.js +67 -0
  3. package/dist/changesets/parser.js.map +1 -1
  4. package/dist/crypto/credentials.d.ts +128 -26
  5. package/dist/crypto/credentials.d.ts.map +1 -1
  6. package/dist/crypto/credentials.js +183 -142
  7. package/dist/crypto/credentials.js.map +1 -1
  8. package/dist/docs/export-document.js +14705 -12949
  9. package/dist/docs/export-document.js.map +3 -3
  10. package/dist/doctor/index.d.ts +1 -1
  11. package/dist/doctor/index.d.ts.map +1 -1
  12. package/dist/doctor/index.js +1 -1
  13. package/dist/doctor/index.js.map +1 -1
  14. package/dist/doctor/nexus-schema-residency.d.ts +1 -1
  15. package/dist/doctor/nexus-schema-residency.d.ts.map +1 -1
  16. package/dist/doctor/nexus-schema-residency.js +1 -0
  17. package/dist/doctor/nexus-schema-residency.js.map +1 -1
  18. package/dist/doctor/project-identity.d.ts +124 -0
  19. package/dist/doctor/project-identity.d.ts.map +1 -0
  20. package/dist/doctor/project-identity.js +307 -0
  21. package/dist/doctor/project-identity.js.map +1 -0
  22. package/dist/doctor/superseded-store.d.ts +8 -0
  23. package/dist/doctor/superseded-store.d.ts.map +1 -1
  24. package/dist/doctor/superseded-store.js +48 -3
  25. package/dist/doctor/superseded-store.js.map +1 -1
  26. package/dist/init.d.ts +7 -0
  27. package/dist/init.d.ts.map +1 -1
  28. package/dist/init.js +17 -2
  29. package/dist/init.js.map +1 -1
  30. package/dist/internal.d.ts +6 -3
  31. package/dist/internal.d.ts.map +1 -1
  32. package/dist/internal.js +4 -2
  33. package/dist/internal.js.map +1 -1
  34. package/dist/llm/credentials-store.d.ts +10 -0
  35. package/dist/llm/credentials-store.d.ts.map +1 -1
  36. package/dist/llm/credentials-store.js +7 -1
  37. package/dist/llm/credentials-store.js.map +1 -1
  38. package/dist/llm/plugin-facade.js +13368 -1550
  39. package/dist/llm/plugin-facade.js.map +3 -3
  40. package/dist/nexus/analyze-orchestrator.d.ts +20 -3
  41. package/dist/nexus/analyze-orchestrator.d.ts.map +1 -1
  42. package/dist/nexus/analyze-orchestrator.js +210 -16
  43. package/dist/nexus/analyze-orchestrator.js.map +1 -1
  44. package/dist/nexus/assessment-store.d.ts +86 -0
  45. package/dist/nexus/assessment-store.d.ts.map +1 -0
  46. package/dist/nexus/assessment-store.js +113 -0
  47. package/dist/nexus/assessment-store.js.map +1 -0
  48. package/dist/nexus/freshness.d.ts +131 -0
  49. package/dist/nexus/freshness.d.ts.map +1 -0
  50. package/dist/nexus/freshness.js +391 -0
  51. package/dist/nexus/freshness.js.map +1 -0
  52. package/dist/nexus/graph-manifest.d.ts +88 -0
  53. package/dist/nexus/graph-manifest.d.ts.map +1 -0
  54. package/dist/nexus/graph-manifest.js +114 -0
  55. package/dist/nexus/graph-manifest.js.map +1 -0
  56. package/dist/nexus/knowledge.d.ts +21 -1
  57. package/dist/nexus/knowledge.d.ts.map +1 -1
  58. package/dist/nexus/knowledge.js +74 -37
  59. package/dist/nexus/knowledge.js.map +1 -1
  60. package/dist/nexus/path-map.d.ts +55 -0
  61. package/dist/nexus/path-map.d.ts.map +1 -0
  62. package/dist/nexus/path-map.js +87 -0
  63. package/dist/nexus/path-map.js.map +1 -0
  64. package/dist/nexus/projects-clean.d.ts +21 -28
  65. package/dist/nexus/projects-clean.d.ts.map +1 -1
  66. package/dist/nexus/projects-clean.js +168 -85
  67. package/dist/nexus/projects-clean.js.map +1 -1
  68. package/dist/nexus/query.d.ts.map +1 -1
  69. package/dist/nexus/query.js +3 -2
  70. package/dist/nexus/query.js.map +1 -1
  71. package/dist/nexus/registry-hygiene.d.ts +70 -0
  72. package/dist/nexus/registry-hygiene.d.ts.map +1 -0
  73. package/dist/nexus/registry-hygiene.js +113 -0
  74. package/dist/nexus/registry-hygiene.js.map +1 -0
  75. package/dist/nexus/registry.d.ts +2 -2
  76. package/dist/nexus/registry.d.ts.map +1 -1
  77. package/dist/nexus/registry.js +48 -12
  78. package/dist/nexus/registry.js.map +1 -1
  79. package/dist/paths.d.ts +26 -0
  80. package/dist/paths.d.ts.map +1 -1
  81. package/dist/paths.js +99 -6
  82. package/dist/paths.js.map +1 -1
  83. package/dist/release/index.d.ts +1 -1
  84. package/dist/release/index.d.ts.map +1 -1
  85. package/dist/release/index.js.map +1 -1
  86. package/dist/release/plan.d.ts +84 -2
  87. package/dist/release/plan.d.ts.map +1 -1
  88. package/dist/release/plan.js +61 -14
  89. package/dist/release/plan.js.map +1 -1
  90. package/dist/release/pr-evidence.d.ts +81 -1
  91. package/dist/release/pr-evidence.d.ts.map +1 -1
  92. package/dist/release/pr-evidence.js +149 -9
  93. package/dist/release/pr-evidence.js.map +1 -1
  94. package/dist/render/nexus/graph/index.d.ts.map +1 -1
  95. package/dist/render/nexus/graph/index.js +8 -0
  96. package/dist/render/nexus/graph/index.js.map +1 -1
  97. package/dist/scaffold/ensure-config.d.ts +12 -3
  98. package/dist/scaffold/ensure-config.d.ts.map +1 -1
  99. package/dist/scaffold/ensure-config.js +61 -38
  100. package/dist/scaffold/ensure-config.js.map +1 -1
  101. package/dist/scaffold/project-identity.d.ts +136 -0
  102. package/dist/scaffold/project-identity.d.ts.map +1 -0
  103. package/dist/scaffold/project-identity.js +225 -0
  104. package/dist/scaffold/project-identity.js.map +1 -0
  105. package/dist/selfimprove/fix-gen.js +13319 -1556
  106. package/dist/selfimprove/fix-gen.js.map +3 -3
  107. package/dist/store/agent-api-key.d.ts +114 -0
  108. package/dist/store/agent-api-key.d.ts.map +1 -0
  109. package/dist/store/agent-api-key.js +136 -0
  110. package/dist/store/agent-api-key.js.map +1 -0
  111. package/dist/store/agent-registry-accessor.d.ts +4 -2
  112. package/dist/store/agent-registry-accessor.d.ts.map +1 -1
  113. package/dist/store/agent-registry-accessor.js +39 -89
  114. package/dist/store/agent-registry-accessor.js.map +1 -1
  115. package/dist/store/api-key-kdf.d.ts +7 -0
  116. package/dist/store/api-key-kdf.d.ts.map +1 -1
  117. package/dist/store/api-key-kdf.js +7 -0
  118. package/dist/store/api-key-kdf.js.map +1 -1
  119. package/dist/store/backup-crypto.d.ts +49 -0
  120. package/dist/store/backup-crypto.d.ts.map +1 -1
  121. package/dist/store/backup-crypto.js +154 -0
  122. package/dist/store/backup-crypto.js.map +1 -1
  123. package/dist/store/credential-transfer.d.ts +303 -0
  124. package/dist/store/credential-transfer.d.ts.map +1 -0
  125. package/dist/store/credential-transfer.js +774 -0
  126. package/dist/store/credential-transfer.js.map +1 -0
  127. package/dist/store/exodus/column-transforms.d.ts +79 -4
  128. package/dist/store/exodus/column-transforms.d.ts.map +1 -1
  129. package/dist/store/exodus/column-transforms.js +121 -4
  130. package/dist/store/exodus/column-transforms.js.map +1 -1
  131. package/dist/store/exodus/index.d.ts +1 -0
  132. package/dist/store/exodus/index.d.ts.map +1 -1
  133. package/dist/store/exodus/index.js +1 -0
  134. package/dist/store/exodus/index.js.map +1 -1
  135. package/dist/store/exodus/migrate.d.ts +17 -1
  136. package/dist/store/exodus/migrate.d.ts.map +1 -1
  137. package/dist/store/exodus/migrate.js +155 -33
  138. package/dist/store/exodus/migrate.js.map +1 -1
  139. package/dist/store/exodus/on-open.d.ts +14 -0
  140. package/dist/store/exodus/on-open.d.ts.map +1 -1
  141. package/dist/store/exodus/on-open.js +115 -6
  142. package/dist/store/exodus/on-open.js.map +1 -1
  143. package/dist/store/exodus/reconcile.d.ts +103 -0
  144. package/dist/store/exodus/reconcile.d.ts.map +1 -0
  145. package/dist/store/exodus/reconcile.js +728 -0
  146. package/dist/store/exodus/reconcile.js.map +1 -0
  147. package/dist/store/exodus/recovery.d.ts.map +1 -1
  148. package/dist/store/exodus/recovery.js +14 -2
  149. package/dist/store/exodus/recovery.js.map +1 -1
  150. package/dist/store/exodus/runtime-targets.d.ts +39 -0
  151. package/dist/store/exodus/runtime-targets.d.ts.map +1 -0
  152. package/dist/store/exodus/runtime-targets.js +63 -0
  153. package/dist/store/exodus/runtime-targets.js.map +1 -0
  154. package/dist/store/exodus/table-name-map.d.ts.map +1 -1
  155. package/dist/store/exodus/table-name-map.js +5 -0
  156. package/dist/store/exodus/table-name-map.js.map +1 -1
  157. package/dist/store/exodus/table-order.d.ts +35 -0
  158. package/dist/store/exodus/table-order.d.ts.map +1 -0
  159. package/dist/store/exodus/table-order.js +62 -0
  160. package/dist/store/exodus/table-order.js.map +1 -0
  161. package/dist/store/exodus/verify-migration.d.ts +4 -1
  162. package/dist/store/exodus/verify-migration.d.ts.map +1 -1
  163. package/dist/store/exodus/verify-migration.js +142 -10
  164. package/dist/store/exodus/verify-migration.js.map +1 -1
  165. package/dist/store/global-salt.d.ts +16 -0
  166. package/dist/store/global-salt.d.ts.map +1 -1
  167. package/dist/store/global-salt.js +22 -7
  168. package/dist/store/global-salt.js.map +1 -1
  169. package/dist/store/legacy-tasks-lineage.d.ts +86 -0
  170. package/dist/store/legacy-tasks-lineage.d.ts.map +1 -0
  171. package/dist/store/legacy-tasks-lineage.js +285 -0
  172. package/dist/store/legacy-tasks-lineage.js.map +1 -0
  173. package/dist/store/migration-manager.d.ts +27 -0
  174. package/dist/store/migration-manager.d.ts.map +1 -1
  175. package/dist/store/migration-manager.js +63 -0
  176. package/dist/store/migration-manager.js.map +1 -1
  177. package/dist/store/portable-bundle-import.d.ts +117 -0
  178. package/dist/store/portable-bundle-import.d.ts.map +1 -0
  179. package/dist/store/portable-bundle-import.js +589 -0
  180. package/dist/store/portable-bundle-import.js.map +1 -0
  181. package/dist/store/portable-bundle-relocate.d.ts +66 -0
  182. package/dist/store/portable-bundle-relocate.d.ts.map +1 -0
  183. package/dist/store/portable-bundle-relocate.js +304 -0
  184. package/dist/store/portable-bundle-relocate.js.map +1 -0
  185. package/dist/store/portable-bundle-scan.d.ts +167 -0
  186. package/dist/store/portable-bundle-scan.d.ts.map +1 -0
  187. package/dist/store/portable-bundle-scan.js +569 -0
  188. package/dist/store/portable-bundle-scan.js.map +1 -0
  189. package/dist/store/portable-bundle.d.ts +146 -0
  190. package/dist/store/portable-bundle.d.ts.map +1 -0
  191. package/dist/store/portable-bundle.js +674 -0
  192. package/dist/store/portable-bundle.js.map +1 -0
  193. package/dist/store/regenerators.d.ts +3 -1
  194. package/dist/store/regenerators.d.ts.map +1 -1
  195. package/dist/store/regenerators.js +6 -2
  196. package/dist/store/regenerators.js.map +1 -1
  197. package/dist/store/schema/cleo-global/nexus.d.ts +98 -0
  198. package/dist/store/schema/cleo-global/nexus.d.ts.map +1 -1
  199. package/dist/store/schema/cleo-global/nexus.js +19 -0
  200. package/dist/store/schema/cleo-global/nexus.js.map +1 -1
  201. package/dist/store/schema/nexus-schema.d.ts +102 -0
  202. package/dist/store/schema/nexus-schema.d.ts.map +1 -1
  203. package/dist/store/schema/nexus-schema.js +24 -0
  204. package/dist/store/schema/nexus-schema.js.map +1 -1
  205. package/dist/store/split-brain-import.d.ts +176 -0
  206. package/dist/store/split-brain-import.d.ts.map +1 -0
  207. package/dist/store/split-brain-import.js +680 -0
  208. package/dist/store/split-brain-import.js.map +1 -0
  209. package/dist/store/sqlite.d.ts +29 -0
  210. package/dist/store/sqlite.d.ts.map +1 -1
  211. package/dist/store/sqlite.js +57 -5
  212. package/dist/store/sqlite.js.map +1 -1
  213. package/dist/system/health.d.ts.map +1 -1
  214. package/dist/system/health.js +30 -5
  215. package/dist/system/health.js.map +1 -1
  216. package/dist/tasks/complete.d.ts.map +1 -1
  217. package/dist/tasks/complete.js +5 -27
  218. package/dist/tasks/complete.js.map +1 -1
  219. package/dist/tasks/evidence.js +1 -1
  220. package/dist/tasks/evidence.js.map +1 -1
  221. package/dist/tasks/verification-policy.d.ts +55 -0
  222. package/dist/tasks/verification-policy.d.ts.map +1 -0
  223. package/dist/tasks/verification-policy.js +75 -0
  224. package/dist/tasks/verification-policy.js.map +1 -0
  225. package/dist/upgrade.d.ts.map +1 -1
  226. package/dist/upgrade.js +60 -0
  227. package/dist/upgrade.js.map +1 -1
  228. package/dist/validation/doctor/checks.d.ts +14 -0
  229. package/dist/validation/doctor/checks.d.ts.map +1 -1
  230. package/dist/validation/doctor/checks.js +33 -0
  231. package/dist/validation/doctor/checks.js.map +1 -1
  232. package/migrations/drizzle-cleo-global/20260924000000_t12354-project-paths/migration.sql +40 -0
  233. package/migrations/drizzle-nexus/20260924000000_t12315-nexus-parse-cache/migration.sql +21 -0
  234. package/package.json +13 -13
  235. package/templates/CLEO-INJECTION.md +3 -3
  236. package/templates/cleo-gitignore +7 -0
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Storage layout of the published graph assessment (T12348).
3
+ *
4
+ * The assessment used to be ONE `_nexus_meta` JSON value holding every
5
+ * retained unresolved/unmodeled reference with its full evidence — 472 MB on
6
+ * this repository, 647k references against a 3.75 MB remainder. Every reader
7
+ * paid to parse and validate all of it: `cleo nexus status` took ~10 s and
8
+ * returned a 472 MB envelope, and every analysis re-read it before starting.
9
+ *
10
+ * The summary (`graph_assessment`) now carries everything except the
11
+ * reference list, plus `referenceCount`; the list lives under
12
+ * `graph_assessment_references` and is read only when asked for. Both are
13
+ * written in the publishing transaction, so they always describe the same
14
+ * generation. A historical value with inline `references` stays readable.
15
+ *
16
+ * The list is stored gzip-compressed (a BLOB), because every publication
17
+ * rewrites it: 453 MB of JSON is 116k pages written to the WAL and 116k more
18
+ * at checkpoint — measured at 0.6 ms per page write on this repository's FUSE
19
+ * mount, most of a 49-minute publication. At gzip level 1 it is 28 MB, costs
20
+ * ~0.6 s to compress and ~0.55 s to inflate. A historical plain-text list is
21
+ * still read as stored.
22
+ *
23
+ * Code placed in `packages/core/` per Package-Boundary Check — verified against AGENTS.md.
24
+ *
25
+ * @task T12348
26
+ * @module nexus/assessment-store
27
+ */
28
+ import { gunzipSync, gzipSync } from 'node:zlib';
29
+ import { sql } from 'drizzle-orm';
30
+ /** `_nexus_meta` key of the assessment summary. */
31
+ export const ASSESSMENT_KEY = 'graph_assessment';
32
+ /** `_nexus_meta` key of the separately stored reference list. */
33
+ export const ASSESSMENT_REFERENCES_KEY = 'graph_assessment_references';
34
+ /** gzip level of the stored reference list: level 1 is ~16x smaller at ~1 s per 450 MB. */
35
+ const REFERENCES_GZIP_LEVEL = 1;
36
+ /**
37
+ * Encode a reference list for storage under {@link ASSESSMENT_REFERENCES_KEY}.
38
+ *
39
+ * @param references - The generation's retained references.
40
+ * @returns gzip-compressed JSON, stored as a BLOB.
41
+ */
42
+ export function encodeStoredReferences(references) {
43
+ return gzipSync(JSON.stringify(references), { level: REFERENCES_GZIP_LEVEL });
44
+ }
45
+ /**
46
+ * Decode a stored reference list back to its JSON text.
47
+ *
48
+ * Accepts the compressed BLOB written since T12348 and the plain JSON text
49
+ * written before it; anything else is malformed metadata.
50
+ *
51
+ * @param value - The raw `_nexus_meta.value` of {@link ASSESSMENT_REFERENCES_KEY}.
52
+ * @returns The list's JSON text.
53
+ * @throws When the value is neither text nor a compressed list.
54
+ * @example
55
+ * ```ts
56
+ * const references = JSON.parse(decodeStoredReferences(row.value));
57
+ * ```
58
+ */
59
+ export function decodeStoredReferences(value) {
60
+ if (typeof value === 'string')
61
+ return value;
62
+ if (value instanceof Uint8Array)
63
+ return gunzipSync(value).toString('utf8');
64
+ throw new Error('Graph reference metadata is neither text nor a compressed list.');
65
+ }
66
+ /**
67
+ * Return the summary form of an assessment: the reference list removed and
68
+ * its length recorded as `referenceCount`.
69
+ *
70
+ * An assessment without a `references` list is returned unchanged, so a
71
+ * summary stays a summary and a historical index without references keeps
72
+ * its shape.
73
+ *
74
+ * @param assessment - Full or summary assessment.
75
+ * @returns The summary a reader of `graph_assessment` observes.
76
+ * @example
77
+ * ```ts
78
+ * const head = assessmentSummary(stagedAssessment);
79
+ * ```
80
+ */
81
+ export function assessmentSummary(assessment) {
82
+ if (assessment.references === undefined)
83
+ return assessment;
84
+ const { references, ...summary } = assessment;
85
+ return { ...summary, referenceCount: references.length };
86
+ }
87
+ /**
88
+ * Write an assessment inside the caller's transaction.
89
+ *
90
+ * - A full assessment writes its summary and replaces the reference list.
91
+ * - A summary that already carries `referenceCount` (for example a provenance
92
+ * re-record of an unchanged generation) rewrites the summary only, keeping
93
+ * the stored list of that same generation.
94
+ * - An assessment with neither removes any stale list.
95
+ *
96
+ * @param tx - Graph database handle or open transaction.
97
+ * @param assessment - Assessment to persist.
98
+ * @returns The summary as written.
99
+ */
100
+ export function writeAssessment(tx, assessment) {
101
+ const summary = assessmentSummary(assessment);
102
+ tx.run(sql `INSERT INTO main._nexus_meta (key, value) VALUES (${ASSESSMENT_KEY}, ${JSON.stringify(summary)})
103
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = strftime('%s', 'now')`);
104
+ if (assessment.references !== undefined) {
105
+ tx.run(sql `INSERT INTO main._nexus_meta (key, value) VALUES (${ASSESSMENT_REFERENCES_KEY}, ${encodeStoredReferences(assessment.references)})
106
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = strftime('%s', 'now')`);
107
+ }
108
+ else if (summary.referenceCount === undefined) {
109
+ tx.run(sql `DELETE FROM main._nexus_meta WHERE key = ${ASSESSMENT_REFERENCES_KEY}`);
110
+ }
111
+ return summary;
112
+ }
113
+ //# sourceMappingURL=assessment-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assessment-store.js","sourceRoot":"","sources":["../../src/nexus/assessment-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAGlC,mDAAmD;AACnD,MAAM,CAAC,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAEjD,iEAAiE;AACjE,MAAM,CAAC,MAAM,yBAAyB,GAAG,6BAA6B,CAAC;AAEvE,2FAA2F;AAC3F,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,UAAgD;IAEhD,OAAO,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC,CAAC;AAChF,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAc;IACnD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,YAAY,UAAU;QAAE,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC3E,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;AACrF,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAgC;IAChE,IAAI,UAAU,CAAC,UAAU,KAAK,SAAS;QAAE,OAAO,UAAU,CAAC;IAC3D,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,GAAG,UAAU,CAAC;IAC9C,OAAO,EAAE,GAAG,OAAO,EAAE,cAAc,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAC7B,EAAmC,EACnC,UAAgC;IAEhC,MAAM,OAAO,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAC9C,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,qDAAqD,cAAc,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;8FACb,CAAC,CAAC;IAC9F,IAAI,UAAU,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACxC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,qDAAqD,yBAAyB,KAAK,sBAAsB,CAAC,UAAU,CAAC,UAAU,CAAC;gGAC9C,CAAC,CAAC;IAChG,CAAC;SAAM,IAAI,OAAO,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;QAChD,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA,4CAA4C,yBAAyB,EAAE,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Code-graph index freshness — disclosed on every graph query, and repaired
3
+ * inline when the repair is small (T12316).
4
+ *
5
+ * A graph answer from a stale index is a confident answer about code that no
6
+ * longer exists. The check compares the published generation's file manifest
7
+ * against the working tree: a file whose size and mtime are unchanged keeps its
8
+ * recorded hash, and only a metadata mismatch is re-hashed, so a checkout or
9
+ * `touch` that changed no bytes is not reported stale.
10
+ *
11
+ * Code placed in `packages/core/` per Package-Boundary Check — verified against AGENTS.md.
12
+ *
13
+ * @task T12316
14
+ * @module nexus/freshness
15
+ */
16
+ import type { GraphIndexFreshness } from '@cleocode/contracts';
17
+ /** Command that refreshes the index; incremental by default since T12315. */
18
+ export declare const NEXUS_REFRESH_COMMAND = "cleo nexus analyze";
19
+ /** Default number of stale files an index query may refresh inline. */
20
+ export declare const DEFAULT_AUTO_REFRESH_MAX_FILES = 25;
21
+ /** Default wall-clock budget for an inline refresh. */
22
+ export declare const DEFAULT_AUTO_REFRESH_BUDGET_MS = 60000;
23
+ /** Options for {@link assessNexusIndexFreshness}. */
24
+ export interface NexusFreshnessOptions {
25
+ /** Files of the queried symbol(s); their own staleness is reported separately. */
26
+ symbolFiles?: readonly string[];
27
+ /** Maximum stale paths listed in the result. @defaultValue 10 */
28
+ sampleLimit?: number;
29
+ }
30
+ /**
31
+ * A freshness verdict plus the complete stale set it was computed from, so the
32
+ * files of a symbol identified only AFTER the query can still be judged.
33
+ */
34
+ export interface NexusFreshnessAssessment {
35
+ /** Disclosed freshness facts. */
36
+ freshness: GraphIndexFreshness;
37
+ /** Every stale path (modified, added, deleted or unreadable). */
38
+ staleFiles: ReadonlySet<string>;
39
+ }
40
+ /**
41
+ * Judge the queried symbol's own files against an assessment.
42
+ * @param assessment - Assessment taken before the query ran.
43
+ * @param files - Files of the queried symbol(s), e.g. from {@link querySymbolFiles}.
44
+ * @returns The freshness facts with `symbolFileStale`/`symbolFile` set when files are known.
45
+ */
46
+ export declare function judgeSymbolFiles(assessment: NexusFreshnessAssessment, files: readonly string[]): GraphIndexFreshness;
47
+ /** Auto-refresh policy, read from `nexus.autoRefresh.*` config unless given. */
48
+ export interface NexusAutoRefreshPolicy {
49
+ /** Whether queries may refresh the index inline. @defaultValue true */
50
+ enabled: boolean;
51
+ /** Most stale files a query refreshes inline. @defaultValue 25 */
52
+ maxFiles: number;
53
+ /** Wall-clock budget; a refresh estimated to exceed it is not started. @defaultValue 60000 */
54
+ budgetMs: number;
55
+ }
56
+ /**
57
+ * Assess how far the published code graph lags the working tree.
58
+ *
59
+ * @param projectRoot - Project whose graph database is inspected.
60
+ * @param options - Symbol files to judge individually and the stale-path sample size.
61
+ * @returns Freshness facts; `status: 'unknown'` carries a `reason` and is never a pass.
62
+ * @example
63
+ * ```ts
64
+ * const freshness = await assessNexusIndexFreshness('/repo', { symbolFiles: ['src/a.ts'] });
65
+ * if (freshness.status === 'stale') console.error(freshness.refreshCommand);
66
+ * ```
67
+ */
68
+ export declare function assessNexusIndexFreshness(projectRoot: string, options?: NexusFreshnessOptions): Promise<GraphIndexFreshness>;
69
+ /**
70
+ * Read the auto-refresh policy from `nexus.autoRefresh.*`, applying defaults.
71
+ * @param projectRoot - Project whose merged config is read.
72
+ * @returns The effective policy.
73
+ */
74
+ export declare function readNexusAutoRefreshPolicy(projectRoot: string): Promise<NexusAutoRefreshPolicy>;
75
+ /**
76
+ * Assess freshness and, when only a few files are stale, refresh the index
77
+ * inline before the caller answers from it.
78
+ *
79
+ * A refresh runs only when `0 < stale ≤ maxFiles` and the recorded cost
80
+ * estimate fits `budgetMs`; the budget also cancels the run at its next phase
81
+ * boundary, and publication is atomic, so an abandoned refresh leaves the
82
+ * previous graph intact. Every decision — refreshed, skipped or failed — is
83
+ * disclosed in `autoRefresh`, and the returned freshness describes the index
84
+ * the caller is about to read.
85
+ *
86
+ * @param projectRoot - Project whose graph is about to be queried.
87
+ * @param policy - Explicit policy; read from config when omitted.
88
+ * @returns Freshness of the index as it stands after any refresh, with its stale set.
89
+ */
90
+ export declare function ensureNexusIndexFresh(projectRoot: string, policy?: NexusAutoRefreshPolicy): Promise<NexusFreshnessAssessment>;
91
+ /**
92
+ * Collect the source files a graph query answer is about.
93
+ *
94
+ * Graph node ids are `<file>::<symbol>`, so a target id names its file; an
95
+ * explicit `filePath` is used when present. Only the answer's own target (or,
96
+ * for symbol lookups, each matched symbol) is considered — callers listed in
97
+ * the answer are not "the queried symbol".
98
+ *
99
+ * @param data - A query operation's result payload.
100
+ * @returns Repository-relative files of the queried symbol(s); empty when none are identifiable.
101
+ */
102
+ export declare function querySymbolFiles(data: unknown): string[];
103
+ /**
104
+ * Assess (and when small, repair) index freshness before a graph query.
105
+ *
106
+ * Never throws: a failed assessment is returned as `status: 'unknown'` with its
107
+ * reason, so it neither blocks the query nor is ever mistaken for fresh.
108
+ *
109
+ * @param projectRoot - Project whose graph is about to be queried.
110
+ * @returns The assessment to judge the answer against.
111
+ */
112
+ export declare function assessNexusFreshnessForQuery(projectRoot: string): Promise<NexusFreshnessAssessment>;
113
+ /**
114
+ * Disclose a non-fresh index as an envelope warning
115
+ * (`W_NEXUS_INDEX_STALE` / `W_NEXUS_INDEX_FRESHNESS_UNKNOWN`), and an inline
116
+ * refresh that just happened as `W_NEXUS_INDEX_REFRESHED` (info). Warnings
117
+ * reach `meta.warnings` through the active collector — never stderr, which
118
+ * would break the one-envelope stream contract (T9775).
119
+ *
120
+ * @param subject - What answered, e.g. `nexus impact`.
121
+ * @param freshness - Freshness of the index the answer came from.
122
+ */
123
+ export declare function discloseNexusFreshness(subject: string, freshness: GraphIndexFreshness): void;
124
+ /**
125
+ * Merge a freshness verdict into envelope extensions' `_nexus` block.
126
+ * @param extensions - Envelope extensions, possibly already carrying `_nexus`.
127
+ * @param freshness - Freshness of the index the answer came from.
128
+ * @returns New extensions with `_nexus.indexFreshness` and `_nexus.freshness` set.
129
+ */
130
+ export declare function withNexusFreshnessMeta(extensions: Record<string, unknown>, freshness: GraphIndexFreshness): Record<string, unknown>;
131
+ //# sourceMappingURL=freshness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshness.d.ts","sourceRoot":"","sources":["../../src/nexus/freshness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAQ/D,6EAA6E;AAC7E,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAE1D,uEAAuE;AACvE,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAEjD,uDAAuD;AACvD,eAAO,MAAM,8BAA8B,QAAS,CAAC;AAKrD,qDAAqD;AACrD,MAAM,WAAW,qBAAqB;IACpC,kFAAkF;IAClF,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,iCAAiC;IACjC,SAAS,EAAE,mBAAmB,CAAC;IAC/B,iEAAiE;IACjE,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACjC;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,wBAAwB,EACpC,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,mBAAmB,CASrB;AAED,gFAAgF;AAChF,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,OAAO,EAAE,OAAO,CAAC;IACjB,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAC;IACjB,8FAA8F;IAC9F,QAAQ,EAAE,MAAM,CAAC;CAClB;AA6BD;;;;;;;;;;;GAWG;AACH,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,mBAAmB,CAAC,CAG9B;AAwFD;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,sBAAsB,CAAC,CAwBjC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,sBAAsB,GAC9B,OAAO,CAAC,wBAAwB,CAAC,CA+DnC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE,CAyBxD;AAED;;;;;;;;GAQG;AACH,wBAAsB,4BAA4B,CAChD,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,wBAAwB,CAAC,CAoBnC;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,mBAAmB,GAAG,IAAI,CA0B5F;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,SAAS,EAAE,mBAAmB,GAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAOzB"}
@@ -0,0 +1,391 @@
1
+ /**
2
+ * Code-graph index freshness — disclosed on every graph query, and repaired
3
+ * inline when the repair is small (T12316).
4
+ *
5
+ * A graph answer from a stale index is a confident answer about code that no
6
+ * longer exists. The check compares the published generation's file manifest
7
+ * against the working tree: a file whose size and mtime are unchanged keeps its
8
+ * recorded hash, and only a metadata mismatch is re-hashed, so a checkout or
9
+ * `touch` that changed no bytes is not reported stale.
10
+ *
11
+ * Code placed in `packages/core/` per Package-Boundary Check — verified against AGENTS.md.
12
+ *
13
+ * @task T12316
14
+ * @module nexus/freshness
15
+ */
16
+ import { performance } from 'node:perf_hooks';
17
+ import { getConfigValue } from '../config/registry.js';
18
+ import { pushWarning } from '../output.js';
19
+ import { getNexusDb } from '../store/nexus-sqlite.js';
20
+ import { runNexusAnalysis } from './analyze-orchestrator.js';
21
+ import { readFileManifest, readRunCost } from './graph-manifest.js';
22
+ /** Command that refreshes the index; incremental by default since T12315. */
23
+ export const NEXUS_REFRESH_COMMAND = 'cleo nexus analyze';
24
+ /** Default number of stale files an index query may refresh inline. */
25
+ export const DEFAULT_AUTO_REFRESH_MAX_FILES = 25;
26
+ /** Default wall-clock budget for an inline refresh. */
27
+ export const DEFAULT_AUTO_REFRESH_BUDGET_MS = 60_000;
28
+ /** Share of changed files above which analysis rebuilds fully (mirrors the pipeline). */
29
+ const FULL_REBUILD_RATIO = 0.3;
30
+ /**
31
+ * Judge the queried symbol's own files against an assessment.
32
+ * @param assessment - Assessment taken before the query ran.
33
+ * @param files - Files of the queried symbol(s), e.g. from {@link querySymbolFiles}.
34
+ * @returns The freshness facts with `symbolFileStale`/`symbolFile` set when files are known.
35
+ */
36
+ export function judgeSymbolFiles(assessment, files) {
37
+ const unique = [...new Set(files)];
38
+ if (unique.length === 0)
39
+ return assessment.freshness;
40
+ const stale = unique.find((file) => assessment.staleFiles.has(file));
41
+ return {
42
+ ...assessment.freshness,
43
+ symbolFileStale: stale !== undefined,
44
+ symbolFile: stale ?? unique[0],
45
+ };
46
+ }
47
+ /** Estimate a refresh from the last recorded run, or `null` when nothing is recorded. */
48
+ function estimateRefreshMs(cost, staleFiles, fileCount) {
49
+ if (!cost)
50
+ return null;
51
+ const parseMs = cost.summary.phaseMs['parse'] ?? 0;
52
+ const parsed = cost.summary.parsedFiles;
53
+ const fixedMs = Math.max(0, cost.durationMs - parseMs);
54
+ const perFileMs = parsed > 0 ? parseMs / parsed : 0;
55
+ const full = fileCount > 0 && staleFiles / fileCount > FULL_REBUILD_RATIO;
56
+ const reparsed = full ? Math.max(parsed, cost.summary.resolvedFiles) : staleFiles;
57
+ return Math.round(fixedMs + reparsed * perFileMs);
58
+ }
59
+ /** Render an estimate for humans and agents alike. */
60
+ function describeEstimate(ms, staleFiles, fileCount) {
61
+ if (staleFiles === 0)
62
+ return 'none needed';
63
+ const kind = fileCount > 0 && staleFiles / fileCount > FULL_REBUILD_RATIO
64
+ ? 'full rebuild'
65
+ : `incremental, re-parses ~${staleFiles} file(s)`;
66
+ if (ms === null)
67
+ return `unknown duration (${kind}; no previous analysis cost recorded)`;
68
+ return `~${Math.max(1, Math.round(ms / 1000))}s (${kind})`;
69
+ }
70
+ /**
71
+ * Assess how far the published code graph lags the working tree.
72
+ *
73
+ * @param projectRoot - Project whose graph database is inspected.
74
+ * @param options - Symbol files to judge individually and the stale-path sample size.
75
+ * @returns Freshness facts; `status: 'unknown'` carries a `reason` and is never a pass.
76
+ * @example
77
+ * ```ts
78
+ * const freshness = await assessNexusIndexFreshness('/repo', { symbolFiles: ['src/a.ts'] });
79
+ * if (freshness.status === 'stale') console.error(freshness.refreshCommand);
80
+ * ```
81
+ */
82
+ export async function assessNexusIndexFreshness(projectRoot, options = {}) {
83
+ const assessment = await assessWithStaleSet(projectRoot, options.sampleLimit);
84
+ return judgeSymbolFiles(assessment, options.symbolFiles ?? []);
85
+ }
86
+ /** Walk the tree once and keep the full stale set alongside the disclosed facts. */
87
+ async function assessWithStaleSet(projectRoot, sampleLimit = 10) {
88
+ const started = performance.now();
89
+ const base = {
90
+ refreshCommand: NEXUS_REFRESH_COMMAND,
91
+ stalePaths: [],
92
+ };
93
+ const db = await getNexusDb(projectRoot);
94
+ let manifest;
95
+ const none = new Set();
96
+ try {
97
+ manifest = readFileManifest(db);
98
+ }
99
+ catch (error) {
100
+ const freshness = {
101
+ ...base,
102
+ indexed: true,
103
+ status: 'unknown',
104
+ lastIndexedAt: null,
105
+ fileCount: 0,
106
+ staleFileCount: -1,
107
+ refreshEstimate: 'unknown',
108
+ checkMs: Math.round(performance.now() - started),
109
+ reason: `the recorded file manifest is unreadable: ${error instanceof Error ? error.message : String(error)}`,
110
+ };
111
+ return { freshness, staleFiles: none };
112
+ }
113
+ if (!manifest) {
114
+ const freshness = {
115
+ ...base,
116
+ indexed: false,
117
+ status: 'unknown',
118
+ lastIndexedAt: null,
119
+ fileCount: 0,
120
+ staleFileCount: -1,
121
+ refreshEstimate: 'unknown',
122
+ checkMs: Math.round(performance.now() - started),
123
+ reason: 'no file manifest is recorded — the project was never indexed, or its index predates ' +
124
+ `freshness tracking; run ${NEXUS_REFRESH_COMMAND} once`,
125
+ };
126
+ return { freshness, staleFiles: none };
127
+ }
128
+ const known = new Map();
129
+ for (const [path, size, mtimeMs, contentHash] of manifest.files)
130
+ known.set(path, { size, mtimeMs, contentHash });
131
+ const { walkRepositoryPaths } = await import('@cleocode/nexus/pipeline');
132
+ const unreadable = [];
133
+ const current = await walkRepositoryPaths(manifest.sourceRoot, undefined, (report) => {
134
+ if (report.status === 'failed')
135
+ unreadable.push(report.path);
136
+ }, manifest.includedRepositories, { knownFiles: known });
137
+ const stale = new Set(unreadable);
138
+ const seen = new Set();
139
+ for (const file of current) {
140
+ seen.add(file.path);
141
+ if (known.get(file.path)?.contentHash !== file.contentHash)
142
+ stale.add(file.path);
143
+ }
144
+ for (const path of known.keys())
145
+ if (!seen.has(path))
146
+ stale.add(path);
147
+ const fileCount = manifest.files.length;
148
+ const estimate = estimateRefreshMs(readRunCost(db), stale.size, fileCount);
149
+ const freshness = {
150
+ ...base,
151
+ indexed: true,
152
+ status: stale.size === 0 ? 'fresh' : 'stale',
153
+ lastIndexedAt: manifest.assessedAt,
154
+ fileCount,
155
+ staleFileCount: stale.size,
156
+ stalePaths: [...stale].sort().slice(0, sampleLimit),
157
+ refreshEstimate: describeEstimate(estimate, stale.size, fileCount),
158
+ checkMs: Math.round(performance.now() - started),
159
+ };
160
+ return { freshness, staleFiles: stale };
161
+ }
162
+ /**
163
+ * Read the auto-refresh policy from `nexus.autoRefresh.*`, applying defaults.
164
+ * @param projectRoot - Project whose merged config is read.
165
+ * @returns The effective policy.
166
+ */
167
+ export async function readNexusAutoRefreshPolicy(projectRoot) {
168
+ const read = async (key) => {
169
+ try {
170
+ return await getConfigValue(`nexus.autoRefresh.${key}`, { projectRoot });
171
+ }
172
+ catch {
173
+ return undefined;
174
+ }
175
+ };
176
+ const [enabled, maxFiles, budgetMs] = await Promise.all([
177
+ read('enabled'),
178
+ read('maxFiles'),
179
+ read('budgetMs'),
180
+ ]);
181
+ return {
182
+ enabled: typeof enabled === 'boolean' ? enabled : true,
183
+ maxFiles: typeof maxFiles === 'number' && Number.isInteger(maxFiles) && maxFiles >= 0
184
+ ? maxFiles
185
+ : DEFAULT_AUTO_REFRESH_MAX_FILES,
186
+ budgetMs: typeof budgetMs === 'number' && Number.isFinite(budgetMs) && budgetMs > 0
187
+ ? budgetMs
188
+ : DEFAULT_AUTO_REFRESH_BUDGET_MS,
189
+ };
190
+ }
191
+ /**
192
+ * Assess freshness and, when only a few files are stale, refresh the index
193
+ * inline before the caller answers from it.
194
+ *
195
+ * A refresh runs only when `0 < stale ≤ maxFiles` and the recorded cost
196
+ * estimate fits `budgetMs`; the budget also cancels the run at its next phase
197
+ * boundary, and publication is atomic, so an abandoned refresh leaves the
198
+ * previous graph intact. Every decision — refreshed, skipped or failed — is
199
+ * disclosed in `autoRefresh`, and the returned freshness describes the index
200
+ * the caller is about to read.
201
+ *
202
+ * @param projectRoot - Project whose graph is about to be queried.
203
+ * @param policy - Explicit policy; read from config when omitted.
204
+ * @returns Freshness of the index as it stands after any refresh, with its stale set.
205
+ */
206
+ export async function ensureNexusIndexFresh(projectRoot, policy) {
207
+ const initial = await assessWithStaleSet(projectRoot);
208
+ const before = initial.freshness;
209
+ if (before.status !== 'stale')
210
+ return initial;
211
+ const effective = policy ?? (await readNexusAutoRefreshPolicy(projectRoot));
212
+ const skip = (reason) => ({
213
+ staleFiles: initial.staleFiles,
214
+ freshness: {
215
+ ...before,
216
+ autoRefresh: { refreshed: false, staleFiles: before.staleFileCount, durationMs: 0, reason },
217
+ },
218
+ });
219
+ if (!effective.enabled)
220
+ return skip('auto-refresh is disabled (nexus.autoRefresh.enabled = false)');
221
+ if (before.staleFileCount > effective.maxFiles)
222
+ return skip(`${before.staleFileCount} stale files exceed nexus.autoRefresh.maxFiles = ${effective.maxFiles}; ` +
223
+ 'answered from the stale index');
224
+ const db = await getNexusDb(projectRoot);
225
+ const estimate = estimateRefreshMs(readRunCost(db), before.staleFileCount, before.fileCount);
226
+ if (estimate !== null && estimate > effective.budgetMs)
227
+ return skip(`estimated refresh ${Math.round(estimate / 1000)}s exceeds nexus.autoRefresh.budgetMs = ` +
228
+ `${effective.budgetMs}; answered from the stale index`);
229
+ const manifest = readFileManifest(db);
230
+ const started = performance.now();
231
+ try {
232
+ const result = await runNexusAnalysis({
233
+ projectRoot,
234
+ repoPath: manifest?.sourceRoot ?? projectRoot,
235
+ ...(manifest ? { includedRepositories: manifest.includedRepositories } : {}),
236
+ parserLimits: { signal: AbortSignal.timeout(effective.budgetMs) },
237
+ });
238
+ const after = await assessWithStaleSet(projectRoot);
239
+ return {
240
+ staleFiles: after.staleFiles,
241
+ freshness: {
242
+ ...after.freshness,
243
+ autoRefresh: {
244
+ refreshed: result.summary.mode !== 'unchanged',
245
+ staleFiles: before.staleFileCount,
246
+ durationMs: Math.round(performance.now() - started),
247
+ reason: `${result.summary.mode}: ${result.summary.reason}`,
248
+ },
249
+ },
250
+ };
251
+ }
252
+ catch (error) {
253
+ return {
254
+ staleFiles: initial.staleFiles,
255
+ freshness: {
256
+ ...before,
257
+ autoRefresh: {
258
+ refreshed: false,
259
+ staleFiles: before.staleFileCount,
260
+ durationMs: Math.round(performance.now() - started),
261
+ reason: `refresh failed, previous graph retained: ${error instanceof Error ? error.message : String(error)}`,
262
+ },
263
+ },
264
+ };
265
+ }
266
+ }
267
+ /**
268
+ * Collect the source files a graph query answer is about.
269
+ *
270
+ * Graph node ids are `<file>::<symbol>`, so a target id names its file; an
271
+ * explicit `filePath` is used when present. Only the answer's own target (or,
272
+ * for symbol lookups, each matched symbol) is considered — callers listed in
273
+ * the answer are not "the queried symbol".
274
+ *
275
+ * @param data - A query operation's result payload.
276
+ * @returns Repository-relative files of the queried symbol(s); empty when none are identifiable.
277
+ */
278
+ export function querySymbolFiles(data) {
279
+ const files = new Set();
280
+ const fromId = (id) => {
281
+ if (typeof id === 'string' && id.includes('::'))
282
+ files.add(id.slice(0, id.indexOf('::')));
283
+ };
284
+ const visit = (value) => {
285
+ if (!value || typeof value !== 'object' || Array.isArray(value))
286
+ return;
287
+ const record = value;
288
+ if (typeof record['filePath'] === 'string')
289
+ files.add(record['filePath']);
290
+ fromId(record['targetNodeId']);
291
+ fromId(record['nodeId']);
292
+ fromId(record['symbolId']);
293
+ };
294
+ visit(data);
295
+ if (data && typeof data === 'object' && !Array.isArray(data)) {
296
+ const record = data;
297
+ for (const key of ['target', 'symbol', 'node'])
298
+ visit(record[key]);
299
+ // Symbol lookups (e.g. `context`) answer with one entry per matched symbol;
300
+ // each entry's own identity counts, never the callers nested inside it.
301
+ for (const key of ['results', 'matches']) {
302
+ const entries = record[key];
303
+ if (Array.isArray(entries))
304
+ for (const entry of entries)
305
+ visit(entry);
306
+ }
307
+ }
308
+ return [...files];
309
+ }
310
+ /**
311
+ * Assess (and when small, repair) index freshness before a graph query.
312
+ *
313
+ * Never throws: a failed assessment is returned as `status: 'unknown'` with its
314
+ * reason, so it neither blocks the query nor is ever mistaken for fresh.
315
+ *
316
+ * @param projectRoot - Project whose graph is about to be queried.
317
+ * @returns The assessment to judge the answer against.
318
+ */
319
+ export async function assessNexusFreshnessForQuery(projectRoot) {
320
+ try {
321
+ return await ensureNexusIndexFresh(projectRoot);
322
+ }
323
+ catch (error) {
324
+ return {
325
+ staleFiles: new Set(),
326
+ freshness: {
327
+ indexed: false,
328
+ status: 'unknown',
329
+ lastIndexedAt: null,
330
+ fileCount: 0,
331
+ staleFileCount: -1,
332
+ stalePaths: [],
333
+ refreshCommand: NEXUS_REFRESH_COMMAND,
334
+ refreshEstimate: 'unknown',
335
+ checkMs: 0,
336
+ reason: `freshness could not be assessed: ${error instanceof Error ? error.message : String(error)}`,
337
+ },
338
+ };
339
+ }
340
+ }
341
+ /**
342
+ * Disclose a non-fresh index as an envelope warning
343
+ * (`W_NEXUS_INDEX_STALE` / `W_NEXUS_INDEX_FRESHNESS_UNKNOWN`), and an inline
344
+ * refresh that just happened as `W_NEXUS_INDEX_REFRESHED` (info). Warnings
345
+ * reach `meta.warnings` through the active collector — never stderr, which
346
+ * would break the one-envelope stream contract (T9775).
347
+ *
348
+ * @param subject - What answered, e.g. `nexus impact`.
349
+ * @param freshness - Freshness of the index the answer came from.
350
+ */
351
+ export function discloseNexusFreshness(subject, freshness) {
352
+ const refresh = freshness.autoRefresh;
353
+ if (refresh?.refreshed) {
354
+ pushWarning({
355
+ code: 'W_NEXUS_INDEX_REFRESHED',
356
+ severity: 'info',
357
+ message: `Refreshed the index inline before answering (${refresh.staleFiles} stale file(s), ${refresh.durationMs}ms): ${refresh.reason}`,
358
+ });
359
+ }
360
+ if (freshness.status === 'fresh')
361
+ return;
362
+ const symbol = freshness.symbolFileStale === true
363
+ ? ` The queried symbol's own file (${freshness.symbolFile}) is among them.`
364
+ : '';
365
+ const message = freshness.status === 'stale'
366
+ ? `${subject} answered from an index ${freshness.staleFileCount} file(s) behind the working tree ` +
367
+ `(indexed ${freshness.lastIndexedAt ?? 'at an unknown time'}; e.g. ${freshness.stalePaths.slice(0, 3).join(', ')}).${symbol} ` +
368
+ `Refresh: ${freshness.refreshCommand} — ${freshness.refreshEstimate}.` +
369
+ (refresh && !refresh.refreshed ? ` Not refreshed inline: ${refresh.reason}.` : '')
370
+ : `${subject} could not establish index freshness: ${freshness.reason ?? 'unknown reason'}.`;
371
+ pushWarning({
372
+ code: freshness.status === 'stale' ? 'W_NEXUS_INDEX_STALE' : 'W_NEXUS_INDEX_FRESHNESS_UNKNOWN',
373
+ severity: 'warn',
374
+ message,
375
+ });
376
+ }
377
+ /**
378
+ * Merge a freshness verdict into envelope extensions' `_nexus` block.
379
+ * @param extensions - Envelope extensions, possibly already carrying `_nexus`.
380
+ * @param freshness - Freshness of the index the answer came from.
381
+ * @returns New extensions with `_nexus.indexFreshness` and `_nexus.freshness` set.
382
+ */
383
+ export function withNexusFreshnessMeta(extensions, freshness) {
384
+ const current = extensions['_nexus'];
385
+ const nexusMeta = current && typeof current === 'object' ? current : {};
386
+ return {
387
+ ...extensions,
388
+ _nexus: { ...nexusMeta, indexFreshness: freshness.status, freshness },
389
+ };
390
+ }
391
+ //# sourceMappingURL=freshness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"freshness.js","sourceRoot":"","sources":["../../src/nexus/freshness.ts"],"names":[],"mappings":"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"}