clinkx 0.2.3 → 0.3.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 (88) hide show
  1. package/README.md +40 -1
  2. package/conf/prompts/json-codereviewer.txt +1 -0
  3. package/conf/prompts/json.txt +1 -0
  4. package/dist/allowed-roots.d.ts +12 -0
  5. package/dist/allowed-roots.js +94 -0
  6. package/dist/allowed-roots.js.map +1 -0
  7. package/dist/context-builder/anchors.d.ts +11 -0
  8. package/dist/context-builder/anchors.js +19 -0
  9. package/dist/context-builder/anchors.js.map +1 -0
  10. package/dist/context-builder/bundle.d.ts +76 -0
  11. package/dist/context-builder/bundle.js +3573 -0
  12. package/dist/context-builder/bundle.js.map +1 -0
  13. package/dist/context-builder/codemap.d.ts +17 -0
  14. package/dist/context-builder/codemap.js +301 -0
  15. package/dist/context-builder/codemap.js.map +1 -0
  16. package/dist/context-builder/config.d.ts +60 -0
  17. package/dist/context-builder/config.js +204 -0
  18. package/dist/context-builder/config.js.map +1 -0
  19. package/dist/context-builder/delegate-packet.d.ts +182 -0
  20. package/dist/context-builder/delegate-packet.js +898 -0
  21. package/dist/context-builder/delegate-packet.js.map +1 -0
  22. package/dist/context-builder/delegate-reconstruction.d.ts +13 -0
  23. package/dist/context-builder/delegate-reconstruction.js +220 -0
  24. package/dist/context-builder/delegate-reconstruction.js.map +1 -0
  25. package/dist/context-builder/delegate-validation.d.ts +18 -0
  26. package/dist/context-builder/delegate-validation.js +367 -0
  27. package/dist/context-builder/delegate-validation.js.map +1 -0
  28. package/dist/context-builder/delegate.d.ts +24 -0
  29. package/dist/context-builder/delegate.js +133 -0
  30. package/dist/context-builder/delegate.js.map +1 -0
  31. package/dist/context-builder/diagnostics.d.ts +27 -0
  32. package/dist/context-builder/diagnostics.js +74 -0
  33. package/dist/context-builder/diagnostics.js.map +1 -0
  34. package/dist/context-builder/discovery.d.ts +118 -0
  35. package/dist/context-builder/discovery.js +1829 -0
  36. package/dist/context-builder/discovery.js.map +1 -0
  37. package/dist/context-builder/globs.d.ts +14 -0
  38. package/dist/context-builder/globs.js +175 -0
  39. package/dist/context-builder/globs.js.map +1 -0
  40. package/dist/context-builder/handler.d.ts +17 -0
  41. package/dist/context-builder/handler.js +3848 -0
  42. package/dist/context-builder/handler.js.map +1 -0
  43. package/dist/context-builder/path-signals.d.ts +7 -0
  44. package/dist/context-builder/path-signals.js +66 -0
  45. package/dist/context-builder/path-signals.js.map +1 -0
  46. package/dist/context-builder/paths.d.ts +30 -0
  47. package/dist/context-builder/paths.js +153 -0
  48. package/dist/context-builder/paths.js.map +1 -0
  49. package/dist/context-builder/progress.d.ts +15 -0
  50. package/dist/context-builder/progress.js +70 -0
  51. package/dist/context-builder/progress.js.map +1 -0
  52. package/dist/context-builder/receipt.d.ts +89 -0
  53. package/dist/context-builder/receipt.js +169 -0
  54. package/dist/context-builder/receipt.js.map +1 -0
  55. package/dist/context-builder/run-id.d.ts +7 -0
  56. package/dist/context-builder/run-id.js +31 -0
  57. package/dist/context-builder/run-id.js.map +1 -0
  58. package/dist/context-builder/schema.d.ts +431 -0
  59. package/dist/context-builder/schema.js +293 -0
  60. package/dist/context-builder/schema.js.map +1 -0
  61. package/dist/context-builder/secrets.d.ts +13 -0
  62. package/dist/context-builder/secrets.js +222 -0
  63. package/dist/context-builder/secrets.js.map +1 -0
  64. package/dist/context-builder/selection.d.ts +52 -0
  65. package/dist/context-builder/selection.js +1649 -0
  66. package/dist/context-builder/selection.js.map +1 -0
  67. package/dist/context-builder/status.d.ts +45 -0
  68. package/dist/context-builder/status.js +105 -0
  69. package/dist/context-builder/status.js.map +1 -0
  70. package/dist/context-builder/storage.d.ts +85 -0
  71. package/dist/context-builder/storage.js +746 -0
  72. package/dist/context-builder/storage.js.map +1 -0
  73. package/dist/context-builder/token-estimate.d.ts +8 -0
  74. package/dist/context-builder/token-estimate.js +17 -0
  75. package/dist/context-builder/token-estimate.js.map +1 -0
  76. package/dist/paths.d.ts +8 -0
  77. package/dist/paths.js +31 -43
  78. package/dist/paths.js.map +1 -1
  79. package/dist/pipeline.d.ts +47 -3
  80. package/dist/pipeline.js +135 -39
  81. package/dist/pipeline.js.map +1 -1
  82. package/dist/server.d.ts +1 -0
  83. package/dist/server.js +40 -10
  84. package/dist/server.js.map +1 -1
  85. package/package.json +2 -1
  86. package/dist/artifacts.d.ts +0 -9
  87. package/dist/artifacts.js +0 -24
  88. package/dist/artifacts.js.map +0 -1
