@mirnoorata/codexa 0.2.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 (364) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +634 -0
  3. package/dist/artifacts.d.ts +2 -0
  4. package/dist/artifacts.js +375 -0
  5. package/dist/artifacts.js.map +1 -0
  6. package/dist/autonomy.d.ts +17 -0
  7. package/dist/autonomy.js +124 -0
  8. package/dist/autonomy.js.map +1 -0
  9. package/dist/autoverify/policy.d.ts +5 -0
  10. package/dist/autoverify/policy.js +18 -0
  11. package/dist/autoverify/policy.js.map +1 -0
  12. package/dist/autoverify.d.ts +45 -0
  13. package/dist/autoverify.js +1041 -0
  14. package/dist/autoverify.js.map +1 -0
  15. package/dist/cache-lock.d.ts +16 -0
  16. package/dist/cache-lock.js +181 -0
  17. package/dist/cache-lock.js.map +1 -0
  18. package/dist/cli/hooks.d.ts +5 -0
  19. package/dist/cli/hooks.js +264 -0
  20. package/dist/cli/hooks.js.map +1 -0
  21. package/dist/cli.d.ts +2 -0
  22. package/dist/cli.js +1034 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/codex-contract.d.ts +2 -0
  25. package/dist/codex-contract.js +78 -0
  26. package/dist/codex-contract.js.map +1 -0
  27. package/dist/command.d.ts +34 -0
  28. package/dist/command.js +162 -0
  29. package/dist/command.js.map +1 -0
  30. package/dist/doctor.d.ts +112 -0
  31. package/dist/doctor.js +518 -0
  32. package/dist/doctor.js.map +1 -0
  33. package/dist/eval/baseline.d.ts +7 -0
  34. package/dist/eval/baseline.js +146 -0
  35. package/dist/eval/baseline.js.map +1 -0
  36. package/dist/eval/historical.d.ts +4 -0
  37. package/dist/eval/historical.js +663 -0
  38. package/dist/eval/historical.js.map +1 -0
  39. package/dist/eval/render.d.ts +2 -0
  40. package/dist/eval/render.js +53 -0
  41. package/dist/eval/render.js.map +1 -0
  42. package/dist/eval/scoring.d.ts +21 -0
  43. package/dist/eval/scoring.js +618 -0
  44. package/dist/eval/scoring.js.map +1 -0
  45. package/dist/eval/synthetic.d.ts +36 -0
  46. package/dist/eval/synthetic.js +107 -0
  47. package/dist/eval/synthetic.js.map +1 -0
  48. package/dist/eval/types.d.ts +36 -0
  49. package/dist/eval/types.js +2 -0
  50. package/dist/eval/types.js.map +1 -0
  51. package/dist/eval.d.ts +140 -0
  52. package/dist/eval.js +551 -0
  53. package/dist/eval.js.map +1 -0
  54. package/dist/git.d.ts +17 -0
  55. package/dist/git.js +189 -0
  56. package/dist/git.js.map +1 -0
  57. package/dist/github-release.d.ts +47 -0
  58. package/dist/github-release.js +610 -0
  59. package/dist/github-release.js.map +1 -0
  60. package/dist/github-sync.d.ts +68 -0
  61. package/dist/github-sync.js +345 -0
  62. package/dist/github-sync.js.map +1 -0
  63. package/dist/graph.d.ts +10 -0
  64. package/dist/graph.js +665 -0
  65. package/dist/graph.js.map +1 -0
  66. package/dist/indexer/aliases.d.ts +2 -0
  67. package/dist/indexer/aliases.js +190 -0
  68. package/dist/indexer/aliases.js.map +1 -0
  69. package/dist/indexer/artifact-writing.d.ts +3 -0
  70. package/dist/indexer/artifact-writing.js +79 -0
  71. package/dist/indexer/artifact-writing.js.map +1 -0
  72. package/dist/indexer/discovery.d.ts +2 -0
  73. package/dist/indexer/discovery.js +5 -0
  74. package/dist/indexer/discovery.js.map +1 -0
  75. package/dist/indexer/external-facts.d.ts +6 -0
  76. package/dist/indexer/external-facts.js +45 -0
  77. package/dist/indexer/external-facts.js.map +1 -0
  78. package/dist/indexer/freshness.d.ts +8 -0
  79. package/dist/indexer/freshness.js +56 -0
  80. package/dist/indexer/freshness.js.map +1 -0
  81. package/dist/indexer/graph-stage.d.ts +2 -0
  82. package/dist/indexer/graph-stage.js +21 -0
  83. package/dist/indexer/graph-stage.js.map +1 -0
  84. package/dist/indexer/parsing.d.ts +30 -0
  85. package/dist/indexer/parsing.js +177 -0
  86. package/dist/indexer/parsing.js.map +1 -0
  87. package/dist/indexer/pipeline.d.ts +5 -0
  88. package/dist/indexer/pipeline.js +8 -0
  89. package/dist/indexer/pipeline.js.map +1 -0
  90. package/dist/indexer/ranking.d.ts +4 -0
  91. package/dist/indexer/ranking.js +134 -0
  92. package/dist/indexer/ranking.js.map +1 -0
  93. package/dist/indexer.d.ts +13 -0
  94. package/dist/indexer.js +395 -0
  95. package/dist/indexer.js.map +1 -0
  96. package/dist/init.d.ts +24 -0
  97. package/dist/init.js +566 -0
  98. package/dist/init.js.map +1 -0
  99. package/dist/language.d.ts +8 -0
  100. package/dist/language.js +123 -0
  101. package/dist/language.js.map +1 -0
  102. package/dist/live-index.d.ts +68 -0
  103. package/dist/live-index.js +215 -0
  104. package/dist/live-index.js.map +1 -0
  105. package/dist/lsp/assist.d.ts +44 -0
  106. package/dist/lsp/assist.js +331 -0
  107. package/dist/lsp/assist.js.map +1 -0
  108. package/dist/lsp/client.d.ts +59 -0
  109. package/dist/lsp/client.js +208 -0
  110. package/dist/lsp/client.js.map +1 -0
  111. package/dist/mcp/compaction.d.ts +15 -0
  112. package/dist/mcp/compaction.js +1249 -0
  113. package/dist/mcp/compaction.js.map +1 -0
  114. package/dist/mcp/envelope.d.ts +44 -0
  115. package/dist/mcp/envelope.js +425 -0
  116. package/dist/mcp/envelope.js.map +1 -0
  117. package/dist/mcp/prompts.d.ts +2 -0
  118. package/dist/mcp/prompts.js +109 -0
  119. package/dist/mcp/prompts.js.map +1 -0
  120. package/dist/mcp/resources.d.ts +2 -0
  121. package/dist/mcp/resources.js +132 -0
  122. package/dist/mcp/resources.js.map +1 -0
  123. package/dist/mcp/runtime.d.ts +15 -0
  124. package/dist/mcp/runtime.js +122 -0
  125. package/dist/mcp/runtime.js.map +1 -0
  126. package/dist/mcp/session-memory.d.ts +3 -0
  127. package/dist/mcp/session-memory.js +61 -0
  128. package/dist/mcp/session-memory.js.map +1 -0
  129. package/dist/mcp/tool-registry.d.ts +269 -0
  130. package/dist/mcp/tool-registry.js +284 -0
  131. package/dist/mcp/tool-registry.js.map +1 -0
  132. package/dist/mcp/tools.d.ts +53 -0
  133. package/dist/mcp/tools.js +372 -0
  134. package/dist/mcp/tools.js.map +1 -0
  135. package/dist/mcp-repo-root.d.ts +16 -0
  136. package/dist/mcp-repo-root.js +322 -0
  137. package/dist/mcp-repo-root.js.map +1 -0
  138. package/dist/mcp-tool-catalog.d.ts +2 -0
  139. package/dist/mcp-tool-catalog.js +2 -0
  140. package/dist/mcp-tool-catalog.js.map +1 -0
  141. package/dist/mcp.d.ts +11 -0
  142. package/dist/mcp.js +332 -0
  143. package/dist/mcp.js.map +1 -0
  144. package/dist/outcome-ranking.d.ts +5 -0
  145. package/dist/outcome-ranking.js +115 -0
  146. package/dist/outcome-ranking.js.map +1 -0
  147. package/dist/parser/context.d.ts +28 -0
  148. package/dist/parser/context.js +2 -0
  149. package/dist/parser/context.js.map +1 -0
  150. package/dist/parser/ecma.d.ts +5 -0
  151. package/dist/parser/ecma.js +388 -0
  152. package/dist/parser/ecma.js.map +1 -0
  153. package/dist/parser/facts.d.ts +12 -0
  154. package/dist/parser/facts.js +137 -0
  155. package/dist/parser/facts.js.map +1 -0
  156. package/dist/parser/json.d.ts +3 -0
  157. package/dist/parser/json.js +318 -0
  158. package/dist/parser/json.js.map +1 -0
  159. package/dist/parser/markdown.d.ts +3 -0
  160. package/dist/parser/markdown.js +180 -0
  161. package/dist/parser/markdown.js.map +1 -0
  162. package/dist/parser/nodes.d.ts +5 -0
  163. package/dist/parser/nodes.js +75 -0
  164. package/dist/parser/nodes.js.map +1 -0
  165. package/dist/parser/python.d.ts +2 -0
  166. package/dist/parser/python.js +307 -0
  167. package/dist/parser/python.js.map +1 -0
  168. package/dist/parser/references.d.ts +3 -0
  169. package/dist/parser/references.js +204 -0
  170. package/dist/parser/references.js.map +1 -0
  171. package/dist/parser/risks.d.ts +4 -0
  172. package/dist/parser/risks.js +62 -0
  173. package/dist/parser/risks.js.map +1 -0
  174. package/dist/parser/routes.d.ts +5 -0
  175. package/dist/parser/routes.js +97 -0
  176. package/dist/parser/routes.js.map +1 -0
  177. package/dist/parser/shallow.d.ts +3 -0
  178. package/dist/parser/shallow.js +545 -0
  179. package/dist/parser/shallow.js.map +1 -0
  180. package/dist/parser/source.d.ts +4 -0
  181. package/dist/parser/source.js +127 -0
  182. package/dist/parser/source.js.map +1 -0
  183. package/dist/parser.d.ts +2 -0
  184. package/dist/parser.js +2 -0
  185. package/dist/parser.js.map +1 -0
  186. package/dist/placeholder-signals.d.ts +15 -0
  187. package/dist/placeholder-signals.js +511 -0
  188. package/dist/placeholder-signals.js.map +1 -0
  189. package/dist/post-edit-outcomes.d.ts +167 -0
  190. package/dist/post-edit-outcomes.js +484 -0
  191. package/dist/post-edit-outcomes.js.map +1 -0
  192. package/dist/queries.d.ts +12 -0
  193. package/dist/queries.js +13 -0
  194. package/dist/queries.js.map +1 -0
  195. package/dist/query/change-plan.d.ts +48 -0
  196. package/dist/query/change-plan.js +858 -0
  197. package/dist/query/change-plan.js.map +1 -0
  198. package/dist/query/compact-data.d.ts +25 -0
  199. package/dist/query/compact-data.js +74 -0
  200. package/dist/query/compact-data.js.map +1 -0
  201. package/dist/query/context.d.ts +5 -0
  202. package/dist/query/context.js +1162 -0
  203. package/dist/query/context.js.map +1 -0
  204. package/dist/query/diff.d.ts +5 -0
  205. package/dist/query/diff.js +111 -0
  206. package/dist/query/diff.js.map +1 -0
  207. package/dist/query/edge-evidence.d.ts +3 -0
  208. package/dist/query/edge-evidence.js +36 -0
  209. package/dist/query/edge-evidence.js.map +1 -0
  210. package/dist/query/formatting.d.ts +14 -0
  211. package/dist/query/formatting.js +67 -0
  212. package/dist/query/formatting.js.map +1 -0
  213. package/dist/query/graph-traversal.d.ts +22 -0
  214. package/dist/query/graph-traversal.js +218 -0
  215. package/dist/query/graph-traversal.js.map +1 -0
  216. package/dist/query/graph.d.ts +14 -0
  217. package/dist/query/graph.js +102 -0
  218. package/dist/query/graph.js.map +1 -0
  219. package/dist/query/impact.d.ts +28 -0
  220. package/dist/query/impact.js +568 -0
  221. package/dist/query/impact.js.map +1 -0
  222. package/dist/query/inspection.d.ts +9 -0
  223. package/dist/query/inspection.js +290 -0
  224. package/dist/query/inspection.js.map +1 -0
  225. package/dist/query/next-tools.d.ts +3 -0
  226. package/dist/query/next-tools.js +25 -0
  227. package/dist/query/next-tools.js.map +1 -0
  228. package/dist/query/placeholders.d.ts +24 -0
  229. package/dist/query/placeholders.js +121 -0
  230. package/dist/query/placeholders.js.map +1 -0
  231. package/dist/query/post-edit/decision.d.ts +49 -0
  232. package/dist/query/post-edit/decision.js +130 -0
  233. package/dist/query/post-edit/decision.js.map +1 -0
  234. package/dist/query/post-edit/dirty-scope.d.ts +16 -0
  235. package/dist/query/post-edit/dirty-scope.js +21 -0
  236. package/dist/query/post-edit/dirty-scope.js.map +1 -0
  237. package/dist/query/post-edit/next-actions.d.ts +22 -0
  238. package/dist/query/post-edit/next-actions.js +44 -0
  239. package/dist/query/post-edit/next-actions.js.map +1 -0
  240. package/dist/query/post-edit/snapshot-contract.d.ts +8 -0
  241. package/dist/query/post-edit/snapshot-contract.js +111 -0
  242. package/dist/query/post-edit/snapshot-contract.js.map +1 -0
  243. package/dist/query/post-edit.d.ts +5 -0
  244. package/dist/query/post-edit.js +1108 -0
  245. package/dist/query/post-edit.js.map +1 -0
  246. package/dist/query/quality.d.ts +43 -0
  247. package/dist/query/quality.js +134 -0
  248. package/dist/query/quality.js.map +1 -0
  249. package/dist/query/raw-search.d.ts +23 -0
  250. package/dist/query/raw-search.js +147 -0
  251. package/dist/query/raw-search.js.map +1 -0
  252. package/dist/query/runtime.d.ts +11 -0
  253. package/dist/query/runtime.js +79 -0
  254. package/dist/query/runtime.js.map +1 -0
  255. package/dist/query/search.d.ts +25 -0
  256. package/dist/query/search.js +429 -0
  257. package/dist/query/search.js.map +1 -0
  258. package/dist/query/session-memory.d.ts +3 -0
  259. package/dist/query/session-memory.js +108 -0
  260. package/dist/query/session-memory.js.map +1 -0
  261. package/dist/query/session.d.ts +41 -0
  262. package/dist/query/session.js +90 -0
  263. package/dist/query/session.js.map +1 -0
  264. package/dist/query/targets.d.ts +25 -0
  265. package/dist/query/targets.js +97 -0
  266. package/dist/query/targets.js.map +1 -0
  267. package/dist/query/test-commands.d.ts +10 -0
  268. package/dist/query/test-commands.js +110 -0
  269. package/dist/query/test-commands.js.map +1 -0
  270. package/dist/query/test-plan.d.ts +6 -0
  271. package/dist/query/test-plan.js +104 -0
  272. package/dist/query/test-plan.js.map +1 -0
  273. package/dist/query/tests.d.ts +48 -0
  274. package/dist/query/tests.js +444 -0
  275. package/dist/query/tests.js.map +1 -0
  276. package/dist/query/verification/shell.d.ts +20 -0
  277. package/dist/query/verification/shell.js +164 -0
  278. package/dist/query/verification/shell.js.map +1 -0
  279. package/dist/query/verification.d.ts +47 -0
  280. package/dist/query/verification.js +1123 -0
  281. package/dist/query/verification.js.map +1 -0
  282. package/dist/query/workflow.d.ts +17 -0
  283. package/dist/query/workflow.js +252 -0
  284. package/dist/query/workflow.js.map +1 -0
  285. package/dist/query/workspace-guidance.d.ts +26 -0
  286. package/dist/query/workspace-guidance.js +214 -0
  287. package/dist/query/workspace-guidance.js.map +1 -0
  288. package/dist/query/worktree-state.d.ts +22 -0
  289. package/dist/query/worktree-state.js +32 -0
  290. package/dist/query/worktree-state.js.map +1 -0
  291. package/dist/query/worktree.d.ts +16 -0
  292. package/dist/query/worktree.js +194 -0
  293. package/dist/query/worktree.js.map +1 -0
  294. package/dist/query-data.d.ts +4 -0
  295. package/dist/query-data.js +112 -0
  296. package/dist/query-data.js.map +1 -0
  297. package/dist/repo-files.d.ts +24 -0
  298. package/dist/repo-files.js +105 -0
  299. package/dist/repo-files.js.map +1 -0
  300. package/dist/resolver.d.ts +9 -0
  301. package/dist/resolver.js +555 -0
  302. package/dist/resolver.js.map +1 -0
  303. package/dist/retrieval.d.ts +46 -0
  304. package/dist/retrieval.js +783 -0
  305. package/dist/retrieval.js.map +1 -0
  306. package/dist/risk-ingest.d.ts +16 -0
  307. package/dist/risk-ingest.js +458 -0
  308. package/dist/risk-ingest.js.map +1 -0
  309. package/dist/rules.d.ts +10 -0
  310. package/dist/rules.js +107 -0
  311. package/dist/rules.js.map +1 -0
  312. package/dist/semantic/python.d.ts +9 -0
  313. package/dist/semantic/python.js +817 -0
  314. package/dist/semantic/python.js.map +1 -0
  315. package/dist/semantic/typescript.d.ts +10 -0
  316. package/dist/semantic/typescript.js +714 -0
  317. package/dist/semantic/typescript.js.map +1 -0
  318. package/dist/semantic-retrieval.d.ts +53 -0
  319. package/dist/semantic-retrieval.js +673 -0
  320. package/dist/semantic-retrieval.js.map +1 -0
  321. package/dist/session-memory/derivation.d.ts +6 -0
  322. package/dist/session-memory/derivation.js +400 -0
  323. package/dist/session-memory/derivation.js.map +1 -0
  324. package/dist/session-memory/event-log.d.ts +23 -0
  325. package/dist/session-memory/event-log.js +126 -0
  326. package/dist/session-memory/event-log.js.map +1 -0
  327. package/dist/session-memory/formatting.d.ts +7 -0
  328. package/dist/session-memory/formatting.js +86 -0
  329. package/dist/session-memory/formatting.js.map +1 -0
  330. package/dist/session-memory/model.d.ts +94 -0
  331. package/dist/session-memory/model.js +17 -0
  332. package/dist/session-memory/model.js.map +1 -0
  333. package/dist/session-memory/runtime.d.ts +24 -0
  334. package/dist/session-memory/runtime.js +289 -0
  335. package/dist/session-memory/runtime.js.map +1 -0
  336. package/dist/session-memory/store.d.ts +27 -0
  337. package/dist/session-memory/store.js +447 -0
  338. package/dist/session-memory/store.js.map +1 -0
  339. package/dist/session-memory.d.ts +1 -0
  340. package/dist/session-memory.js +2 -0
  341. package/dist/session-memory.js.map +1 -0
  342. package/dist/static-analysis.d.ts +36 -0
  343. package/dist/static-analysis.js +505 -0
  344. package/dist/static-analysis.js.map +1 -0
  345. package/dist/symbol-report-ingest.d.ts +8 -0
  346. package/dist/symbol-report-ingest.js +504 -0
  347. package/dist/symbol-report-ingest.js.map +1 -0
  348. package/dist/task-snapshots.d.ts +41 -0
  349. package/dist/task-snapshots.js +430 -0
  350. package/dist/task-snapshots.js.map +1 -0
  351. package/dist/types.d.ts +848 -0
  352. package/dist/types.js +12 -0
  353. package/dist/types.js.map +1 -0
  354. package/dist/util.d.ts +11 -0
  355. package/dist/util.js +63 -0
  356. package/dist/util.js.map +1 -0
  357. package/dist/version.d.ts +1 -0
  358. package/dist/version.js +5 -0
  359. package/dist/version.js.map +1 -0
  360. package/package.json +81 -0
  361. package/plugins/codexa/.codex-plugin/plugin.json +38 -0
  362. package/plugins/codexa/.mcp.json +20 -0
  363. package/plugins/codexa/scripts/codexa-mcp.js +100 -0
  364. package/plugins/codexa/skills/codexa/SKILL.md +48 -0