@@ -0,0 +1,898 @@
1
+ import { boundContextBuilderOmissions, isRequestedEvidenceOmission, requestedEvidenceOmission, } from "./diagnostics.js";
2
+ import { normalizeContextBuilderRootRelativePath, } from "./paths.js";
3
+ import { scanHighConfidenceSecretContent, scanSecretPath } from "./secrets.js";
4
+ import { estimateContextBuilderTokensFromUtf8Bytes } from "./token-estimate.js";
5
+ export const CONTEXT_BUILDER_DELEGATE_PACKET_CAP_DEFAULTS = Object.freeze({
6
+ max_candidates: 300,
7
+ max_search_records: 300,
8
+ max_slice_records: 300,
9
+ max_omissions: 200,
10
+ max_paths_per_omission: 20,
11
+ max_total_evidence_bytes: 120_000,
12
+ max_preview_bytes: 500,
13
+ max_slice_excerpt_bytes: 1_000,
14
+ max_task_chars: 4_000,
15
+ max_packet_estimated_tokens: 44_000,
16
+ });
17
+ export const CONTEXT_BUILDER_DELEGATE_PACKET_CAP_PROFILE_DEFAULTS = Object.freeze({
18
+ handoff_small: {
19
+ max_candidates: 120,
20
+ max_search_records: 120,
21
+ max_slice_records: 120,
22
+ max_total_evidence_bytes: 60_000,
23
+ max_preview_bytes: 400,
24
+ max_slice_excerpt_bytes: 800,
25
+ max_packet_estimated_tokens: 22_000,
26
+ },
27
+ implementation_medium: {
28
+ max_candidates: 300,
29
+ max_search_records: 300,
30
+ max_slice_records: 300,
31
+ max_total_evidence_bytes: 120_000,
32
+ max_preview_bytes: 500,
33
+ max_slice_excerpt_bytes: 1_000,
34
+ max_packet_estimated_tokens: 44_000,
35
+ },
36
+ review_deep: {
37
+ max_candidates: 260,
38
+ max_search_records: 260,
39
+ max_slice_records: 260,
40
+ max_total_evidence_bytes: 100_000,
41
+ max_preview_bytes: 500,
42
+ max_slice_excerpt_bytes: 900,
43
+ max_packet_estimated_tokens: 40_000,
44
+ },
45
+ });
46
+ const MAX_CURATOR_PROPOSAL_SELECTED = 50;
47
+ const MAX_CURATOR_PROPOSAL_RANGES_PER_SELECTION = 20;
48
+ const MAX_CURATOR_PROPOSAL_WARNINGS = 50;
49
+ const MAX_CURATOR_PROPOSAL_OPEN_QUESTIONS = 50;
50
+ const MAX_DELEGATE_PACKET_JSON_BYTES = 92_000;
51
+ export function buildContextBuilderCuratorPacket(input) {
52
+ return buildContextBuilderDelegatePacket("curator", input);
53
+ }
54
+ export function buildContextBuilderFinalizerPacket(input) {
55
+ return buildContextBuilderDelegatePacket("finalizer", input);
56
+ }
57
+ export function contextBuilderCandidateId(rootIndex, path) {
58
+ return `c:${rootIndex}:${path}`;
59
+ }
60
+ export function contextBuilderRangeId(candidateId, startLine, endLine) {
61
+ return `r:${candidateId}:${startLine}-${endLine}`;
62
+ }
63
+ function buildContextBuilderDelegatePacket(purpose, input) {
64
+ const caps = normalizeCaps(input.caps, input.budget);
65
+ const state = {
66
+ caps,
67
+ evidenceBytes: 0,
68
+ evidenceByteCapHit: false,
69
+ searchIncluded: 0,
70
+ searchOmitted: 0,
71
+ sliceIncluded: 0,
72
+ sliceOmitted: 0,
73
+ };
74
+ const selectedIds = new Set(input.selection.selected.map((selected) => contextBuilderCandidateId(selected.root_index, selected.path)));
75
+ const selectedRanks = new Map(input.selection.selected.map((selected, index) => [
76
+ contextBuilderCandidateId(selected.root_index, selected.path),
77
+ index,
78
+ ]));
79
+ const selectedRanges = buildSelectedRangeIndex(input.selection.selected);
80
+ const evidence = buildCandidateEvidenceIndex(input);
81
+ const seeds = buildCandidateSeeds(input, selectedIds, selectedRanks, evidence).filter(shouldIncludeDelegateCandidateSeed);
82
+ const requestedCoverage = buildRequestedPacketCoverage(input, selectedRanges);
83
+ const requestedCoverageIndex = buildRequestedCoverageIndex(requestedCoverage);
84
+ const candidates = seeds
85
+ .map((seed) => buildPacketCandidate(seed, input, selectedRanges, requestedCoverageIndex, state))
86
+ .filter((candidate) => candidate.ranges.length > 0)
87
+ .slice(0, caps.max_candidates);
88
+ const candidatesOmittedByCountCap = Math.max(0, seeds.length - candidates.length);
89
+ const candidateLineCounts = new Map(candidates.map((candidate) => [candidate.id, candidate.line_count]));
90
+ const candidateIds = new Set(candidateLineCounts.keys());
91
+ const deterministicSelection = buildDeterministicSelection(input.selection.selected, candidateIds);
92
+ const packet = {
93
+ version: "context-builder.delegate-packet.v1",
94
+ purpose,
95
+ task: sanitizePacketText(input.task, caps.max_task_chars).text,
96
+ rules: {
97
+ local_candidate_universe_only: true,
98
+ provider_must_not_discover_paths: true,
99
+ source_authority: "server",
100
+ absolute_paths_included: false,
101
+ raw_full_content_included: false,
102
+ },
103
+ budget: input.budget,
104
+ candidates,
105
+ deterministic_selection: {
106
+ metrics: input.selection.metrics,
107
+ selected: deterministicSelection,
108
+ },
109
+ omissions: buildPacketOmissions(input.discovery.omissions, input.selection.omissions, caps),
110
+ metrics: {
111
+ discovery: input.discovery.metrics,
112
+ selection: input.selection.metrics,
113
+ candidates_included: candidates.length,
114
+ candidates_omitted_by_packet_cap: candidatesOmittedByCountCap,
115
+ search_records_included: state.searchIncluded,
116
+ search_records_omitted_by_packet_cap: state.searchOmitted,
117
+ slice_records_included: state.sliceIncluded,
118
+ slice_records_omitted_by_packet_cap: state.sliceOmitted,
119
+ evidence_bytes: state.evidenceBytes,
120
+ evidence_byte_cap_hit: state.evidenceByteCapHit,
121
+ packet_estimated_tokens: 0,
122
+ packet_token_cap_hit: false,
123
+ },
124
+ ...(purpose === "finalizer" && "curator_proposal" in input
125
+ ? {
126
+ curator_proposal: sanitizeCuratorProposal(input.curator_proposal, candidateLineCounts, caps),
127
+ local_selection_summary: {
128
+ selected: deterministicSelection,
129
+ },
130
+ }
131
+ : {}),
132
+ };
133
+ syncSelectionSummariesToCandidateRanges(packet);
134
+ enforcePacketTokenCap(packet, caps, requestedCoverageIndex);
135
+ syncCandidateCoverageToPacketRanges(packet);
136
+ syncSelectionSummariesToCandidateRanges(packet);
137
+ appendMissingRequestedCoverageOmissions(packet, requestedCoverage);
138
+ return packet;
139
+ }
140
+ function buildCandidateSeeds(input, selectedIds, selectedRanks, evidence) {
141
+ const eligibleTree = new Map();
142
+ for (const file of input.discovery.tree) {
143
+ const normalized = normalizePacketPath(file.path);
144
+ if (normalized == null ||
145
+ !file.eligible ||
146
+ !file.content_eligible ||
147
+ file.omission_reason != null) {
148
+ continue;
149
+ }
150
+ eligibleTree.set(candidateKey(file.root_index, normalized), {
151
+ ...file,
152
+ path: normalized,
153
+ });
154
+ }
155
+ const seeds = [];
156
+ for (const candidate of input.discovery.content_candidates) {
157
+ const normalized = normalizePacketPath(candidate.path);
158
+ if (normalized == null) {
159
+ continue;
160
+ }
161
+ const treeFile = eligibleTree.get(candidateKey(candidate.root_index, normalized));
162
+ if (treeFile == null) {
163
+ continue;
164
+ }
165
+ const id = contextBuilderCandidateId(candidate.root_index, normalized);
166
+ seeds.push({
167
+ id,
168
+ root_index: candidate.root_index,
169
+ path: normalized,
170
+ line_count: Math.max(0, candidate.line_count),
171
+ size_bytes: Math.max(0, treeFile.size_bytes),
172
+ estimated_tokens: estimateContextBuilderTokensFromUtf8Bytes(Math.max(0, treeFile.size_bytes)),
173
+ deterministic_selected: selectedIds.has(id),
174
+ deterministic_rank: selectedRanks.get(id) ?? Number.MAX_SAFE_INTEGER,
175
+ has_focus_evidence: evidence.focusIds.has(id),
176
+ has_slice_evidence: evidence.sliceIds.has(id),
177
+ has_search_evidence: evidence.searchIds.has(id),
178
+ });
179
+ }
180
+ return seeds.sort(compareCandidateSeeds);
181
+ }
182
+ function shouldIncludeDelegateCandidateSeed(seed) {
183
+ if (seed.has_focus_evidence) {
184
+ return true;
185
+ }
186
+ return !isWorkbenchArtifactPath(seed.path);
187
+ }
188
+ function isWorkbenchArtifactPath(path) {
189
+ return path.startsWith(".ai/") || path.includes("/.ai/");
190
+ }
191
+ function buildCandidateEvidenceIndex(input) {
192
+ const focusIds = new Set(input.discovery.slices
193
+ .filter((slice) => slice.source === "focus")
194
+ .map((slice) => contextBuilderCandidateId(slice.root_index, slice.path)));
195
+ for (const candidate of input.discovery.content_candidates) {
196
+ const normalized = normalizePacketPath(candidate.path);
197
+ if (normalized != null &&
198
+ candidateMatchesFocusPath(candidate.root_index, normalized, input.focus_paths ?? [])) {
199
+ focusIds.add(contextBuilderCandidateId(candidate.root_index, normalized));
200
+ }
201
+ }
202
+ return {
203
+ focusIds,
204
+ sliceIds: new Set(input.discovery.slices.map((slice) => contextBuilderCandidateId(slice.root_index, slice.path))),
205
+ searchIds: new Set(input.discovery.search.map((hit) => contextBuilderCandidateId(hit.root_index, hit.path))),
206
+ };
207
+ }
208
+ function candidateMatchesFocusPath(rootIndex, path, focusPaths) {
209
+ return focusPaths.some((focus) => {
210
+ if (focus.root_index !== rootIndex) {
211
+ return false;
212
+ }
213
+ if (focus.kind === "file") {
214
+ return path === focus.root_relative_path;
215
+ }
216
+ return (path === focus.root_relative_path ||
217
+ path.startsWith(`${focus.root_relative_path}/`));
218
+ });
219
+ }
220
+ function buildPacketCandidate(seed, input, selectedRanges, requestedCoverage, state) {
221
+ const ranges = buildRanges(seed, input.discovery.slices, selectedRanges.get(seed.id) ?? [], state);
222
+ const searchHits = buildSearchHits(seed, input.discovery.search, state);
223
+ const coverage = buildDeterministicCoverage(ranges, selectedRanges.get(seed.id) ?? []);
224
+ const requiredFocusRanges = (requestedCoverage.get(seed.id) ?? [])
225
+ .filter((range) => isCoveredByPacketRanges(ranges, range))
226
+ .map((range) => ({ ...range }));
227
+ return {
228
+ id: seed.id,
229
+ root_index: seed.root_index,
230
+ path: seed.path,
231
+ line_count: seed.line_count,
232
+ size_bytes: seed.size_bytes,
233
+ estimated_tokens: seed.estimated_tokens,
234
+ discovery_reason: discoveryReason(ranges, searchHits),
235
+ focus_requested: seed.has_focus_evidence,
236
+ ...(requiredFocusRanges.length === 0
237
+ ? {}
238
+ : { required_focus_ranges: requiredFocusRanges }),
239
+ deterministic_selected: seed.deterministic_selected,
240
+ deterministic_coverage: coverage.status,
241
+ deterministic_ranges: coverage.selected,
242
+ uncovered_packet_ranges: coverage.uncovered,
243
+ ranges,
244
+ search_hits: searchHits,
245
+ };
246
+ }
247
+ function buildSelectedRangeIndex(selected) {
248
+ const byCandidate = new Map();
249
+ for (const file of selected) {
250
+ const normalized = normalizePacketPath(file.path);
251
+ if (normalized == null) {
252
+ continue;
253
+ }
254
+ const candidateId = contextBuilderCandidateId(file.root_index, normalized);
255
+ byCandidate.set(candidateId, file.ranges.map((range) => ({
256
+ id: contextBuilderRangeId(candidateId, range.start_line, range.end_line),
257
+ start_line: range.start_line,
258
+ end_line: range.end_line,
259
+ })));
260
+ }
261
+ return byCandidate;
262
+ }
263
+ function buildRequestedPacketCoverage(input, selectedRanges) {
264
+ const requestedByCandidate = new Map();
265
+ const appendRange = (rootIndex, path, range) => {
266
+ const candidateId = contextBuilderCandidateId(rootIndex, path);
267
+ const coverage = requestedByCandidate.get(candidateId) ??
268
+ {
269
+ candidate_id: candidateId,
270
+ root_index: rootIndex,
271
+ path,
272
+ ranges: [],
273
+ };
274
+ if (!coverage.ranges.some((existing) => existing.start_line === range.start_line &&
275
+ existing.end_line === range.end_line)) {
276
+ coverage.ranges.push(range);
277
+ }
278
+ requestedByCandidate.set(candidateId, coverage);
279
+ };
280
+ for (const [candidateId, ranges] of selectedRanges) {
281
+ const selection = input.selection.selected.find((file) => {
282
+ const normalized = normalizePacketPath(file.path);
283
+ return (normalized != null &&
284
+ contextBuilderCandidateId(file.root_index, normalized) === candidateId);
285
+ });
286
+ if (selection == null) {
287
+ continue;
288
+ }
289
+ const normalized = normalizePacketPath(selection.path);
290
+ if (normalized == null) {
291
+ continue;
292
+ }
293
+ if (!candidateMatchesFocusPath(selection.root_index, normalized, input.focus_paths ?? [])) {
294
+ continue;
295
+ }
296
+ for (const range of ranges) {
297
+ appendRange(selection.root_index, normalized, range);
298
+ }
299
+ }
300
+ for (const slice of input.discovery.slices) {
301
+ const normalized = normalizePacketPath(slice.path);
302
+ if (normalized == null) {
303
+ continue;
304
+ }
305
+ const isRequested = slice.source === "focus" ||
306
+ candidateMatchesFocusPath(slice.root_index, normalized, input.focus_paths ?? []);
307
+ if (!isRequested) {
308
+ continue;
309
+ }
310
+ const candidateId = contextBuilderCandidateId(slice.root_index, normalized);
311
+ appendRange(slice.root_index, normalized, {
312
+ id: contextBuilderRangeId(candidateId, slice.start_line, slice.end_line),
313
+ start_line: slice.start_line,
314
+ end_line: slice.end_line,
315
+ });
316
+ }
317
+ return [...requestedByCandidate.values()].map((coverage) => ({
318
+ ...coverage,
319
+ ranges: coverage.ranges.sort((left, right) => left.start_line - right.start_line || left.end_line - right.end_line),
320
+ }));
321
+ }
322
+ function buildDeterministicCoverage(packetRanges, selectedRanges) {
323
+ const selected = selectedRanges.filter((range) => isCoveredByPacketRanges(packetRanges, range));
324
+ const uncovered = packetRanges
325
+ .filter((range) => !isCoveredByPacketRanges(selected, range))
326
+ .map((range) => ({
327
+ id: range.id,
328
+ start_line: range.start_line,
329
+ end_line: range.end_line,
330
+ }));
331
+ const status = selected.length === 0
332
+ ? "none"
333
+ : uncovered.length === 0
334
+ ? "complete"
335
+ : "partial";
336
+ return { status, selected, uncovered };
337
+ }
338
+ function buildRanges(seed, slices, deterministicRanges, state) {
339
+ const ranges = [];
340
+ const sortedSlices = [...slices].sort((left, right) => {
341
+ const leftDeterministic = sliceCoveredByRanges(left, deterministicRanges) ? 0 : 1;
342
+ const rightDeterministic = sliceCoveredByRanges(right, deterministicRanges) ? 0 : 1;
343
+ return leftDeterministic - rightDeterministic || compareSlicesForPacket(left, right);
344
+ });
345
+ for (const slice of sortedSlices) {
346
+ if (slice.root_index !== seed.root_index || slice.path !== seed.path) {
347
+ continue;
348
+ }
349
+ if (state.sliceIncluded >= state.caps.max_slice_records) {
350
+ state.sliceOmitted += 1;
351
+ continue;
352
+ }
353
+ if (!isValidRange(slice.start_line, slice.end_line, seed.line_count)) {
354
+ state.sliceOmitted += 1;
355
+ continue;
356
+ }
357
+ const excerpt = takeEvidenceText(slice.content, state.caps.max_slice_excerpt_bytes, state);
358
+ ranges.push({
359
+ id: contextBuilderRangeId(seed.id, slice.start_line, slice.end_line),
360
+ start_line: slice.start_line,
361
+ end_line: slice.end_line,
362
+ source: slice.source,
363
+ estimated_tokens: estimateContextBuilderTokensFromUtf8Bytes(Buffer.byteLength(slice.content, "utf8")),
364
+ excerpt: excerpt.text,
365
+ excerpt_truncated: excerpt.truncated,
366
+ });
367
+ state.sliceIncluded += 1;
368
+ }
369
+ return ranges;
370
+ }
371
+ function sliceCoveredByRanges(slice, ranges) {
372
+ return ranges.some((range) => range.start_line <= slice.start_line && range.end_line >= slice.end_line);
373
+ }
374
+ function buildSearchHits(seed, search, state) {
375
+ const hits = [];
376
+ for (const hit of [...search].sort(compareSearchForPacket)) {
377
+ if (hit.root_index !== seed.root_index || hit.path !== seed.path) {
378
+ continue;
379
+ }
380
+ if (state.searchIncluded >= state.caps.max_search_records) {
381
+ state.searchOmitted += 1;
382
+ continue;
383
+ }
384
+ if (!isValidLine(hit.line, seed.line_count)) {
385
+ state.searchOmitted += 1;
386
+ continue;
387
+ }
388
+ const preview = takeEvidenceText(hit.preview, state.caps.max_preview_bytes, state);
389
+ hits.push({
390
+ line: hit.line,
391
+ column: Math.max(1, hit.column),
392
+ search_term_index: Math.max(0, hit.search_term_index),
393
+ preview: preview.text,
394
+ preview_truncated: preview.truncated,
395
+ });
396
+ state.searchIncluded += 1;
397
+ }
398
+ return hits;
399
+ }
400
+ function buildDeterministicSelection(selected, candidateIds) {
401
+ return selected
402
+ .map((file) => {
403
+ const normalized = normalizePacketPath(file.path);
404
+ if (normalized == null) {
405
+ return undefined;
406
+ }
407
+ const candidateId = contextBuilderCandidateId(file.root_index, normalized);
408
+ if (!candidateIds.has(candidateId)) {
409
+ return undefined;
410
+ }
411
+ return {
412
+ candidate_id: candidateId,
413
+ root_index: file.root_index,
414
+ path: normalized,
415
+ ranges: file.ranges.map((range) => ({
416
+ id: contextBuilderRangeId(candidateId, range.start_line, range.end_line),
417
+ start_line: range.start_line,
418
+ end_line: range.end_line,
419
+ })),
420
+ source: file.source,
421
+ bytes: file.bytes,
422
+ estimated_tokens: file.estimated_tokens,
423
+ };
424
+ })
425
+ .filter((item) => item != null);
426
+ }
427
+ function sanitizeCuratorProposal(proposal, candidateLineCounts, caps) {
428
+ const maxSelected = Math.min(caps.max_candidates, MAX_CURATOR_PROPOSAL_SELECTED);
429
+ const maxRangesPerSelection = Math.min(caps.max_paths_per_omission, MAX_CURATOR_PROPOSAL_RANGES_PER_SELECTION);
430
+ const maxWarnings = Math.min(caps.max_omissions, MAX_CURATOR_PROPOSAL_WARNINGS);
431
+ const maxOpenQuestions = Math.min(caps.max_omissions, MAX_CURATOR_PROPOSAL_OPEN_QUESTIONS);
432
+ return {
433
+ selected: proposal.selected
434
+ .map((selection) => {
435
+ const lineCount = candidateLineCounts.get(selection.candidate_id);
436
+ if (lineCount == null) {
437
+ return undefined;
438
+ }
439
+ return {
440
+ candidate_id: selection.candidate_id,
441
+ ranges: selection.ranges
442
+ .filter((range) => isValidRange(range.start_line, range.end_line, lineCount))
443
+ .slice(0, maxRangesPerSelection)
444
+ .map((range) => ({
445
+ start_line: range.start_line,
446
+ end_line: range.end_line,
447
+ reason: sanitizePacketText(range.reason, caps.max_preview_bytes).text,
448
+ })),
449
+ reason: sanitizePacketText(selection.reason, caps.max_preview_bytes).text,
450
+ };
451
+ })
452
+ .filter((selection) => selection != null && selection.ranges.length > 0)
453
+ .sort((left, right) => left.candidate_id.localeCompare(right.candidate_id))
454
+ .slice(0, maxSelected),
455
+ warnings: proposal.warnings
456
+ .slice(0, maxWarnings)
457
+ .map((warning) => sanitizePacketText(warning, caps.max_preview_bytes).text),
458
+ open_questions: proposal.open_questions
459
+ .slice(0, maxOpenQuestions)
460
+ .map((question) => sanitizePacketText(question, caps.max_preview_bytes).text),
461
+ };
462
+ }
463
+ function buildPacketOmissions(discoveryOmissions, selectionOmissions, caps) {
464
+ return boundContextBuilderOmissions([...discoveryOmissions, ...selectionOmissions].map((omission) => ({
465
+ ...(omission.root_index == null ? {} : { root_index: omission.root_index }),
466
+ reason: omission.reason,
467
+ message: omission.message,
468
+ ...(omission.paths == null
469
+ ? {}
470
+ : {
471
+ paths: omission.paths
472
+ .map(normalizePacketPath)
473
+ .filter((item) => item != null),
474
+ }),
475
+ })), {
476
+ max_omissions: caps.max_omissions,
477
+ max_paths_per_omission: caps.max_paths_per_omission,
478
+ });
479
+ }
480
+ function enforcePacketTokenCap(packet, caps, requestedCoverage) {
481
+ const maxTokens = Math.max(1, caps.max_packet_estimated_tokens);
482
+ packet.metrics.packet_estimated_tokens = estimatePacketTokens(packet);
483
+ while (packet.metrics.packet_estimated_tokens > maxTokens ||
484
+ estimatePacketJsonBytes(packet) > MAX_DELEGATE_PACKET_JSON_BYTES) {
485
+ if (dropOneEvidence(packet)) {
486
+ packet.metrics.packet_token_cap_hit = true;
487
+ packet.metrics.packet_estimated_tokens = estimatePacketTokens(packet);
488
+ continue;
489
+ }
490
+ if (dropOneCuratorProposalMetadata(packet)) {
491
+ packet.metrics.packet_token_cap_hit = true;
492
+ packet.metrics.packet_estimated_tokens = estimatePacketTokens(packet);
493
+ continue;
494
+ }
495
+ if (dropOneCandidateRecord(packet, requestedCoverage)) {
496
+ packet.metrics.packet_token_cap_hit = true;
497
+ packet.metrics.packet_estimated_tokens = estimatePacketTokens(packet);
498
+ continue;
499
+ }
500
+ if (dropOneCandidate(packet, requestedCoverage)) {
501
+ packet.metrics.packet_token_cap_hit = true;
502
+ packet.metrics.packet_estimated_tokens = estimatePacketTokens(packet);
503
+ continue;
504
+ }
505
+ packet.metrics.packet_token_cap_hit = true;
506
+ packet.metrics.packet_estimated_tokens = estimatePacketTokens(packet);
507
+ return;
508
+ }
509
+ }
510
+ function dropOneEvidence(packet) {
511
+ for (const candidate of [...packet.candidates].reverse()) {
512
+ const range = candidate.ranges.at(-1);
513
+ if (range != null && range.excerpt.length > 0) {
514
+ packet.metrics.evidence_bytes -= Buffer.byteLength(range.excerpt, "utf8");
515
+ range.excerpt = "";
516
+ range.excerpt_truncated = true;
517
+ packet.metrics.evidence_byte_cap_hit = true;
518
+ return true;
519
+ }
520
+ const hit = candidate.search_hits.at(-1);
521
+ if (hit != null && hit.preview.length > 0) {
522
+ packet.metrics.evidence_bytes -= Buffer.byteLength(hit.preview, "utf8");
523
+ hit.preview = "";
524
+ hit.preview_truncated = true;
525
+ packet.metrics.evidence_byte_cap_hit = true;
526
+ return true;
527
+ }
528
+ }
529
+ return false;
530
+ }
531
+ function dropOneCuratorProposalMetadata(packet) {
532
+ const proposal = packet.curator_proposal;
533
+ if (proposal == null) {
534
+ return false;
535
+ }
536
+ if (proposal.open_questions.pop() != null) {
537
+ return true;
538
+ }
539
+ if (proposal.warnings.pop() != null) {
540
+ return true;
541
+ }
542
+ for (const selection of [...proposal.selected].reverse()) {
543
+ for (const range of [...selection.ranges].reverse()) {
544
+ if (range.reason.length > 0) {
545
+ range.reason = "";
546
+ return true;
547
+ }
548
+ }
549
+ if (selection.reason.length > 0) {
550
+ selection.reason = "";
551
+ return true;
552
+ }
553
+ }
554
+ return false;
555
+ }
556
+ function dropOneCandidateRecord(packet, requestedCoverage) {
557
+ for (const candidate of [...packet.candidates].reverse()) {
558
+ const hit = candidate.search_hits.pop();
559
+ if (hit != null) {
560
+ packet.metrics.evidence_bytes -= Buffer.byteLength(hit.preview, "utf8");
561
+ packet.metrics.search_records_omitted_by_packet_cap += 1;
562
+ return true;
563
+ }
564
+ if (candidate.ranges.length > 1) {
565
+ const range = candidate.ranges.pop();
566
+ if (range != null) {
567
+ if (!curatorProposalStillCovered(packet, candidate.id, candidate.ranges) ||
568
+ !requestedCoverageStillCovered(requestedCoverage, candidate.id, candidate.ranges)) {
569
+ candidate.ranges.push(range);
570
+ continue;
571
+ }
572
+ packet.metrics.evidence_bytes -= Buffer.byteLength(range.excerpt, "utf8");
573
+ packet.metrics.slice_records_omitted_by_packet_cap += 1;
574
+ pruneReferencesToRange(packet, candidate.id, range.id);
575
+ return true;
576
+ }
577
+ }
578
+ }
579
+ return false;
580
+ }
581
+ function dropOneCandidate(packet, requestedCoverage) {
582
+ if (packet.candidates.length <= 1) {
583
+ return false;
584
+ }
585
+ for (let index = packet.candidates.length - 1; index >= 0; index -= 1) {
586
+ const candidate = packet.candidates[index];
587
+ if (candidate == null ||
588
+ requestedCoverage.has(candidate.id) ||
589
+ wouldRemoveCuratorProposalSelection(packet, candidate.id)) {
590
+ continue;
591
+ }
592
+ packet.candidates.splice(index, 1);
593
+ packet.metrics.candidates_included = packet.candidates.length;
594
+ packet.metrics.candidates_omitted_by_packet_cap += 1;
595
+ pruneReferencesToCandidate(packet, candidate.id);
596
+ return true;
597
+ }
598
+ return false;
599
+ }
600
+ function buildRequestedCoverageIndex(requestedCoverage) {
601
+ return new Map(requestedCoverage.map((coverage) => [coverage.candidate_id, coverage.ranges]));
602
+ }
603
+ function requestedCoverageStillCovered(requestedCoverage, candidateId, remainingRanges) {
604
+ const requiredRanges = requestedCoverage.get(candidateId);
605
+ if (requiredRanges == null || requiredRanges.length === 0) {
606
+ return true;
607
+ }
608
+ return requiredRanges.every((range) => isCoveredByPacketRanges(remainingRanges, range));
609
+ }
610
+ function curatorProposalStillCovered(packet, candidateId, remainingRanges) {
611
+ const proposalSelections = packet.curator_proposal?.selected.filter((selection) => selection.candidate_id === candidateId) ?? [];
612
+ return proposalSelections.every((selection) => selection.ranges.every((range) => isCoveredByPacketRanges(remainingRanges, range)));
613
+ }
614
+ function isCoveredByPacketRanges(ranges, target) {
615
+ let nextLine = target.start_line;
616
+ for (const range of [...ranges].sort((left, right) => left.start_line - right.start_line || left.end_line - right.end_line)) {
617
+ if (range.end_line < nextLine) {
618
+ continue;
619
+ }
620
+ if (range.start_line > nextLine) {
621
+ return false;
622
+ }
623
+ nextLine = Math.max(nextLine, range.end_line + 1);
624
+ if (nextLine > target.end_line) {
625
+ return true;
626
+ }
627
+ }
628
+ return false;
629
+ }
630
+ function wouldRemoveCuratorProposalSelection(packet, candidateId) {
631
+ const proposal = packet.curator_proposal;
632
+ if (proposal == null || proposal.selected.length === 0) {
633
+ return false;
634
+ }
635
+ return proposal.selected.some((selection) => selection.candidate_id === candidateId);
636
+ }
637
+ function syncSelectionSummariesToCandidateRanges(packet) {
638
+ const synced = buildCandidateRangeSelectionSummary(packet);
639
+ packet.deterministic_selection.selected = synced;
640
+ if (packet.local_selection_summary != null) {
641
+ packet.local_selection_summary.selected = synced.map((selection) => ({
642
+ ...selection,
643
+ ranges: selection.ranges.map((range) => ({ ...range })),
644
+ }));
645
+ }
646
+ }
647
+ function appendMissingRequestedCoverageOmissions(packet, requestedCoverage) {
648
+ if (requestedCoverage.length === 0) {
649
+ return;
650
+ }
651
+ const candidateById = new Map(packet.candidates.map((candidate) => [candidate.id, candidate]));
652
+ const existingRequestedOmissionPaths = new Set(packet.omissions
653
+ .filter(isRequestedEvidenceOmission)
654
+ .flatMap((omission) => omission.paths ?? []));
655
+ for (const coverage of requestedCoverage) {
656
+ const candidate = candidateById.get(coverage.candidate_id);
657
+ const missingRanges = candidate == null
658
+ ? coverage.ranges
659
+ : coverage.ranges.filter((range) => !isCoveredByPacketRanges(candidate.ranges, range));
660
+ if (missingRanges.length === 0 || existingRequestedOmissionPaths.has(coverage.path)) {
661
+ continue;
662
+ }
663
+ packet.omissions.push(requestedEvidenceOmission({
664
+ root_index: coverage.root_index,
665
+ kind: packet.metrics.packet_token_cap_hit
666
+ ? "packet_token_cap"
667
+ : "candidate_cap",
668
+ message: packet.metrics.packet_token_cap_hit
669
+ ? "focused or selected coverage was pruned from the delegate packet token budget"
670
+ : "focused or selected coverage could not be represented within delegate packet candidate caps",
671
+ paths: [coverage.path],
672
+ }));
673
+ existingRequestedOmissionPaths.add(coverage.path);
674
+ }
675
+ }
676
+ function syncCandidateCoverageToPacketRanges(packet) {
677
+ for (const candidate of packet.candidates) {
678
+ candidate.deterministic_ranges = (candidate.deterministic_ranges ?? []).filter((range) => isCoveredByPacketRanges(candidate.ranges, range));
679
+ candidate.uncovered_packet_ranges = (candidate.uncovered_packet_ranges ?? []).filter((range) => isCoveredByPacketRanges(candidate.ranges, range));
680
+ candidate.deterministic_coverage =
681
+ candidate.deterministic_ranges.length === 0
682
+ ? "none"
683
+ : candidate.uncovered_packet_ranges.length === 0
684
+ ? "complete"
685
+ : "partial";
686
+ }
687
+ }
688
+ function buildCandidateRangeSelectionSummary(packet) {
689
+ const existing = new Map(packet.deterministic_selection.selected.map((selection) => [
690
+ selection.candidate_id,
691
+ selection,
692
+ ]));
693
+ return packet.candidates
694
+ .filter((candidate) => candidate.deterministic_selected)
695
+ .map((candidate) => {
696
+ const ranges = (candidate.deterministic_ranges ?? []).filter((range) => isCoveredByPacketRanges(candidate.ranges, range));
697
+ if (ranges.length === 0) {
698
+ return undefined;
699
+ }
700
+ const prior = existing.get(candidate.id);
701
+ return {
702
+ candidate_id: candidate.id,
703
+ root_index: candidate.root_index,
704
+ path: candidate.path,
705
+ ranges: ranges.map((range) => ({
706
+ id: range.id,
707
+ start_line: range.start_line,
708
+ end_line: range.end_line,
709
+ })),
710
+ source: prior?.source ?? candidate.ranges[0]?.source ?? "search",
711
+ bytes: prior?.bytes ?? candidate.size_bytes,
712
+ estimated_tokens: prior?.estimated_tokens ?? candidate.estimated_tokens,
713
+ };
714
+ })
715
+ .filter((selection) => selection != null);
716
+ }
717
+ function pruneReferencesToRange(packet, candidateId, rangeId) {
718
+ pruneCandidateRangeReferences(packet, candidateId, rangeId);
719
+ pruneSelectionRangeReferences(packet.deterministic_selection.selected, candidateId, rangeId);
720
+ if (packet.local_selection_summary != null) {
721
+ pruneSelectionRangeReferences(packet.local_selection_summary.selected, candidateId, rangeId);
722
+ }
723
+ }
724
+ function pruneCandidateRangeReferences(packet, candidateId, rangeId) {
725
+ const candidate = packet.candidates.find((item) => item.id === candidateId);
726
+ if (candidate == null) {
727
+ return;
728
+ }
729
+ candidate.deterministic_ranges = (candidate.deterministic_ranges ?? []).filter((range) => range.id !== rangeId);
730
+ candidate.uncovered_packet_ranges = (candidate.uncovered_packet_ranges ?? []).filter((range) => range.id !== rangeId);
731
+ candidate.deterministic_coverage =
732
+ candidate.deterministic_ranges.length === 0
733
+ ? "none"
734
+ : candidate.uncovered_packet_ranges.length === 0
735
+ ? "complete"
736
+ : "partial";
737
+ }
738
+ function pruneSelectionRangeReferences(selections, candidateId, rangeId) {
739
+ for (let index = selections.length - 1; index >= 0; index -= 1) {
740
+ const selection = selections[index];
741
+ if (selection == null || selection.candidate_id !== candidateId) {
742
+ continue;
743
+ }
744
+ selection.ranges = selection.ranges.filter((range) => range.id !== rangeId);
745
+ if (selection.ranges.length === 0) {
746
+ selections.splice(index, 1);
747
+ }
748
+ }
749
+ }
750
+ function pruneReferencesToCandidate(packet, candidateId) {
751
+ packet.deterministic_selection.selected =
752
+ packet.deterministic_selection.selected.filter((selection) => selection.candidate_id !== candidateId);
753
+ if (packet.local_selection_summary != null) {
754
+ packet.local_selection_summary.selected =
755
+ packet.local_selection_summary.selected.filter((selection) => selection.candidate_id !== candidateId);
756
+ }
757
+ if (packet.curator_proposal != null) {
758
+ packet.curator_proposal.selected = packet.curator_proposal.selected.filter((selection) => selection.candidate_id !== candidateId);
759
+ }
760
+ }
761
+ function takeEvidenceText(text, maxBytes, state) {
762
+ if (state.evidenceBytes >= state.caps.max_total_evidence_bytes) {
763
+ state.evidenceByteCapHit = true;
764
+ return { text: "", truncated: true };
765
+ }
766
+ const remaining = state.caps.max_total_evidence_bytes - state.evidenceBytes;
767
+ const bounded = sanitizePacketText(text, Math.min(maxBytes, remaining));
768
+ state.evidenceBytes += Buffer.byteLength(bounded.text, "utf8");
769
+ if (bounded.truncated || state.evidenceBytes >= state.caps.max_total_evidence_bytes) {
770
+ state.evidenceByteCapHit = true;
771
+ }
772
+ return bounded;
773
+ }
774
+ function sanitizePacketText(text, maxBytes) {
775
+ const secretSafe = scanHighConfidenceSecretContent(text).length > 0
776
+ ? "[redacted-sensitive]"
777
+ : redactAbsolutePaths(text);
778
+ return boundUtf8(secretSafe.replace(/\u0000/g, "?"), maxBytes);
779
+ }
780
+ function boundUtf8(text, maxBytes) {
781
+ const safeMax = Math.max(0, maxBytes);
782
+ let output = "";
783
+ let bytes = 0;
784
+ for (const char of text) {
785
+ const charBytes = Buffer.byteLength(char, "utf8");
786
+ if (bytes + charBytes > safeMax) {
787
+ return { text: output, truncated: true };
788
+ }
789
+ output += char;
790
+ bytes += charBytes;
791
+ }
792
+ return { text: output, truncated: false };
793
+ }
794
+ function normalizePacketPath(input) {
795
+ if (input.includes("\u0000") ||
796
+ input.startsWith("/") ||
797
+ input.startsWith("\\") ||
798
+ /^[A-Za-z]:[\\/]/.test(input)) {
799
+ return undefined;
800
+ }
801
+ try {
802
+ const normalized = normalizeContextBuilderRootRelativePath(input);
803
+ if (normalized === "" || scanSecretPath(normalized).length > 0) {
804
+ return undefined;
805
+ }
806
+ return normalized;
807
+ }
808
+ catch {
809
+ return undefined;
810
+ }
811
+ }
812
+ function normalizeCaps(caps, budget) {
813
+ const merged = {
814
+ ...CONTEXT_BUILDER_DELEGATE_PACKET_CAP_DEFAULTS,
815
+ max_packet_estimated_tokens: Math.min(budget.target_estimated_tokens, CONTEXT_BUILDER_DELEGATE_PACKET_CAP_DEFAULTS.max_packet_estimated_tokens),
816
+ ...caps,
817
+ };
818
+ return {
819
+ max_candidates: positiveInteger(merged.max_candidates),
820
+ max_search_records: positiveInteger(merged.max_search_records),
821
+ max_slice_records: positiveInteger(merged.max_slice_records),
822
+ max_omissions: positiveInteger(merged.max_omissions),
823
+ max_paths_per_omission: positiveInteger(merged.max_paths_per_omission),
824
+ max_total_evidence_bytes: positiveInteger(merged.max_total_evidence_bytes),
825
+ max_preview_bytes: positiveInteger(merged.max_preview_bytes),
826
+ max_slice_excerpt_bytes: positiveInteger(merged.max_slice_excerpt_bytes),
827
+ max_task_chars: positiveInteger(merged.max_task_chars),
828
+ max_packet_estimated_tokens: positiveInteger(merged.max_packet_estimated_tokens),
829
+ };
830
+ }
831
+ function positiveInteger(value) {
832
+ return Number.isSafeInteger(value) && value > 0 ? value : 1;
833
+ }
834
+ function discoveryReason(ranges, searchHits) {
835
+ if (ranges.some((range) => range.source === "focus")) {
836
+ return "focus_path";
837
+ }
838
+ if (searchHits.length > 0 || ranges.some((range) => range.source === "search")) {
839
+ return "search_hit";
840
+ }
841
+ return "eligible_candidate";
842
+ }
843
+ function candidateKey(rootIndex, path) {
844
+ return `${rootIndex}\u0000${path}`;
845
+ }
846
+ function isValidRange(startLine, endLine, lineCount) {
847
+ return lineCount > 0 && startLine >= 1 && endLine >= startLine && endLine <= lineCount;
848
+ }
849
+ function isValidLine(line, lineCount) {
850
+ return lineCount > 0 && line >= 1 && line <= lineCount;
851
+ }
852
+ function estimatePacketTokens(packet) {
853
+ return estimateContextBuilderTokensFromUtf8Bytes(estimatePacketJsonBytes(packet));
854
+ }
855
+ function estimatePacketJsonBytes(packet) {
856
+ return Buffer.byteLength(JSON.stringify(packet), "utf8");
857
+ }
858
+ function redactAbsolutePaths(text) {
859
+ return text
860
+ .replace(/\b[A-Za-z]:[\\/][^\s"'`)]+/g, "[redacted-absolute-path]")
861
+ .replace(/(^|[\s"'(])\/[^\s"'`)]+/g, "$1[redacted-absolute-path]");
862
+ }
863
+ function compareCandidateSeeds(left, right) {
864
+ return (booleanRank(right.has_focus_evidence) - booleanRank(left.has_focus_evidence) ||
865
+ booleanRank(right.deterministic_selected) -
866
+ booleanRank(left.deterministic_selected) ||
867
+ left.deterministic_rank - right.deterministic_rank ||
868
+ booleanRank(right.has_slice_evidence) - booleanRank(left.has_slice_evidence) ||
869
+ booleanRank(right.has_search_evidence) - booleanRank(left.has_search_evidence) ||
870
+ left.root_index - right.root_index ||
871
+ left.path.localeCompare(right.path));
872
+ }
873
+ function booleanRank(value) {
874
+ return value ? 1 : 0;
875
+ }
876
+ function compareSlicesForPacket(left, right) {
877
+ return (left.root_index - right.root_index ||
878
+ left.path.localeCompare(right.path) ||
879
+ left.start_line - right.start_line ||
880
+ left.end_line - right.end_line ||
881
+ sourceRank(left.source) - sourceRank(right.source) ||
882
+ (left.search_term_index ?? Number.MAX_SAFE_INTEGER) -
883
+ (right.search_term_index ?? Number.MAX_SAFE_INTEGER));
884
+ }
885
+ function compareSearchForPacket(left, right) {
886
+ return (left.root_index - right.root_index ||
887
+ left.path.localeCompare(right.path) ||
888
+ left.line - right.line ||
889
+ left.column - right.column ||
890
+ left.search_term_index - right.search_term_index);
891
+ }
892
+ function comparePacketSelections(left, right) {
893
+ return left.root_index - right.root_index || left.path.localeCompare(right.path);
894
+ }
895
+ function sourceRank(source) {
896
+ return source === "focus" ? 0 : 1;
897
+ }
898
+ //# sourceMappingURL=delegate-packet.js.map