@@ -0,0 +1,1249 @@
1
+ import { CURRENT_VERIFICATION_PROVENANCE } from "../types.js";
2
+ import { asCodexaQueryData, asPostEditReviewData } from "../query-data.js";
3
+ const DEFAULT_MCP_STRUCTURED_DATA_TARGET_BYTES = 96_000;
4
+ const MIN_MCP_STRUCTURED_DATA_TARGET_BYTES = 4_000;
5
+ const MAX_MCP_STRUCTURED_DATA_TARGET_BYTES = 512_000;
6
+ export function mcpStructuredDataTargetBytes() {
7
+ const raw = process.env.CODEXA_MCP_STRUCTURED_BUDGET_BYTES;
8
+ if (!raw) {
9
+ return DEFAULT_MCP_STRUCTURED_DATA_TARGET_BYTES;
10
+ }
11
+ if (!/^\d+$/u.test(raw.trim())) {
12
+ return DEFAULT_MCP_STRUCTURED_DATA_TARGET_BYTES;
13
+ }
14
+ const parsed = Number.parseInt(raw.trim(), 10);
15
+ return Math.min(MAX_MCP_STRUCTURED_DATA_TARGET_BYTES, Math.max(MIN_MCP_STRUCTURED_DATA_TARGET_BYTES, parsed));
16
+ }
17
+ const CONCISE_RESPONSE_TARGET_BYTES = 12_000;
18
+ export function compactMcpResult(result, options) {
19
+ if (!result.data || typeof result.data !== "object" || Array.isArray(result.data)) {
20
+ return result;
21
+ }
22
+ const originalData = result.data;
23
+ const originalBytes = structuredByteLength(originalData);
24
+ const mode = typeof originalData.mode === "string" ? originalData.mode : inferMcpDataMode(originalData);
25
+ const effectiveMode = mode ?? "unknown";
26
+ const typedData = asCodexaQueryData(originalData, mode);
27
+ const compaction = (typedData ? compactMcpDataByMode(typedData) : undefined) ?? compactGenericMcpData(originalData, effectiveMode);
28
+ const clamped = clampLargeStrings(compaction.data);
29
+ const dataWithoutMetrics = withMergedTruncation(clamped.value, compaction.truncation);
30
+ const compactedBytes = structuredByteLength(dataWithoutMetrics);
31
+ const baseTargetBytes = mcpStructuredDataTargetBytes();
32
+ const targetBytes = options?.format === "concise" ? Math.min(baseTargetBytes, CONCISE_RESPONSE_TARGET_BYTES) : baseTargetBytes;
33
+ const structuredData = {
34
+ compacted: compaction.compacted || compactedBytes < originalBytes,
35
+ originalBytes,
36
+ targetBytes,
37
+ stringTruncations: clamped.stringTruncations,
38
+ mode: effectiveMode,
39
+ verificationProvenance: boundedVerificationProvenance(originalData.verificationProvenance)
40
+ };
41
+ let data = attachMcpMetrics(dataWithoutMetrics, structuredData);
42
+ const returnedBytes = structuredByteLength(data);
43
+ if (returnedBytes > targetBytes) {
44
+ data = enforceMcpStructuredBudget(dataWithoutMetrics, structuredData, returnedBytes, effectiveMode, targetBytes);
45
+ }
46
+ return {
47
+ ...result,
48
+ data
49
+ };
50
+ }
51
+ export function compactNonPostEditMcpResult(result, options) {
52
+ return compactMcpResult(result, options);
53
+ }
54
+ export function inferMcpDataMode(data) {
55
+ if (Array.isArray(data.verificationCommands) && Array.isArray(data.verificationCoverage) && Array.isArray(data.tests)) {
56
+ return Array.isArray(data.focusFiles) || Array.isArray(data.nextReads) ? "context_pack" : "test_plan";
57
+ }
58
+ return undefined;
59
+ }
60
+ function compactMcpDataByMode(data) {
61
+ if (data.mode === "post_edit_review") {
62
+ const compacted = compactPostEditMcpResult({ freshness: {}, text: "", data });
63
+ return { data: compacted.data, truncation: compacted.data.truncation ?? {}, compacted: true };
64
+ }
65
+ if (data.mode === "context_pack" || data.mode === "task_brief") {
66
+ return compactContextPacketData(data, data.mode);
67
+ }
68
+ if (data.mode === "focus_brief" || data.mode === "session_context") {
69
+ return compactFocusBriefData(data);
70
+ }
71
+ if (data.mode === "change_plan") {
72
+ return compactChangePlanData(data);
73
+ }
74
+ if (data.mode === "test_plan") {
75
+ return compactTestPlanData(data);
76
+ }
77
+ return undefined;
78
+ }
79
+ function compactGenericMcpData(data, mode) {
80
+ const truncation = {};
81
+ const compacted = compactGenericValue(data, { arrayLimit: 40, objectKeyLimit: 80, maxDepth: 8 }, truncation);
82
+ const record = isRecord(compacted) ? compacted : { value: compacted };
83
+ const dataWithMode = typeof record.mode === "string" ? record : { mode, ...record };
84
+ return { data: dataWithMode, truncation, compacted: true };
85
+ }
86
+ function enforceMcpStructuredBudget(dataWithoutMetrics, structuredData, preEnforcementBytes, mode, targetBytes) {
87
+ const hardTruncation = mergeTruncation(truncationFromValue(dataWithoutMetrics.truncation), {
88
+ "__mcp.hardBudget": { total: preEnforcementBytes, returned: targetBytes }
89
+ });
90
+ const hardCompacted = compactGenericValue(dataWithoutMetrics, { arrayLimit: 12, objectKeyLimit: 40, maxDepth: 6 }, hardTruncation);
91
+ const hardClamped = clampLargeStrings(hardCompacted, 240);
92
+ const hardRecord = isRecord(hardClamped.value) ? hardClamped.value : { value: hardClamped.value };
93
+ const hardData = withMergedTruncation(reattachGuidanceFields(typeof hardRecord.mode === "string" ? hardRecord : { mode, ...hardRecord }, dataWithoutMetrics, hardTruncation), hardTruncation);
94
+ const hardResult = attachMcpMetrics(hardData, {
95
+ ...structuredData,
96
+ compacted: true,
97
+ hardBudgetEnforced: true,
98
+ preEnforcementBytes,
99
+ budgetCompaction: "hard",
100
+ stringTruncations: metricNumber(structuredData, "stringTruncations") + hardClamped.stringTruncations
101
+ });
102
+ if (structuredByteLength(hardResult) <= targetBytes) {
103
+ return hardResult;
104
+ }
105
+ const summaryTruncation = mergeTruncation(hardTruncation, {
106
+ "__mcp.summaryBudget": { total: structuredByteLength(hardResult), returned: targetBytes }
107
+ });
108
+ const summaryClamped = clampLargeStrings(buildMcpBudgetSummaryData(dataWithoutMetrics, mode, summaryTruncation), 160);
109
+ const summaryRecord = isRecord(summaryClamped.value) ? summaryClamped.value : { value: summaryClamped.value };
110
+ const summaryResult = attachMcpMetrics(withMergedTruncation(summaryRecord, summaryTruncation), {
111
+ ...structuredData,
112
+ compacted: true,
113
+ hardBudgetEnforced: true,
114
+ preEnforcementBytes,
115
+ budgetCompaction: "summary",
116
+ stringTruncations: metricNumber(structuredData, "stringTruncations") + hardClamped.stringTruncations + summaryClamped.stringTruncations
117
+ });
118
+ if (structuredByteLength(summaryResult) <= targetBytes) {
119
+ return summaryResult;
120
+ }
121
+ const fallbackTruncation = mergeTruncation(summaryTruncation, {
122
+ "__mcp.fallbackBudget": { total: structuredByteLength(summaryResult), returned: targetBytes }
123
+ });
124
+ const fallbackClamped = clampLargeStrings({
125
+ mode,
126
+ task: typeof dataWithoutMetrics.task === "string" ? dataWithoutMetrics.task.slice(0, 160) : dataWithoutMetrics.task,
127
+ verdict: dataWithoutMetrics.verdict,
128
+ editReadiness: dataWithoutMetrics.editReadiness,
129
+ followCandidate: compactFollowCandidate(dataWithoutMetrics.followCandidate),
130
+ snapshotBlock: compactSnapshotBlock(dataWithoutMetrics.snapshotBlock),
131
+ targetCandidates: Array.isArray(dataWithoutMetrics.targetCandidates) ? dataWithoutMetrics.targetCandidates.slice(0, 8).map(compactTargetCandidate) : dataWithoutMetrics.targetCandidates,
132
+ packetVerdict: dataWithoutMetrics.packetVerdict,
133
+ verificationProvenance: boundedVerificationProvenance(dataWithoutMetrics.verificationProvenance),
134
+ nextTools: compactNextTools(dataWithoutMetrics.nextTools, fallbackTruncation),
135
+ systemMessage: stringValue(dataWithoutMetrics.systemMessage),
136
+ runtime: compactSession(dataWithoutMetrics.runtime),
137
+ truncation: fallbackTruncation
138
+ }, 160);
139
+ const fallbackRecord = isRecord(fallbackClamped.value) ? fallbackClamped.value : { value: fallbackClamped.value };
140
+ const fallbackResult = attachMcpMetrics(fallbackRecord, {
141
+ ...structuredData,
142
+ compacted: true,
143
+ hardBudgetEnforced: true,
144
+ preEnforcementBytes,
145
+ budgetCompaction: "fallback",
146
+ stringTruncations: metricNumber(structuredData, "stringTruncations") + hardClamped.stringTruncations + summaryClamped.stringTruncations + fallbackClamped.stringTruncations
147
+ });
148
+ if (structuredByteLength(fallbackResult) <= targetBytes) {
149
+ return fallbackResult;
150
+ }
151
+ // Last-resort tier: evidence-bearing fields are dropped entirely so the
152
+ // verdict and routing guidance always fit the host's hard result limit.
153
+ const minimalTruncation = mergeTruncation(fallbackTruncation, {
154
+ "__mcp.minimalBudget": { total: structuredByteLength(fallbackResult), returned: targetBytes }
155
+ });
156
+ const minimalClamped = clampLargeStrings({
157
+ mode,
158
+ task: typeof dataWithoutMetrics.task === "string" ? dataWithoutMetrics.task.slice(0, 160) : undefined,
159
+ verdict: dataWithoutMetrics.verdict,
160
+ editReadiness: dataWithoutMetrics.editReadiness,
161
+ packetVerdict: dataWithoutMetrics.packetVerdict,
162
+ verificationProvenance: boundedVerificationProvenance(dataWithoutMetrics.verificationProvenance),
163
+ nextTools: compactNextTools(dataWithoutMetrics.nextTools, minimalTruncation),
164
+ systemMessage: stringValue(dataWithoutMetrics.systemMessage),
165
+ truncation: minimalTruncation
166
+ }, 160);
167
+ const minimalRecord = isRecord(minimalClamped.value) ? minimalClamped.value : { value: minimalClamped.value };
168
+ const minimalMetrics = {
169
+ ...structuredData,
170
+ compacted: true,
171
+ hardBudgetEnforced: true,
172
+ preEnforcementBytes,
173
+ budgetCompaction: "minimal",
174
+ stringTruncations: metricNumber(structuredData, "stringTruncations") + hardClamped.stringTruncations + summaryClamped.stringTruncations + fallbackClamped.stringTruncations + minimalClamped.stringTruncations
175
+ };
176
+ const minimalResult = attachMcpMetrics(minimalRecord, minimalMetrics);
177
+ if (structuredByteLength(minimalResult) <= targetBytes) {
178
+ return minimalResult;
179
+ }
180
+ // Unbounded inputs (provenance objects, wide nextTools) can survive string
181
+ // clamping; the verdict and tool names alone must always fit.
182
+ const nextToolNames = Array.isArray(dataWithoutMetrics.nextTools)
183
+ ? dataWithoutMetrics.nextTools.slice(0, 5).flatMap((tool) => {
184
+ if (typeof tool === "string") {
185
+ return [tool.slice(0, 80)];
186
+ }
187
+ return isRecord(tool) && typeof tool.tool === "string" ? [tool.tool.slice(0, 80)] : [];
188
+ })
189
+ : undefined;
190
+ return attachMcpMetrics({
191
+ mode,
192
+ verdict: typeof dataWithoutMetrics.verdict === "string" ? dataWithoutMetrics.verdict.slice(0, 160) : undefined,
193
+ packetVerdict: typeof dataWithoutMetrics.packetVerdict === "string" ? dataWithoutMetrics.packetVerdict.slice(0, 160) : undefined,
194
+ nextTools: nextToolNames,
195
+ systemMessage: stringValue(dataWithoutMetrics.systemMessage)?.slice(0, 160),
196
+ truncation: { "__mcp.verdictOnlyBudget": { total: structuredByteLength(minimalResult), returned: targetBytes } }
197
+ }, minimalMetrics);
198
+ }
199
+ function buildMcpBudgetSummaryData(data, mode, truncation) {
200
+ return {
201
+ mode,
202
+ task: data.task,
203
+ verdict: data.verdict,
204
+ editReadiness: data.editReadiness,
205
+ followCandidate: compactFollowCandidate(data.followCandidate),
206
+ snapshotBlock: compactSnapshotBlock(data.snapshotBlock),
207
+ targetCandidates: compactSummaryArray("targetCandidates", data.targetCandidates, 8, truncation, compactTargetCandidate),
208
+ packetVerdict: data.packetVerdict,
209
+ nextTools: compactNextTools(data.nextTools, truncation),
210
+ systemMessage: stringValue(data.systemMessage),
211
+ files: compactSummaryArray("files", data.files, 12, truncation),
212
+ plannedEditTargets: compactSummaryArray("plannedEditTargets", data.plannedEditTargets, 12, truncation),
213
+ changedFiles: compactSummaryArray("changedFiles", data.changedFiles, 12, truncation),
214
+ tests: compactSummaryArray("tests", data.tests, 12, truncation, compactTestRecommendation),
215
+ verificationCommands: compactSummaryArray("verificationCommands", data.verificationCommands, 10, truncation),
216
+ verificationProvenance: boundedVerificationProvenance(data.verificationProvenance),
217
+ commandEnvelopes: compactSummaryArray("commandEnvelopes", data.commandEnvelopes, 10, truncation, compactCommandEnvelope),
218
+ verificationCommandPlan: compactSummaryArray("verificationCommandPlan", data.verificationCommandPlan, 10, truncation, compactVerificationPlan),
219
+ verificationLedgerPreview: compactSummaryArray("verificationLedgerPreview", data.verificationLedgerPreview, 10, truncation, compactVerificationLedgerEntry),
220
+ verificationLedger: compactSummaryArray("verificationLedger", data.verificationLedger, 10, truncation, compactVerificationLedgerEntry),
221
+ driftReasons: compactSummaryArray("driftReasons", data.driftReasons, 8, truncation),
222
+ nextActions: compactSummaryArray("nextActions", data.nextActions, 8, truncation),
223
+ snapshot: compactBudgetSnapshot(data.snapshot, truncation),
224
+ runtime: compactSession(data.runtime),
225
+ truncation
226
+ };
227
+ }
228
+ function reattachGuidanceFields(record, source, truncation) {
229
+ const nextTools = compactNextTools(source.nextTools, truncation);
230
+ return {
231
+ ...record,
232
+ ...(nextTools === undefined ? {} : { nextTools }),
233
+ ...(typeof source.systemMessage === "string" ? { systemMessage: source.systemMessage } : {})
234
+ };
235
+ }
236
+ function compactBudgetSnapshot(value, truncation) {
237
+ if (!isRecord(value)) {
238
+ return value;
239
+ }
240
+ return {
241
+ taskId: value.taskId,
242
+ createdAt: value.createdAt,
243
+ changeType: value.changeType,
244
+ plannedEditTargets: compactSummaryArray("snapshot.plannedEditTargets", value.plannedEditTargets, 10, truncation),
245
+ plannedFiles: compactSummaryArray("snapshot.plannedFiles", value.plannedFiles, 10, truncation),
246
+ plannedTests: compactSummaryArray("snapshot.plannedTests", value.plannedTests, 10, truncation, compactTestRecommendation),
247
+ requiredWorkflowCheckCount: typeof value.requiredWorkflowCheckCount === "number" ? value.requiredWorkflowCheckCount : Array.isArray(value.requiredWorkflowChecks) ? value.requiredWorkflowChecks.length : undefined,
248
+ requiredDependencyCheckCount: typeof value.requiredDependencyCheckCount === "number" ? value.requiredDependencyCheckCount : Array.isArray(value.requiredDependencyChecks) ? value.requiredDependencyChecks.length : undefined
249
+ };
250
+ }
251
+ // The provenance marker is a small fixed shape in practice; an oversized one is
252
+ // untrusted input and must not ride into every compaction tier via the metrics.
253
+ function boundedVerificationProvenance(value) {
254
+ if (!isRecord(value)) {
255
+ return undefined;
256
+ }
257
+ return structuredByteLength(value) <= 2_000 ? value : { truncated: true };
258
+ }
259
+ function attachMcpMetrics(dataWithoutMetrics, structuredData) {
260
+ let returnedBytes = 0;
261
+ for (let attempt = 0; attempt < 20; attempt += 1) {
262
+ const candidate = {
263
+ ...dataWithoutMetrics,
264
+ mcp: {
265
+ ...structuredData,
266
+ returnedBytes
267
+ }
268
+ };
269
+ const bytes = structuredByteLength(candidate);
270
+ if (bytes === returnedBytes) {
271
+ return candidate;
272
+ }
273
+ returnedBytes = bytes;
274
+ }
275
+ const candidate = {
276
+ ...dataWithoutMetrics,
277
+ mcp: {
278
+ ...structuredData,
279
+ returnedBytes
280
+ }
281
+ };
282
+ return candidate;
283
+ }
284
+ function withMergedTruncation(data, truncation) {
285
+ const merged = mergeTruncation(truncationFromValue(data.truncation), truncation);
286
+ if (Object.keys(merged).length === 0) {
287
+ return data;
288
+ }
289
+ return { ...data, truncation: merged };
290
+ }
291
+ function mergeTruncation(...records) {
292
+ const merged = {};
293
+ for (const record of records) {
294
+ if (!record) {
295
+ continue;
296
+ }
297
+ for (const [key, value] of Object.entries(record)) {
298
+ if (value && typeof value.total === "number" && typeof value.returned === "number") {
299
+ merged[key] = value;
300
+ }
301
+ }
302
+ }
303
+ return merged;
304
+ }
305
+ function truncationFromValue(value) {
306
+ if (!isRecord(value)) {
307
+ return {};
308
+ }
309
+ const truncation = {};
310
+ for (const [key, entry] of Object.entries(value)) {
311
+ if (!isRecord(entry)) {
312
+ continue;
313
+ }
314
+ const total = entry.total;
315
+ const returned = entry.returned;
316
+ if (typeof total === "number" && typeof returned === "number") {
317
+ truncation[key] = { total, returned };
318
+ }
319
+ }
320
+ return truncation;
321
+ }
322
+ function metricNumber(data, key) {
323
+ const value = data[key];
324
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
325
+ }
326
+ export function compactPostEditMcpResult(result) {
327
+ if (!result.data || typeof result.data !== "object") {
328
+ return result;
329
+ }
330
+ const data = asPostEditReviewData(result.data);
331
+ if (!data) {
332
+ return result;
333
+ }
334
+ const snapshot = data.snapshot && typeof data.snapshot === "object" ? data.snapshot : undefined;
335
+ const outcome = data.outcome && typeof data.outcome === "object" ? data.outcome : undefined;
336
+ const truncation = compactPostEditTruncation(data, snapshot, outcome);
337
+ return {
338
+ ...result,
339
+ data: {
340
+ mode: data.mode,
341
+ task: data.task,
342
+ verdict: data.verdict,
343
+ inspectMode: data.inspectMode,
344
+ inspectReasons: limitArray(data.inspectReasons, 12),
345
+ completionAuthority: data.completionAuthority,
346
+ files: data.files,
347
+ reviewTargets: data.reviewTargets,
348
+ changedSinceSnapshot: limitArray(data.changedSinceSnapshot, 40),
349
+ changedGroups: limitArray(data.changedGroups, 20),
350
+ resolvedBaselineFiles: limitArray(data.resolvedBaselineFiles, 30),
351
+ unplannedEditedFiles: data.unplannedEditedFiles,
352
+ plannedRenames: limitArray(data.plannedRenames, 20),
353
+ unplannedChangedSymbols: limitArray(data.unplannedChangedSymbols, 20),
354
+ plannedButUntouchedFiles: limitArray(data.plannedButUntouchedFiles, 30),
355
+ headChanged: data.headChanged,
356
+ symbolDeltas: limitArray(data.symbolDeltas, 20),
357
+ modifiedSymbols: limitArray(data.modifiedSymbols, 40),
358
+ modifiedPublicSymbols: limitArray(data.modifiedPublicSymbols, 40),
359
+ riskDeltas: limitArray(data.riskDeltas, 20),
360
+ affectedTests: limitArray(data.affectedTests, 30),
361
+ tests: limitArray(data.tests, 30),
362
+ testsNotRun: limitArray(data.testsNotRun, 30),
363
+ missedLikelyTests: limitArray(data.missedLikelyTests, 30),
364
+ ranTests: data.ranTests,
365
+ ranCommands: Array.isArray(data.ranCommands) ? data.ranCommands.map((command) => (typeof command === "string" ? redactMcpText(command) : command)) : data.ranCommands,
366
+ ranCommandReports: compactCommandReportList(data.ranCommandReports, 30),
367
+ commandEnvelopes: compactCommandEnvelopeList(data.commandEnvelopes, 30),
368
+ waivedChecks: data.waivedChecks,
369
+ waivers: data.waivers,
370
+ verificationCoverage: limitArray(data.verificationCoverage, 40),
371
+ verificationLedger: limitArray(data.verificationLedger, 60),
372
+ verificationProvenance: data.verificationProvenance ?? CURRENT_VERIFICATION_PROVENANCE,
373
+ sessionMemory: data.sessionMemory,
374
+ priorSessionMemory: data.priorSessionMemory,
375
+ waivedVerification: limitArray(data.waivedVerification, 30),
376
+ unindexedEditedFiles: data.unindexedEditedFiles,
377
+ riskEscalations: limitArray(data.riskEscalations, 20),
378
+ workflows: limitArray(data.workflows, 12),
379
+ workflowChecks: limitArray(data.workflowChecks, 20),
380
+ dependencyChecks: limitArray(data.dependencyChecks, 30),
381
+ quality: data.quality,
382
+ driftReasons: data.driftReasons,
383
+ nextActions: data.nextActions,
384
+ nextTools: compactNextTools(data.nextTools, truncation),
385
+ systemMessage: stringValue(data.systemMessage),
386
+ truncation: Object.keys(truncation).length > 0 ? truncation : undefined,
387
+ snapshotLoad: compactSnapshotLoad(data.snapshotLoad),
388
+ snapshot: snapshot
389
+ ? {
390
+ taskId: snapshot.taskId,
391
+ createdAt: snapshot.createdAt,
392
+ changeType: snapshot.changeType,
393
+ plannedEditTargets: limitArray(snapshot.plannedEditTargets, 30),
394
+ plannedFiles: limitArray(snapshot.plannedFiles, 40),
395
+ plannedTests: limitArray(snapshot.plannedTests, 20),
396
+ requiredWorkflowCheckCount: typeof snapshot.requiredWorkflowCheckCount === "number" ? snapshot.requiredWorkflowCheckCount : Array.isArray(snapshot.requiredWorkflowChecks) ? snapshot.requiredWorkflowChecks.length : 0,
397
+ requiredDependencyCheckCount: typeof snapshot.requiredDependencyCheckCount === "number" ? snapshot.requiredDependencyCheckCount : Array.isArray(snapshot.requiredDependencyChecks) ? snapshot.requiredDependencyChecks.length : 0
398
+ }
399
+ : undefined,
400
+ outcome: outcome
401
+ ? {
402
+ outcomeId: outcome.outcomeId,
403
+ persisted: outcome.persisted,
404
+ verdict: outcome.verdict,
405
+ inspectMode: outcome.inspectMode,
406
+ inspectReasons: limitArray(outcome.inspectReasons, 12),
407
+ completionAuthority: outcome.completionAuthority,
408
+ path: outcome.path,
409
+ driftReasons: outcome.driftReasons,
410
+ calibrationLabels: outcome.calibrationLabels,
411
+ testsNotRun: limitArray(outcome.testsNotRun, 30),
412
+ missedLikelyTests: limitArray(outcome.missedLikelyTests, 30),
413
+ ranTests: outcome.ranTests,
414
+ ranCommands: Array.isArray(outcome.ranCommands) ? outcome.ranCommands.map((command) => (typeof command === "string" ? redactMcpText(command) : command)) : outcome.ranCommands,
415
+ ranCommandReports: compactCommandReportList(outcome.ranCommandReports, 30),
416
+ commandEnvelopes: compactCommandEnvelopeList(outcome.commandEnvelopes, 30),
417
+ waivedChecks: outcome.waivedChecks,
418
+ waivers: outcome.waivers,
419
+ verificationCoverage: limitArray(outcome.verificationCoverage, 40),
420
+ verificationLedger: limitArray(outcome.verificationLedger, 60),
421
+ verificationProvenance: outcome.verificationProvenance ?? data.verificationProvenance ?? CURRENT_VERIFICATION_PROVENANCE,
422
+ waivedVerification: limitArray(nonEmptyArray(outcome.waivedVerification) ? outcome.waivedVerification : data.waivedVerification, 30),
423
+ modifiedPublicSymbols: limitArray(outcome.modifiedPublicSymbols, 40),
424
+ hookSummary: outcome.hookSummary,
425
+ truncation: nestedTruncation("outcome", truncation)
426
+ }
427
+ : undefined
428
+ }
429
+ };
430
+ }
431
+ function compactPostEditTruncation(data, snapshot, outcome) {
432
+ return {
433
+ ...truncatedArray("changedSinceSnapshot", data.changedSinceSnapshot, 40),
434
+ ...truncatedArray("changedGroups", data.changedGroups, 20),
435
+ ...truncatedArray("resolvedBaselineFiles", data.resolvedBaselineFiles, 30),
436
+ ...truncatedArray("plannedRenames", data.plannedRenames, 20),
437
+ ...truncatedArray("unplannedChangedSymbols", data.unplannedChangedSymbols, 20),
438
+ ...truncatedArray("plannedButUntouchedFiles", data.plannedButUntouchedFiles, 30),
439
+ ...truncatedArray("symbolDeltas", data.symbolDeltas, 20),
440
+ ...truncatedArray("modifiedSymbols", data.modifiedSymbols, 40),
441
+ ...truncatedArray("modifiedPublicSymbols", data.modifiedPublicSymbols, 40),
442
+ ...truncatedArray("riskDeltas", data.riskDeltas, 20),
443
+ ...truncatedArray("affectedTests", data.affectedTests, 30),
444
+ ...truncatedArray("tests", data.tests, 30),
445
+ ...truncatedArray("testsNotRun", data.testsNotRun, 30),
446
+ ...truncatedArray("missedLikelyTests", data.missedLikelyTests, 30),
447
+ ...truncatedArray("ranCommandReports", data.ranCommandReports, 30),
448
+ ...truncatedArray("commandEnvelopes", data.commandEnvelopes, 30),
449
+ ...truncatedArray("verificationCoverage", data.verificationCoverage, 40),
450
+ ...truncatedArray("verificationLedger", data.verificationLedger, 60),
451
+ ...truncatedArray("waivedVerification", data.waivedVerification, 30),
452
+ ...truncatedArray("riskEscalations", data.riskEscalations, 20),
453
+ ...truncatedArray("workflows", data.workflows, 12),
454
+ ...truncatedArray("workflowChecks", data.workflowChecks, 20),
455
+ ...truncatedArray("dependencyChecks", data.dependencyChecks, 30),
456
+ ...truncatedArray("snapshot.plannedEditTargets", snapshot?.plannedEditTargets, 30),
457
+ ...truncatedArray("snapshot.plannedFiles", snapshot?.plannedFiles, 40),
458
+ ...truncatedArray("snapshot.plannedTests", snapshot?.plannedTests, 20),
459
+ ...truncatedArray("outcome.testsNotRun", outcome?.testsNotRun, 30),
460
+ ...truncatedArray("outcome.missedLikelyTests", outcome?.missedLikelyTests, 30),
461
+ ...truncatedArray("outcome.ranCommandReports", outcome?.ranCommandReports, 30),
462
+ ...truncatedArray("outcome.commandEnvelopes", outcome?.commandEnvelopes, 30),
463
+ ...truncatedArray("outcome.verificationCoverage", outcome?.verificationCoverage, 40),
464
+ ...truncatedArray("outcome.verificationLedger", outcome?.verificationLedger, 60),
465
+ ...truncatedArray("outcome.waivedVerification", outcome ? (outcome.waivedVerification ?? data.waivedVerification) : undefined, 30),
466
+ ...truncatedArray("outcome.modifiedPublicSymbols", outcome?.modifiedPublicSymbols, 40)
467
+ };
468
+ }
469
+ function compactContextPacketData(data, mode) {
470
+ const limit = createArrayLimiter();
471
+ const compacted = {
472
+ mode,
473
+ task: data.task,
474
+ changeType: data.changeType,
475
+ actionability: data.actionability,
476
+ tokenBudget: data.tokenBudget,
477
+ packetVerdict: data.packetVerdict,
478
+ focusFiles: limit("focusFiles", data.focusFiles, 20, compactFocusEntry),
479
+ changedFiles: limit("changedFiles", data.changedFiles, 40),
480
+ changedEntries: limit("changedEntries", data.changedEntries, 40, compactChangedEntry),
481
+ changedSymbols: limit("changedSymbols", data.changedSymbols, 40, compactSymbolLike),
482
+ unindexedChanged: limit("unindexedChanged", data.unindexedChanged, 40),
483
+ groups: limit("groups", data.groups, 20, compactGroup),
484
+ tests: limit("tests", data.tests, 30, compactTestRecommendation),
485
+ snippets: limit("snippets", data.snippets, 12),
486
+ contextSources: limit("contextSources", data.contextSources, 12),
487
+ warnings: limit("warnings", data.warnings, 20),
488
+ nextReads: limit("nextReads", data.nextReads, 20),
489
+ baseline: data.baseline,
490
+ retrieval: compactRetrieval(data.retrieval),
491
+ diagnostics: limit("diagnostics", data.diagnostics, 20),
492
+ recipes: limit("recipes", data.recipes, 12),
493
+ verificationCommands: limit("verificationCommands", data.verificationCommands, 20),
494
+ verificationCoverage: limit("verificationCoverage", data.verificationCoverage, 40, compactVerificationCoverage),
495
+ verificationCommandPlan: limit("verificationCommandPlan", data.verificationCommandPlan, 30, compactVerificationPlan),
496
+ value: data.value,
497
+ quality: data.quality,
498
+ worktree: data.worktree,
499
+ worktreeDegradationReasons: data.worktreeDegradationReasons,
500
+ gaps: limit("gaps", data.gaps, 30),
501
+ nextTools: compactNextTools(data.nextTools, limit.truncation),
502
+ systemMessage: stringValue(data.systemMessage),
503
+ session: compactSession(data.session),
504
+ sessionMemory: data.sessionMemory,
505
+ runtime: data.runtime,
506
+ truncation: Object.keys(limit.truncation).length > 0 ? limit.truncation : undefined
507
+ };
508
+ return { data: compacted, truncation: limit.truncation, compacted: true };
509
+ }
510
+ function compactFocusBriefData(data) {
511
+ const limit = createArrayLimiter();
512
+ const compacted = {
513
+ mode: data.mode,
514
+ task: data.task,
515
+ actionability: data.actionability,
516
+ retrieval: compactRetrieval(data.retrieval),
517
+ packetVerdict: data.packetVerdict,
518
+ diagnostics: limit("diagnostics", data.diagnostics, 20),
519
+ focusFiles: limit("focusFiles", data.focusFiles, 20, compactFileFact),
520
+ workflows: limit("workflows", data.workflows, 12, compactWorkflow),
521
+ modules: limit("modules", data.modules, 20, compactModule),
522
+ groups: limit("groups", data.groups, 20, compactGroup),
523
+ tests: limit("tests", data.tests, 30, compactTestRecommendation),
524
+ nextCall: data.nextCall,
525
+ sessionMemory: data.sessionMemory,
526
+ quality: data.quality,
527
+ worktree: data.worktree,
528
+ worktreeDegradationReasons: data.worktreeDegradationReasons,
529
+ gaps: limit("gaps", data.gaps, 30),
530
+ nextTools: compactNextTools(data.nextTools, limit.truncation),
531
+ systemMessage: stringValue(data.systemMessage),
532
+ runtime: data.runtime,
533
+ truncation: Object.keys(limit.truncation).length > 0 ? limit.truncation : undefined
534
+ };
535
+ return { data: compacted, truncation: limit.truncation, compacted: true };
536
+ }
537
+ function compactChangePlanData(data) {
538
+ const limit = createArrayLimiter();
539
+ const compactFocus = data.focus && typeof data.focus === "object" && !Array.isArray(data.focus) ? compactFocusBriefData(data.focus) : undefined;
540
+ const compactContext = data.context && typeof data.context === "object" && !Array.isArray(data.context) ? compactContextPacketData(data.context, "context_pack") : undefined;
541
+ const snapshotLimit = createArrayLimiter();
542
+ const snapshotDirtyLimit = createArrayLimiter();
543
+ const snapshot = data.snapshot && typeof data.snapshot === "object" && !Array.isArray(data.snapshot) ? data.snapshot : undefined;
544
+ const compacted = {
545
+ mode: data.mode,
546
+ editReadiness: data.editReadiness,
547
+ followCandidate: compactFollowCandidate(data.followCandidate),
548
+ snapshotBlock: compactSnapshotBlock(data.snapshotBlock),
549
+ targetCandidates: limit("targetCandidates", data.targetCandidates, 12, compactTargetCandidate),
550
+ steps: limit("steps", data.steps, 12),
551
+ focus: compactFocus?.data,
552
+ context: compactContext?.data,
553
+ files: limit("files", data.files, 30),
554
+ plannedEditTargets: limit("plannedEditTargets", data.plannedEditTargets, 30),
555
+ tests: limit("tests", data.tests, 30, compactTestRecommendation),
556
+ recipes: limit("recipes", data.recipes, 12),
557
+ quality: data.quality,
558
+ requiredWorkflowChecks: limit("requiredWorkflowChecks", data.requiredWorkflowChecks, 20, compactCheck),
559
+ requiredDependencyChecks: limit("requiredDependencyChecks", data.requiredDependencyChecks, 30, compactCheck),
560
+ sessionMemory: data.sessionMemory,
561
+ nextTools: compactNextTools(data.nextTools, limit.truncation),
562
+ systemMessage: stringValue(data.systemMessage),
563
+ snapshot: snapshot
564
+ ? {
565
+ taskId: snapshot.taskId,
566
+ createdAt: snapshot.createdAt,
567
+ changeType: snapshot.changeType,
568
+ task: snapshot.task,
569
+ plannedEditTargets: snapshotLimit("plannedEditTargets", snapshot.plannedEditTargets, 30),
570
+ plannedFiles: snapshotLimit("plannedFiles", snapshot.plannedFiles, 40),
571
+ focusFiles: snapshotLimit("focusFiles", snapshot.focusFiles, 20, compactFileFact),
572
+ plannedTests: snapshotLimit("plannedTests", snapshot.plannedTests, 20, compactTestRecommendation),
573
+ sessionMemory: snapshot.sessionMemory,
574
+ requiredWorkflowCheckCount: typeof snapshot.requiredWorkflowCheckCount === "number" ? snapshot.requiredWorkflowCheckCount : Array.isArray(snapshot.requiredWorkflowChecks) ? snapshot.requiredWorkflowChecks.length : 0,
575
+ requiredDependencyCheckCount: typeof snapshot.requiredDependencyCheckCount === "number" ? snapshot.requiredDependencyCheckCount : Array.isArray(snapshot.requiredDependencyChecks) ? snapshot.requiredDependencyChecks.length : 0,
576
+ recipes: snapshotLimit("recipes", snapshot.recipes, 12),
577
+ gaps: snapshotLimit("gaps", snapshot.gaps, 20),
578
+ warnings: snapshotLimit("warnings", snapshot.warnings, 20),
579
+ dirtyBaseline: snapshot.dirtyBaseline && typeof snapshot.dirtyBaseline === "object" && !Array.isArray(snapshot.dirtyBaseline)
580
+ ? {
581
+ headCommit: snapshot.dirtyBaseline.headCommit,
582
+ indexedAt: snapshot.dirtyBaseline.indexedAt,
583
+ changedEntries: snapshotDirtyLimit("changedEntries", snapshot.dirtyBaseline.changedEntries, 20, compactChangedEntry),
584
+ dirtyFiles: snapshotDirtyLimit("dirtyFiles", snapshot.dirtyBaseline.dirtyFiles, 20),
585
+ truncation: Object.keys(snapshotDirtyLimit.truncation).length > 0 ? snapshotDirtyLimit.truncation : undefined
586
+ }
587
+ : undefined,
588
+ baselineCounts: {
589
+ symbolBaseline: isRecord(snapshot.symbolBaseline) ? Object.keys(snapshot.symbolBaseline).length : 0,
590
+ riskBaseline: isRecord(snapshot.riskBaseline) ? Object.keys(snapshot.riskBaseline).length : 0
591
+ },
592
+ quality: snapshot.quality,
593
+ truncation: Object.keys(snapshotLimit.truncation).length > 0 ? snapshotLimit.truncation : undefined
594
+ }
595
+ : undefined,
596
+ runtime: data.runtime
597
+ };
598
+ const truncation = {
599
+ ...limit.truncation,
600
+ ...prefixTruncation("snapshot", snapshotLimit.truncation),
601
+ ...prefixTruncation("snapshot.dirtyBaseline", snapshotDirtyLimit.truncation),
602
+ ...prefixTruncation("focus", compactFocus?.truncation),
603
+ ...prefixTruncation("context", compactContext?.truncation)
604
+ };
605
+ return { data: compacted, truncation, compacted: true };
606
+ }
607
+ function compactSnapshotBlock(value) {
608
+ if (!isRecord(value)) {
609
+ return value;
610
+ }
611
+ return {
612
+ taskId: value.taskId,
613
+ path: value.path,
614
+ reason: value.reason
615
+ };
616
+ }
617
+ function compactFollowCandidate(value) {
618
+ if (!isRecord(value)) {
619
+ return value;
620
+ }
621
+ return {
622
+ status: value.status,
623
+ requested: value.requested,
624
+ candidateId: value.candidateId,
625
+ rank: value.rank,
626
+ kind: value.kind,
627
+ path: value.path,
628
+ reason: value.reason,
629
+ plannedEditTargets: limitArray(value.plannedEditTargets, 8),
630
+ validationReasons: limitArray(value.validationReasons, 8),
631
+ snapshotLoad: isRecord(value.snapshotLoad)
632
+ ? {
633
+ latestTaskId: value.snapshotLoad.latestTaskId,
634
+ missingReason: value.snapshotLoad.missingReason,
635
+ error: value.snapshotLoad.error
636
+ }
637
+ : undefined
638
+ };
639
+ }
640
+ function compactTargetCandidate(value) {
641
+ if (!isRecord(value)) {
642
+ return value;
643
+ }
644
+ return {
645
+ candidateId: value.candidateId,
646
+ rank: value.rank,
647
+ kind: value.kind,
648
+ path: value.path,
649
+ symbol: isRecord(value.symbol)
650
+ ? {
651
+ id: value.symbol.id,
652
+ name: value.symbol.name,
653
+ qualifiedName: value.symbol.qualifiedName,
654
+ kind: value.symbol.kind
655
+ }
656
+ : undefined,
657
+ score: value.score,
658
+ confidence: value.confidence,
659
+ evidence: limitArray(value.evidence, 8),
660
+ missingAnchors: limitArray(value.missingAnchors, 8),
661
+ validationStatus: value.validationStatus,
662
+ validationReasons: limitArray(value.validationReasons, 8),
663
+ wouldPlanEditTargets: limitArray(value.wouldPlanEditTargets, 8),
664
+ wouldRecommendTests: limitArray(value.wouldRecommendTests, 8),
665
+ candidateRisk: isRecord(value.candidateRisk)
666
+ ? {
667
+ score: value.candidateRisk.score,
668
+ reasons: limitArray(value.candidateRisk.reasons, 6)
669
+ }
670
+ : undefined,
671
+ nextChangePlanArgs: value.nextChangePlanArgs,
672
+ rawSearchQueries: limitArray(value.rawSearchQueries, 4)
673
+ };
674
+ }
675
+ function compactTestPlanData(data) {
676
+ const limit = createArrayLimiter();
677
+ const compacted = {
678
+ mode: data.mode ?? "test_plan",
679
+ changedFiles: limit("changedFiles", data.changedFiles, 40),
680
+ changedEntries: limit("changedEntries", data.changedEntries, 40, compactChangedEntry),
681
+ changedSymbols: limit("changedSymbols", data.changedSymbols, 40, compactSymbolLike),
682
+ unindexedChanged: limit("unindexedChanged", data.unindexedChanged, 40),
683
+ groups: limit("groups", data.groups, 20, compactGroup),
684
+ tests: limit("tests", data.tests, 30, compactTestRecommendation),
685
+ outcomeLearning: limit("outcomeLearning", data.outcomeLearning, 12),
686
+ verificationCommands: limit("verificationCommands", data.verificationCommands, 20),
687
+ verificationCoverage: limit("verificationCoverage", data.verificationCoverage, 40, compactVerificationCoverage),
688
+ commandEnvelopes: limit("commandEnvelopes", data.commandEnvelopes, 60),
689
+ verificationCommandPlan: limit("verificationCommandPlan", data.verificationCommandPlan, 30, compactVerificationPlan),
690
+ verificationLedger: limit("verificationLedger", data.verificationLedger, 60, compactVerificationLedgerEntry),
691
+ verificationLedgerPreview: limit("verificationLedgerPreview", data.verificationLedgerPreview, 60, compactVerificationLedgerEntry),
692
+ verificationProvenance: data.verificationProvenance,
693
+ testsNotRun: limit("testsNotRun", data.testsNotRun, 30, compactTestRecommendation),
694
+ sessionMemory: data.sessionMemory,
695
+ worktree: data.worktree,
696
+ worktreeDegradationReasons: data.worktreeDegradationReasons,
697
+ gaps: limit("gaps", data.gaps, 30),
698
+ nextTools: compactNextTools(data.nextTools, limit.truncation),
699
+ systemMessage: stringValue(data.systemMessage),
700
+ runtime: data.runtime,
701
+ truncation: Object.keys(limit.truncation).length > 0 ? limit.truncation : undefined
702
+ };
703
+ return { data: compacted, truncation: limit.truncation, compacted: true };
704
+ }
705
+ function createArrayLimiter() {
706
+ const truncation = {};
707
+ const limiter = ((name, value, limit, map) => {
708
+ if (!Array.isArray(value)) {
709
+ return value;
710
+ }
711
+ const returned = value.slice(0, limit).map((entry) => (map ? map(entry) : entry));
712
+ if (value.length > limit) {
713
+ truncation[name] = { total: value.length, returned: limit };
714
+ }
715
+ return returned;
716
+ });
717
+ limiter.truncation = truncation;
718
+ return limiter;
719
+ }
720
+ function prefixTruncation(prefix, truncation) {
721
+ if (!truncation) {
722
+ return {};
723
+ }
724
+ return Object.fromEntries(Object.entries(truncation).map(([key, value]) => [`${prefix}.${key}`, value]));
725
+ }
726
+ function nestedTruncation(prefix, truncation) {
727
+ const nestedPrefix = `${prefix}.`;
728
+ const nested = Object.fromEntries(Object.entries(truncation).filter(([key]) => key.startsWith(nestedPrefix)).map(([key, value]) => [key.slice(nestedPrefix.length), value]));
729
+ return Object.keys(nested).length > 0 ? nested : undefined;
730
+ }
731
+ function compactFileFact(value) {
732
+ if (!isRecord(value)) {
733
+ return value;
734
+ }
735
+ const record = value;
736
+ return {
737
+ id: record.id,
738
+ type: record.type,
739
+ path: record.path,
740
+ language: record.language,
741
+ dirty: record.dirty,
742
+ generated: record.generated,
743
+ test: record.test,
744
+ rank: record.rank,
745
+ symbolCount: record.symbolCount,
746
+ usageCount: record.usageCount,
747
+ importCount: record.importCount,
748
+ riskScore: record.riskScore,
749
+ source: record.source,
750
+ confidence: record.confidence
751
+ };
752
+ }
753
+ function compactFocusEntry(value) {
754
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
755
+ return value;
756
+ }
757
+ const record = value;
758
+ const truncation = {};
759
+ const reasons = compactArrayField("reasons", record.reasons, 10, truncation);
760
+ const matchedTerms = compactArrayField("matchedTerms", record.matchedTerms, 12, truncation);
761
+ return {
762
+ file: compactFileFact(record.file),
763
+ reasons: reasons.value,
764
+ rank: record.rank,
765
+ score: record.score,
766
+ tier: record.tier,
767
+ matchedTerms: matchedTerms.value,
768
+ truncation: Object.keys(truncation).length > 0 ? truncation : undefined
769
+ };
770
+ }
771
+ function compactTestRecommendation(value) {
772
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
773
+ return value;
774
+ }
775
+ const record = value;
776
+ return {
777
+ path: record.path,
778
+ reason: record.reason,
779
+ rank: record.rank,
780
+ evidenceTier: record.evidenceTier,
781
+ command: record.command,
782
+ commandSource: record.commandSource,
783
+ commandConfidence: record.commandConfidence,
784
+ provenance: record.provenance
785
+ };
786
+ }
787
+ export function compactNextTools(value, truncation, pathName = "nextTools") {
788
+ if (!Array.isArray(value)) {
789
+ return value;
790
+ }
791
+ if (value.length > 8 && truncation) {
792
+ truncation[pathName] = { total: value.length, returned: 8 };
793
+ }
794
+ return value.slice(0, 8).map((entry, index) => compactNextTool(entry, truncation, `${pathName}.${index}`));
795
+ }
796
+ function compactNextTool(value, truncation, pathName = "nextTools.entry") {
797
+ if (typeof value === "string") {
798
+ return value;
799
+ }
800
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
801
+ return value;
802
+ }
803
+ const record = value;
804
+ const localTruncation = {};
805
+ return {
806
+ schemaVersion: record.schemaVersion,
807
+ tool: record.tool,
808
+ reason: typeof record.reason === "string" ? record.reason.slice(0, 240) : record.reason,
809
+ requiredInputs: compactGenericValue(record.requiredInputs, { arrayLimit: 8, objectKeyLimit: 16, maxDepth: 3 }, truncation ?? localTruncation, `${pathName}.requiredInputs`),
810
+ readOnly: record.readOnly,
811
+ writes: limitArray(record.writes, 8)
812
+ };
813
+ }
814
+ function compactCommandEnvelope(value) {
815
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
816
+ return value;
817
+ }
818
+ const record = value;
819
+ return {
820
+ command: typeof record.command === "string" ? redactMcpText(record.command) : record.command,
821
+ cwd: typeof record.cwd === "string" ? redactMcpText(record.cwd) : record.cwd,
822
+ packageManager: typeof record.packageManager === "string" ? redactMcpText(record.packageManager) : record.packageManager,
823
+ workspace: typeof record.workspace === "string" ? redactMcpText(record.workspace) : record.workspace,
824
+ packageRoot: typeof record.packageRoot === "string" ? redactMcpText(record.packageRoot) : record.packageRoot,
825
+ packageName: typeof record.packageName === "string" ? redactMcpText(record.packageName) : record.packageName,
826
+ scriptName: typeof record.scriptName === "string" ? redactMcpText(record.scriptName) : record.scriptName,
827
+ args: Array.isArray(record.args) ? sanitizeCommandArgs(record.args.slice(0, 20)) : record.args,
828
+ argsTruncated: Array.isArray(record.args) && record.args.length > 20 ? { total: record.args.length, returned: 20 } : undefined,
829
+ exitCode: record.exitCode,
830
+ durationMs: record.durationMs,
831
+ stdoutSummary: typeof record.stdoutSummary === "string" ? redactMcpText(record.stdoutSummary) : record.stdoutSummary,
832
+ stderrSummary: typeof record.stderrSummary === "string" ? redactMcpText(record.stderrSummary) : record.stderrSummary,
833
+ outputSummary: typeof record.outputSummary === "string" ? redactMcpText(record.outputSummary) : record.outputSummary,
834
+ source: record.source,
835
+ scopeStatus: record.scopeStatus,
836
+ classifierVersion: record.classifierVersion
837
+ };
838
+ }
839
+ function compactCommandReportList(value, limit) {
840
+ return Array.isArray(value) ? value.slice(0, limit).map(compactCommandReport) : value;
841
+ }
842
+ function compactCommandEnvelopeList(value, limit) {
843
+ return Array.isArray(value) ? value.slice(0, limit).map(compactCommandEnvelope) : value;
844
+ }
845
+ function compactCommandReport(value) {
846
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
847
+ return value;
848
+ }
849
+ const record = value;
850
+ return {
851
+ ...record,
852
+ command: typeof record.command === "string" ? redactMcpText(record.command) : record.command,
853
+ cwd: typeof record.cwd === "string" ? redactMcpText(record.cwd) : record.cwd,
854
+ workspace: typeof record.workspace === "string" ? redactMcpText(record.workspace) : record.workspace,
855
+ packageRoot: typeof record.packageRoot === "string" ? redactMcpText(record.packageRoot) : record.packageRoot,
856
+ packageName: typeof record.packageName === "string" ? redactMcpText(record.packageName) : record.packageName,
857
+ packageManager: typeof record.packageManager === "string" ? redactMcpText(record.packageManager) : record.packageManager,
858
+ scriptName: typeof record.scriptName === "string" ? redactMcpText(record.scriptName) : record.scriptName,
859
+ args: Array.isArray(record.args) ? sanitizeCommandArgs(record.args) : record.args,
860
+ stdoutSummary: typeof record.stdoutSummary === "string" ? redactMcpText(record.stdoutSummary) : record.stdoutSummary,
861
+ stderrSummary: typeof record.stderrSummary === "string" ? redactMcpText(record.stderrSummary) : record.stderrSummary,
862
+ outputSummary: typeof record.outputSummary === "string" ? redactMcpText(record.outputSummary) : record.outputSummary
863
+ };
864
+ }
865
+ function sanitizeCommandArgs(args) {
866
+ let redactNext = false;
867
+ return args.map((arg) => {
868
+ if (typeof arg !== "string") {
869
+ return arg;
870
+ }
871
+ if (redactNext) {
872
+ redactNext = false;
873
+ return "<redacted>";
874
+ }
875
+ if (isSecretFlag(arg) && !arg.includes("=")) {
876
+ redactNext = true;
877
+ return redactMcpText(arg) ?? "";
878
+ }
879
+ return redactMcpText(redactSecretArg(arg)) ?? "";
880
+ });
881
+ }
882
+ function redactMcpText(value) {
883
+ return redactSecretText(value)
884
+ ?.replace(/(^|[\s([,{])\/[^\s;|)\]'",]+/gu, "$1<abs-path>")
885
+ .replace(/(^|[\s([,{])(?:\.\.?\/)[^\s;|)\]'",]+/gu, "$1<rel-path>");
886
+ }
887
+ function redactSecretText(value) {
888
+ return value
889
+ ?.replace(/(^|[\s([,{])((?:--?[a-z0-9-]*(?:token|secret|password|passwd|pwd|api[-_]?key|access[-_]?key|auth|credential|cookie)[a-z0-9-]*)(?:=|\s+))([^\s;|)\]'",]+)/giu, "$1$2<redacted>")
890
+ .replace(/(\b[A-Z_]*(?:TOKEN|SECRET|PASSWORD|PASSWD|PWD|API_?KEY|ACCESS_?KEY|AUTH|CREDENTIAL|COOKIE)[A-Z0-9_]*=)([^\s;|)\]'",]+)/gu, "$1<redacted>")
891
+ .replace(/\b(Bearer)\s+[A-Za-z0-9._~+/-]+=*/giu, "$1 <redacted>");
892
+ }
893
+ function redactSecretArg(value) {
894
+ if (/^Bearer\s+/iu.test(value)) {
895
+ return "Bearer <redacted>";
896
+ }
897
+ if (isSecretFlag(value) && value.includes("=")) {
898
+ return value.replace(/=.*/u, "=<redacted>");
899
+ }
900
+ if (/^(?:[A-Z_]*(?:TOKEN|SECRET|PASSWORD|PASSWD|PWD|API_?KEY|ACCESS_?KEY|AUTH|CREDENTIAL|COOKIE)[A-Z0-9_]*)=/iu.test(value)) {
901
+ return value.replace(/=.*/u, "=<redacted>");
902
+ }
903
+ return value;
904
+ }
905
+ function isSecretFlag(value) {
906
+ return /^--?[a-z0-9-]*(?:token|secret|password|passwd|pwd|api-?key|access-?key|auth|credential|cookie)[a-z0-9-]*(?:=.*)?$/iu.test(value);
907
+ }
908
+ function compactWorkflow(value) {
909
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
910
+ return value;
911
+ }
912
+ const record = value;
913
+ const truncation = {};
914
+ const relatedFiles = compactArrayField("relatedFiles", record.relatedFiles, 20, truncation);
915
+ const tests = compactArrayField("tests", record.tests, 20, truncation);
916
+ const steps = compactArrayField("steps", record.steps, 16, truncation, compactWorkflowStep);
917
+ return {
918
+ id: record.id,
919
+ title: record.title,
920
+ workflowKind: record.workflowKind,
921
+ entryPath: record.entryPath,
922
+ relatedFiles: relatedFiles.value,
923
+ tests: tests.value,
924
+ summary: record.summary,
925
+ rank: record.rank,
926
+ confidence: record.confidence,
927
+ steps: steps.value,
928
+ truncation: Object.keys(truncation).length > 0 ? truncation : undefined
929
+ };
930
+ }
931
+ function compactWorkflowStep(value) {
932
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
933
+ return value;
934
+ }
935
+ const record = value;
936
+ return {
937
+ kind: record.kind,
938
+ label: record.label,
939
+ path: record.path,
940
+ line: record.line,
941
+ targetPath: record.targetPath,
942
+ confidence: record.confidence,
943
+ reason: record.reason
944
+ };
945
+ }
946
+ function compactModule(value) {
947
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
948
+ return value;
949
+ }
950
+ const record = value;
951
+ const truncation = {};
952
+ const files = compactArrayField("files", record.files, 20, truncation);
953
+ const reasons = compactArrayField("reasons", record.reasons, 10, truncation);
954
+ return {
955
+ name: record.name,
956
+ score: record.score,
957
+ rank: record.rank,
958
+ summary: record.summary,
959
+ files: files.value,
960
+ reasons: reasons.value,
961
+ truncation: Object.keys(truncation).length > 0 ? truncation : undefined
962
+ };
963
+ }
964
+ function compactGroup(value) {
965
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
966
+ return value;
967
+ }
968
+ const record = value;
969
+ const truncation = {};
970
+ const files = compactArrayField("files", record.files, 30, truncation);
971
+ const symbols = compactArrayField("symbols", record.symbols, 20, truncation);
972
+ return {
973
+ name: record.name,
974
+ module: record.module,
975
+ kind: record.kind,
976
+ language: record.language,
977
+ risk: record.risk,
978
+ files: files.value,
979
+ changes: record.changes,
980
+ symbols: symbols.value,
981
+ truncation: Object.keys(truncation).length > 0 ? truncation : undefined
982
+ };
983
+ }
984
+ function compactChangedEntry(value) {
985
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
986
+ return value;
987
+ }
988
+ const record = value;
989
+ return { path: record.path, status: record.status, oldPath: record.oldPath };
990
+ }
991
+ function compactSymbolLike(value) {
992
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
993
+ return value;
994
+ }
995
+ const record = value;
996
+ return {
997
+ id: record.id,
998
+ path: record.path,
999
+ name: record.name,
1000
+ qualifiedName: record.qualifiedName,
1001
+ kind: record.kind,
1002
+ exported: record.exported,
1003
+ line: typeof record.line === "number" ? record.line : undefined,
1004
+ range: record.range
1005
+ };
1006
+ }
1007
+ function compactVerificationCoverage(value) {
1008
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1009
+ return value;
1010
+ }
1011
+ const record = value;
1012
+ const truncation = {};
1013
+ const details = compactArrayField("details", record.details, 8, truncation);
1014
+ return {
1015
+ kind: record.kind,
1016
+ command: record.command,
1017
+ source: record.source,
1018
+ confidence: record.confidence,
1019
+ scope: record.scope,
1020
+ targetPath: record.targetPath,
1021
+ details: details.value,
1022
+ exitCode: record.exitCode,
1023
+ durationMs: record.durationMs,
1024
+ outputSummary: record.outputSummary,
1025
+ commandEnvelope: compactCommandEnvelope(record.commandEnvelope),
1026
+ truncation: Object.keys(truncation).length > 0 ? truncation : undefined
1027
+ };
1028
+ }
1029
+ function compactVerificationPlan(value) {
1030
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1031
+ return value;
1032
+ }
1033
+ const record = value;
1034
+ const truncation = {};
1035
+ const covers = compactArrayField("covers", record.covers, 12, truncation);
1036
+ const targetPaths = compactArrayField("targetPaths", record.targetPaths, 20, truncation);
1037
+ const scopes = compactArrayField("scopes", record.scopes, 12, truncation);
1038
+ const sources = compactArrayField("sources", record.sources, 12, truncation);
1039
+ return {
1040
+ command: record.command,
1041
+ covers: covers.value,
1042
+ targetPaths: targetPaths.value,
1043
+ scopes: scopes.value,
1044
+ sources: sources.value,
1045
+ confidence: record.confidence,
1046
+ truncation: Object.keys(truncation).length > 0 ? truncation : undefined
1047
+ };
1048
+ }
1049
+ function compactVerificationLedgerEntry(value) {
1050
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1051
+ return value;
1052
+ }
1053
+ const record = value;
1054
+ const truncation = {};
1055
+ const evidence = compactArrayField("evidence", record.evidence, 8, truncation);
1056
+ const coverageKinds = compactArrayField("coverageKinds", record.coverageKinds, 12, truncation);
1057
+ return {
1058
+ kind: record.kind,
1059
+ recommended: record.recommended,
1060
+ target: record.target,
1061
+ status: record.status,
1062
+ evidence: evidence.value,
1063
+ missingReason: record.missingReason,
1064
+ waiverReason: record.waiverReason,
1065
+ notApplicableReason: record.notApplicableReason,
1066
+ coverageKinds: coverageKinds.value,
1067
+ command: record.command,
1068
+ source: record.source,
1069
+ truncation: Object.keys(truncation).length > 0 ? truncation : undefined
1070
+ };
1071
+ }
1072
+ function compactCheck(value) {
1073
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1074
+ return value;
1075
+ }
1076
+ const record = value;
1077
+ const truncation = {};
1078
+ const evidence = compactArrayField("evidence", record.evidence, 8, truncation);
1079
+ return {
1080
+ kind: record.kind,
1081
+ target: record.target,
1082
+ status: record.status,
1083
+ reason: record.reason,
1084
+ evidence: evidence.value,
1085
+ truncation: Object.keys(truncation).length > 0 ? truncation : undefined
1086
+ };
1087
+ }
1088
+ function compactRetrieval(value) {
1089
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1090
+ return value;
1091
+ }
1092
+ const record = value;
1093
+ const limit = createArrayLimiter();
1094
+ const intentConfidence = compactIntentConfidence(record.intentConfidence);
1095
+ return {
1096
+ broad: record.broad,
1097
+ intents: limit("intents", record.intents, 12),
1098
+ diagnostics: limit("diagnostics", record.diagnostics, 20),
1099
+ intentConfidence,
1100
+ modules: limit("modules", record.modules, 20, compactModule),
1101
+ workflows: limit("workflows", record.workflows, 12, compactWorkflow),
1102
+ matchCount: Array.isArray(record.matches) ? record.matches.length : undefined,
1103
+ matches: limit("matches", record.matches, 20, compactFocusEntry),
1104
+ truncation: Object.keys(limit.truncation).length > 0 ? limit.truncation : undefined
1105
+ };
1106
+ }
1107
+ function compactIntentConfidence(value) {
1108
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1109
+ return value;
1110
+ }
1111
+ const record = value;
1112
+ const limit = createArrayLimiter();
1113
+ const compacted = {
1114
+ ...record,
1115
+ anchors: limit("anchors", record.anchors, 6),
1116
+ missingAnchors: limit("missingAnchors", record.missingAnchors, 6),
1117
+ reasons: limit("reasons", record.reasons, 12)
1118
+ };
1119
+ return {
1120
+ ...compacted,
1121
+ truncation: Object.keys(limit.truncation).length > 0 ? limit.truncation : undefined
1122
+ };
1123
+ }
1124
+ function compactSession(value) {
1125
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1126
+ return value;
1127
+ }
1128
+ const record = value;
1129
+ const limit = createArrayLimiter();
1130
+ const compacted = {
1131
+ commandBudgetMs: record.commandBudgetMs,
1132
+ maxResultBytes: record.maxResultBytes,
1133
+ maxResults: record.maxResults,
1134
+ provenance: limit("provenance", record.provenance, 30)
1135
+ };
1136
+ return {
1137
+ ...compacted,
1138
+ truncation: Object.keys(limit.truncation).length > 0 ? limit.truncation : undefined
1139
+ };
1140
+ }
1141
+ function compactArrayField(name, value, limit, truncation, map) {
1142
+ if (!Array.isArray(value)) {
1143
+ return { value };
1144
+ }
1145
+ const returned = value.slice(0, limit).map((entry) => (map ? map(entry) : entry));
1146
+ if (value.length > limit) {
1147
+ truncation[name] = { total: value.length, returned: limit };
1148
+ }
1149
+ return { value: returned, truncation: value.length > limit ? { [name]: { total: value.length, returned: limit } } : undefined };
1150
+ }
1151
+ function compactGenericValue(value, options, truncation, pathName = "value", depth = options.maxDepth) {
1152
+ if (Array.isArray(value)) {
1153
+ const returned = value.slice(0, options.arrayLimit).map((entry) => compactGenericValue(entry, options, truncation, pathName, depth - 1));
1154
+ if (value.length > options.arrayLimit) {
1155
+ truncation[pathName] = { total: value.length, returned: options.arrayLimit };
1156
+ }
1157
+ return returned;
1158
+ }
1159
+ if (!isRecord(value)) {
1160
+ return value;
1161
+ }
1162
+ const entries = Object.entries(value).filter(([key]) => key !== "mcp");
1163
+ if (depth <= 0) {
1164
+ const keys = entries.map(([key]) => key);
1165
+ if (keys.length > options.objectKeyLimit) {
1166
+ truncation[`${pathName}.__keys`] = { total: keys.length, returned: options.objectKeyLimit };
1167
+ }
1168
+ return {
1169
+ compactedObject: true,
1170
+ keyCount: keys.length,
1171
+ keys: keys.slice(0, options.objectKeyLimit)
1172
+ };
1173
+ }
1174
+ const selected = entries.slice(0, options.objectKeyLimit);
1175
+ if (entries.length > options.objectKeyLimit) {
1176
+ truncation[`${pathName}.__keys`] = { total: entries.length, returned: options.objectKeyLimit };
1177
+ }
1178
+ return Object.fromEntries(selected.map(([key, entry]) => [key, compactGenericValue(entry, options, truncation, pathName === "value" ? key : `${pathName}.${key}`, depth - 1)]));
1179
+ }
1180
+ function compactSummaryArray(name, value, limit, truncation, map) {
1181
+ if (!Array.isArray(value)) {
1182
+ return value;
1183
+ }
1184
+ const returned = value.slice(0, limit).map((entry) => (map ? map(entry) : entry));
1185
+ if (value.length > limit) {
1186
+ const previous = truncation[name];
1187
+ truncation[name] = { total: Math.max(previous?.total ?? 0, value.length), returned: limit };
1188
+ }
1189
+ return returned;
1190
+ }
1191
+ function isRecord(value) {
1192
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1193
+ }
1194
+ function clampLargeStrings(value, maxLength = 1000) {
1195
+ let stringTruncations = 0;
1196
+ const visit = (entry, depth) => {
1197
+ if (typeof entry === "string") {
1198
+ if (entry.length <= maxLength) {
1199
+ return entry;
1200
+ }
1201
+ stringTruncations += 1;
1202
+ return `${entry.slice(0, maxLength - 3)}...`;
1203
+ }
1204
+ if (depth <= 0 || !entry || typeof entry !== "object") {
1205
+ return entry;
1206
+ }
1207
+ if (Array.isArray(entry)) {
1208
+ return entry.map((item) => visit(item, depth - 1));
1209
+ }
1210
+ return Object.fromEntries(Object.entries(entry).map(([key, item]) => [key, visit(item, depth - 1)]));
1211
+ };
1212
+ return { value: visit(value, 12), stringTruncations };
1213
+ }
1214
+ function structuredByteLength(value) {
1215
+ try {
1216
+ const serialized = JSON.stringify(value);
1217
+ return serialized ? Buffer.byteLength(serialized, "utf8") : 0;
1218
+ }
1219
+ catch {
1220
+ return Number.MAX_SAFE_INTEGER;
1221
+ }
1222
+ }
1223
+ function truncatedArray(name, value, limit) {
1224
+ return Array.isArray(value) && value.length > limit ? { [name]: { total: value.length, returned: limit } } : {};
1225
+ }
1226
+ function limitArray(value, limit) {
1227
+ return Array.isArray(value) ? value.slice(0, limit) : value;
1228
+ }
1229
+ function nonEmptyArray(value) {
1230
+ return Array.isArray(value) && value.length > 0;
1231
+ }
1232
+ function compactSnapshotLoad(value) {
1233
+ if (!isRecord(value)) {
1234
+ return value;
1235
+ }
1236
+ return {
1237
+ taskId: value.taskId,
1238
+ path: typeof value.path === "string" ? value.path.split("/.codex/").pop()?.replace(/^/, ".codex/") ?? value.path : value.path,
1239
+ missingReason: value.missingReason,
1240
+ error: value.error,
1241
+ recoveredLatest: value.recoveredLatest,
1242
+ ambiguousLatest: value.ambiguousLatest,
1243
+ ambiguityReason: value.ambiguityReason
1244
+ };
1245
+ }
1246
+ function stringValue(value) {
1247
+ return typeof value === "string" && value.length > 0 ? value : undefined;
1248
+ }
1249
+ //# sourceMappingURL=compaction.js.map