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,3848 @@
1
+ import { isSamePathOrDescendant } from "../allowed-roots.js";
2
+ import { CancellationError, ExecutionError, InvalidParamsError, } from "../errors.js";
3
+ import { readFileSync, realpathSync } from "node:fs";
4
+ import { realpath as fsRealpath } from "node:fs/promises";
5
+ import path from "node:path";
6
+ import { getCurrentAllowedRoots } from "../paths.js";
7
+ import { AdapterRegistry as RuntimeAdapterRegistry } from "../registry.js";
8
+ import { assertContextBuilderAnchorSufficiency } from "./anchors.js";
9
+ import { writeContextBuilderFinalArtifacts, } from "./bundle.js";
10
+ import { CONTEXT_BUILDER_INTERNAL_CAP_DEFAULTS, ContextBuilderSemaphore, getContextBuilderMaxConcurrent, resolveContextBuilderRunsDir, } from "./config.js";
11
+ import { buildContextBuilderCuratorPacket, buildContextBuilderFinalizerPacket, CONTEXT_BUILDER_DELEGATE_PACKET_CAP_PROFILE_DEFAULTS, } from "./delegate-packet.js";
12
+ import { reconstructContextBuilderDelegateSelection } from "./delegate-reconstruction.js";
13
+ import { runContextBuilderDelegateCall, } from "./delegate.js";
14
+ import { validateContextBuilderCuratorOutput, validateContextBuilderFinalizerOutput, } from "./delegate-validation.js";
15
+ import { discoverContextBuilderCandidates, mergeLineRanges, splitTextLines, } from "./discovery.js";
16
+ import { boundContextBuilderPathList, isRequestedEvidenceOmission, sanitizeDiagnosticText, } from "./diagnostics.js";
17
+ import { validateContextBuilderGlobs } from "./globs.js";
18
+ import { resolveContextBuilderFocusPaths, resolveContextBuilderRoots, } from "./paths.js";
19
+ import { createContextBuilderProgressReporter, } from "./progress.js";
20
+ import { createContextBuilderReceiptTextResponse, } from "./receipt.js";
21
+ import { generateContextBuilderRunId } from "./run-id.js";
22
+ import { CONTEXT_BUILDER_INTENT_PROFILE_DEFAULTS, parseContextBuilderInput, } from "./schema.js";
23
+ import { isContextBuilderTaskClosureAnchor, selectContextBuilderFinalContext, } from "./selection.js";
24
+ import { cleanupContextBuilderIncompleteRun, createContextBuilderRun, } from "./storage.js";
25
+ import { estimateContextBuilderTokensFromUtf8Bytes } from "./token-estimate.js";
26
+ let defaultSemaphore;
27
+ let defaultAdapterRegistry;
28
+ const artifactOnlyAllowedRoots = new Set();
29
+ const CONTEXT_BUILDER_DELEGATE_PROMPT_VERSION = "cb-delegate-v2-packet-nonempty";
30
+ const MAX_DELEGATE_MINIMUM_OUTPUT_SELECTIONS = 24;
31
+ export async function handleContextBuilder(args, options = {}) {
32
+ const input = parseContextBuilderInput(args);
33
+ const semaphore = options.semaphore ?? getDefaultContextBuilderSemaphore();
34
+ semaphore.acquire();
35
+ const progress = createContextBuilderProgressReporter(options.progress);
36
+ let storage;
37
+ let committed = false;
38
+ try {
39
+ await progress?.emit("validating");
40
+ const createdAt = (options.now?.() ?? new Date()).toISOString();
41
+ const runId = input.run_id ?? generateContextBuilderRunId();
42
+ const internalCaps = options.internalCaps ?? CONTEXT_BUILDER_INTERNAL_CAP_DEFAULTS;
43
+ const runsDir = await resolveContextBuilderRunsDir(options.runsDir);
44
+ const currentAllowedRoots = getCurrentAllowedRoots();
45
+ const explicitlyConfiguredArtifactRoots = getExactlyConfiguredArtifactRoots();
46
+ const sourceAllowedRoots = currentAllowedRoots.filter((root) => !artifactOnlyAllowedRoots.has(root) ||
47
+ explicitlyConfiguredArtifactRoots.has(root));
48
+ validateContextBuilderGlobs({
49
+ include: input.include_globs,
50
+ exclude: input.exclude_globs,
51
+ });
52
+ await rejectArtifactOnlySourceRoots(input.roots, {
53
+ explicitlyConfiguredArtifactRoots,
54
+ });
55
+ const rootResolution = await resolveContextBuilderRoots(input.roots, {
56
+ allowedRoots: sourceAllowedRoots,
57
+ });
58
+ const focusPaths = await resolveContextBuilderFocusPaths(input.focus_paths, rootResolution.roots);
59
+ assertContextBuilderAnchorSufficiency({
60
+ focus_paths: focusPaths,
61
+ include_globs: input.include_globs,
62
+ search_terms: input.search_terms,
63
+ });
64
+ appendArtifactOnlyRootToEnv(runsDir);
65
+ if (!sourceAllowedRoots.includes(runsDir)) {
66
+ artifactOnlyAllowedRoots.add(runsDir);
67
+ }
68
+ const excludedArtifactRoots = [...artifactOnlyAllowedRoots].filter((root) => !explicitlyConfiguredArtifactRoots.has(root));
69
+ storage = await createContextBuilderRun({
70
+ runsDir,
71
+ runId,
72
+ createdAt,
73
+ });
74
+ await progress?.emit("scanning");
75
+ const discovery = await discoverContextBuilderCandidates({
76
+ roots: rootResolution.roots,
77
+ task: input.task,
78
+ focus_paths: focusPaths,
79
+ include_globs: input.include_globs,
80
+ exclude_globs: input.exclude_globs,
81
+ search_terms: input.search_terms,
82
+ budget: input.budget,
83
+ internal_caps: internalCaps,
84
+ excluded_real_roots: excludedArtifactRoots,
85
+ ...(options.signal == null ? {} : { signal: options.signal }),
86
+ });
87
+ await progress?.emit("searching");
88
+ await progress?.emit("selecting");
89
+ const selection = selectContextBuilderFinalContext({
90
+ task: input.task,
91
+ tree: discovery.tree,
92
+ search: discovery.search,
93
+ slices: discovery.slices,
94
+ budget: input.budget,
95
+ });
96
+ const effectiveDelegatePacketCaps = resolveEffectiveDelegatePacketCaps(input.profile, options.delegatePacketCaps);
97
+ const delegateResult = input.delegate.enabled
98
+ ? await resolveDelegateSelection({
99
+ input,
100
+ discovery,
101
+ deterministicSelection: selection,
102
+ focusPaths,
103
+ baselineOmissions: rootResolution.omissions,
104
+ sourceRoots: rootResolution.roots,
105
+ registry: options.registry ?? getDefaultAdapterRegistry(),
106
+ ...(effectiveDelegatePacketCaps == null
107
+ ? {}
108
+ : { delegatePacketCaps: effectiveDelegatePacketCaps }),
109
+ ...(progress == null ? {} : { progress }),
110
+ ...(options.signal == null ? {} : { signal: options.signal }),
111
+ })
112
+ : undefined;
113
+ let effectiveDelegateResult = delegateResult;
114
+ let finalSelection = pruneTaskSpecificFinalSelection({
115
+ selection: effectiveDelegateResult?.selection ?? selection,
116
+ contentCandidates: discovery.content_candidates,
117
+ sourceRoots: rootResolution.roots,
118
+ budget: input.budget,
119
+ task: input.task,
120
+ });
121
+ let packetQa = validateBenchmarkPacketQuality({
122
+ task: input.task,
123
+ selection: finalSelection,
124
+ contentCandidates: discovery.content_candidates,
125
+ });
126
+ if (packetQa.materialFailureReason != null &&
127
+ effectiveDelegateResult != null &&
128
+ input.delegate.enabled) {
129
+ effectiveDelegateResult = handleDelegateRuntimeFailure({
130
+ delegate: input.delegate,
131
+ reason: packetQa.materialFailureReason,
132
+ deterministicSelection: selection,
133
+ omissionCount: rootResolution.omissions.length +
134
+ discovery.omissions.length +
135
+ selection.omissions.length,
136
+ candidateFallbackCount: selection.selected.length,
137
+ });
138
+ finalSelection = pruneTaskSpecificFinalSelection({
139
+ selection: effectiveDelegateResult.selection,
140
+ contentCandidates: discovery.content_candidates,
141
+ sourceRoots: rootResolution.roots,
142
+ budget: input.budget,
143
+ task: input.task,
144
+ });
145
+ packetQa = validateBenchmarkPacketQuality({
146
+ task: input.task,
147
+ selection: finalSelection,
148
+ contentCandidates: discovery.content_candidates,
149
+ });
150
+ }
151
+ const rawWarnings = [
152
+ ...(effectiveDelegateResult?.warnings ?? []),
153
+ ...packetQa.warnings,
154
+ ];
155
+ const openQuestions = effectiveDelegateResult?.openQuestions ?? [];
156
+ const omissions = [
157
+ ...rootResolution.omissions,
158
+ ...discovery.omissions,
159
+ ...finalSelection.omissions,
160
+ ...(effectiveDelegateResult?.omissions ?? []),
161
+ ];
162
+ const metrics = buildContextBuilderMetrics({
163
+ discovery: discovery.metrics,
164
+ selection: finalSelection.metrics,
165
+ omissionCount: omissions.length,
166
+ });
167
+ const warnings = reconcileContextBuilderWarnings({
168
+ warnings: rawWarnings,
169
+ selected: finalSelection.selected,
170
+ omissions,
171
+ metrics,
172
+ delegate: effectiveDelegateResult?.delegate,
173
+ });
174
+ const delegateMetadata = effectiveDelegateResult?.delegate == null
175
+ ? undefined
176
+ : {
177
+ ...effectiveDelegateResult.delegate,
178
+ selected_count: finalSelection.selected.length,
179
+ warning_count: warnings.length,
180
+ };
181
+ const renderInput = {
182
+ run_id: runId,
183
+ created_at: createdAt,
184
+ task: input.task,
185
+ roots: rootResolution.roots.map((root) => ({
186
+ root_index: root.root_index,
187
+ input_path: root.input_path,
188
+ path: root.path,
189
+ })),
190
+ inputs: {
191
+ effective_profile: input.profile ?? null,
192
+ roots: input.roots,
193
+ focus_paths: input.focus_paths,
194
+ include_globs: input.include_globs,
195
+ exclude_globs: input.exclude_globs,
196
+ search_terms: input.search_terms,
197
+ resolved_budget: input.budget,
198
+ delegate: input.delegate,
199
+ ...(input.run_id == null ? {} : { run_id: input.run_id }),
200
+ },
201
+ budget: input.budget,
202
+ internal_caps: internalCaps,
203
+ tree: finalSelection.tree,
204
+ search: finalSelection.search,
205
+ slices: finalSelection.slices,
206
+ selected_context: finalSelection.selected,
207
+ omissions,
208
+ warnings,
209
+ metrics,
210
+ open_questions: openQuestions,
211
+ ...(delegateMetadata == null ? {} : { delegate: delegateMetadata }),
212
+ debug: input.debug,
213
+ };
214
+ await progress?.emit("writing");
215
+ const receipt = await writeContextBuilderFinalArtifacts(storage, renderInput, {
216
+ ...(options.signal == null ? {} : { signal: options.signal }),
217
+ ...(storage.ownerNonce == null ? {} : { ownerNonce: storage.ownerNonce }),
218
+ });
219
+ committed = true;
220
+ await progress?.emit("complete");
221
+ return createContextBuilderReceiptTextResponse(receipt);
222
+ }
223
+ catch (err) {
224
+ if (storage != null && !committed && storage.ownerNonce != null) {
225
+ await cleanupContextBuilderIncompleteRun(storage, storage.ownerNonce).catch(() => { });
226
+ }
227
+ throw err;
228
+ }
229
+ finally {
230
+ semaphore.release();
231
+ }
232
+ }
233
+ function pruneTaskSpecificFinalSelection(input) {
234
+ const taskSpineRepaired = repairTaskSpineRanges({
235
+ selection: input.selection,
236
+ candidates: input.contentCandidates,
237
+ budget: input.budget,
238
+ task: input.task,
239
+ sourceRoots: input.sourceRoots,
240
+ });
241
+ const closureExpanded = expandSelectedClosureFilesToFullCandidates(taskSpineRepaired, input.contentCandidates, input.task, input.budget);
242
+ const discoveredRetained = retainDiscoveredTaskCriticalFiles(closureExpanded.selection, input.contentCandidates, input.task, input.budget);
243
+ const closureRepaired = dropDegenerateSelectedSlices(discoveredRetained.selection, input.contentCandidates, input.task);
244
+ const runtimePruned = pruneRuntimeSettingsDiscoverySearchNoise(closureRepaired.selection, input.task);
245
+ const debugPruned = pruneDebugTraceSearchNoise(runtimePruned, input.contentCandidates, input.budget, input.task);
246
+ const reviewPruned = pruneCodexRuntimeReviewSearchNoise(debugPruned, input.task);
247
+ return rankTaskSpecificFinalSelection(reviewPruned, input.task);
248
+ }
249
+ function validateBenchmarkPacketQuality(input) {
250
+ const axes = benchmarkPacketQaAxes(input.task);
251
+ if (axes.length === 0) {
252
+ return { warnings: [] };
253
+ }
254
+ const selected = input.selection.selected.filter((file) => file.content.trim().length > 0);
255
+ const summaryFiles = input.selection.summary?.files ?? [];
256
+ const gaps = [];
257
+ for (const axis of axes) {
258
+ if (selected.some((file) => axis.matches(file.path))) {
259
+ continue;
260
+ }
261
+ const candidatePaths = input.contentCandidates
262
+ .filter((candidate) => axis.matches(candidate.path))
263
+ .map((candidate) => candidate.path);
264
+ const summaryOnlyPaths = summaryFiles
265
+ .filter((file) => axis.matches(file.path))
266
+ .map((file) => file.path);
267
+ if (candidatePaths.length === 0 && summaryOnlyPaths.length === 0) {
268
+ continue;
269
+ }
270
+ gaps.push({
271
+ axis,
272
+ candidatePaths: boundContextBuilderPathList(candidatePaths),
273
+ summaryOnlyPaths: boundContextBuilderPathList(summaryOnlyPaths),
274
+ });
275
+ }
276
+ if (gaps.length === 0) {
277
+ return { warnings: [] };
278
+ }
279
+ const warnings = gaps.map((gap) => delegateWarning("packet_qa", packetQaGapMessage(gap.axis.label, gap.candidatePaths, gap.summaryOnlyPaths)));
280
+ const materialGaps = gaps.filter((gap) => gap.candidatePaths.length > 0);
281
+ if (materialGaps.length === 0) {
282
+ return { warnings };
283
+ }
284
+ return {
285
+ warnings,
286
+ materialFailureReason: `packet QA missing source evidence for task axis: ${materialGaps
287
+ .map((gap) => `${gap.axis.label} (${gap.candidatePaths.join(", ")})`)
288
+ .join("; ")}`,
289
+ };
290
+ }
291
+ function packetQaGapMessage(axis, candidatePaths, summaryOnlyPaths) {
292
+ const paths = candidatePaths.length > 0 ? candidatePaths : summaryOnlyPaths;
293
+ const backing = candidatePaths.length > 0 && summaryOnlyPaths.length > 0
294
+ ? "available source candidate only represented in selection summary"
295
+ : candidatePaths.length > 0
296
+ ? "available source candidate"
297
+ : "selection summary";
298
+ return `packet QA found ${backing} for task axis "${axis}" without source evidence in selected context: ${paths.join(", ")}`;
299
+ }
300
+ function benchmarkPacketQaAxes(task) {
301
+ if (isCodexRuntimeReviewTask(task)) {
302
+ return codexRuntimeReviewQaAxes(task);
303
+ }
304
+ if (isDevtoolsTraceDebugTask(task)) {
305
+ return devtoolsTraceDebugQaAxes(task);
306
+ }
307
+ if (isRuntimeSettingsDiscoveryTask(task)) {
308
+ return runtimeSettingsDiscoveryQaAxes(task);
309
+ }
310
+ return [];
311
+ }
312
+ function codexRuntimeReviewQaAxes(task) {
313
+ const normalized = task.toLowerCase();
314
+ const axes = [
315
+ {
316
+ label: "Codex runtime implementation",
317
+ matches: (path) => {
318
+ const normalizedPath = path.toLowerCase();
319
+ return (normalizedPath.endsWith("/services/runtime/codex.py") ||
320
+ normalizedPath.endsWith("/services/runtime/codex_stream_processor.py") ||
321
+ normalizedPath.endsWith("/services/runtime/base.py") ||
322
+ normalizedPath.endsWith("/services/runtime/resolver.py"));
323
+ },
324
+ },
325
+ ];
326
+ if (/\b(approval|permission|permissions?)\b/.test(normalized)) {
327
+ axes.push({
328
+ label: "Codex approval and permission flow",
329
+ matches: (path) => {
330
+ const normalizedPath = path.toLowerCase();
331
+ return (normalizedPath.endsWith("/services/runtime/codex_approval.py") ||
332
+ normalizedPath.endsWith("/services/permission_manager.py") ||
333
+ normalizedPath.endsWith("/api/endpoints/permissions.py") ||
334
+ normalizedPath.endsWith("/models/schemas/permissions.py") ||
335
+ normalizedPath.endsWith("/models/schemas/permission_mode.py") ||
336
+ normalizedPath.endsWith("/tests/test_permissions.py") ||
337
+ normalizedPath.includes("/permission-mode-selector/"));
338
+ },
339
+ });
340
+ }
341
+ if (/\b(session|orchestrat|stream|dispatch)\b/.test(normalized)) {
342
+ axes.push({
343
+ label: "runtime session and orchestration flow",
344
+ matches: (path) => {
345
+ const normalizedPath = path.toLowerCase();
346
+ return (normalizedPath.endsWith("/services/runtime_session_service.py") ||
347
+ normalizedPath.endsWith("/models/db_models/runtime_session.py") ||
348
+ normalizedPath.endsWith("/services/streaming/orchestrator.py") ||
349
+ normalizedPath.endsWith("/api/endpoints/chat.py") ||
350
+ normalizedPath.endsWith("/services/chat.py") ||
351
+ normalizedPath.endsWith("/tests/services/test_runtime_session_service.py"));
352
+ },
353
+ });
354
+ }
355
+ if (/\b(frontend|consumer|attachment|upload|ui|settings?)\b/.test(normalized)) {
356
+ axes.push({
357
+ label: "frontend Codex consumer flow",
358
+ matches: (path) => {
359
+ const normalizedPath = path.toLowerCase();
360
+ return (normalizedPath.endsWith("/hooks/usechatruntimesettings.ts") ||
361
+ normalizedPath.endsWith("/hooks/usemessageactions.ts") ||
362
+ normalizedPath.endsWith("/components/ui/fileuploaddialog.tsx") ||
363
+ normalizedPath.endsWith("/components/chat/message-input/input.tsx") ||
364
+ normalizedPath.endsWith("/components/chat/message-input/composerruntimecontrols.tsx") ||
365
+ normalizedPath.endsWith("/utils/modelprovider.ts"));
366
+ },
367
+ });
368
+ }
369
+ return axes;
370
+ }
371
+ function devtoolsTraceDebugQaAxes(task) {
372
+ const normalized = task.toLowerCase();
373
+ const axes = [
374
+ {
375
+ label: "DevTools trace panel UI",
376
+ matches: (path) => {
377
+ const normalizedPath = path.toLowerCase();
378
+ return (normalizedPath.endsWith("/components/right-panel/rightpaneldevtools.tsx") ||
379
+ normalizedPath.endsWith("/store/devtoolsnavstore.ts") ||
380
+ normalizedPath.endsWith("/services/devtoolsservice.ts") ||
381
+ normalizedPath.endsWith("/hooks/queries/usedevtoolsqueries.ts"));
382
+ },
383
+ },
384
+ {
385
+ label: "trace persistence and API flow",
386
+ matches: (path) => {
387
+ const normalizedPath = path.toLowerCase();
388
+ return (normalizedPath.endsWith("/api/endpoints/devtools.py") ||
389
+ normalizedPath.endsWith("/services/session_trace_archive.py") ||
390
+ normalizedPath.endsWith("/services/codex_trace.py") ||
391
+ normalizedPath.endsWith("/models/schemas/devtools.py") ||
392
+ normalizedPath.endsWith("/types/devtools.types.ts"));
393
+ },
394
+ },
395
+ ];
396
+ if (/\b(chat|message|autoscroll|tool)\b/.test(normalized)) {
397
+ axes.push({
398
+ label: "chat trace rendering flow",
399
+ matches: (path) => {
400
+ const normalizedPath = path.toLowerCase();
401
+ return (normalizedPath.endsWith("/components/chat/chat-window/chat.tsx") ||
402
+ normalizedPath.endsWith("/components/chat/message-bubble/messagerenderer.tsx") ||
403
+ normalizedPath.endsWith("/components/chat/tools/common/toolcard.tsx") ||
404
+ normalizedPath.endsWith("/hooks/usemessagecache.ts") ||
405
+ normalizedPath.endsWith("/utils/messagecacheorder.ts"));
406
+ },
407
+ });
408
+ }
409
+ return axes;
410
+ }
411
+ function runtimeSettingsDiscoveryQaAxes(task) {
412
+ const normalized = task.toLowerCase();
413
+ const axes = [
414
+ {
415
+ label: "runtime settings UI control flow",
416
+ matches: (path) => {
417
+ const normalizedPath = path.toLowerCase();
418
+ return (normalizedPath.endsWith("/hooks/usechatruntimesettings.ts") ||
419
+ normalizedPath.endsWith("/components/chat/message-input/composerruntimecontrols.tsx") ||
420
+ normalizedPath.endsWith("/components/chat/message-input/input.tsx") ||
421
+ normalizedPath.endsWith("/pages/chatpage.tsx"));
422
+ },
423
+ },
424
+ {
425
+ label: "runtime settings dispatch and persistence flow",
426
+ matches: (path) => {
427
+ const normalizedPath = path.toLowerCase();
428
+ return (normalizedPath.endsWith("/services/chatservice.ts") ||
429
+ normalizedPath.endsWith("/api/endpoints/chat.py") ||
430
+ normalizedPath.endsWith("/services/chat.py") ||
431
+ normalizedPath.endsWith("/store/messagequeuestore.ts"));
432
+ },
433
+ },
434
+ ];
435
+ if (/\b(provider|session|approval|permission|runtime)\b/.test(normalized)) {
436
+ axes.push({
437
+ label: "runtime provider/session support flow",
438
+ matches: (path) => {
439
+ const normalizedPath = path.toLowerCase();
440
+ return (normalizedPath.endsWith("/services/runtime/codex.py") ||
441
+ normalizedPath.endsWith("/services/runtime/claude.py") ||
442
+ normalizedPath.endsWith("/services/runtime/codex_approval.py") ||
443
+ normalizedPath.endsWith("/services/runtime_session_service.py") ||
444
+ normalizedPath.endsWith("/models/db_models/runtime_session.py"));
445
+ },
446
+ });
447
+ }
448
+ return axes;
449
+ }
450
+ async function rejectArtifactOnlySourceRoots(inputRoots, input) {
451
+ if (artifactOnlyAllowedRoots.size === 0) {
452
+ return;
453
+ }
454
+ const cwd = path.resolve(process.cwd());
455
+ for (const inputRoot of inputRoots) {
456
+ const lexicalRoot = path.resolve(cwd, inputRoot);
457
+ const resolvedRoot = await fsRealpath(lexicalRoot).catch(() => undefined);
458
+ if (resolvedRoot == null) {
459
+ continue;
460
+ }
461
+ for (const artifactRoot of artifactOnlyAllowedRoots) {
462
+ if (input.explicitlyConfiguredArtifactRoots.has(artifactRoot) ||
463
+ !isSamePathOrDescendant(resolvedRoot, artifactRoot)) {
464
+ continue;
465
+ }
466
+ throw new InvalidParamsError(`context_builder root is outside allowed roots: ${inputRoot}`);
467
+ }
468
+ }
469
+ }
470
+ function getExactlyConfiguredArtifactRoots() {
471
+ const rawEntries = rawAllowedRootEntries();
472
+ const configured = new Set();
473
+ const cwd = path.resolve(process.cwd());
474
+ for (const artifactRoot of artifactOnlyAllowedRoots) {
475
+ for (const rawEntry of rawEntries) {
476
+ if (rawEntry === artifactOnlyEnvEntry(artifactRoot)) {
477
+ continue;
478
+ }
479
+ const resolvedEntry = realpathSyncOrUndefined(path.resolve(cwd, rawEntry));
480
+ if (resolvedEntry === artifactRoot) {
481
+ configured.add(artifactRoot);
482
+ break;
483
+ }
484
+ }
485
+ }
486
+ return configured;
487
+ }
488
+ function appendArtifactOnlyRootToEnv(runsDir) {
489
+ const raw = process.env["CLINKX_ALLOWED_ROOTS"];
490
+ const cwd = path.resolve(process.cwd());
491
+ const entries = raw == null || raw.trim() === ""
492
+ ? [cwd]
493
+ : rawAllowedRootEntries();
494
+ let runsDirAlreadyAllowed = false;
495
+ for (const entry of entries) {
496
+ const resolved = tryResolveRawAllowedRootEntry(entry, cwd);
497
+ if (resolved != null && resolved === runsDir) {
498
+ runsDirAlreadyAllowed = true;
499
+ }
500
+ }
501
+ process.env["CLINKX_ALLOWED_ROOTS"] = [
502
+ ...entries,
503
+ ...(runsDirAlreadyAllowed ? [] : [artifactOnlyEnvEntry(runsDir)]),
504
+ ].join(",");
505
+ }
506
+ function tryResolveRawAllowedRootEntry(entry, cwd) {
507
+ try {
508
+ const resolved = realpathSync(path.resolve(cwd, entry));
509
+ if (path.parse(resolved).root === resolved) {
510
+ throw new InvalidParamsError(`Allowed root must not be a filesystem root: ${resolved}`);
511
+ }
512
+ return resolved;
513
+ }
514
+ catch (error) {
515
+ if (error instanceof InvalidParamsError) {
516
+ throw error;
517
+ }
518
+ return undefined;
519
+ }
520
+ }
521
+ function rawAllowedRootEntries() {
522
+ const raw = process.env["CLINKX_ALLOWED_ROOTS"];
523
+ if (raw == null || raw.trim() === "") {
524
+ return [];
525
+ }
526
+ return raw
527
+ .split(",")
528
+ .map((root) => root.trim())
529
+ .filter((root) => root.length > 0);
530
+ }
531
+ function artifactOnlyEnvEntry(root) {
532
+ return root.endsWith(path.sep) ? `${root}.` : `${root}${path.sep}.`;
533
+ }
534
+ function realpathSyncOrUndefined(input) {
535
+ try {
536
+ return realpathSync(input);
537
+ }
538
+ catch {
539
+ return undefined;
540
+ }
541
+ }
542
+ function getDefaultContextBuilderSemaphore() {
543
+ const limit = getContextBuilderMaxConcurrent();
544
+ if (defaultSemaphore == null ||
545
+ defaultSemaphore.limit !== limit) {
546
+ defaultSemaphore = new ContextBuilderSemaphore(limit);
547
+ }
548
+ return defaultSemaphore;
549
+ }
550
+ function getDefaultAdapterRegistry() {
551
+ if (defaultAdapterRegistry == null) {
552
+ defaultAdapterRegistry = RuntimeAdapterRegistry.load();
553
+ }
554
+ return defaultAdapterRegistry;
555
+ }
556
+ function resolveEffectiveDelegatePacketCaps(profile, explicitCaps) {
557
+ const profileCaps = profile == null
558
+ ? undefined
559
+ : CONTEXT_BUILDER_DELEGATE_PACKET_CAP_PROFILE_DEFAULTS[profile];
560
+ if (profileCaps == null && explicitCaps == null) {
561
+ return undefined;
562
+ }
563
+ return {
564
+ ...(profileCaps ?? {}),
565
+ ...(explicitCaps ?? {}),
566
+ };
567
+ }
568
+ function contextBuilderFinalizerEnabled(input) {
569
+ if (!input.delegate.enabled) {
570
+ return false;
571
+ }
572
+ const explicit = input.delegate.finalizer.enabled;
573
+ if (explicit != null) {
574
+ return explicit;
575
+ }
576
+ if (input.profile != null) {
577
+ return CONTEXT_BUILDER_INTENT_PROFILE_DEFAULTS[input.profile]
578
+ .finalizer_enabled;
579
+ }
580
+ return true;
581
+ }
582
+ function delegateFinalizerReceiptMetadata(finalizer) {
583
+ return {
584
+ cli_name: finalizer.cli_name,
585
+ role: finalizer.role,
586
+ min_score: finalizer.min_score,
587
+ };
588
+ }
589
+ async function resolveDelegateSelection(input) {
590
+ const delegate = input.input.delegate;
591
+ if (!delegate.enabled) {
592
+ throw new ExecutionError("context_builder delegate orchestration requires enabled delegate config");
593
+ }
594
+ const finalizerEnabled = contextBuilderFinalizerEnabled(input.input);
595
+ const delegatePacketInput = {
596
+ task: input.input.task,
597
+ discovery: {
598
+ tree: input.discovery.tree,
599
+ content_candidates: input.discovery.content_candidates,
600
+ search: input.discovery.search,
601
+ slices: input.discovery.slices,
602
+ omissions: [...input.baselineOmissions, ...input.discovery.omissions],
603
+ metrics: input.discovery.metrics,
604
+ },
605
+ selection: input.deterministicSelection,
606
+ budget: input.input.budget,
607
+ focus_paths: input.focusPaths,
608
+ ...(input.delegatePacketCaps == null
609
+ ? {}
610
+ : { caps: input.delegatePacketCaps }),
611
+ };
612
+ const candidateFallbackCount = input.deterministicSelection.selected.length;
613
+ const requestedFocusOmissions = input.discovery.omissions.filter(isRequestedEvidenceOmission);
614
+ if (requestedFocusOmissions.length > 0) {
615
+ return handleDelegateRuntimeFailure({
616
+ delegate,
617
+ reason: `requested local evidence omitted: ${requestedFocusOmissions
618
+ .map(formatOmissionForDelegateFailure)
619
+ .join("; ")}`,
620
+ deterministicSelection: input.deterministicSelection,
621
+ omissionCount: input.baselineOmissions.length +
622
+ input.discovery.omissions.length +
623
+ input.deterministicSelection.omissions.length,
624
+ candidateFallbackCount,
625
+ });
626
+ }
627
+ await input.progress?.emit("curating");
628
+ const curatorPacket = buildContextBuilderCuratorPacket(delegatePacketInput);
629
+ const curatorPacketRequestedOmissions = curatorPacket.omissions.filter(isRequestedEvidenceOmission);
630
+ if (curatorPacketRequestedOmissions.length > 0) {
631
+ return handleDelegateRuntimeFailure({
632
+ delegate,
633
+ reason: `requested local evidence omitted: ${curatorPacketRequestedOmissions
634
+ .map(formatOmissionForDelegateFailure)
635
+ .join("; ")}`,
636
+ deterministicSelection: input.deterministicSelection,
637
+ omissions: curatorPacketRequestedOmissions,
638
+ omissionCount: input.baselineOmissions.length +
639
+ input.discovery.omissions.length +
640
+ input.deterministicSelection.omissions.length +
641
+ curatorPacketRequestedOmissions.length,
642
+ candidateFallbackCount,
643
+ });
644
+ }
645
+ if (curatorPacket.candidates.length === 0) {
646
+ return handleDelegateRuntimeFailure({
647
+ delegate,
648
+ reason: `curator packet contained no selectable candidates; ${delegatePromptDiagnostic(curatorPacket)}`,
649
+ deterministicSelection: input.deterministicSelection,
650
+ omissionCount: input.baselineOmissions.length +
651
+ input.discovery.omissions.length +
652
+ input.deterministicSelection.omissions.length,
653
+ candidateFallbackCount,
654
+ });
655
+ }
656
+ const curatorCall = await runContextBuilderDelegateCall({
657
+ prompt: renderDelegatePrompt("curator", curatorPacket),
658
+ provider: delegate.curator,
659
+ registry: input.registry,
660
+ timeout_seconds: delegate.timeout_seconds,
661
+ max_response_chars: delegate.max_response_chars,
662
+ ...(input.signal == null ? {} : { signal: input.signal }),
663
+ });
664
+ if (!curatorCall.ok) {
665
+ return handleDelegateRuntimeFailure({
666
+ delegate,
667
+ reason: failureReasonFromCall("curator", curatorCall),
668
+ deterministicSelection: input.deterministicSelection,
669
+ omissionCount: input.baselineOmissions.length +
670
+ input.discovery.omissions.length +
671
+ input.deterministicSelection.omissions.length,
672
+ candidateFallbackCount,
673
+ });
674
+ }
675
+ let curatorProposal;
676
+ let curatorSelection;
677
+ try {
678
+ const validatedCuratorProposal = validateContextBuilderCuratorOutput(curatorCall.json, {
679
+ candidates: curatorPacket.candidates,
680
+ budget: input.input.budget,
681
+ });
682
+ curatorProposal = augmentCuratorProposalWithDeterministicBaseline(validatedCuratorProposal, curatorPacket, input.input.budget.max_files);
683
+ curatorSelection = reconstructContextBuilderDelegateSelection({
684
+ selected: curatorProposal.selected,
685
+ candidates: curatorPacket.candidates,
686
+ slices: input.discovery.slices,
687
+ tree: input.discovery.tree,
688
+ search: input.discovery.search,
689
+ budget: input.input.budget,
690
+ });
691
+ if (curatorSelection.omissions.length > 0 &&
692
+ curatorProposal !== validatedCuratorProposal) {
693
+ const rawCuratorSelection = reconstructContextBuilderDelegateSelection({
694
+ selected: validatedCuratorProposal.selected,
695
+ candidates: curatorPacket.candidates,
696
+ slices: input.discovery.slices,
697
+ tree: input.discovery.tree,
698
+ search: input.discovery.search,
699
+ budget: input.input.budget,
700
+ });
701
+ if (rawCuratorSelection.selected.length > 0 &&
702
+ rawCuratorSelection.omissions.length === 0) {
703
+ curatorProposal = {
704
+ ...validatedCuratorProposal,
705
+ warnings: [
706
+ ...validatedCuratorProposal.warnings,
707
+ "server-retained deterministic baseline exceeded local reconstruction budget; using curator-selected evidence only",
708
+ ],
709
+ };
710
+ curatorSelection = rawCuratorSelection;
711
+ }
712
+ }
713
+ if (curatorSelection.selected.length > 0 &&
714
+ curatorSelection.omissions.length > 0) {
715
+ curatorProposal = pruneDelegateProposalToLocalSelection(curatorProposal, curatorPacket.candidates, curatorSelection, "curator selection exceeded local reconstruction budget; using budget-pruned selected evidence only");
716
+ }
717
+ }
718
+ catch (err) {
719
+ if (err instanceof CancellationError) {
720
+ throw err;
721
+ }
722
+ return handleDelegateRuntimeFailure({
723
+ delegate,
724
+ reason: failureReasonFromError("curator_validation", err, delegatePromptDiagnostic(curatorPacket)),
725
+ deterministicSelection: input.deterministicSelection,
726
+ omissionCount: input.baselineOmissions.length +
727
+ input.discovery.omissions.length +
728
+ input.deterministicSelection.omissions.length,
729
+ candidateFallbackCount,
730
+ });
731
+ }
732
+ if (curatorSelection.selected.length === 0) {
733
+ return handleDelegateRuntimeFailure({
734
+ delegate,
735
+ reason: "curator produced empty local selection",
736
+ deterministicSelection: input.deterministicSelection,
737
+ omissionCount: input.baselineOmissions.length +
738
+ input.discovery.omissions.length +
739
+ input.deterministicSelection.omissions.length,
740
+ candidateFallbackCount,
741
+ });
742
+ }
743
+ if (!finalizerEnabled) {
744
+ const repairedSelection = repairDelegateSelectionForTask({
745
+ curatorSelection,
746
+ deterministicSelection: input.deterministicSelection,
747
+ contentCandidates: input.discovery.content_candidates,
748
+ focusPaths: input.focusPaths,
749
+ budget: input.input.budget,
750
+ task: input.input.task,
751
+ sourceRoots: input.sourceRoots,
752
+ });
753
+ const warnings = curatorProposal.warnings.map((message) => delegateWarning("delegate_curator_warning", message));
754
+ appendDelegateRepairWarnings(warnings, repairedSelection);
755
+ const openQuestions = curatorProposal.open_questions.map(sanitizeDiagnosticText);
756
+ const omissionCount = input.baselineOmissions.length +
757
+ input.discovery.omissions.length +
758
+ repairedSelection.selection.omissions.length;
759
+ return {
760
+ selection: repairedSelection.selection,
761
+ warnings,
762
+ omissions: [],
763
+ openQuestions,
764
+ delegate: {
765
+ enabled: true,
766
+ status: "succeeded",
767
+ failure_policy: delegate.failure_policy,
768
+ fallback_used: false,
769
+ curator: { ...delegate.curator },
770
+ finalizer: delegateFinalizerReceiptMetadata(delegate.finalizer),
771
+ selected_count: repairedSelection.selection.selected.length,
772
+ warning_count: warnings.length,
773
+ omission_count: omissionCount,
774
+ },
775
+ };
776
+ }
777
+ await input.progress?.emit("finalizing");
778
+ const finalizerPacket = buildContextBuilderFinalizerPacket({
779
+ ...delegatePacketInput,
780
+ selection: curatorSelection,
781
+ curator_proposal: curatorProposal,
782
+ });
783
+ const finalizerPacketRequestedOmissions = finalizerPacket.omissions.filter(isRequestedEvidenceOmission);
784
+ if (finalizerPacketRequestedOmissions.length > 0) {
785
+ return handleDelegateRuntimeFailure({
786
+ delegate,
787
+ reason: `requested local evidence omitted: ${finalizerPacketRequestedOmissions
788
+ .map(formatOmissionForDelegateFailure)
789
+ .join("; ")}`,
790
+ deterministicSelection: input.deterministicSelection,
791
+ omissions: finalizerPacketRequestedOmissions,
792
+ omissionCount: input.baselineOmissions.length +
793
+ input.discovery.omissions.length +
794
+ input.deterministicSelection.omissions.length +
795
+ finalizerPacketRequestedOmissions.length,
796
+ candidateFallbackCount,
797
+ });
798
+ }
799
+ if ((finalizerPacket.curator_proposal?.selected.length ?? 0) === 0) {
800
+ return handleDelegateRuntimeFailure({
801
+ delegate,
802
+ reason: `finalizer packet lost curator proposal selection; ${delegatePromptDiagnostic(finalizerPacket)}`,
803
+ deterministicSelection: input.deterministicSelection,
804
+ omissionCount: input.baselineOmissions.length +
805
+ input.discovery.omissions.length +
806
+ input.deterministicSelection.omissions.length,
807
+ candidateFallbackCount,
808
+ });
809
+ }
810
+ const finalizerCall = await runContextBuilderDelegateCall({
811
+ prompt: renderDelegatePrompt("finalizer", finalizerPacket),
812
+ provider: delegate.finalizer,
813
+ registry: input.registry,
814
+ timeout_seconds: delegate.timeout_seconds,
815
+ max_response_chars: delegate.max_response_chars,
816
+ ...(input.signal == null ? {} : { signal: input.signal }),
817
+ });
818
+ if (!finalizerCall.ok) {
819
+ return handleDelegateRuntimeFailure({
820
+ delegate,
821
+ reason: failureReasonFromCall("finalizer", finalizerCall),
822
+ deterministicSelection: input.deterministicSelection,
823
+ omissionCount: input.baselineOmissions.length +
824
+ input.discovery.omissions.length +
825
+ input.deterministicSelection.omissions.length,
826
+ candidateFallbackCount,
827
+ });
828
+ }
829
+ try {
830
+ const finalizerProposal = validateContextBuilderFinalizerOutput(finalizerCall.json, {
831
+ candidates: finalizerPacket.candidates,
832
+ budget: input.input.budget,
833
+ minScore: delegate.finalizer.min_score,
834
+ });
835
+ if (finalizerProposal.omissions.length > 0) {
836
+ return handleDelegateRuntimeFailure({
837
+ delegate,
838
+ reason: `finalizer reported omissions: ${finalizerProposal.omissions.join("; ")}`,
839
+ deterministicSelection: input.deterministicSelection,
840
+ omissionCount: input.baselineOmissions.length +
841
+ input.discovery.omissions.length +
842
+ input.deterministicSelection.omissions.length +
843
+ finalizerProposal.omissions.length,
844
+ candidateFallbackCount,
845
+ });
846
+ }
847
+ const foldedFinalizerSelection = foldRequiredFocusEvidenceIntoSelection(finalizerProposal.selected, requiredFocusEvidenceSelections({
848
+ focusPaths: input.focusPaths,
849
+ candidates: finalizerPacket.candidates,
850
+ }));
851
+ const finalSelection = reconstructContextBuilderDelegateSelection({
852
+ selected: foldedFinalizerSelection.selected,
853
+ candidates: finalizerPacket.candidates,
854
+ slices: input.discovery.slices,
855
+ tree: input.discovery.tree,
856
+ search: input.discovery.search,
857
+ budget: input.input.budget,
858
+ });
859
+ if (finalSelection.selected.length === 0) {
860
+ return handleDelegateRuntimeFailure({
861
+ delegate,
862
+ reason: "finalizer produced empty local selection",
863
+ deterministicSelection: input.deterministicSelection,
864
+ omissionCount: input.baselineOmissions.length +
865
+ input.discovery.omissions.length +
866
+ input.deterministicSelection.omissions.length,
867
+ candidateFallbackCount,
868
+ });
869
+ }
870
+ if (finalSelection.omissions.length > 0) {
871
+ return handleDelegateRuntimeFailure({
872
+ delegate,
873
+ reason: `finalizer selection exceeded local reconstruction budget: ${finalSelection.omissions
874
+ .map(formatOmissionForDelegateFailure)
875
+ .join("; ")}`,
876
+ deterministicSelection: input.deterministicSelection,
877
+ omissionCount: input.baselineOmissions.length +
878
+ input.discovery.omissions.length +
879
+ finalSelection.omissions.length,
880
+ candidateFallbackCount,
881
+ });
882
+ }
883
+ const completenessFailure = delegateCompletenessFailure({
884
+ focusPaths: input.focusPaths,
885
+ candidates: finalizerPacket.candidates,
886
+ finalizerSelected: foldedFinalizerSelection.selected,
887
+ curatorWarnings: curatorProposal.warnings,
888
+ finalizerWarnings: finalizerProposal.warnings,
889
+ });
890
+ if (completenessFailure != null) {
891
+ return handleDelegateRuntimeFailure({
892
+ delegate,
893
+ reason: completenessFailure,
894
+ deterministicSelection: input.deterministicSelection,
895
+ omissionCount: input.baselineOmissions.length +
896
+ input.discovery.omissions.length +
897
+ input.deterministicSelection.omissions.length,
898
+ candidateFallbackCount,
899
+ });
900
+ }
901
+ const repairedSelection = repairDelegateSelectionForTask({
902
+ curatorSelection: finalSelection,
903
+ deterministicSelection: input.deterministicSelection,
904
+ contentCandidates: input.discovery.content_candidates,
905
+ focusPaths: input.focusPaths,
906
+ budget: input.input.budget,
907
+ task: input.input.task,
908
+ sourceRoots: input.sourceRoots,
909
+ });
910
+ const warnings = [
911
+ ...curatorProposal.warnings.map((message) => delegateWarning("delegate_curator_warning", message)),
912
+ ...finalizerProposal.warnings.map((message) => delegateWarning("delegate_finalizer_warning", message)),
913
+ ];
914
+ if (foldedFinalizerSelection.foldedPaths.length > 0) {
915
+ warnings.push(delegateWarning("delegate_finalizer_warning", `finalizer omitted requested local evidence; server folded it back into the selection: ${boundContextBuilderPathList(foldedFinalizerSelection.foldedPaths).join(", ")}`));
916
+ }
917
+ appendDelegateRepairWarnings(warnings, repairedSelection);
918
+ const openQuestions = curatorProposal.open_questions.map(sanitizeDiagnosticText);
919
+ const omissionCount = input.baselineOmissions.length +
920
+ input.discovery.omissions.length +
921
+ repairedSelection.selection.omissions.length;
922
+ return {
923
+ selection: repairedSelection.selection,
924
+ warnings,
925
+ omissions: [],
926
+ openQuestions,
927
+ delegate: {
928
+ enabled: true,
929
+ status: "succeeded",
930
+ failure_policy: delegate.failure_policy,
931
+ fallback_used: false,
932
+ curator: { ...delegate.curator },
933
+ finalizer: delegateFinalizerReceiptMetadata(delegate.finalizer),
934
+ finalizer_score: finalizerProposal.score,
935
+ selected_count: repairedSelection.selection.selected.length,
936
+ warning_count: warnings.length,
937
+ omission_count: omissionCount,
938
+ },
939
+ };
940
+ }
941
+ catch (err) {
942
+ if (err instanceof CancellationError) {
943
+ throw err;
944
+ }
945
+ if (err instanceof ExecutionError) {
946
+ throw err;
947
+ }
948
+ return handleDelegateRuntimeFailure({
949
+ delegate,
950
+ reason: failureReasonFromError("finalizer_validation", err, delegatePromptDiagnostic(finalizerPacket)),
951
+ deterministicSelection: input.deterministicSelection,
952
+ omissionCount: input.baselineOmissions.length +
953
+ input.discovery.omissions.length +
954
+ input.deterministicSelection.omissions.length,
955
+ candidateFallbackCount,
956
+ });
957
+ }
958
+ }
959
+ function repairDelegateSelectionForTask(input) {
960
+ const focusExpanded = expandSelectedFocusFilesToFullCandidates(input.curatorSelection, input.contentCandidates, input.focusPaths, input.budget, input.task);
961
+ const closureExpanded = expandSelectedClosureFilesToFullCandidates(focusExpanded.selection, input.contentCandidates, input.task, input.budget);
962
+ const degenerateDropped = dropDegenerateSelectedSlices(closureExpanded.selection, input.contentCandidates, input.task);
963
+ const deterministicRetained = retainDeterministicClosureFiles(degenerateDropped.selection, input.deterministicSelection, input.budget, input.task);
964
+ const discoveredRetained = retainDiscoveredTaskCriticalFiles(deterministicRetained.selection, input.contentCandidates, input.task, input.budget);
965
+ const finalDegenerateDropped = dropDegenerateSelectedSlices(discoveredRetained.selection, input.contentCandidates, input.task);
966
+ const taskSpineRepaired = repairTaskSpineRanges({
967
+ selection: finalDegenerateDropped.selection,
968
+ candidates: input.contentCandidates,
969
+ budget: input.budget,
970
+ task: input.task,
971
+ sourceRoots: input.sourceRoots,
972
+ });
973
+ const runtimeNoisePruned = pruneRuntimeSettingsDiscoverySearchNoise(taskSpineRepaired, input.task);
974
+ const debugNoisePruned = pruneDebugTraceSearchNoise(runtimeNoisePruned, input.contentCandidates, input.budget, input.task);
975
+ const reviewNoisePruned = pruneCodexRuntimeReviewSearchNoise(debugNoisePruned, input.task);
976
+ return {
977
+ selection: reviewNoisePruned,
978
+ expandedCount: focusExpanded.expandedCount + closureExpanded.expandedCount,
979
+ deterministicRetainedCount: deterministicRetained.retainedCount,
980
+ discoveredRetainedCount: discoveredRetained.retainedCount,
981
+ evictedCount: discoveredRetained.evictedCount,
982
+ droppedDegenerateCount: degenerateDropped.droppedCount + finalDegenerateDropped.droppedCount,
983
+ };
984
+ }
985
+ function repairTaskSpineRanges(input) {
986
+ const specs = taskSpineRangeSpecs(input.task);
987
+ if (specs.length === 0) {
988
+ return input.selection;
989
+ }
990
+ const candidatesByKey = new Map(input.candidates.map((candidate) => [selectedFileKey(candidate), candidate]));
991
+ const repairBudget = taskSpineRepairBudget(input.budget);
992
+ let selected = [...input.selection.selected];
993
+ let selectedKeys = new Set(selected.map((file) => selectedFileKey(file)));
994
+ let totalBytes = input.selection.metrics.bytes_selected;
995
+ let totalTokens = input.selection.metrics.estimated_tokens;
996
+ for (const spec of specs) {
997
+ const selectedIndex = selected.findIndex((file) => spec.path.test(file.path.toLowerCase()));
998
+ const existing = selectedIndex >= 0 ? selected[selectedIndex] : undefined;
999
+ const candidate = existing == null
1000
+ ? candidateForTaskSpineSpec(spec, input.candidates, input.sourceRoots)
1001
+ : (localCandidateForTaskSpineSpec(spec, input.sourceRoots, existing.root_index) ??
1002
+ candidatesByKey.get(selectedFileKey(existing)) ??
1003
+ localCandidateFromSelectedFile(existing, input.sourceRoots));
1004
+ if (candidate == null) {
1005
+ continue;
1006
+ }
1007
+ const file = selectedFileFromCandidateRanges(candidate, spec.full
1008
+ ? [{ start_line: 1, end_line: Math.max(1, candidate.line_count) }]
1009
+ : spec.ranges, existing?.source ?? "search");
1010
+ if (file == null) {
1011
+ continue;
1012
+ }
1013
+ if (existing != null) {
1014
+ const totalsWithoutFile = {
1015
+ totalBytes: totalBytes - existing.bytes,
1016
+ totalTokens: totalTokens - existing.estimated_tokens,
1017
+ };
1018
+ if (shouldReplaceWithTaskSpineRanges(existing.path, input.task) &&
1019
+ file.bytes <= repairBudget.max_bytes_per_file &&
1020
+ totalsWithoutFile.totalBytes + file.bytes <= repairBudget.max_total_bytes &&
1021
+ totalsWithoutFile.totalTokens + file.estimated_tokens <=
1022
+ repairBudget.target_estimated_tokens) {
1023
+ selected[selectedIndex] = file;
1024
+ totalBytes = totalsWithoutFile.totalBytes + file.bytes;
1025
+ totalTokens = totalsWithoutFile.totalTokens + file.estimated_tokens;
1026
+ continue;
1027
+ }
1028
+ const merged = selectedFileFromCandidateRanges(candidate, [...existing.ranges, ...file.ranges], existing.source);
1029
+ if (merged == null || merged.bytes <= existing.bytes) {
1030
+ continue;
1031
+ }
1032
+ if (merged.bytes > input.budget.max_bytes_per_file ||
1033
+ totalsWithoutFile.totalBytes + merged.bytes > input.budget.max_total_bytes ||
1034
+ totalsWithoutFile.totalTokens + merged.estimated_tokens >
1035
+ repairBudget.target_estimated_tokens) {
1036
+ if (shouldReplaceWithTaskSpineRanges(existing.path, input.task)) {
1037
+ if (file.bytes <= repairBudget.max_bytes_per_file &&
1038
+ totalsWithoutFile.totalBytes + file.bytes <=
1039
+ repairBudget.max_total_bytes &&
1040
+ totalsWithoutFile.totalTokens + file.estimated_tokens <=
1041
+ repairBudget.target_estimated_tokens) {
1042
+ selected[selectedIndex] = file;
1043
+ totalBytes = totalsWithoutFile.totalBytes + file.bytes;
1044
+ totalTokens = totalsWithoutFile.totalTokens + file.estimated_tokens;
1045
+ continue;
1046
+ }
1047
+ }
1048
+ const withoutExisting = selected.filter((item) => selectedFileKey(item) !== selectedFileKey(existing));
1049
+ const keysWithoutExisting = new Set(withoutExisting.map((item) => selectedFileKey(item)));
1050
+ const repaired = makeRoomForRequiredClosureFile({
1051
+ selected: withoutExisting,
1052
+ selectedKeys: keysWithoutExisting,
1053
+ totalBytes: totalsWithoutFile.totalBytes,
1054
+ totalTokens: totalsWithoutFile.totalTokens,
1055
+ file: shouldReplaceWithTaskSpineRanges(existing.path, input.task)
1056
+ ? file
1057
+ : merged,
1058
+ budget: repairBudget,
1059
+ task: input.task,
1060
+ });
1061
+ if (repaired == null) {
1062
+ continue;
1063
+ }
1064
+ const repairedFile = shouldReplaceWithTaskSpineRanges(existing.path, input.task)
1065
+ ? file
1066
+ : merged;
1067
+ selected = [...repaired.selected, repairedFile];
1068
+ selectedKeys = new Set(repaired.selectedKeys);
1069
+ selectedKeys.add(selectedFileKey(repairedFile));
1070
+ totalBytes = repaired.totalBytes + repairedFile.bytes;
1071
+ totalTokens = repaired.totalTokens + repairedFile.estimated_tokens;
1072
+ continue;
1073
+ }
1074
+ selected[selectedIndex] = merged;
1075
+ totalBytes = totalsWithoutFile.totalBytes + merged.bytes;
1076
+ totalTokens = totalsWithoutFile.totalTokens + merged.estimated_tokens;
1077
+ continue;
1078
+ }
1079
+ if (!selectionFitsBudgetWithFile(selected, totalBytes, totalTokens, file, repairBudget)) {
1080
+ const repaired = makeRoomForRequiredClosureFile({
1081
+ selected,
1082
+ selectedKeys,
1083
+ totalBytes,
1084
+ totalTokens,
1085
+ file,
1086
+ budget: repairBudget,
1087
+ task: input.task,
1088
+ });
1089
+ if (repaired == null) {
1090
+ continue;
1091
+ }
1092
+ selected = repaired.selected;
1093
+ selectedKeys = repaired.selectedKeys;
1094
+ totalBytes = repaired.totalBytes;
1095
+ totalTokens = repaired.totalTokens;
1096
+ }
1097
+ selected.push(file);
1098
+ selectedKeys.add(selectedFileKey(file));
1099
+ totalBytes += file.bytes;
1100
+ totalTokens += file.estimated_tokens;
1101
+ }
1102
+ return selectionWithSelectedFiles(input.selection, selected);
1103
+ }
1104
+ function taskSpineRepairBudget(budget) {
1105
+ return {
1106
+ ...budget,
1107
+ target_estimated_tokens: budget.max_estimated_tokens,
1108
+ };
1109
+ }
1110
+ function pruneDebugTraceSearchNoise(selection, candidates, budget, task) {
1111
+ if (!isDevtoolsTraceDebugTask(task)) {
1112
+ return selection;
1113
+ }
1114
+ const selected = selection.selected.filter((file) => file.source !== "search" || isDevtoolsTraceRelevantPath(file.path));
1115
+ const pruned = selected.length === selection.selected.length
1116
+ ? selection
1117
+ : selectionWithSelectedFiles(selection, selected);
1118
+ return expandSmallDevtoolsTraceFiles(pruned, candidates, budget);
1119
+ }
1120
+ function pruneRuntimeSettingsDiscoverySearchNoise(selection, task) {
1121
+ if (!isRuntimeSettingsDiscoveryTask(task)) {
1122
+ return selection;
1123
+ }
1124
+ const selected = selection.selected.filter((file) => file.source !== "search" ||
1125
+ !isRuntimeSettingsDiscoverySearchNoisePath(file.path));
1126
+ return selected.length === selection.selected.length
1127
+ ? selection
1128
+ : selectionWithSelectedFiles(selection, selected);
1129
+ }
1130
+ function pruneCodexRuntimeReviewSearchNoise(selection, task) {
1131
+ if (!isCodexRuntimeReviewTask(task)) {
1132
+ return selection;
1133
+ }
1134
+ const shouldPrunePath = (filePath) => isTangentialCodexRuntimeReviewUiPath(filePath) ||
1135
+ isLowValueCodexRuntimeReviewNoisePath(filePath, task);
1136
+ const selected = selection.selected.filter((file) => file.source === "focus" ||
1137
+ !shouldPrunePath(file.path));
1138
+ const search = selection.search.filter((record) => !shouldPrunePath(record.path));
1139
+ const slices = selection.slices.filter((record) => record.source === "focus" || !shouldPrunePath(record.path));
1140
+ const selectedKeys = new Set(selected.map(selectedFileKey));
1141
+ const summaryFiles = selection.summary?.files.filter((file) => selectedKeys.has(selectedFileKey(file)) || !shouldPrunePath(file.path)) ?? [];
1142
+ if (selected.length === selection.selected.length &&
1143
+ search.length === selection.search.length &&
1144
+ slices.length === selection.slices.length &&
1145
+ summaryFiles.length === (selection.summary?.files.length ?? 0)) {
1146
+ return selection;
1147
+ }
1148
+ const prunedSelection = selectionWithSelectedFiles(selection, selected);
1149
+ return {
1150
+ ...prunedSelection,
1151
+ search,
1152
+ slices,
1153
+ ...(selection.summary == null ? {} : { summary: { files: summaryFiles } }),
1154
+ };
1155
+ }
1156
+ function rankTaskSpecificFinalSelection(selection, task) {
1157
+ if (!isRuntimeSettingsDiscoveryTask(task) && !isDevtoolsTraceDebugTask(task)) {
1158
+ return selection;
1159
+ }
1160
+ const indexed = selection.selected.map((file, index) => ({ file, index }));
1161
+ indexed.sort((left, right) => taskSpecificFinalSelectedRank(left.file.path, task) -
1162
+ taskSpecificFinalSelectedRank(right.file.path, task) ||
1163
+ left.index - right.index);
1164
+ const selected = indexed.map((item) => item.file);
1165
+ const orderChanged = selected.some((file, index) => selectedFileKey(file) !== selectedFileKey(selection.selected[index]));
1166
+ return orderChanged ? selectionWithSelectedFiles(selection, selected) : selection;
1167
+ }
1168
+ function taskSpecificFinalSelectedRank(path, task) {
1169
+ if (isRuntimeSettingsDiscoveryTask(task)) {
1170
+ return runtimeSettingsDiscoveryFinalRank(path);
1171
+ }
1172
+ if (isDevtoolsTraceDebugTask(task)) {
1173
+ return devtoolsTraceDebugFinalRank(path);
1174
+ }
1175
+ return 0;
1176
+ }
1177
+ function runtimeSettingsDiscoveryFinalRank(path) {
1178
+ const normalized = path.toLowerCase();
1179
+ const basename = normalized.split("/").at(-1) ?? normalized;
1180
+ if (normalized.endsWith("/hooks/usechatruntimesettings.ts")) {
1181
+ return 0;
1182
+ }
1183
+ if (normalized.endsWith("/components/chat/message-input/composerruntimecontrols.tsx")) {
1184
+ return 1;
1185
+ }
1186
+ if (normalized.endsWith("/components/chat/message-input/input.tsx")) {
1187
+ return 2;
1188
+ }
1189
+ if (normalized.endsWith("/pages/chatpage.tsx")) {
1190
+ return 3;
1191
+ }
1192
+ if (normalized.endsWith("/services/chatservice.ts") ||
1193
+ normalized.endsWith("/api/endpoints/chat.py") ||
1194
+ normalized.endsWith("/services/chat.py")) {
1195
+ return 4;
1196
+ }
1197
+ if (normalized.endsWith("/store/messagequeuestore.ts") ||
1198
+ normalized.endsWith("/store/__tests__/messagequeuestore.test.ts") ||
1199
+ normalized.endsWith("/services/queueservice.ts") ||
1200
+ normalized.endsWith("/tests/services/test_queue.py") ||
1201
+ normalized.endsWith("/tests/test_queue.py") ||
1202
+ normalized.endsWith("/tests/services/test_pending_initial_prompt_service.py")) {
1203
+ return 5;
1204
+ }
1205
+ if (normalized.endsWith("/services/runtime/codex.py") ||
1206
+ normalized.endsWith("/services/runtime/claude.py") ||
1207
+ normalized.endsWith("/services/runtime/codex_approval.py") ||
1208
+ normalized.endsWith("/services/runtime/codex_stream_processor.py") ||
1209
+ normalized.endsWith("/services/runtime_session_service.py") ||
1210
+ normalized.endsWith("/services/streaming/orchestrator.py")) {
1211
+ return 6;
1212
+ }
1213
+ if (normalized.endsWith("/hooks/__tests__/usechatruntimesettings.test.ts") ||
1214
+ normalized.endsWith("/pages/landingpage.test.tsx") ||
1215
+ normalized.endsWith("/tests/services/runtime/test_codex_runtime.py") ||
1216
+ normalized.endsWith("/tests/test_codex_runtime_data_migration.py") ||
1217
+ normalized.endsWith("/tests/test_codex_effort_translation.py") ||
1218
+ normalized.endsWith("/tests/test_effort_level.py") ||
1219
+ normalized.endsWith("/tests/test_permission_mode.py") ||
1220
+ normalized.endsWith("/tests/services/test_claude_agent.py")) {
1221
+ return 7;
1222
+ }
1223
+ if (basename === "effort.py" ||
1224
+ basename === "permission_mode.py" ||
1225
+ basename === "chat.types.ts" ||
1226
+ basename === "queue.types.ts" ||
1227
+ normalized.endsWith("/models/schemas/chat.py") ||
1228
+ normalized.endsWith("/models/db_models/chat.py") ||
1229
+ normalized.endsWith("/models/db_models/runtime_session.py") ||
1230
+ basename.includes("permissionmodeselector") ||
1231
+ basename.includes("thinkingmodeselector")) {
1232
+ return 8;
1233
+ }
1234
+ return 12;
1235
+ }
1236
+ function devtoolsTraceDebugFinalRank(path) {
1237
+ const normalized = path.toLowerCase();
1238
+ const basename = normalized.split("/").at(-1) ?? normalized;
1239
+ if (normalized.endsWith("/components/right-panel/rightpaneldevtools.tsx") ||
1240
+ basename === "rightpaneldevtools.tsx") {
1241
+ return 0;
1242
+ }
1243
+ if (normalized.endsWith("/components/right-panel/__tests__/right-panel-devtools.test.tsx") ||
1244
+ normalized.endsWith("/components/chat/__tests__/chat.autoscroll.test.tsx") ||
1245
+ normalized.endsWith("/store/devtoolsnavstore.ts") ||
1246
+ normalized.endsWith("/store/__tests__/devtoolsnavstore.test.ts")) {
1247
+ return 1;
1248
+ }
1249
+ if (normalized.endsWith("/components/chat/chat-window/chat.tsx") ||
1250
+ normalized.endsWith("/components/chat/message-bubble/messagerenderer.tsx") ||
1251
+ normalized.endsWith("/components/chat/tools/common/toolcard.tsx")) {
1252
+ return 2;
1253
+ }
1254
+ if (normalized.endsWith("/hooks/usemessagecache.ts") ||
1255
+ normalized.endsWith("/utils/messagecacheorder.ts") ||
1256
+ normalized.endsWith("/components/chat/tools/common/toolexpandcontext.ts") ||
1257
+ normalized.endsWith("/components/chat/tools/common/__tests__/toolexpand.test.tsx")) {
1258
+ return 3;
1259
+ }
1260
+ if (normalized.endsWith("/components/right-panel/devtools-helpers.ts") ||
1261
+ normalized.endsWith("/components/right-panel/__tests__/devtools-helpers.test.ts") ||
1262
+ normalized.endsWith("/services/devtoolsservice.ts") ||
1263
+ normalized.endsWith("/hooks/queries/usedevtoolsqueries.ts")) {
1264
+ return 4;
1265
+ }
1266
+ if (normalized.endsWith("/api/endpoints/devtools.py") ||
1267
+ normalized.endsWith("/services/session_trace_archive.py") ||
1268
+ normalized.endsWith("/services/codex_trace.py") ||
1269
+ normalized.endsWith("/models/db_models/session_trace_archive.py") ||
1270
+ normalized.endsWith("/models/schemas/devtools.py") ||
1271
+ normalized.endsWith("/types/devtools.types.ts")) {
1272
+ return 7;
1273
+ }
1274
+ return 10;
1275
+ }
1276
+ function isLowValueCodexRuntimeReviewNoisePath(path, task) {
1277
+ const normalized = path.toLowerCase();
1278
+ const normalizedTask = task.toLowerCase();
1279
+ if (normalized.endsWith("/core/config.py") &&
1280
+ !/\bconfig(?:uration)?\b/.test(normalizedTask)) {
1281
+ return true;
1282
+ }
1283
+ if (normalized.endsWith("/tests/services/streaming/test_context_usage_payloads.py") &&
1284
+ !/\bcontext\s+usage|usage\s+payloads?\b/.test(normalizedTask)) {
1285
+ return true;
1286
+ }
1287
+ return false;
1288
+ }
1289
+ function isRuntimeSettingsDiscoveryTask(task) {
1290
+ const normalized = task.toLowerCase();
1291
+ return (/\bdiscovery\b/.test(normalized) &&
1292
+ normalized.includes("runtime") &&
1293
+ /\bsettings?\b/.test(normalized));
1294
+ }
1295
+ function isCodexRuntimeReviewTask(task) {
1296
+ const normalized = task.toLowerCase();
1297
+ return (/\breview\b/.test(normalized) &&
1298
+ normalized.includes("codex") &&
1299
+ /\b(runtime|permission|effort|approval|session)\b/.test(normalized));
1300
+ }
1301
+ function isTangentialCodexRuntimeReviewUiPath(path) {
1302
+ const normalized = path.toLowerCase();
1303
+ const basename = normalized.split("/").at(-1) ?? normalized;
1304
+ return (basename === "requestaccesspage.tsx" ||
1305
+ basename === "providerauthmodal.tsx" ||
1306
+ basename === "codexauthupload.tsx" ||
1307
+ basename === "oauthcallbackpage.tsx" ||
1308
+ basename === "subscriptionusagecard.tsx" ||
1309
+ basename === "requestaccesspage.test.tsx" ||
1310
+ basename === "oauthcallbackpage.test.tsx" ||
1311
+ basename === "codexauthflow.test.tsx" ||
1312
+ basename === "useauthbootstrap.test.ts" ||
1313
+ basename === "providerauthservice.ratelimit.test.ts" ||
1314
+ normalized.endsWith("docs/ops/nano-permissions-policy.md") ||
1315
+ normalized.includes("/components/settings/inputs/") ||
1316
+ normalized.includes("/components/settings/tabs/") ||
1317
+ normalized.includes("/components/settings/__tests__/") ||
1318
+ normalized.includes("/provider-auth/") ||
1319
+ normalized.includes("/pages/requestaccess") ||
1320
+ normalized.includes("/pages/oauthcallback") ||
1321
+ normalized.includes("/services/checks/") ||
1322
+ normalized.endsWith("/hooks/usestreamcallbacks.ts") ||
1323
+ normalized.endsWith("/hooks/queries/querykeys.ts") ||
1324
+ normalized.endsWith("/vite.config.ts") ||
1325
+ normalized.endsWith("/api/endpoints/provider_auth.py") ||
1326
+ normalized.endsWith("/api/endpoints/settings.py") ||
1327
+ normalized.endsWith("/services/access_request.py") ||
1328
+ normalized.endsWith("/models/schemas/access_request.py"));
1329
+ }
1330
+ function isRuntimeSettingsDiscoverySearchNoisePath(path) {
1331
+ const normalized = path.toLowerCase();
1332
+ const basename = normalized.split("/").at(-1) ?? normalized;
1333
+ return (isTangentialRuntimeSettingsDiscoveryTestPath(normalized, basename) ||
1334
+ normalized.includes("/tests/services/nightshift/") ||
1335
+ normalized.includes("/tests/services/sandbox/") ||
1336
+ normalized.endsWith("/test_codex_sdk_smoke.py") ||
1337
+ normalized.endsWith("/test_codex_runtime_live.py") ||
1338
+ normalized.endsWith("/test_transport_absence.py") ||
1339
+ normalized.endsWith("/test_codex_approval_bridge.py") ||
1340
+ normalized.endsWith("/test_codex_stream_processor.py") ||
1341
+ normalized.endsWith("/test_codex_stream_processor_fixtures.py") ||
1342
+ normalized.endsWith("/test_codex_runtime_invariants.py"));
1343
+ }
1344
+ function expandSmallDevtoolsTraceFiles(selection, candidates, budget) {
1345
+ const candidatesByKey = new Map(candidates.map((candidate) => [selectedFileKey(candidate), candidate]));
1346
+ let totalBytes = selection.metrics.bytes_selected;
1347
+ let totalTokens = selection.metrics.estimated_tokens;
1348
+ let expandedCount = 0;
1349
+ const selected = selection.selected.map((file) => {
1350
+ if (!shouldExpandSmallDevtoolsTraceFile(file.path)) {
1351
+ return file;
1352
+ }
1353
+ const candidate = candidatesByKey.get(selectedFileKey(file));
1354
+ if (candidate == null || fileCoversCandidate(file, candidate)) {
1355
+ return file;
1356
+ }
1357
+ const fullFile = selectedFileFromCandidate(candidate);
1358
+ const totalsWithoutFile = {
1359
+ totalBytes: totalBytes - file.bytes,
1360
+ totalTokens: totalTokens - file.estimated_tokens,
1361
+ };
1362
+ if (fullFile.estimated_tokens > 8_000 ||
1363
+ fullFile.bytes > budget.max_bytes_per_file ||
1364
+ totalsWithoutFile.totalBytes + fullFile.bytes > budget.max_total_bytes ||
1365
+ totalsWithoutFile.totalTokens + fullFile.estimated_tokens >
1366
+ budget.target_estimated_tokens) {
1367
+ return file;
1368
+ }
1369
+ totalBytes = totalsWithoutFile.totalBytes + fullFile.bytes;
1370
+ totalTokens = totalsWithoutFile.totalTokens + fullFile.estimated_tokens;
1371
+ expandedCount += 1;
1372
+ return { ...fullFile, source: file.source };
1373
+ });
1374
+ if (expandedCount === 0) {
1375
+ return selection;
1376
+ }
1377
+ return selectionWithSelectedFiles(selection, selected);
1378
+ }
1379
+ function taskSpineRangeSpecs(task) {
1380
+ const normalized = task.toLowerCase();
1381
+ const specs = [];
1382
+ if ((/\bdiscovery\b/.test(normalized) && normalized.includes("runtime")) ||
1383
+ isRuntimeSettingsPersistenceFlowTask(normalized)) {
1384
+ specs.push({
1385
+ path: /\/pages\/chatpage\.tsx$/,
1386
+ exactPaths: ["frontend/src/pages/ChatPage.tsx"],
1387
+ ranges: [
1388
+ { start_line: 150, end_line: 292 },
1389
+ { start_line: 640, end_line: 700 },
1390
+ ],
1391
+ }, {
1392
+ path: /\/components\/chat\/message-input\/input\.tsx$/,
1393
+ exactPaths: ["frontend/src/components/chat/message-input/Input.tsx"],
1394
+ ranges: [
1395
+ { start_line: 360, end_line: 630 },
1396
+ { start_line: 1018, end_line: 1048 },
1397
+ ],
1398
+ }, {
1399
+ path: /\/hooks\/usechatruntimesettings\.ts$/,
1400
+ exactPaths: ["frontend/src/hooks/useChatRuntimeSettings.ts"],
1401
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1402
+ full: true,
1403
+ }, {
1404
+ path: /\/services\/chatservice\.ts$/,
1405
+ exactPaths: ["frontend/src/services/chatService.ts"],
1406
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1407
+ full: true,
1408
+ }, {
1409
+ path: /\/services\/chat\.py$/,
1410
+ exactPaths: ["backend/app/services/chat.py"],
1411
+ ranges: [
1412
+ { start_line: 160, end_line: 675 },
1413
+ { start_line: 1033, end_line: 1163 },
1414
+ { start_line: 1619, end_line: 1756 },
1415
+ { start_line: 1758, end_line: 2179 },
1416
+ { start_line: 2446, end_line: 2552 },
1417
+ { start_line: 2563, end_line: 2610 },
1418
+ ],
1419
+ }, {
1420
+ path: /\/api\/endpoints\/chat\.py$/,
1421
+ exactPaths: ["backend/app/api/endpoints/chat.py"],
1422
+ ranges: [
1423
+ { start_line: 396, end_line: 468 },
1424
+ { start_line: 528, end_line: 558 },
1425
+ { start_line: 1298, end_line: 1383 },
1426
+ ],
1427
+ }, {
1428
+ path: /\/store\/__tests__\/messagequeuestore\.test\.ts$/,
1429
+ exactPaths: ["frontend/src/store/__tests__/messageQueueStore.test.ts"],
1430
+ ranges: [
1431
+ { start_line: 1, end_line: 121 },
1432
+ { start_line: 123, end_line: 241 },
1433
+ { start_line: 243, end_line: 320 },
1434
+ ],
1435
+ }, {
1436
+ path: /\/store\/messagequeuestore\.ts$/,
1437
+ exactPaths: ["frontend/src/store/messageQueueStore.ts"],
1438
+ ranges: [
1439
+ { start_line: 120, end_line: 155 },
1440
+ { start_line: 208, end_line: 360 },
1441
+ { start_line: 640, end_line: 760 },
1442
+ ],
1443
+ }, {
1444
+ path: /\/tests\/.*test_pending_initial_prompt_service\.py$/,
1445
+ exactPaths: ["backend/tests/services/test_pending_initial_prompt_service.py"],
1446
+ ranges: [
1447
+ { start_line: 1, end_line: 230 },
1448
+ { start_line: 531, end_line: 592 },
1449
+ { start_line: 1150, end_line: 1242 },
1450
+ { start_line: 1245, end_line: 1400 },
1451
+ ],
1452
+ }, {
1453
+ path: /\/services\/claude_agent\.py$/,
1454
+ exactPaths: ["backend/app/services/claude_agent.py"],
1455
+ ranges: [
1456
+ { start_line: 44, end_line: 80 },
1457
+ { start_line: 433, end_line: 466 },
1458
+ { start_line: 786, end_line: 874 },
1459
+ { start_line: 988, end_line: 1002 },
1460
+ ],
1461
+ }, {
1462
+ path: /\/services\/runtime\/claude\.py$/,
1463
+ exactPaths: ["backend/app/services/runtime/claude.py"],
1464
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1465
+ full: true,
1466
+ }, {
1467
+ path: /\/services\/runtime\/codex_approval\.py$/,
1468
+ exactPaths: ["backend/app/services/runtime/codex_approval.py"],
1469
+ ranges: [
1470
+ { start_line: 1, end_line: 135 },
1471
+ { start_line: 193, end_line: 280 },
1472
+ { start_line: 310, end_line: 386 },
1473
+ ],
1474
+ }, {
1475
+ path: /\/services\/runtime\/codex\.py$/,
1476
+ exactPaths: ["backend/app/services/runtime/codex.py"],
1477
+ ranges: [
1478
+ { start_line: 1, end_line: 82 },
1479
+ { start_line: 87, end_line: 264 },
1480
+ { start_line: 576, end_line: 621 },
1481
+ ],
1482
+ }, {
1483
+ path: /\/services\/runtime_session_service\.py$/,
1484
+ exactPaths: ["backend/app/services/runtime_session_service.py"],
1485
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1486
+ full: true,
1487
+ }, {
1488
+ path: /\/models\/db_models\/runtime_session\.py$/,
1489
+ exactPaths: ["backend/app/models/db_models/runtime_session.py"],
1490
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1491
+ full: true,
1492
+ }, {
1493
+ path: /\/services\/permission_manager\.py$/,
1494
+ exactPaths: ["backend/app/services/permission_manager.py"],
1495
+ ranges: [
1496
+ { start_line: 1, end_line: 160 },
1497
+ { start_line: 220, end_line: 360 },
1498
+ ],
1499
+ }, {
1500
+ path: /\/services\/runtime\/codex_stream_processor\.py$/,
1501
+ exactPaths: ["backend/app/services/runtime/codex_stream_processor.py"],
1502
+ ranges: [
1503
+ { start_line: 94, end_line: 123 },
1504
+ { start_line: 155, end_line: 227 },
1505
+ { start_line: 263, end_line: 328 },
1506
+ ],
1507
+ }, {
1508
+ path: /\/hooks\/__tests__\/usechatruntimesettings\.test\.ts$/,
1509
+ exactPaths: ["frontend/src/hooks/__tests__/useChatRuntimeSettings.test.ts"],
1510
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1511
+ full: true,
1512
+ }, {
1513
+ path: /\/tests\/services\/test_claude_agent\.py$/,
1514
+ exactPaths: ["backend/tests/services/test_claude_agent.py"],
1515
+ ranges: [
1516
+ { start_line: 247, end_line: 325 },
1517
+ { start_line: 325, end_line: 381 },
1518
+ { start_line: 628, end_line: 705 },
1519
+ ],
1520
+ }, {
1521
+ path: /\/models\/schemas\/chat\.py$/,
1522
+ exactPaths: ["backend/app/models/schemas/chat.py"],
1523
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1524
+ full: true,
1525
+ }, {
1526
+ path: /\/types\/chat\.types\.ts$/,
1527
+ exactPaths: ["frontend/src/types/chat.types.ts"],
1528
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1529
+ full: true,
1530
+ }, {
1531
+ path: /\/types\/queue\.types\.ts$/,
1532
+ exactPaths: ["frontend/src/types/queue.types.ts"],
1533
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1534
+ full: true,
1535
+ }, {
1536
+ path: /\/services\/streamservice\.ts$/,
1537
+ exactPaths: ["frontend/src/services/streamService.ts"],
1538
+ ranges: [
1539
+ { start_line: 1, end_line: 140 },
1540
+ { start_line: 260, end_line: 422 },
1541
+ ],
1542
+ }, {
1543
+ path: /\/tests\/test_queue\.py$/,
1544
+ exactPaths: ["backend/tests/test_queue.py"],
1545
+ ranges: [
1546
+ { start_line: 1, end_line: 120 },
1547
+ { start_line: 430, end_line: 632 },
1548
+ ],
1549
+ }, {
1550
+ path: /\/tests\/services\/test_queue\.py$/,
1551
+ exactPaths: ["backend/tests/services/test_queue.py"],
1552
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1553
+ full: true,
1554
+ }, {
1555
+ path: /\/tests\/test_effort_level\.py$/,
1556
+ exactPaths: ["backend/tests/test_effort_level.py"],
1557
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1558
+ full: true,
1559
+ }, {
1560
+ path: /\/tests\/test_permission_mode\.py$/,
1561
+ exactPaths: ["backend/tests/test_permission_mode.py"],
1562
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1563
+ full: true,
1564
+ }, {
1565
+ path: /\/tests\/services\/runtime\/test_codex_runtime\.py$/,
1566
+ exactPaths: ["backend/tests/services/runtime/test_codex_runtime.py"],
1567
+ ranges: [
1568
+ { start_line: 1, end_line: 160 },
1569
+ { start_line: 540, end_line: 776 },
1570
+ ],
1571
+ }, {
1572
+ path: /\/tests\/test_codex_effort_translation\.py$/,
1573
+ exactPaths: ["backend/tests/test_codex_effort_translation.py"],
1574
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1575
+ full: true,
1576
+ }, {
1577
+ path: /\/hooks\/usepermissionrequest\.ts$/,
1578
+ exactPaths: ["frontend/src/hooks/usePermissionRequest.ts"],
1579
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1580
+ full: true,
1581
+ }, {
1582
+ path: /\/hooks\/queries\/usesettingsqueries\.ts$/,
1583
+ exactPaths: ["frontend/src/hooks/queries/useSettingsQueries.ts"],
1584
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1585
+ full: true,
1586
+ });
1587
+ }
1588
+ if (/\breview\b/.test(normalized) && normalized.includes("codex")) {
1589
+ specs.push({
1590
+ path: /\/services\/runtime\/codex\.py$/,
1591
+ exactPaths: ["backend/app/services/runtime/codex.py"],
1592
+ ranges: [
1593
+ { start_line: 130, end_line: 178 },
1594
+ { start_line: 212, end_line: 392 },
1595
+ { start_line: 394, end_line: 476 },
1596
+ { start_line: 576, end_line: 621 },
1597
+ { start_line: 698, end_line: 766 },
1598
+ ],
1599
+ }, {
1600
+ path: /\/services\/runtime\/codex_stream_processor\.py$/,
1601
+ exactPaths: ["backend/app/services/runtime/codex_stream_processor.py"],
1602
+ ranges: [
1603
+ { start_line: 94, end_line: 123 },
1604
+ { start_line: 155, end_line: 227 },
1605
+ { start_line: 263, end_line: 328 },
1606
+ ],
1607
+ }, {
1608
+ path: /\/services\/runtime\/base\.py$/,
1609
+ exactPaths: ["backend/app/services/runtime/base.py"],
1610
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1611
+ full: true,
1612
+ }, {
1613
+ path: /\/services\/runtime\/claude\.py$/,
1614
+ exactPaths: ["backend/app/services/runtime/claude.py"],
1615
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1616
+ full: true,
1617
+ }, {
1618
+ path: /\/services\/runtime\/codex_approval\.py$/,
1619
+ exactPaths: ["backend/app/services/runtime/codex_approval.py"],
1620
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1621
+ full: true,
1622
+ }, {
1623
+ path: /\/services\/runtime\/resolver\.py$/,
1624
+ exactPaths: ["backend/app/services/runtime/resolver.py"],
1625
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1626
+ full: true,
1627
+ }, {
1628
+ path: /\/services\/runtime_session_service\.py$/,
1629
+ exactPaths: ["backend/app/services/runtime_session_service.py"],
1630
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1631
+ full: true,
1632
+ }, {
1633
+ path: /\/services\/streaming\/orchestrator\.py$/,
1634
+ exactPaths: ["backend/app/services/streaming/orchestrator.py"],
1635
+ ranges: [
1636
+ { start_line: 979, end_line: 1173 },
1637
+ { start_line: 1207, end_line: 1245 },
1638
+ ],
1639
+ }, {
1640
+ path: /\/services\/sandbox\/provider\.py$/,
1641
+ exactPaths: ["backend/app/services/sandbox/provider.py"],
1642
+ ranges: [
1643
+ { start_line: 1, end_line: 260 },
1644
+ { start_line: 760, end_line: 920 },
1645
+ ],
1646
+ }, {
1647
+ path: /\/services\/streaming\/context_usage\.py$/,
1648
+ exactPaths: ["backend/app/services/streaming/context_usage.py"],
1649
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1650
+ full: true,
1651
+ }, {
1652
+ path: /\/services\/providerauthservice\.ts$/,
1653
+ exactPaths: ["frontend/src/services/providerAuthService.ts"],
1654
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1655
+ full: true,
1656
+ }, {
1657
+ path: /\/services\/streamservice\.ts$/,
1658
+ exactPaths: ["frontend/src/services/streamService.ts"],
1659
+ ranges: [
1660
+ { start_line: 1, end_line: 140 },
1661
+ { start_line: 260, end_line: 422 },
1662
+ ],
1663
+ }, {
1664
+ path: /\/hooks\/usechatruntimesettings\.ts$/,
1665
+ exactPaths: ["frontend/src/hooks/useChatRuntimeSettings.ts"],
1666
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1667
+ full: true,
1668
+ }, {
1669
+ path: /\/services\/permission_manager\.py$/,
1670
+ exactPaths: ["backend/app/services/permission_manager.py"],
1671
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1672
+ full: true,
1673
+ }, {
1674
+ path: /\/services\/model_provider_auth\.py$/,
1675
+ exactPaths: ["backend/app/services/model_provider_auth.py"],
1676
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1677
+ full: true,
1678
+ }, {
1679
+ path: /\/tests\/services\/test_model_provider_auth\.py$/,
1680
+ exactPaths: ["backend/tests/services/test_model_provider_auth.py"],
1681
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1682
+ full: true,
1683
+ }, {
1684
+ path: /\/tests\/services\/runtime\/test_codex_stream_processor\.py$/,
1685
+ exactPaths: ["backend/tests/services/runtime/test_codex_stream_processor.py"],
1686
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1687
+ full: true,
1688
+ }, {
1689
+ path: /\/tests\/services\/runtime\/test_codex_approval_bridge\.py$/,
1690
+ exactPaths: ["backend/tests/services/runtime/test_codex_approval_bridge.py"],
1691
+ ranges: [
1692
+ { start_line: 1, end_line: 80 },
1693
+ { start_line: 193, end_line: 280 },
1694
+ { start_line: 310, end_line: 386 },
1695
+ { start_line: 449, end_line: 565 },
1696
+ { start_line: 953, end_line: 1068 },
1697
+ { start_line: 1100, end_line: 1165 },
1698
+ ],
1699
+ }, {
1700
+ path: /\/tests\/services\/runtime\/test_resolver\.py$/,
1701
+ exactPaths: ["backend/tests/services/runtime/test_resolver.py"],
1702
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1703
+ full: true,
1704
+ }, {
1705
+ path: /\/tests\/services\/test_runtime_session_service\.py$/,
1706
+ exactPaths: ["backend/tests/services/test_runtime_session_service.py"],
1707
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1708
+ full: true,
1709
+ }, {
1710
+ path: /\/api\/endpoints\/chat\.py$/,
1711
+ exactPaths: ["backend/app/api/endpoints/chat.py"],
1712
+ ranges: [
1713
+ { start_line: 1, end_line: 120 },
1714
+ { start_line: 390, end_line: 570 },
1715
+ { start_line: 1215, end_line: 1400 },
1716
+ ],
1717
+ }, {
1718
+ path: /\/api\/endpoints\/permissions\.py$/,
1719
+ exactPaths: ["backend/app/api/endpoints/permissions.py"],
1720
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1721
+ full: true,
1722
+ }, {
1723
+ path: /\/services\/chat\.py$/,
1724
+ exactPaths: ["backend/app/services/chat.py"],
1725
+ ranges: [
1726
+ { start_line: 160, end_line: 675 },
1727
+ { start_line: 777, end_line: 851 },
1728
+ { start_line: 1131, end_line: 1177 },
1729
+ { start_line: 1619, end_line: 1756 },
1730
+ { start_line: 1878, end_line: 2170 },
1731
+ { start_line: 2454, end_line: 2508 },
1732
+ { start_line: 2570, end_line: 2594 },
1733
+ ],
1734
+ }, {
1735
+ path: /\/services\/claude_agent\.py$/,
1736
+ exactPaths: ["backend/app/services/claude_agent.py"],
1737
+ ranges: [
1738
+ { start_line: 44, end_line: 80 },
1739
+ { start_line: 433, end_line: 466 },
1740
+ { start_line: 786, end_line: 874 },
1741
+ { start_line: 988, end_line: 1002 },
1742
+ ],
1743
+ }, {
1744
+ path: /\/components\/chat\/message-input\/input\.tsx$/,
1745
+ exactPaths: ["frontend/src/components/chat/message-input/Input.tsx"],
1746
+ ranges: [
1747
+ { start_line: 360, end_line: 630 },
1748
+ { start_line: 1018, end_line: 1048 },
1749
+ ],
1750
+ }, {
1751
+ path: /\/components\/chat\/message-input\/composerruntimecontrols\.tsx$/,
1752
+ exactPaths: ["frontend/src/components/chat/message-input/ComposerRuntimeControls.tsx"],
1753
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1754
+ full: true,
1755
+ }, {
1756
+ path: /\/hooks\/usemessageactions\.ts$/,
1757
+ exactPaths: ["frontend/src/hooks/useMessageActions.ts"],
1758
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1759
+ full: true,
1760
+ }, {
1761
+ path: /\/components\/ui\/fileuploaddialog\.tsx$/,
1762
+ exactPaths: ["frontend/src/components/ui/FileUploadDialog.tsx"],
1763
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1764
+ full: true,
1765
+ }, {
1766
+ path: /\/components\/ui\/fileuploaddialog\.codex\.test\.tsx$/,
1767
+ exactPaths: ["frontend/src/components/ui/FileUploadDialog.codex.test.tsx"],
1768
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1769
+ full: true,
1770
+ }, {
1771
+ path: /\/hooks\/usepermissionrequest\.ts$/,
1772
+ exactPaths: ["frontend/src/hooks/usePermissionRequest.ts"],
1773
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1774
+ full: true,
1775
+ }, {
1776
+ path: /\/utils\/modelprovider\.ts$/,
1777
+ exactPaths: ["frontend/src/utils/modelProvider.ts"],
1778
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1779
+ full: true,
1780
+ }, {
1781
+ path: /\/components\/chat\/message-input\/inputsettingspopover\.tsx$/,
1782
+ exactPaths: ["frontend/src/components/chat/message-input/InputSettingsPopover.tsx"],
1783
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1784
+ full: true,
1785
+ }, {
1786
+ path: /\/permissionmodeselector\.tsx$/,
1787
+ exactPaths: ["frontend/src/components/chat/permission-mode-selector/PermissionModeSelector.tsx"],
1788
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1789
+ full: true,
1790
+ }, {
1791
+ path: /\/thinkingmodeselector\.tsx$/,
1792
+ exactPaths: ["frontend/src/components/chat/thinking-mode-selector/ThinkingModeSelector.tsx"],
1793
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1794
+ full: true,
1795
+ }, {
1796
+ path: /\/models\/schemas\/chat\.py$/,
1797
+ exactPaths: ["backend/app/models/schemas/chat.py"],
1798
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1799
+ full: true,
1800
+ }, {
1801
+ path: /\/models\/schemas\/permission_mode\.py$/,
1802
+ exactPaths: ["backend/app/models/schemas/permission_mode.py"],
1803
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1804
+ full: true,
1805
+ }, {
1806
+ path: /\/models\/schemas\/permissions\.py$/,
1807
+ exactPaths: ["backend/app/models/schemas/permissions.py"],
1808
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1809
+ full: true,
1810
+ }, {
1811
+ path: /\/models\/db_models\/ai_model\.py$/,
1812
+ exactPaths: ["backend/app/models/db_models/ai_model.py"],
1813
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1814
+ full: true,
1815
+ }, {
1816
+ path: /\/api\/endpoints\/ai_models\.py$/,
1817
+ exactPaths: ["backend/app/api/endpoints/ai_models.py"],
1818
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1819
+ full: true,
1820
+ }, {
1821
+ path: /\/tests\/test_ai_models_codex_gate\.py$/,
1822
+ exactPaths: ["backend/tests/test_ai_models_codex_gate.py"],
1823
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1824
+ full: true,
1825
+ }, {
1826
+ path: /\/tests\/test_permissions\.py$/,
1827
+ exactPaths: ["backend/tests/test_permissions.py"],
1828
+ ranges: [
1829
+ { start_line: 1, end_line: 230 },
1830
+ { start_line: 306, end_line: 389 },
1831
+ { start_line: 489, end_line: 555 },
1832
+ ],
1833
+ });
1834
+ }
1835
+ if (isDevtoolsTraceDebugTask(task)) {
1836
+ specs.push({
1837
+ path: /\/right-panel\/rightpaneldevtools\.tsx$/,
1838
+ exactPaths: ["frontend/src/components/right-panel/RightPanelDevtools.tsx"],
1839
+ ranges: [
1840
+ { start_line: 1, end_line: 115 },
1841
+ { start_line: 528, end_line: 745 },
1842
+ { start_line: 840, end_line: 948 },
1843
+ ],
1844
+ }, {
1845
+ path: /\/right-panel\/__tests__\/right-panel-devtools\.test\.tsx$/,
1846
+ exactPaths: ["frontend/src/components/right-panel/__tests__/right-panel-devtools.test.tsx"],
1847
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1848
+ full: true,
1849
+ }, {
1850
+ path: /\/right-panel\/devtools-helpers\.ts$/,
1851
+ exactPaths: ["frontend/src/components/right-panel/devtools-helpers.ts"],
1852
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1853
+ full: true,
1854
+ }, {
1855
+ path: /\/store\/devtoolsnavstore\.ts$/,
1856
+ exactPaths: ["frontend/src/store/devtoolsNavStore.ts"],
1857
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1858
+ full: true,
1859
+ }, {
1860
+ path: /\/services\/devtoolsservice\.ts$/,
1861
+ exactPaths: ["frontend/src/services/devtoolsService.ts"],
1862
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1863
+ full: true,
1864
+ }, {
1865
+ path: /\/hooks\/queries\/usedevtoolsqueries\.ts$/,
1866
+ exactPaths: ["frontend/src/hooks/queries/useDevtoolsQueries.ts"],
1867
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1868
+ full: true,
1869
+ }, {
1870
+ path: /\/components\/chat\/chat-window\/chat\.tsx$/,
1871
+ exactPaths: ["frontend/src/components/chat/chat-window/Chat.tsx"],
1872
+ ranges: [
1873
+ { start_line: 450, end_line: 615 },
1874
+ { start_line: 670, end_line: 750 },
1875
+ ],
1876
+ }, {
1877
+ path: /\/components\/chat\/message-bubble\/message\.tsx$/,
1878
+ exactPaths: ["frontend/src/components/chat/message-bubble/Message.tsx"],
1879
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1880
+ full: true,
1881
+ }, {
1882
+ path: /\/pages\/chatpage\.tsx$/,
1883
+ exactPaths: ["frontend/src/pages/ChatPage.tsx"],
1884
+ ranges: [
1885
+ { start_line: 150, end_line: 292 },
1886
+ { start_line: 640, end_line: 700 },
1887
+ ],
1888
+ }, {
1889
+ path: /\/components\/chat\/message-input\/input\.tsx$/,
1890
+ exactPaths: ["frontend/src/components/chat/message-input/Input.tsx"],
1891
+ ranges: [
1892
+ { start_line: 360, end_line: 630 },
1893
+ { start_line: 1018, end_line: 1048 },
1894
+ ],
1895
+ }, {
1896
+ path: /\/api\/endpoints\/chat\.py$/,
1897
+ exactPaths: ["backend/app/api/endpoints/chat.py"],
1898
+ ranges: [
1899
+ { start_line: 390, end_line: 570 },
1900
+ { start_line: 1215, end_line: 1400 },
1901
+ ],
1902
+ }, {
1903
+ path: /\/services\/claude_agent\.py$/,
1904
+ exactPaths: ["backend/app/services/claude_agent.py"],
1905
+ ranges: [
1906
+ { start_line: 44, end_line: 80 },
1907
+ { start_line: 433, end_line: 466 },
1908
+ { start_line: 786, end_line: 874 },
1909
+ { start_line: 988, end_line: 1002 },
1910
+ ],
1911
+ }, {
1912
+ path: /\/store\/__tests__\/devtoolsnavstore\.test\.ts$/,
1913
+ exactPaths: ["frontend/src/store/__tests__/devtoolsNavStore.test.ts"],
1914
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1915
+ full: true,
1916
+ }, {
1917
+ path: /\/models\/schemas\/devtools\.py$/,
1918
+ exactPaths: ["backend/app/models/schemas/devtools.py"],
1919
+ ranges: [{ start_line: 1, end_line: Number.MAX_SAFE_INTEGER }],
1920
+ full: true,
1921
+ });
1922
+ }
1923
+ return specs;
1924
+ }
1925
+ function isRuntimeSettingsPersistenceFlowTask(normalizedTask) {
1926
+ return (normalizedTask.includes("runtime") &&
1927
+ /\bsettings?\b/.test(normalizedTask) &&
1928
+ /\b(validat(?:e|es|ed|ing|ion)|dropp?ed|dropp?ing|drops?|persist(?:s|ed|ing|ence)?|dispatch(?:es|ed|ing)?)\b/.test(normalizedTask));
1929
+ }
1930
+ function isTangentialRuntimeSettingsDiscoveryTestPath(normalizedPath, basename) {
1931
+ return (basename === "test_codex_e2e_live.py" ||
1932
+ basename === "test_codex_sdk_smoke.py" ||
1933
+ basename === "test_codex_runtime_live.py" ||
1934
+ basename === "test_transport_absence.py" ||
1935
+ basename === "test_resolver.py" ||
1936
+ normalizedPath.includes("nightshift") ||
1937
+ /\/tests?\/.*codex.*approval.*\.(py|ts|tsx)$/.test(normalizedPath));
1938
+ }
1939
+ function candidateForTaskSpineSpec(spec, candidates, sourceRoots) {
1940
+ const local = localCandidateForTaskSpineSpec(spec, sourceRoots);
1941
+ if (local != null) {
1942
+ return local;
1943
+ }
1944
+ const discovered = candidates.find((item) => spec.path.test(item.path.toLowerCase()));
1945
+ if (discovered != null) {
1946
+ return discovered;
1947
+ }
1948
+ return undefined;
1949
+ }
1950
+ function localCandidateForTaskSpineSpec(spec, sourceRoots, preferredRootIndex) {
1951
+ for (const exactPath of spec.exactPaths ?? []) {
1952
+ const local = localCandidateFromExactPath(exactPath, sourceRoots, preferredRootIndex);
1953
+ if (local != null) {
1954
+ return local;
1955
+ }
1956
+ }
1957
+ return undefined;
1958
+ }
1959
+ function localCandidateFromSelectedFile(file, sourceRoots) {
1960
+ return localCandidateFromExactPath(file.path, sourceRoots, file.root_index);
1961
+ }
1962
+ function localCandidateFromExactPath(relativePath, sourceRoots, preferredRootIndex) {
1963
+ const rootIndexes = preferredRootIndex == null
1964
+ ? sourceRoots.map((_, index) => index)
1965
+ : [preferredRootIndex];
1966
+ for (const rootIndex of rootIndexes) {
1967
+ const root = sourceRoots[rootIndex];
1968
+ if (root == null) {
1969
+ continue;
1970
+ }
1971
+ const absolutePath = path.join(root.path, relativePath);
1972
+ try {
1973
+ const content = readFileSync(absolutePath, "utf8");
1974
+ return {
1975
+ root_index: rootIndex,
1976
+ path: relativePath,
1977
+ absolute_path: absolutePath,
1978
+ content,
1979
+ byte_length: Buffer.byteLength(content, "utf8"),
1980
+ line_count: splitTextLines(content).length,
1981
+ has_final_newline: content.endsWith("\n"),
1982
+ };
1983
+ }
1984
+ catch {
1985
+ continue;
1986
+ }
1987
+ }
1988
+ return undefined;
1989
+ }
1990
+ function shouldReplaceWithTaskSpineRanges(path, task) {
1991
+ const normalized = path.toLowerCase();
1992
+ const normalizedTask = task.toLowerCase();
1993
+ if (/\bdiscovery\b/.test(normalizedTask) &&
1994
+ normalizedTask.includes("runtime") &&
1995
+ (normalized.endsWith("/services/chat.py") ||
1996
+ normalized.endsWith("/services/claude_agent.py"))) {
1997
+ return true;
1998
+ }
1999
+ if (isDevtoolsTraceDebugTask(task) &&
2000
+ (normalized.endsWith("/components/right-panel/rightpaneldevtools.tsx") ||
2001
+ normalized.endsWith("/components/chat/chat-window/chat.tsx") ||
2002
+ normalized.endsWith("/pages/chatpage.tsx") ||
2003
+ normalized.endsWith("/components/chat/message-input/input.tsx") ||
2004
+ normalized.endsWith("/api/endpoints/chat.py") ||
2005
+ normalized.endsWith("/services/claude_agent.py"))) {
2006
+ return true;
2007
+ }
2008
+ if (isCodexRuntimeReviewTask(task) &&
2009
+ (normalized.endsWith("/services/runtime/codex.py") ||
2010
+ normalized.endsWith("/services/runtime/codex_approval.py") ||
2011
+ normalized.endsWith("/services/runtime/codex_stream_processor.py") ||
2012
+ normalized.endsWith("/services/streaming/orchestrator.py") ||
2013
+ normalized.endsWith("/services/chat.py") ||
2014
+ normalized.endsWith("/tests/services/runtime/test_codex_approval_bridge.py") ||
2015
+ normalized.endsWith("/tests/test_permissions.py") ||
2016
+ normalized.endsWith("/services/claude_agent.py"))) {
2017
+ return true;
2018
+ }
2019
+ return false;
2020
+ }
2021
+ function selectedFileFromCandidateRanges(candidate, ranges, source) {
2022
+ const taskSpineContent = readTaskSpineCandidateContent(candidate);
2023
+ const sourceLines = splitTextLines(taskSpineContent);
2024
+ if (sourceLines.length === 0) {
2025
+ return null;
2026
+ }
2027
+ const lineCount = sourceLines.length;
2028
+ const bounded = mergeLineRanges(ranges
2029
+ .map((range) => ({
2030
+ start_line: Math.max(1, range.start_line),
2031
+ end_line: Math.min(Math.max(1, lineCount), range.end_line),
2032
+ }))
2033
+ .filter((range) => range.start_line <= range.end_line));
2034
+ if (bounded.length === 0) {
2035
+ return null;
2036
+ }
2037
+ const content = bounded
2038
+ .flatMap((range) => sourceLines.slice(range.start_line - 1, range.end_line))
2039
+ .join("\n");
2040
+ const bytes = Buffer.byteLength(content, "utf8");
2041
+ if (bytes <= 0) {
2042
+ return null;
2043
+ }
2044
+ return {
2045
+ root_index: candidate.root_index,
2046
+ path: candidate.path,
2047
+ ranges: bounded,
2048
+ content,
2049
+ bytes,
2050
+ estimated_tokens: estimateContextBuilderTokensFromUtf8Bytes(bytes),
2051
+ source,
2052
+ };
2053
+ }
2054
+ function readTaskSpineCandidateContent(candidate) {
2055
+ try {
2056
+ return readFileSync(candidate.absolute_path, "utf8");
2057
+ }
2058
+ catch {
2059
+ return candidate.content;
2060
+ }
2061
+ }
2062
+ function appendDelegateRepairWarnings(warnings, repair) {
2063
+ if (repair.expandedCount > 0) {
2064
+ warnings.push(delegateWarning("delegate_curator_warning", `server-expanded ${repair.expandedCount} selected file(s) to full context`));
2065
+ }
2066
+ if (repair.droppedDegenerateCount > 0) {
2067
+ warnings.push(delegateWarning("delegate_curator_warning", `server-dropped ${repair.droppedDegenerateCount} degenerate selected slice(s)`));
2068
+ }
2069
+ if (repair.deterministicRetainedCount > 0) {
2070
+ warnings.push(delegateWarning("delegate_curator_warning", `server-retained ${repair.deterministicRetainedCount} compact deterministic closure file(s) after curator underselection`));
2071
+ }
2072
+ if (repair.discoveredRetainedCount > 0) {
2073
+ warnings.push(delegateWarning("delegate_curator_warning", `server-retained ${repair.discoveredRetainedCount} task-critical discovered closure file(s) after curator underselection`));
2074
+ }
2075
+ if (repair.evictedCount > 0) {
2076
+ warnings.push(delegateWarning("delegate_curator_warning", `server-evicted ${repair.evictedCount} lower-priority selected file(s) to retain required closure`));
2077
+ }
2078
+ }
2079
+ function retainDeterministicClosureFiles(selection, deterministicSelection, budget, task) {
2080
+ const selectedKeys = new Set(selection.selected.map((file) => selectedFileKey(file)));
2081
+ let totalBytes = selection.metrics.bytes_selected;
2082
+ let totalTokens = selection.metrics.estimated_tokens;
2083
+ const selected = [...selection.selected];
2084
+ let retainedCount = 0;
2085
+ for (const file of deterministicSelection.selected) {
2086
+ if (selectedKeys.has(selectedFileKey(file)) ||
2087
+ !isRetainableClosureFile(file, task)) {
2088
+ continue;
2089
+ }
2090
+ if (selected.length >= budget.max_files ||
2091
+ file.bytes > budget.max_bytes_per_file ||
2092
+ totalBytes + file.bytes > budget.max_total_bytes ||
2093
+ totalTokens + file.estimated_tokens > budget.target_estimated_tokens) {
2094
+ continue;
2095
+ }
2096
+ selected.push(file);
2097
+ selectedKeys.add(selectedFileKey(file));
2098
+ totalBytes += file.bytes;
2099
+ totalTokens += file.estimated_tokens;
2100
+ retainedCount += 1;
2101
+ }
2102
+ if (retainedCount === 0) {
2103
+ return { selection, retainedCount };
2104
+ }
2105
+ return {
2106
+ retainedCount,
2107
+ selection: {
2108
+ ...selection,
2109
+ selected,
2110
+ metrics: {
2111
+ files_selected: selected.length,
2112
+ files_omitted: selection.metrics.files_omitted,
2113
+ bytes_selected: totalBytes,
2114
+ estimated_tokens: totalTokens,
2115
+ truncated: selection.metrics.truncated,
2116
+ },
2117
+ },
2118
+ };
2119
+ }
2120
+ function expandSelectedFocusFilesToFullCandidates(selection, candidates, focusPaths, budget, task = "") {
2121
+ if (!shouldExpandFocusFilesForTask(task)) {
2122
+ return { selection, expandedCount: 0 };
2123
+ }
2124
+ const focusKeys = new Set(focusPaths
2125
+ .filter((focus) => focus.kind === "file")
2126
+ .map((focus) => `${focus.root_index}\u0000${focus.root_relative_path}`));
2127
+ if (focusKeys.size === 0) {
2128
+ return { selection, expandedCount: 0 };
2129
+ }
2130
+ const candidatesByKey = new Map(candidates.map((candidate) => [selectedFileKey(candidate), candidate]));
2131
+ let totalBytes = selection.metrics.bytes_selected;
2132
+ let totalTokens = selection.metrics.estimated_tokens;
2133
+ let expandedCount = 0;
2134
+ const selected = selection.selected.map((file) => {
2135
+ const key = selectedFileKey(file);
2136
+ if (!focusKeys.has(key)) {
2137
+ return file;
2138
+ }
2139
+ const candidate = candidatesByKey.get(key);
2140
+ if (candidate == null) {
2141
+ return file;
2142
+ }
2143
+ const fullFile = selectedFileFromCandidate(candidate);
2144
+ if (fullFile.bytes <= file.bytes || fileCoversCandidate(file, candidate)) {
2145
+ return file;
2146
+ }
2147
+ if (fullFile.estimated_tokens >
2148
+ focusExpansionTokenLimit(candidate.path, task, budget)) {
2149
+ return file;
2150
+ }
2151
+ const totalsWithoutFile = {
2152
+ totalBytes: totalBytes - file.bytes,
2153
+ totalTokens: totalTokens - file.estimated_tokens,
2154
+ };
2155
+ if (fullFile.bytes > budget.max_bytes_per_file ||
2156
+ totalsWithoutFile.totalBytes + fullFile.bytes > budget.max_total_bytes ||
2157
+ totalsWithoutFile.totalTokens + fullFile.estimated_tokens >
2158
+ budget.target_estimated_tokens) {
2159
+ return file;
2160
+ }
2161
+ totalBytes = totalsWithoutFile.totalBytes + fullFile.bytes;
2162
+ totalTokens = totalsWithoutFile.totalTokens + fullFile.estimated_tokens;
2163
+ expandedCount += 1;
2164
+ return { ...fullFile, source: file.source };
2165
+ });
2166
+ if (expandedCount === 0) {
2167
+ return { selection, expandedCount };
2168
+ }
2169
+ return {
2170
+ expandedCount,
2171
+ selection: {
2172
+ ...selection,
2173
+ selected,
2174
+ metrics: {
2175
+ files_selected: selected.length,
2176
+ files_omitted: selection.metrics.files_omitted,
2177
+ bytes_selected: totalBytes,
2178
+ estimated_tokens: totalTokens,
2179
+ truncated: selection.metrics.truncated,
2180
+ },
2181
+ },
2182
+ };
2183
+ }
2184
+ function shouldExpandFocusFilesForTask(task) {
2185
+ return /\b(debug(?:ging)?|review|discovery|implement(?:ation)?|fix|diagnose)\b/i.test(task);
2186
+ }
2187
+ function focusExpansionTokenLimit(path, task, budget) {
2188
+ const normalized = path.toLowerCase();
2189
+ const normalizedTask = task.toLowerCase();
2190
+ if (/\b(debug|debugging|diagnose|diagnosis|diagnostic)\b/.test(normalizedTask) &&
2191
+ normalized.endsWith("/rightpaneldevtools.tsx")) {
2192
+ return 35_000;
2193
+ }
2194
+ if (/\b(review|discovery|provider|runtime|codex|claude)\b/.test(normalizedTask) &&
2195
+ normalized.includes("/services/runtime/")) {
2196
+ return Math.min(18_000, Math.floor(budget.target_estimated_tokens * 0.2));
2197
+ }
2198
+ return Math.min(12_000, Math.floor(budget.target_estimated_tokens * 0.18));
2199
+ }
2200
+ function expandSelectedClosureFilesToFullCandidates(selection, candidates, task, budget) {
2201
+ const candidatesByKey = new Map(candidates.map((candidate) => [selectedFileKey(candidate), candidate]));
2202
+ let totalBytes = selection.metrics.bytes_selected;
2203
+ let totalTokens = selection.metrics.estimated_tokens;
2204
+ let expandedCount = 0;
2205
+ const selected = selection.selected.map((file) => {
2206
+ if (!isRetainableClosureFile(file, task) &&
2207
+ !isContextBuilderTaskClosureAnchor(file.path, task) &&
2208
+ !isTaskCriticalDiscoveredClosure(file.path, task)) {
2209
+ return file;
2210
+ }
2211
+ const candidate = candidatesByKey.get(selectedFileKey(file));
2212
+ if (candidate == null || fileCoversCandidate(file, candidate)) {
2213
+ return file;
2214
+ }
2215
+ if (candidate.byte_length > retainableClosureByteLimit(candidate.path, task)) {
2216
+ return file;
2217
+ }
2218
+ const fullFile = selectedFileFromCandidate(candidate);
2219
+ const totalsWithoutFile = {
2220
+ totalBytes: totalBytes - file.bytes,
2221
+ totalTokens: totalTokens - file.estimated_tokens,
2222
+ };
2223
+ if (fullFile.bytes > budget.max_bytes_per_file ||
2224
+ totalsWithoutFile.totalBytes + fullFile.bytes > budget.max_total_bytes ||
2225
+ totalsWithoutFile.totalTokens + fullFile.estimated_tokens >
2226
+ budget.target_estimated_tokens) {
2227
+ return file;
2228
+ }
2229
+ totalBytes = totalsWithoutFile.totalBytes + fullFile.bytes;
2230
+ totalTokens = totalsWithoutFile.totalTokens + fullFile.estimated_tokens;
2231
+ expandedCount += 1;
2232
+ return { ...fullFile, source: file.source };
2233
+ });
2234
+ if (expandedCount === 0) {
2235
+ return { selection, expandedCount };
2236
+ }
2237
+ return {
2238
+ expandedCount,
2239
+ selection: {
2240
+ ...selection,
2241
+ selected,
2242
+ metrics: {
2243
+ files_selected: selected.length,
2244
+ files_omitted: selection.metrics.files_omitted,
2245
+ bytes_selected: totalBytes,
2246
+ estimated_tokens: totalTokens,
2247
+ truncated: selection.metrics.truncated,
2248
+ },
2249
+ },
2250
+ };
2251
+ }
2252
+ function retainDiscoveredTaskCriticalFiles(selection, candidates, task, budget) {
2253
+ let selectedKeys = new Set(selection.selected.map((file) => selectedFileKey(file)));
2254
+ let totalBytes = selection.metrics.bytes_selected;
2255
+ let totalTokens = selection.metrics.estimated_tokens;
2256
+ let selected = [...selection.selected];
2257
+ let retainedCount = 0;
2258
+ let evictedCount = 0;
2259
+ for (const candidate of [...candidates]
2260
+ .filter((item) => !isTangentialTaskClosureCandidate(item.path, task) &&
2261
+ (isContextBuilderTaskClosureAnchor(item.path, task) ||
2262
+ isTaskCriticalDiscoveredClosure(item.path, task)))
2263
+ .sort((left, right) => compareTaskCriticalCandidates(left, right, task))) {
2264
+ const key = selectedFileKey(candidate);
2265
+ if (selectedKeys.has(key) ||
2266
+ (candidate.byte_length > retainableClosureByteLimit(candidate.path, task) &&
2267
+ compactCandidateForRequiredClosure(candidate, task) == null)) {
2268
+ continue;
2269
+ }
2270
+ const file = candidate.byte_length > retainableClosureByteLimit(candidate.path, task)
2271
+ ? compactCandidateForRequiredClosure(candidate, task)
2272
+ : selectedFileFromCandidate(candidate);
2273
+ if (file == null) {
2274
+ continue;
2275
+ }
2276
+ if (!selectionFitsBudgetWithFile(selected, totalBytes, totalTokens, file, budget)) {
2277
+ const repaired = makeRoomForRequiredClosureFile({
2278
+ selected,
2279
+ selectedKeys,
2280
+ totalBytes,
2281
+ totalTokens,
2282
+ file,
2283
+ budget,
2284
+ task,
2285
+ });
2286
+ if (repaired == null) {
2287
+ continue;
2288
+ }
2289
+ selected = repaired.selected;
2290
+ selectedKeys = repaired.selectedKeys;
2291
+ totalBytes = repaired.totalBytes;
2292
+ totalTokens = repaired.totalTokens;
2293
+ evictedCount += repaired.evictedCount;
2294
+ }
2295
+ selected.push(file);
2296
+ selectedKeys.add(key);
2297
+ totalBytes += file.bytes;
2298
+ totalTokens += file.estimated_tokens;
2299
+ retainedCount += 1;
2300
+ }
2301
+ if (retainedCount === 0 && evictedCount === 0) {
2302
+ return { selection, retainedCount, evictedCount };
2303
+ }
2304
+ return {
2305
+ retainedCount,
2306
+ evictedCount,
2307
+ selection: {
2308
+ ...selection,
2309
+ selected,
2310
+ metrics: {
2311
+ files_selected: selected.length,
2312
+ files_omitted: selection.metrics.files_omitted,
2313
+ bytes_selected: totalBytes,
2314
+ estimated_tokens: totalTokens,
2315
+ truncated: selection.metrics.truncated,
2316
+ },
2317
+ },
2318
+ };
2319
+ }
2320
+ function dropDegenerateSelectedSlices(selection, candidates, task) {
2321
+ const candidatesByKey = new Map(candidates.map((candidate) => [selectedFileKey(candidate), candidate]));
2322
+ const selected = selection.selected.filter((file) => {
2323
+ if (file.content.trim().length === 0) {
2324
+ return false;
2325
+ }
2326
+ if (!isDegenerateSelectedSlice(file) || file.source === "focus") {
2327
+ return true;
2328
+ }
2329
+ if (!isRequiredClosurePath(file.path, task)) {
2330
+ return true;
2331
+ }
2332
+ const candidate = candidatesByKey.get(selectedFileKey(file));
2333
+ return (candidate != null &&
2334
+ fileCoversCandidate(file, candidate) &&
2335
+ isRequiredClosurePath(candidate.path, task));
2336
+ });
2337
+ const droppedCount = selection.selected.length - selected.length;
2338
+ if (droppedCount === 0) {
2339
+ return { selection, droppedCount };
2340
+ }
2341
+ return {
2342
+ droppedCount,
2343
+ selection: selectionWithSelectedFiles(selection, selected),
2344
+ };
2345
+ }
2346
+ function makeRoomForRequiredClosureFile(input) {
2347
+ if (input.file.bytes > input.budget.max_bytes_per_file) {
2348
+ return null;
2349
+ }
2350
+ const incomingRank = taskCriticalPathRank(input.file.path, input.task);
2351
+ let selected = [...input.selected];
2352
+ let selectedKeys = new Set(input.selectedKeys);
2353
+ let totalBytes = input.totalBytes;
2354
+ let totalTokens = input.totalTokens;
2355
+ let evictedCount = 0;
2356
+ if (!selectionFitsBudgetWithFile(selected, totalBytes, totalTokens, input.file, input.budget)) {
2357
+ const compacted = compactSelectedFilesForRequiredClosure({
2358
+ selected,
2359
+ totalBytes,
2360
+ totalTokens,
2361
+ incomingFile: input.file,
2362
+ task: input.task,
2363
+ });
2364
+ selected = compacted.selected;
2365
+ totalBytes = compacted.totalBytes;
2366
+ totalTokens = compacted.totalTokens;
2367
+ }
2368
+ const evictionOrder = selected
2369
+ .map((file, index) => ({ file, index }))
2370
+ .filter(({ file }) => canEvictForRequiredClosure(file, input.task, incomingRank))
2371
+ .sort((left, right) => selectedEvictionRank(right.file, input.task, incomingRank) -
2372
+ selectedEvictionRank(left.file, input.task, incomingRank) ||
2373
+ right.index - left.index);
2374
+ for (const { file } of evictionOrder) {
2375
+ if (selectionFitsBudgetWithFile(selected, totalBytes, totalTokens, input.file, input.budget)) {
2376
+ break;
2377
+ }
2378
+ const index = selected.findIndex((item) => selectedFileKey(item) === selectedFileKey(file));
2379
+ if (index < 0) {
2380
+ continue;
2381
+ }
2382
+ const [removed] = selected.splice(index, 1);
2383
+ if (removed == null) {
2384
+ continue;
2385
+ }
2386
+ selectedKeys.delete(selectedFileKey(removed));
2387
+ totalBytes -= removed.bytes;
2388
+ totalTokens -= removed.estimated_tokens;
2389
+ evictedCount += 1;
2390
+ }
2391
+ if (!selectionFitsBudgetWithFile(selected, totalBytes, totalTokens, input.file, input.budget)) {
2392
+ return null;
2393
+ }
2394
+ return { selected, selectedKeys, totalBytes, totalTokens, evictedCount };
2395
+ }
2396
+ function selectionFitsBudgetWithFile(selected, totalBytes, totalTokens, file, budget) {
2397
+ return (selected.length < budget.max_files &&
2398
+ file.bytes <= budget.max_bytes_per_file &&
2399
+ totalBytes + file.bytes <= budget.max_total_bytes &&
2400
+ totalTokens + file.estimated_tokens <= budget.target_estimated_tokens);
2401
+ }
2402
+ const REQUIRED_CLOSURE_COMPACT_MIN_TOKENS = 3_000;
2403
+ const REQUIRED_CLOSURE_COMPACT_HEAD_LINES = 60;
2404
+ const REQUIRED_CLOSURE_COMPACT_CONTEXT_LINES = 24;
2405
+ const REQUIRED_CLOSURE_COMPACT_MAX_LINES = 260;
2406
+ function compactSelectedFilesForRequiredClosure(input) {
2407
+ let totalBytes = input.totalBytes;
2408
+ let totalTokens = input.totalTokens;
2409
+ const selected = input.selected.map((file) => {
2410
+ const compacted = compactSelectedFileForRequiredClosure(file, input.incomingFile, input.task);
2411
+ if (compacted == null) {
2412
+ return file;
2413
+ }
2414
+ totalBytes = totalBytes - file.bytes + compacted.bytes;
2415
+ totalTokens = totalTokens - file.estimated_tokens + compacted.estimated_tokens;
2416
+ return compacted;
2417
+ });
2418
+ return { selected, totalBytes, totalTokens };
2419
+ }
2420
+ function compactSelectedFileForRequiredClosure(file, incomingFile, task) {
2421
+ if (file.source !== "focus" ||
2422
+ isProtectedReviewFocusPath(file.path, task) ||
2423
+ file.estimated_tokens <= REQUIRED_CLOSURE_COMPACT_MIN_TOKENS ||
2424
+ selectedRangeLineCount(file) <= REQUIRED_CLOSURE_COMPACT_HEAD_LINES) {
2425
+ return null;
2426
+ }
2427
+ const sourceLines = splitTextLines(file.content);
2428
+ if (sourceLines.length <= REQUIRED_CLOSURE_COMPACT_HEAD_LINES) {
2429
+ return null;
2430
+ }
2431
+ const sourceLineNumbers = selectedFileContentLineNumbers(file, sourceLines.length);
2432
+ if (sourceLineNumbers.length !== sourceLines.length) {
2433
+ return null;
2434
+ }
2435
+ const tokens = new Set([
2436
+ ...tokenizeRepairWords(task),
2437
+ ...tokenizeRepairWords(incomingFile.path),
2438
+ ...tokenizeRepairWords(file.path),
2439
+ ]);
2440
+ const selectedLineNumbers = new Set();
2441
+ addOriginalLineWindow(selectedLineNumbers, sourceLineNumbers, sourceLineNumbers[0] ?? 1, (sourceLineNumbers[0] ?? 1) + REQUIRED_CLOSURE_COMPACT_HEAD_LINES - 1);
2442
+ for (let index = 0; index < sourceLines.length; index++) {
2443
+ if (selectedLineNumbers.size >= REQUIRED_CLOSURE_COMPACT_MAX_LINES) {
2444
+ break;
2445
+ }
2446
+ const line = sourceLines[index] ?? "";
2447
+ if (!lineMatchesRepairTokens(line, tokens)) {
2448
+ continue;
2449
+ }
2450
+ const originalLine = sourceLineNumbers[index];
2451
+ if (originalLine == null) {
2452
+ continue;
2453
+ }
2454
+ addOriginalLineWindow(selectedLineNumbers, sourceLineNumbers, originalLine - REQUIRED_CLOSURE_COMPACT_CONTEXT_LINES, originalLine + REQUIRED_CLOSURE_COMPACT_CONTEXT_LINES);
2455
+ }
2456
+ if (selectedLineNumbers.size >= sourceLines.length) {
2457
+ return null;
2458
+ }
2459
+ const ranges = mergeLineRanges([...selectedLineNumbers].map((line) => ({
2460
+ start_line: line,
2461
+ end_line: line,
2462
+ })));
2463
+ const linesByOriginalLine = new Map();
2464
+ for (let index = 0; index < sourceLines.length; index++) {
2465
+ const lineNumber = sourceLineNumbers[index];
2466
+ if (lineNumber != null) {
2467
+ linesByOriginalLine.set(lineNumber, sourceLines[index] ?? "");
2468
+ }
2469
+ }
2470
+ const content = ranges
2471
+ .flatMap((range) => {
2472
+ const lines = [];
2473
+ for (let line = range.start_line; line <= range.end_line; line++) {
2474
+ const contentLine = linesByOriginalLine.get(line);
2475
+ if (contentLine != null) {
2476
+ lines.push(contentLine);
2477
+ }
2478
+ }
2479
+ return lines;
2480
+ })
2481
+ .join("\n");
2482
+ const bytes = Buffer.byteLength(content, "utf8");
2483
+ if (bytes >= file.bytes) {
2484
+ return null;
2485
+ }
2486
+ return {
2487
+ ...file,
2488
+ ranges,
2489
+ content,
2490
+ bytes,
2491
+ estimated_tokens: estimateContextBuilderTokensFromUtf8Bytes(bytes),
2492
+ };
2493
+ }
2494
+ function selectedFileContentLineNumbers(file, lineCount) {
2495
+ const numbers = [];
2496
+ for (const range of file.ranges) {
2497
+ for (let line = range.start_line; line <= range.end_line; line++) {
2498
+ numbers.push(line);
2499
+ if (numbers.length >= lineCount) {
2500
+ return numbers;
2501
+ }
2502
+ }
2503
+ }
2504
+ return numbers;
2505
+ }
2506
+ function addOriginalLineWindow(selectedLineNumbers, availableLineNumbers, startLine, endLine) {
2507
+ const available = new Set(availableLineNumbers);
2508
+ for (let line = startLine; line <= endLine; line++) {
2509
+ if (selectedLineNumbers.size >= REQUIRED_CLOSURE_COMPACT_MAX_LINES) {
2510
+ return;
2511
+ }
2512
+ if (available.has(line)) {
2513
+ selectedLineNumbers.add(line);
2514
+ }
2515
+ }
2516
+ }
2517
+ function lineMatchesRepairTokens(line, tokens) {
2518
+ for (const token of tokenizeRepairWords(line)) {
2519
+ if (tokens.has(token)) {
2520
+ return true;
2521
+ }
2522
+ }
2523
+ return false;
2524
+ }
2525
+ function tokenizeRepairWords(input) {
2526
+ return input
2527
+ .toLowerCase()
2528
+ .split(/[^a-z0-9]+/)
2529
+ .filter((token) => token.length >= 3 && !REPAIR_STOP_WORDS.has(token));
2530
+ }
2531
+ const REPAIR_STOP_WORDS = new Set([
2532
+ "app",
2533
+ "src",
2534
+ "the",
2535
+ "and",
2536
+ "for",
2537
+ "with",
2538
+ "from",
2539
+ "this",
2540
+ "that",
2541
+ "file",
2542
+ "test",
2543
+ "tests",
2544
+ ]);
2545
+ function canEvictForRequiredClosure(file, task, incomingRank) {
2546
+ const existingRank = taskCriticalPathRank(file.path, task);
2547
+ if (file.source === "focus") {
2548
+ return (incomingRank <= 0 &&
2549
+ existingRank > incomingRank &&
2550
+ !isProtectedReviewFocusPath(file.path, task));
2551
+ }
2552
+ if (isRequiredClosurePath(file.path, task) && existingRank <= incomingRank) {
2553
+ return false;
2554
+ }
2555
+ return true;
2556
+ }
2557
+ function selectedEvictionRank(file, task, incomingRank) {
2558
+ let rank = file.estimated_tokens;
2559
+ if (isDegenerateSelectedSlice(file)) {
2560
+ rank += 10_000;
2561
+ }
2562
+ if (!isRequiredClosurePath(file.path, task)) {
2563
+ rank += 5_000;
2564
+ }
2565
+ rank += Math.max(0, taskCriticalPathRank(file.path, task) - incomingRank) * 500;
2566
+ if (isGenericSelectedPath(file.path)) {
2567
+ rank += 1_000;
2568
+ }
2569
+ return rank;
2570
+ }
2571
+ function isDegenerateSelectedSlice(file) {
2572
+ return file.content.trim().length === 0 || selectedRangeLineCount(file) <= 1;
2573
+ }
2574
+ function selectedRangeLineCount(file) {
2575
+ return file.ranges.reduce((total, range) => total + Math.max(0, range.end_line - range.start_line + 1), 0);
2576
+ }
2577
+ function isRequiredClosurePath(path, task) {
2578
+ return (isContextBuilderTaskClosureAnchor(path, task) ||
2579
+ isTaskCriticalDiscoveredClosure(path, task) ||
2580
+ taskCriticalPathRank(path, task) <= 0);
2581
+ }
2582
+ function isGenericSelectedPath(path) {
2583
+ const normalized = path.toLowerCase();
2584
+ return (normalized.includes("/settings/") ||
2585
+ normalized.includes("/components/ui/") ||
2586
+ normalized.includes("/admin/") ||
2587
+ normalized.includes("/models/db_models/__init__.py") ||
2588
+ normalized.includes("/db/base.py"));
2589
+ }
2590
+ function isDevtoolsTraceDebugTask(task) {
2591
+ const normalized = task.toLowerCase();
2592
+ return (/\b(debug|debugging|diagnose|diagnosis|diagnostic)\b/.test(normalized) &&
2593
+ normalized.includes("devtools") &&
2594
+ normalized.includes("trace"));
2595
+ }
2596
+ function isDevtoolsTraceRelevantPath(path) {
2597
+ if (isTangentialDevtoolsTraceDebugPath(path)) {
2598
+ return false;
2599
+ }
2600
+ const normalized = path.toLowerCase();
2601
+ return (normalized.includes("/right-panel/") ||
2602
+ normalized.endsWith("/rightpaneldevtools.tsx") ||
2603
+ normalized.includes("/store/devtoolsnavstore") ||
2604
+ normalized.includes("/store/__tests__/devtoolsnavstore.test.ts") ||
2605
+ normalized.includes("/services/devtoolsservice") ||
2606
+ normalized.includes("/hooks/queries/usedevtoolsqueries") ||
2607
+ normalized.includes("/hooks/queries/querykeys") ||
2608
+ normalized.endsWith("/querykeys.ts") ||
2609
+ normalized.includes("/types/devtools.types") ||
2610
+ normalized.endsWith("/models/schemas/devtools.py") ||
2611
+ normalized.includes("/api/endpoints/devtools.py") ||
2612
+ normalized.includes("/session_trace_archive") ||
2613
+ normalized.endsWith("/services/codex_trace.py") ||
2614
+ normalized.includes("/chat-window/chat.tsx") ||
2615
+ normalized.includes("/chat/__tests__/chat.test.tsx") ||
2616
+ normalized.includes("/message-bubble/message.tsx") ||
2617
+ normalized.includes("/message-bubble/messagerenderer.tsx") ||
2618
+ normalized.includes("/tools/common/toolcard.tsx") ||
2619
+ normalized.includes("/tools/common/toolexpandcontext.ts") ||
2620
+ normalized.includes("/tools/common/__tests__/toolexpand.test.tsx") ||
2621
+ normalized.includes("/hooks/usemessagecache.ts") ||
2622
+ normalized.includes("/utils/messagecacheorder.ts"));
2623
+ }
2624
+ function shouldExpandSmallDevtoolsTraceFile(path) {
2625
+ const normalized = path.toLowerCase();
2626
+ return (normalized.endsWith("/rightpanel.tsx") ||
2627
+ normalized.endsWith("/tools/common/toolcard.tsx") ||
2628
+ normalized.endsWith("/tools/common/toolexpandcontext.ts"));
2629
+ }
2630
+ function isTangentialDevtoolsTraceDebugPath(path) {
2631
+ const normalized = path.toLowerCase();
2632
+ const basename = normalized.split("/").at(-1) ?? normalized;
2633
+ return (basename === "advancedblocknoteeditor.tsx" ||
2634
+ basename === "githubsettingspopover.tsx" ||
2635
+ basename === "input.tsx" ||
2636
+ basename === "inputsettingspopover.tsx" ||
2637
+ basename === "mentionsuggestionspanel.tsx" ||
2638
+ basename === "segmentbuilder.ts" ||
2639
+ basename === "sendbutton.tsx" ||
2640
+ basename === "slashcommandspanel.tsx" ||
2641
+ normalized === "backend/tests/test_devtools_trace_archive.py" ||
2642
+ normalized.endsWith("/backend/tests/test_devtools_trace_archive.py"));
2643
+ }
2644
+ function isTangentialTaskClosureCandidate(path, task) {
2645
+ return ((isDevtoolsTraceDebugTask(task) && isTangentialDevtoolsTraceDebugPath(path)) ||
2646
+ (isCodexRuntimeReviewTask(task) && isTangentialCodexRuntimeReviewUiPath(path)));
2647
+ }
2648
+ function isProtectedReviewFocusPath(path, task) {
2649
+ if (!/\breview\b/i.test(task)) {
2650
+ return false;
2651
+ }
2652
+ const normalized = path.toLowerCase();
2653
+ return (normalized.includes("/services/runtime/") ||
2654
+ normalized.endsWith("/services/runtime_session_service.py") ||
2655
+ normalized.endsWith("/services/streaming/orchestrator.py") ||
2656
+ normalized.includes("/tests/services/runtime/") ||
2657
+ normalized.endsWith("/tests/services/test_runtime_session_service.py"));
2658
+ }
2659
+ function selectionWithSelectedFiles(selection, selected) {
2660
+ const bytes = selected.reduce((total, file) => total + file.bytes, 0);
2661
+ const tokens = selected.reduce((total, file) => total + file.estimated_tokens, 0);
2662
+ return {
2663
+ ...selection,
2664
+ selected,
2665
+ metrics: {
2666
+ files_selected: selected.length,
2667
+ files_omitted: selection.metrics.files_omitted,
2668
+ bytes_selected: bytes,
2669
+ estimated_tokens: tokens,
2670
+ truncated: selection.metrics.truncated,
2671
+ },
2672
+ };
2673
+ }
2674
+ function selectedFileKey(file) {
2675
+ return `${file.root_index}\u0000${file.path}`;
2676
+ }
2677
+ const RETAINABLE_CLOSURE_MAX_BYTES = 24_000;
2678
+ const RETAINABLE_PROVIDER_IMPL_MAX_BYTES = 48_000;
2679
+ function isRetainableClosureFile(file, task) {
2680
+ if (file.bytes > retainableClosureByteLimit(file.path, task)) {
2681
+ return false;
2682
+ }
2683
+ const normalized = file.path.toLowerCase();
2684
+ const basename = normalized.split("/").at(-1) ?? normalized;
2685
+ return (normalized.includes("/types/") ||
2686
+ normalized.includes("/schemas/") ||
2687
+ normalized.includes("/constants.") ||
2688
+ normalized.includes("/config.") ||
2689
+ normalized.includes("/querykeys.") ||
2690
+ normalized.includes("/messagerenderer.") ||
2691
+ normalized.includes("/message-bubble/message.") ||
2692
+ normalized.includes("/toolcard.") ||
2693
+ normalized.includes("/toolexpandcontext.") ||
2694
+ normalized.includes("/messagecacheorder.") ||
2695
+ normalized.includes("/session_trace_archive.") ||
2696
+ normalized.includes("/runtime/base.") ||
2697
+ normalized.includes("/claude_agent.") ||
2698
+ normalized.includes("/rightpanel.") ||
2699
+ basename.endsWith(".types.ts") ||
2700
+ basename === "api.types.ts" ||
2701
+ basename === "types.ts" ||
2702
+ basename === "schema.ts" ||
2703
+ basename === "schemas.ts" ||
2704
+ basename === "constants.ts" ||
2705
+ basename === "constants.py" ||
2706
+ basename === "config.ts" ||
2707
+ normalized.endsWith("/core/config.py") ||
2708
+ basename === "querykeys.ts" ||
2709
+ basename === "permission_mode.py" ||
2710
+ basename === "effort.py" ||
2711
+ basename === "codex_trace.py");
2712
+ }
2713
+ function retainableClosureByteLimit(path, task) {
2714
+ const normalized = path.toLowerCase();
2715
+ if (normalized.endsWith("codex_trace.py")) {
2716
+ return 12_000;
2717
+ }
2718
+ if (/\b(provider|runtime|codex|claude|review|discovery)\b/.test(task.toLowerCase()) &&
2719
+ (normalized.endsWith("/claude_agent.py") ||
2720
+ normalized.endsWith("/runtime/base.py"))) {
2721
+ return RETAINABLE_PROVIDER_IMPL_MAX_BYTES;
2722
+ }
2723
+ return RETAINABLE_CLOSURE_MAX_BYTES;
2724
+ }
2725
+ function selectedFileFromCandidate(candidate) {
2726
+ const bytes = Buffer.byteLength(candidate.content, "utf8");
2727
+ return {
2728
+ root_index: candidate.root_index,
2729
+ path: candidate.path,
2730
+ ranges: [{ start_line: 1, end_line: Math.max(1, candidate.line_count) }],
2731
+ content: candidate.content,
2732
+ bytes,
2733
+ estimated_tokens: estimateContextBuilderTokensFromUtf8Bytes(bytes),
2734
+ source: "search",
2735
+ };
2736
+ }
2737
+ function compactCandidateForRequiredClosure(candidate, task) {
2738
+ const sourceLines = splitTextLines(candidate.content);
2739
+ if (sourceLines.length === 0) {
2740
+ return null;
2741
+ }
2742
+ const tokens = new Set([
2743
+ ...tokenizeRepairWords(task),
2744
+ ...tokenizeRepairWords(candidate.path),
2745
+ ]);
2746
+ const selectedLineNumbers = new Set();
2747
+ const availableLineNumbers = sourceLines.map((_, index) => index + 1);
2748
+ addOriginalLineWindow(selectedLineNumbers, availableLineNumbers, 1, REQUIRED_CLOSURE_COMPACT_HEAD_LINES);
2749
+ for (let index = 0; index < sourceLines.length; index++) {
2750
+ if (selectedLineNumbers.size >= REQUIRED_CLOSURE_COMPACT_MAX_LINES) {
2751
+ break;
2752
+ }
2753
+ const line = sourceLines[index] ?? "";
2754
+ if (!lineMatchesRepairTokens(line, tokens)) {
2755
+ continue;
2756
+ }
2757
+ const originalLine = index + 1;
2758
+ addOriginalLineWindow(selectedLineNumbers, availableLineNumbers, originalLine - REQUIRED_CLOSURE_COMPACT_CONTEXT_LINES, originalLine + REQUIRED_CLOSURE_COMPACT_CONTEXT_LINES);
2759
+ }
2760
+ if (selectedLineNumbers.size === 0 || selectedLineNumbers.size >= sourceLines.length) {
2761
+ return null;
2762
+ }
2763
+ const ranges = mergeLineRanges([...selectedLineNumbers].map((line) => ({
2764
+ start_line: line,
2765
+ end_line: line,
2766
+ })));
2767
+ const content = ranges
2768
+ .flatMap((range) => sourceLines.slice(range.start_line - 1, range.end_line))
2769
+ .join("\n");
2770
+ const bytes = Buffer.byteLength(content, "utf8");
2771
+ if (bytes <= 0 || bytes >= candidate.byte_length) {
2772
+ return null;
2773
+ }
2774
+ return {
2775
+ root_index: candidate.root_index,
2776
+ path: candidate.path,
2777
+ ranges,
2778
+ content,
2779
+ bytes,
2780
+ estimated_tokens: estimateContextBuilderTokensFromUtf8Bytes(bytes),
2781
+ source: "search",
2782
+ };
2783
+ }
2784
+ function isTaskCriticalDiscoveredClosure(path, task) {
2785
+ const normalizedTask = task.toLowerCase();
2786
+ const normalized = path.toLowerCase();
2787
+ const basename = normalized.split("/").at(-1) ?? normalized;
2788
+ const providerRuntimeTask = /\b(provider|provider-specific|runtime|codex|claude)\b/.test(normalizedTask);
2789
+ if (/\bdebug(?:ging)?\b/.test(normalizedTask) &&
2790
+ !isTangentialDevtoolsTraceDebugPath(path) &&
2791
+ (basename === "codex_trace.py" ||
2792
+ basename === "session_trace_archive.py" ||
2793
+ basename === "toolcard.tsx" ||
2794
+ basename === "devtools-helpers.ts" ||
2795
+ basename === "devtoolsservice.ts" ||
2796
+ basename === "usedevtoolsqueries.ts" ||
2797
+ basename === "devtoolsnavstore.ts" ||
2798
+ basename === "messagerenderer.tsx" ||
2799
+ basename === "rightpaneldevtools.tsx" ||
2800
+ basename === "rightpanel.tsx" ||
2801
+ basename === "usemessagecache.ts" ||
2802
+ basename === "chat.tsx" ||
2803
+ basename === "right-panel-devtools.test.tsx" ||
2804
+ normalized.endsWith("/api/endpoints/devtools.py") ||
2805
+ normalized.endsWith("/models/db_models/session_trace_archive.py") ||
2806
+ normalized.includes("devtools-helpers.test") ||
2807
+ normalized.includes("toolexpand.test") ||
2808
+ normalized.includes("devtoolsnavstore.test"))) {
2809
+ return true;
2810
+ }
2811
+ if (/\breview\b/.test(normalizedTask) &&
2812
+ !isTangentialCodexRuntimeReviewUiPath(path) &&
2813
+ ((normalized.endsWith("/core/config.py") &&
2814
+ /\bconfig(?:uration)?\b/.test(normalizedTask)) ||
2815
+ basename === "constants.py" ||
2816
+ basename === "permission_manager.py" ||
2817
+ basename === "ai_model.py" ||
2818
+ basename === "permissions.py" ||
2819
+ basename === "permission_mode.py" ||
2820
+ basename === "permissions.ts" ||
2821
+ basename === "effort.py" ||
2822
+ basename === "usepermissionrequest.ts" ||
2823
+ basename === "usemessageactions.ts" ||
2824
+ basename === "fileuploaddialog.tsx" ||
2825
+ basename === "modelprovider.ts" ||
2826
+ basename === "ai_models.py" ||
2827
+ basename === "test_ai_models_codex_gate.py" ||
2828
+ basename === "model_provider_auth.py" ||
2829
+ basename === "chat.types.ts" ||
2830
+ basename === "chatservice.ts" ||
2831
+ normalized.endsWith("/api/endpoints/chat.py") ||
2832
+ normalized.endsWith("/services/chat.py") ||
2833
+ basename === "streamservice.ts" ||
2834
+ basename === "fileuploaddialog.codex.test.tsx" ||
2835
+ basename === "test_permissions.py" ||
2836
+ basename === "test_model_provider_auth.py" ||
2837
+ normalized.endsWith("/api/endpoints/permissions.py") ||
2838
+ isTaskCriticalReviewDoc(normalized) ||
2839
+ normalized.includes("resolver") && normalized.includes("test") ||
2840
+ normalized.includes("modelprovider") && normalized.includes("test"))) {
2841
+ return true;
2842
+ }
2843
+ if (/\bdiscovery\b/.test(normalizedTask) &&
2844
+ (basename === "permission_mode.py" ||
2845
+ normalized.endsWith("/services/chat.py") ||
2846
+ normalized.endsWith("/components/chat/chat-window/chat.tsx") ||
2847
+ normalized.endsWith("/components/chat/message-input/input.tsx") ||
2848
+ normalized.endsWith("/components/chat/message-input/composerruntimecontrols.tsx") ||
2849
+ normalized.endsWith("/components/chat/message-input/inputsettingspopover.tsx") ||
2850
+ normalized.endsWith("/hooks/usechatruntimesettings.ts") ||
2851
+ normalized.endsWith("/pages/chatpage.tsx") ||
2852
+ normalized.endsWith("/api/endpoints/chat.py") ||
2853
+ normalized.endsWith("/models/db_models/chat.py") ||
2854
+ normalized.endsWith("/models/schemas/chat.py") ||
2855
+ basename === "chatservice.ts" ||
2856
+ basename === "messagequeuestore.ts" ||
2857
+ basename === "streamservice.ts" ||
2858
+ basename === "messagequeuestore.ts" ||
2859
+ basename === "usepermissionrequest.ts" ||
2860
+ basename === "usesettingsqueries.ts" ||
2861
+ basename === "chat_processor.py" ||
2862
+ basename === "landingpage.tsx" ||
2863
+ basename === "usechatstreaming.ts" ||
2864
+ basename === "usemessageactions.ts" ||
2865
+ basename === "queue.py" ||
2866
+ basename === "test_chat.py" ||
2867
+ basename === "test_queue.py" ||
2868
+ normalized.endsWith("/tests/services/test_queue.py") ||
2869
+ basename === "test_effort_level.py" ||
2870
+ basename === "test_permission_mode.py" ||
2871
+ basename === "test_codex_runtime.py" ||
2872
+ basename === "test_codex_effort_translation.py" ||
2873
+ normalized.endsWith("/services/runtime/claude.py") ||
2874
+ normalized.endsWith("/services/runtime/codex.py") ||
2875
+ normalized.endsWith("/services/runtime/claude.py") ||
2876
+ normalized.endsWith("/services/runtime/base.py") ||
2877
+ normalized.endsWith("/services/runtime/claude.py") ||
2878
+ normalized.endsWith("/services/runtime/codex_approval.py") ||
2879
+ normalized.endsWith("/services/runtime_session_service.py") ||
2880
+ basename === "test_pending_initial_prompt_service.py" ||
2881
+ basename === "queue.types.ts" ||
2882
+ basename === "chat.types.ts" ||
2883
+ basename.includes("permissionmodeselector") ||
2884
+ basename.includes("thinkingmodeselector"))) {
2885
+ return true;
2886
+ }
2887
+ if (providerRuntimeTask &&
2888
+ /\b(provider-specific|provider\s+semantics|providers?|claude|agent|symmetry)\b/.test(normalizedTask) &&
2889
+ (basename === "claude_agent.py" || normalized.endsWith("/runtime/base.py"))) {
2890
+ return true;
2891
+ }
2892
+ return false;
2893
+ }
2894
+ function fileCoversCandidate(file, candidate) {
2895
+ return file.ranges.some((range) => range.start_line <= 1 &&
2896
+ range.end_line >= Math.max(1, candidate.line_count));
2897
+ }
2898
+ function compareTaskCriticalCandidates(left, right, task) {
2899
+ return (taskCriticalPathRank(left.path, task) - taskCriticalPathRank(right.path, task) ||
2900
+ left.byte_length - right.byte_length ||
2901
+ left.root_index - right.root_index ||
2902
+ left.path.localeCompare(right.path));
2903
+ }
2904
+ function taskCriticalPathRank(path, task) {
2905
+ const normalized = path.toLowerCase();
2906
+ const basename = normalized.split("/").at(-1) ?? normalized;
2907
+ const normalizedTask = task.toLowerCase();
2908
+ if (/\bdiscovery\b/.test(normalizedTask)) {
2909
+ if (isRuntimeSettingsDiscoveryTask(task) &&
2910
+ isTangentialRuntimeSettingsDiscoveryTestPath(normalized, basename)) {
2911
+ return 5;
2912
+ }
2913
+ if (isRuntimeSettingsDiscoveryTask(task)) {
2914
+ const runtimeRank = runtimeSettingsDiscoveryTaskCriticalRank(normalized, basename);
2915
+ if (runtimeRank != null) {
2916
+ return runtimeRank;
2917
+ }
2918
+ }
2919
+ if (normalized.endsWith("/services/chat.py") ||
2920
+ normalized.endsWith("/components/chat/chat-window/chat.tsx") ||
2921
+ normalized.endsWith("/components/chat/message-input/input.tsx") ||
2922
+ normalized.endsWith("/components/chat/message-input/composerruntimecontrols.tsx") ||
2923
+ normalized.endsWith("/components/chat/message-input/inputsettingspopover.tsx") ||
2924
+ normalized.endsWith("/pages/chatpage.tsx") ||
2925
+ normalized.endsWith("/models/db_models/chat.py") ||
2926
+ normalized.endsWith("/models/schemas/chat.py") ||
2927
+ basename === "chatservice.ts" ||
2928
+ basename === "streamservice.ts" ||
2929
+ basename === "usemessageactions.ts" ||
2930
+ basename === "usechatstreaming.ts" ||
2931
+ basename === "landingpage.tsx" ||
2932
+ basename === "chat_processor.py" ||
2933
+ basename === "test_queue.py" ||
2934
+ normalized.endsWith("/tests/services/test_queue.py") ||
2935
+ basename === "test_chat.py" ||
2936
+ basename === "test_queue_service.py" ||
2937
+ basename === "test_chat_processor.py" ||
2938
+ normalized.endsWith("/services/runtime/claude.py") ||
2939
+ normalized.endsWith("/services/runtime/codex.py") ||
2940
+ normalized.endsWith("/services/runtime/codex_stream_processor.py") ||
2941
+ normalized.endsWith("/services/runtime/base.py") ||
2942
+ normalized.endsWith("/services/runtime/claude.py") ||
2943
+ normalized.endsWith("/services/runtime/codex_approval.py") ||
2944
+ normalized.endsWith("/services/runtime_session_service.py") ||
2945
+ normalized.endsWith("/models/db_models/runtime_session.py") ||
2946
+ normalized.endsWith("/services/permission_manager.py") ||
2947
+ normalized.endsWith("/hooks/__tests__/usechatruntimesettings.test.ts") ||
2948
+ normalized.endsWith("/pages/landingpage.test.tsx") ||
2949
+ normalized.endsWith("/tests/test_codex_runtime_data_migration.py") ||
2950
+ basename === "chat.types.ts" ||
2951
+ basename === "queue.types.ts" ||
2952
+ basename.includes("permissionmodeselector") ||
2953
+ basename.includes("thinkingmodeselector")) {
2954
+ return 0;
2955
+ }
2956
+ if (basename === "test_effort_level.py" ||
2957
+ basename === "test_permission_mode.py" ||
2958
+ basename === "test_codex_runtime.py" ||
2959
+ basename === "test_codex_effort_translation.py") {
2960
+ return 1;
2961
+ }
2962
+ if ((basename === "claude_agent.py" || basename === "test_claude_agent.py") &&
2963
+ /\b(provider-specific|provider\s+semantics|providers?|claude|agent|symmetry)\b/.test(normalizedTask)) {
2964
+ return 0;
2965
+ }
2966
+ if (basename === "test_codex_e2e_live.py" ||
2967
+ basename === "test_codex_sdk_smoke.py" ||
2968
+ basename === "test_transport_absence.py" ||
2969
+ basename === "test_codex_runtime_live.py" ||
2970
+ basename === "test_resolver.py") {
2971
+ return 5;
2972
+ }
2973
+ }
2974
+ if (/\breview\b/.test(normalizedTask)) {
2975
+ if (normalized.endsWith("/api/endpoints/permissions.py") ||
2976
+ (normalized.endsWith("/core/config.py") &&
2977
+ /\bconfig(?:uration)?\b/.test(normalizedTask)) ||
2978
+ normalized.endsWith("/services/runtime/codex.py") ||
2979
+ normalized.endsWith("/services/runtime/codex_approval.py") ||
2980
+ normalized.endsWith("/services/runtime/codex_stream_processor.py") ||
2981
+ normalized.endsWith("/services/runtime/resolver.py") ||
2982
+ normalized.endsWith("/services/runtime_session_service.py") ||
2983
+ normalized.endsWith("/services/sandbox/provider.py") ||
2984
+ normalized.endsWith("/services/streaming/context_usage.py") ||
2985
+ normalized.endsWith("/services/model_provider_auth.py") ||
2986
+ normalized.endsWith("/services/providerauthservice.ts") ||
2987
+ normalized.endsWith("/services/streamservice.ts") ||
2988
+ normalized.endsWith("/hooks/usechatruntimesettings.ts") ||
2989
+ normalized.endsWith("/components/chat/permission-mode-selector/permissionmodeselector.tsx") ||
2990
+ normalized.endsWith("/components/chat/thinking-mode-selector/thinkingmodeselector.tsx") ||
2991
+ normalized.endsWith("/components/chat/message-input/composerruntimecontrols.tsx") ||
2992
+ normalized.endsWith("/api/endpoints/ai_models.py") ||
2993
+ normalized.endsWith("/tests/test_ai_models_codex_gate.py") ||
2994
+ normalized.endsWith("/services/streaming/orchestrator.py") ||
2995
+ (normalized.endsWith("/tests/services/streaming/test_context_usage_payloads.py") &&
2996
+ /\bcontext\s+usage|usage\s+payloads?\b/.test(normalizedTask)) ||
2997
+ normalized.includes("/tests/services/runtime/") ||
2998
+ normalized.endsWith("/tests/services/test_model_provider_auth.py") ||
2999
+ normalized.endsWith("/tests/services/test_runtime_session_service.py") ||
3000
+ normalized.endsWith("/api/endpoints/chat.py") ||
3001
+ normalized.endsWith("/services/chat.py") ||
3002
+ normalized.endsWith("/models/db_models/ai_model.py") ||
3003
+ basename === "constants.py" ||
3004
+ basename === "usepermissionrequest.ts" ||
3005
+ basename === "usemessageactions.ts" ||
3006
+ basename === "fileuploaddialog.tsx" ||
3007
+ basename === "modelprovider.ts" ||
3008
+ basename === "test_permissions.py" ||
3009
+ basename === "permission_manager.py" ||
3010
+ basename === "chatservice.ts" ||
3011
+ basename === "chat.types.ts") {
3012
+ return 0;
3013
+ }
3014
+ if (isTaskCriticalReviewDoc(normalized)) {
3015
+ return 2;
3016
+ }
3017
+ if (normalized.includes("/admin/config.py") ||
3018
+ normalized.includes("/.ai/memory-bank/")) {
3019
+ return 5;
3020
+ }
3021
+ }
3022
+ if (isDevtoolsTraceDebugTask(task)) {
3023
+ if (isTangentialDevtoolsTraceDebugPath(path)) {
3024
+ return 5;
3025
+ }
3026
+ if (normalized.endsWith("/components/right-panel/rightpaneldevtools.tsx") ||
3027
+ normalized.endsWith("/components/right-panel/__tests__/right-panel-devtools.test.tsx") ||
3028
+ normalized.endsWith("/components/chat/__tests__/chat.autoscroll.test.tsx") ||
3029
+ normalized.endsWith("/components/right-panel/devtools-helpers.ts") ||
3030
+ normalized.endsWith("/store/devtoolsnavstore.ts") ||
3031
+ normalized.endsWith("/store/__tests__/devtoolsnavstore.test.ts") ||
3032
+ normalized.endsWith("/components/chat/chat-window/chat.tsx") ||
3033
+ normalized.endsWith("/components/chat/message-bubble/messagerenderer.tsx") ||
3034
+ normalized.endsWith("/components/chat/tools/common/toolcard.tsx") ||
3035
+ normalized.endsWith("/components/chat/message-bubble/message.tsx")) {
3036
+ return 0;
3037
+ }
3038
+ if (normalized.endsWith("/hooks/queries/usedevtoolsqueries.ts") ||
3039
+ normalized.endsWith("/services/devtoolsservice.ts") ||
3040
+ normalized.endsWith("/hooks/queries/querykeys.ts") ||
3041
+ normalized.endsWith("/utils/messagecacheorder.ts") ||
3042
+ normalized.endsWith("/hooks/usemessagecache.ts") ||
3043
+ normalized.endsWith("/components/chat/tools/common/toolexpandcontext.ts") ||
3044
+ normalized.endsWith("/components/chat/tools/common/__tests__/toolexpand.test.tsx")) {
3045
+ return 1;
3046
+ }
3047
+ if (normalized.endsWith("/api/endpoints/devtools.py") ||
3048
+ normalized.endsWith("/services/session_trace_archive.py")) {
3049
+ return 3;
3050
+ }
3051
+ if (normalized.endsWith("/models/db_models/session_trace_archive.py") ||
3052
+ normalized.endsWith("/models/schemas/devtools.py") ||
3053
+ normalized.endsWith("/services/codex_trace.py") ||
3054
+ normalized.endsWith("/types/devtools.types.ts")) {
3055
+ return 4;
3056
+ }
3057
+ if (normalized.endsWith("/pages/chatpage.tsx") ||
3058
+ normalized.endsWith("/components/chat/message-input/input.tsx") ||
3059
+ normalized.endsWith("/api/endpoints/chat.py") ||
3060
+ normalized.endsWith("/services/claude_agent.py") ||
3061
+ normalized.endsWith("/services/chat.py") ||
3062
+ normalized.endsWith("/services/chatservice.ts")) {
3063
+ return 4;
3064
+ }
3065
+ }
3066
+ if (basename === "permission_mode.py" ||
3067
+ basename === "effort.py" ||
3068
+ basename === "permissions.py" ||
3069
+ basename === "constants.py" ||
3070
+ basename === "config.py" ||
3071
+ basename === "querykeys.ts" ||
3072
+ basename.endsWith(".types.ts")) {
3073
+ return 0;
3074
+ }
3075
+ if (basename.endsWith(".test.tsx") || basename.endsWith(".test.ts")) {
3076
+ return 2;
3077
+ }
3078
+ return 1;
3079
+ }
3080
+ function runtimeSettingsDiscoveryTaskCriticalRank(normalizedPath, basename) {
3081
+ if (normalizedPath.endsWith("/hooks/usechatruntimesettings.ts")) {
3082
+ return 0;
3083
+ }
3084
+ if (normalizedPath.endsWith("/components/chat/message-input/composerruntimecontrols.tsx") ||
3085
+ normalizedPath.endsWith("/components/chat/message-input/input.tsx") ||
3086
+ normalizedPath.endsWith("/pages/chatpage.tsx")) {
3087
+ return 0;
3088
+ }
3089
+ if (normalizedPath.endsWith("/services/chatservice.ts") ||
3090
+ normalizedPath.endsWith("/api/endpoints/chat.py") ||
3091
+ normalizedPath.endsWith("/services/chat.py")) {
3092
+ return 0;
3093
+ }
3094
+ if (normalizedPath.endsWith("/store/messagequeuestore.ts") ||
3095
+ normalizedPath.endsWith("/store/__tests__/messagequeuestore.test.ts") ||
3096
+ normalizedPath.endsWith("/services/queueservice.ts") ||
3097
+ normalizedPath.endsWith("/tests/services/test_queue.py") ||
3098
+ normalizedPath.endsWith("/tests/test_queue.py") ||
3099
+ normalizedPath.endsWith("/tests/services/test_pending_initial_prompt_service.py")) {
3100
+ return 0;
3101
+ }
3102
+ if (normalizedPath.endsWith("/services/runtime/codex.py") ||
3103
+ normalizedPath.endsWith("/services/runtime/claude.py") ||
3104
+ normalizedPath.endsWith("/services/runtime/codex_approval.py") ||
3105
+ normalizedPath.endsWith("/services/runtime/codex_stream_processor.py") ||
3106
+ normalizedPath.endsWith("/services/runtime_session_service.py") ||
3107
+ normalizedPath.endsWith("/services/streaming/orchestrator.py")) {
3108
+ return 0;
3109
+ }
3110
+ if (normalizedPath.endsWith("/hooks/__tests__/usechatruntimesettings.test.ts") ||
3111
+ normalizedPath.endsWith("/pages/landingpage.test.tsx") ||
3112
+ normalizedPath.endsWith("/tests/services/runtime/test_codex_runtime.py") ||
3113
+ normalizedPath.endsWith("/tests/test_codex_runtime_data_migration.py") ||
3114
+ normalizedPath.endsWith("/tests/test_codex_effort_translation.py") ||
3115
+ normalizedPath.endsWith("/tests/test_effort_level.py") ||
3116
+ normalizedPath.endsWith("/tests/test_permission_mode.py") ||
3117
+ normalizedPath.endsWith("/tests/services/test_claude_agent.py")) {
3118
+ return 1;
3119
+ }
3120
+ if (basename === "effort.py" ||
3121
+ basename === "permission_mode.py" ||
3122
+ basename === "chat.types.ts" ||
3123
+ basename === "queue.types.ts" ||
3124
+ normalizedPath.endsWith("/models/schemas/chat.py") ||
3125
+ normalizedPath.endsWith("/models/db_models/chat.py") ||
3126
+ normalizedPath.endsWith("/models/db_models/runtime_session.py") ||
3127
+ basename.includes("permissionmodeselector") ||
3128
+ basename.includes("thinkingmodeselector")) {
3129
+ return 2;
3130
+ }
3131
+ return null;
3132
+ }
3133
+ function isTaskCriticalReviewDoc(normalizedPath) {
3134
+ if (!normalizedPath.endsWith(".md")) {
3135
+ return false;
3136
+ }
3137
+ if (normalizedPath.startsWith(".ai/memory-bank/") || normalizedPath.includes("/.ai/memory-bank/")) {
3138
+ return false;
3139
+ }
3140
+ if (normalizedPath.startsWith(".ai/") || normalizedPath.includes("/.ai/")) {
3141
+ return false;
3142
+ }
3143
+ if (normalizedPath.endsWith("docs/ops/nano-permissions-policy.md")) {
3144
+ return false;
3145
+ }
3146
+ return (/(^|\/)docs?\/.*(codex|approval|permission|session|runtime).*\.md$/.test(normalizedPath));
3147
+ }
3148
+ function handleDelegateRuntimeFailure(input) {
3149
+ const failureReason = sanitizeDiagnosticText(input.reason);
3150
+ if (input.delegate.failure_policy === "fail") {
3151
+ throw new ExecutionError(`context_builder delegate failed: ${failureReason}`);
3152
+ }
3153
+ const warnings = [
3154
+ delegateWarning("delegate_fallback", `Delegate curation failed; deterministic selection was used. ${failureReason}`),
3155
+ ];
3156
+ return {
3157
+ selection: input.deterministicSelection,
3158
+ warnings,
3159
+ omissions: [...(input.omissions ?? [])],
3160
+ openQuestions: [],
3161
+ delegate: {
3162
+ enabled: true,
3163
+ status: "partial",
3164
+ failure_policy: input.delegate.failure_policy,
3165
+ fallback_used: true,
3166
+ curator: { ...input.delegate.curator },
3167
+ finalizer: delegateFinalizerReceiptMetadata(input.delegate.finalizer),
3168
+ selected_count: input.candidateFallbackCount,
3169
+ warning_count: warnings.length,
3170
+ omission_count: input.omissionCount,
3171
+ failure_reason: failureReason,
3172
+ },
3173
+ };
3174
+ }
3175
+ function formatOmissionForDelegateFailure(omission) {
3176
+ const paths = omission.paths == null || omission.paths.length === 0
3177
+ ? "unknown focused path"
3178
+ : boundContextBuilderPathList(omission.paths).join(", ");
3179
+ return `${omission.reason} (${paths}): ${sanitizeDiagnosticText(omission.message)}`;
3180
+ }
3181
+ function rangeCoveredByRanges(target, ranges) {
3182
+ let nextLine = target.start_line;
3183
+ for (const range of [...ranges].sort((left, right) => left.start_line - right.start_line || left.end_line - right.end_line)) {
3184
+ if (range.end_line < nextLine) {
3185
+ continue;
3186
+ }
3187
+ if (range.start_line > nextLine) {
3188
+ return false;
3189
+ }
3190
+ nextLine = Math.max(nextLine, range.end_line + 1);
3191
+ if (nextLine > target.end_line) {
3192
+ return true;
3193
+ }
3194
+ }
3195
+ return false;
3196
+ }
3197
+ function pruneDelegateProposalToLocalSelection(proposal, candidates, selection, warning) {
3198
+ const candidatesByPath = new Map();
3199
+ for (const candidate of candidates) {
3200
+ candidatesByPath.set(`${candidate.root_index}:${candidate.path}`, candidate);
3201
+ }
3202
+ const selected = selection.selected.flatMap((file) => {
3203
+ const candidate = candidatesByPath.get(`${file.root_index}:${file.path}`);
3204
+ if (candidate == null) {
3205
+ return [];
3206
+ }
3207
+ const original = proposal.selected.find((item) => item.candidate_id === candidate.id);
3208
+ return [
3209
+ {
3210
+ candidate_id: candidate.id,
3211
+ ranges: file.ranges.map((range) => ({
3212
+ start_line: range.start_line,
3213
+ end_line: range.end_line,
3214
+ reason: "budget-pruned local selection range",
3215
+ })),
3216
+ reason: original?.reason ??
3217
+ "retained because it fit the local reconstruction budget",
3218
+ },
3219
+ ];
3220
+ });
3221
+ return {
3222
+ ...proposal,
3223
+ selected,
3224
+ warnings: proposal.warnings.includes(warning)
3225
+ ? proposal.warnings
3226
+ : [...proposal.warnings, warning],
3227
+ };
3228
+ }
3229
+ function delegateCompletenessFailure(input) {
3230
+ const materialWarnings = [
3231
+ ...input.curatorWarnings,
3232
+ ...input.finalizerWarnings,
3233
+ ].filter((warning) => isMaterialDelegateEvidenceWarning(warning) &&
3234
+ !warningReferencesSelectedDelegateCandidate({
3235
+ warning,
3236
+ candidates: input.candidates,
3237
+ selected: input.finalizerSelected,
3238
+ }));
3239
+ if (materialWarnings.length > 0) {
3240
+ return `delegate warnings reported material evidence gaps: ${materialWarnings.join("; ")}`;
3241
+ }
3242
+ const required = requiredFocusEvidenceSelections(input);
3243
+ if (required.length === 0) {
3244
+ return undefined;
3245
+ }
3246
+ const selectedByCandidate = new Map();
3247
+ for (const selection of input.finalizerSelected) {
3248
+ selectedByCandidate.set(selection.candidate_id, [
3249
+ ...(selectedByCandidate.get(selection.candidate_id) ?? []),
3250
+ ...selection.ranges,
3251
+ ]);
3252
+ }
3253
+ const missing = required.filter((selection) => {
3254
+ const selectedRanges = selectedByCandidate.get(selection.candidate_id) ?? [];
3255
+ return selection.ranges.some((range) => !rangeCoveredByRanges(range, selectedRanges));
3256
+ });
3257
+ if (missing.length === 0) {
3258
+ return undefined;
3259
+ }
3260
+ return `delegate finalizer omitted requested local evidence: ${missing
3261
+ .map((selection) => `${selection.path}#${selection.ranges
3262
+ .map((range) => `${range.start_line}-${range.end_line}`)
3263
+ .join(",")}`)
3264
+ .join("; ")}`;
3265
+ }
3266
+ function warningReferencesSelectedDelegateCandidate(input) {
3267
+ const selectedCandidateIds = new Set(input.selected.map((selection) => selection.candidate_id));
3268
+ const selectedFiles = input.candidates
3269
+ .filter((candidate) => selectedCandidateIds.has(candidate.id))
3270
+ .map((candidate) => ({
3271
+ root_index: candidate.root_index,
3272
+ path: candidate.path,
3273
+ ranges: candidate.ranges.map((range) => ({
3274
+ start_line: range.start_line,
3275
+ end_line: range.end_line,
3276
+ })),
3277
+ content: "",
3278
+ bytes: candidate.size_bytes,
3279
+ estimated_tokens: candidate.estimated_tokens,
3280
+ source: candidate.discovery_reason === "focus_path" ? "focus" : "search",
3281
+ }));
3282
+ return isStaleSelectedContextOmissionWarning(input.warning.toLowerCase(), selectedFiles);
3283
+ }
3284
+ function requiredFocusEvidenceSelections(input) {
3285
+ if (input.focusPaths.length === 0) {
3286
+ return [];
3287
+ }
3288
+ return input.candidates
3289
+ .filter((candidate) => candidate.focus_requested === true &&
3290
+ (candidate.required_focus_ranges?.length ?? 0) > 0 &&
3291
+ candidateMatchesFocusPath(candidate, input.focusPaths))
3292
+ .map((candidate) => ({
3293
+ candidate_id: candidate.id,
3294
+ path: candidate.path,
3295
+ ranges: candidate.required_focus_ranges.map((range) => ({
3296
+ start_line: range.start_line,
3297
+ end_line: range.end_line,
3298
+ })),
3299
+ }));
3300
+ }
3301
+ function foldRequiredFocusEvidenceIntoSelection(finalizerSelected, requiredFocus) {
3302
+ if (requiredFocus.length === 0) {
3303
+ return { selected: [...finalizerSelected], foldedPaths: [] };
3304
+ }
3305
+ const selectedByCandidate = new Map();
3306
+ for (const selection of finalizerSelected) {
3307
+ selectedByCandidate.set(selection.candidate_id, {
3308
+ candidate_id: selection.candidate_id,
3309
+ reason: selection.reason,
3310
+ ranges: selection.ranges.map((range) => ({ ...range })),
3311
+ });
3312
+ }
3313
+ const foldedPaths = [];
3314
+ for (const required of requiredFocus) {
3315
+ const existing = selectedByCandidate.get(required.candidate_id);
3316
+ const existingRanges = existing?.ranges ?? [];
3317
+ const hasUncoveredRange = required.ranges.some((range) => !rangeCoveredByRanges(range, existingRanges));
3318
+ if (!hasUncoveredRange) {
3319
+ continue;
3320
+ }
3321
+ foldedPaths.push(required.path);
3322
+ const ranges = mergeLineRanges([
3323
+ ...existingRanges.map((range) => ({
3324
+ start_line: range.start_line,
3325
+ end_line: range.end_line,
3326
+ })),
3327
+ ...required.ranges,
3328
+ ]).map((range) => ({
3329
+ start_line: range.start_line,
3330
+ end_line: range.end_line,
3331
+ reason: "server-folded requested local evidence omitted by finalizer",
3332
+ }));
3333
+ selectedByCandidate.set(required.candidate_id, {
3334
+ candidate_id: required.candidate_id,
3335
+ reason: existing?.reason ?? "requested local focus evidence preserved by server",
3336
+ ranges,
3337
+ });
3338
+ }
3339
+ return { selected: [...selectedByCandidate.values()], foldedPaths };
3340
+ }
3341
+ function candidateMatchesFocusPath(candidate, focusPaths) {
3342
+ return focusPaths.some((focus) => {
3343
+ if (focus.root_index !== candidate.root_index) {
3344
+ return false;
3345
+ }
3346
+ if (focus.kind === "file") {
3347
+ return candidate.path === focus.root_relative_path;
3348
+ }
3349
+ return isSameRootRelativePathOrDescendant(candidate.path, focus.root_relative_path);
3350
+ });
3351
+ }
3352
+ function isSameRootRelativePathOrDescendant(candidatePath, parentPath) {
3353
+ if (parentPath === "") {
3354
+ return true;
3355
+ }
3356
+ return candidatePath === parentPath || candidatePath.startsWith(`${parentPath}/`);
3357
+ }
3358
+ function isMaterialDelegateEvidenceWarning(message) {
3359
+ const text = message.toLowerCase();
3360
+ if (isNonBlockingDelegateWarning(text)) {
3361
+ return false;
3362
+ }
3363
+ return (/\b(required|requested|focus(?:ed)?)\b.{0,80}\b(missing|missed|incomplete|unavailable|insufficient|omitted|not selected|not selectable|unselectable|not present)\b/.test(text) ||
3364
+ /\b(missing|missed|incomplete|unavailable|insufficient|omitted|not selected|not selectable|unselectable|not present)\b.{0,80}\b(required|requested|focus(?:ed)?)\b/.test(text) ||
3365
+ /\bselected\b.{0,80}\b(not selectable|unselectable|not present)\b/.test(text) ||
3366
+ /\boutside (?:the )?selected ranges?\b/.test(text));
3367
+ }
3368
+ function isNonBlockingDelegateWarning(text) {
3369
+ return (/\bpacket evidence omitted full source excerpts\b/.test(text) ||
3370
+ /\bfull source excerpts? (?:were )?omitted\b/.test(text) ||
3371
+ /\bfull-file focus ranges?\b.{0,120}\b(?:excerpts?|full source)\b.{0,80}\b(?:omitted|truncated)\b/.test(text) ||
3372
+ /\bfull source excerpts?\b.{0,80}\bunavailable\b.{0,120}\bwhole-file focus ranges?\b/.test(text) ||
3373
+ isSecretSafetyOmissionWarning(text) ||
3374
+ /\bomitted from deterministic_selection\b.{0,120}\bbut selected\b/.test(text) ||
3375
+ isSpeculativeIrrelevantOmissionWarning(text) ||
3376
+ isFocusPreservingSkipWarning(text) ||
3377
+ isDeterministicExpansionWarning(text));
3378
+ }
3379
+ function isSecretSafetyOmissionWarning(text) {
3380
+ return (/\b(?:high-confidence secret|secret detection|secret safety|secret[- ]safe|redacted|redacted-safe|redaction)\b/.test(text) &&
3381
+ /\b(?:omitted|excluded|not selected|not requested|should not be requested|unavailable)\b/.test(text));
3382
+ }
3383
+ function isFocusPreservingSkipWarning(text) {
3384
+ return (/\b(?:unrelated|irrelevant|out-of-scope|low[- ]signal)\b.{0,120}\b(?:not selected|omitted|skipped)\b.{0,80}\bpreserve focus\b/.test(text) ||
3385
+ /\b(?:not selected|omitted|skipped)\b.{0,120}\b(?:unrelated|irrelevant|out-of-scope|low[- ]signal)\b.{0,80}\bpreserve focus\b/.test(text));
3386
+ }
3387
+ function isSpeculativeIrrelevantOmissionWarning(text) {
3388
+ if (!/\b(?:may|might|could)\b.{0,80}\b(?:omit|omits|omitted|missing)\b/.test(text)) {
3389
+ return false;
3390
+ }
3391
+ if (/\b(required|requested)\b/.test(text)) {
3392
+ return false;
3393
+ }
3394
+ return /\b(additional|broader|other|unrelated|irrelevant|repository|out-of-packet|outside (?:this|the) bounded packet)\b/.test(text);
3395
+ }
3396
+ function isDeterministicExpansionWarning(text) {
3397
+ return (/\bselection\b.{0,80}\b(?:intentionally\s+)?(?:exceeds|exceeded|expands beyond|expanded beyond|extends beyond|extended beyond)\b.{0,120}\bdeterministic\b.{0,160}\binsufficient\b/.test(text) &&
3398
+ !/\b(missing|missed|omitted|not selected|not selectable|unselectable|not present|unavailable)\b/.test(text));
3399
+ }
3400
+ function augmentCuratorProposalWithDeterministicBaseline(proposal, packet, maxSelections) {
3401
+ const deterministicSelected = packet.deterministic_selection?.selected ?? [];
3402
+ if (deterministicSelected.length === 0 ||
3403
+ proposal.selected.length >= maxSelections) {
3404
+ return proposal;
3405
+ }
3406
+ const selectedByCandidate = new Map();
3407
+ for (const selection of proposal.selected) {
3408
+ selectedByCandidate.set(selection.candidate_id, {
3409
+ candidate_id: selection.candidate_id,
3410
+ ranges: [...selection.ranges],
3411
+ reason: selection.reason,
3412
+ });
3413
+ }
3414
+ let added = 0;
3415
+ for (const selection of deterministicSelected) {
3416
+ const existing = selectedByCandidate.get(selection.candidate_id);
3417
+ if (existing == null) {
3418
+ if (selectedByCandidate.size >= maxSelections) {
3419
+ break;
3420
+ }
3421
+ selectedByCandidate.set(selection.candidate_id, {
3422
+ candidate_id: selection.candidate_id,
3423
+ ranges: selection.ranges.map((range) => ({
3424
+ start_line: range.start_line,
3425
+ end_line: range.end_line,
3426
+ reason: "deterministic baseline retained because curator underselected local evidence",
3427
+ })),
3428
+ reason: "server-retained deterministic baseline candidate for finalizer review",
3429
+ });
3430
+ added += 1;
3431
+ continue;
3432
+ }
3433
+ const deterministicRanges = selection.ranges.map((range) => ({
3434
+ start_line: range.start_line,
3435
+ end_line: range.end_line,
3436
+ reason: "deterministic baseline range retained because curator expanded local evidence",
3437
+ }));
3438
+ if (totalSelectedRangeLines(deterministicRanges) < totalSelectedRangeLines(existing.ranges)) {
3439
+ existing.ranges = deterministicRanges;
3440
+ added += 1;
3441
+ }
3442
+ }
3443
+ if (added === 0) {
3444
+ return proposal;
3445
+ }
3446
+ return {
3447
+ selected: [...selectedByCandidate.values()],
3448
+ warnings: [
3449
+ ...proposal.warnings,
3450
+ `curator selected fewer local candidates than the deterministic baseline; retained ${added} deterministic baseline candidate/range item(s) for finalizer review`,
3451
+ ],
3452
+ open_questions: proposal.open_questions,
3453
+ };
3454
+ }
3455
+ function totalSelectedRangeLines(ranges) {
3456
+ return ranges.reduce((total, range) => total + Math.max(0, range.end_line - range.start_line + 1), 0);
3457
+ }
3458
+ export function renderDelegatePrompt(stage, packet) {
3459
+ const outputShape = stage === "curator"
3460
+ ? '{"selected":[{"candidate_id":"c:0:path","ranges":[{"start_line":1,"end_line":1,"reason":"why this range"}],"reason":"why this file"}],"warnings":[],"open_questions":[]}'
3461
+ : '{"score":9,"approved":true,"selected":[{"candidate_id":"c:0:path","ranges":[{"start_line":1,"end_line":1,"reason":"why this range"}],"reason":"why this file"}],"warnings":[],"omissions":[]}';
3462
+ const stageRules = stage === "curator"
3463
+ ? [
3464
+ "Curator-specific rules:",
3465
+ "- The packet is the complete local evidence. Do not run commands, read files, discover paths, or use filesystem state.",
3466
+ "- selected:[] is invalid when packet.candidates is non-empty. It will fail server validation.",
3467
+ "- If packet.candidates is non-empty, selected MUST contain at least one candidate.",
3468
+ "- Use packet.deterministic_selection.selected as the safe starting point; keep relevant deterministic candidates unless the task clearly excludes them.",
3469
+ "- Treat the minimum valid JSON example as a floor, not a complete packet. Add task-critical candidates from packet.candidates when deterministic_selection is sparse or omissions show important local evidence was budget-pruned.",
3470
+ "- Do not return selected:[] to express uncertainty. Select the closest relevant local candidate and put caveats in warnings or open_questions.",
3471
+ ]
3472
+ : [
3473
+ "Finalizer-specific rules:",
3474
+ "- The packet is the complete local evidence. Do not run commands, read files, discover paths, or use filesystem state.",
3475
+ "- selected:[] is invalid when approving. It will fail server validation.",
3476
+ "- If approving, selected MUST contain at least one candidate.",
3477
+ "- Start from packet.curator_proposal.selected and keep only candidates that are locally supported by packet.candidates.",
3478
+ "- Treat packet.deterministic_selection.selected as server-ranked required baseline evidence. If the curator underselected or warned about sparse evidence, add relevant deterministic candidates/ranges that are present in packet.candidates instead of lowering the score for evidence the packet already provides.",
3479
+ "- Do not reject solely because the curator warning says broader implementation may exist when deterministic_selection and packet.candidates contain concrete task-critical ranges for that concern.",
3480
+ "- If the selected packet evidence is insufficient for the bounded task, set approved:false and explain concrete omissions; the server will treat that as delegate failure according to failure_policy.",
3481
+ "- If approving with score at or above the requested minimum, omissions MUST be []. Put speculative out-of-packet concerns or 'may contain more detail' caveats in warnings instead.",
3482
+ ];
3483
+ const minimumOutput = buildMinimumDelegateOutput(stage, packet);
3484
+ return [
3485
+ `You are the context_builder ${stage}.`,
3486
+ `Prompt version: ${CONTEXT_BUILDER_DELEGATE_PROMPT_VERSION}.`,
3487
+ "Return exactly one strict JSON object and no prose.",
3488
+ "For this tool call, the JSON packet below is the only source of truth.",
3489
+ stage === "curator"
3490
+ ? "Never answer with selected:[]. If candidates exist, choose at least one candidate_id and one eligible range from packet.candidates or packet.deterministic_selection.selected."
3491
+ : "Never answer with selected:[]. If approving, choose at least one candidate_id and one eligible range from packet.curator_proposal.selected.",
3492
+ "Use only candidate_id and ranges from the packet. Do not add paths or source content.",
3493
+ "Every selected range must stay within one of that candidate's packet.ranges entries.",
3494
+ stage === "curator"
3495
+ ? "Use the excerpt, search_hits, deterministic_selection, omissions, and task fields as evidence; the packet intentionally omits full source content."
3496
+ : "Use the excerpt, search_hits, curator_proposal, deterministic_selection, omissions, and task fields as evidence; the packet intentionally omits full source content.",
3497
+ ...stageRules,
3498
+ ...(minimumOutput == null
3499
+ ? []
3500
+ : [
3501
+ "If unsure, return this minimum valid JSON object rather than an empty selection:",
3502
+ minimumOutput,
3503
+ ]),
3504
+ `Required JSON shape: ${outputShape}`,
3505
+ "Invalid output example: {\"selected\":[],\"warnings\":[],\"open_questions\":[]}",
3506
+ "",
3507
+ "Packet:",
3508
+ JSON.stringify(packet),
3509
+ "",
3510
+ "Return the JSON object now. If candidates exist, selected must be non-empty.",
3511
+ ].join("\n");
3512
+ }
3513
+ function buildMinimumDelegateOutput(stage, packet) {
3514
+ const minimumSelections = packetMinimumSelections(stage, packet);
3515
+ if (minimumSelections.length === 0) {
3516
+ return null;
3517
+ }
3518
+ const selected = minimumSelections.map((selection) => ({
3519
+ candidate_id: selection.candidate_id,
3520
+ ranges: selection.ranges.map((range) => ({
3521
+ start_line: range.start_line,
3522
+ end_line: range.end_line,
3523
+ reason: "locally supported range from the packet",
3524
+ })),
3525
+ reason: "minimum valid local selection for the requested context",
3526
+ }));
3527
+ const output = stage === "curator"
3528
+ ? {
3529
+ selected,
3530
+ warnings: [
3531
+ "minimum deterministic selection used; review packet evidence for more context",
3532
+ ],
3533
+ open_questions: [],
3534
+ }
3535
+ : {
3536
+ score: 10,
3537
+ approved: true,
3538
+ selected,
3539
+ warnings: [
3540
+ "minimum curator proposal selection used; review packet evidence for more context",
3541
+ ],
3542
+ omissions: [],
3543
+ };
3544
+ return JSON.stringify(output);
3545
+ }
3546
+ function packetMinimumSelections(stage, packet) {
3547
+ if (packet == null || typeof packet !== "object") {
3548
+ return [];
3549
+ }
3550
+ const record = packet;
3551
+ if (stage === "finalizer") {
3552
+ const proposal = record["curator_proposal"];
3553
+ const proposalSelected = proposal != null && typeof proposal === "object"
3554
+ ? proposal["selected"]
3555
+ : undefined;
3556
+ return packetSelectionsFromValues(proposalSelected);
3557
+ }
3558
+ const deterministic = record["deterministic_selection"];
3559
+ const deterministicSelected = deterministic != null && typeof deterministic === "object"
3560
+ ? deterministic["selected"]
3561
+ : undefined;
3562
+ const deterministicSelections = packetSelectionsFromValues(deterministicSelected);
3563
+ const candidateSelections = packetCandidateSelectionsFromValues(record["candidates"]);
3564
+ if (deterministicSelections.length > 0) {
3565
+ return mergePacketSelections([
3566
+ ...deterministicSelections,
3567
+ ...candidateSelections,
3568
+ ]).slice(0, MAX_DELEGATE_MINIMUM_OUTPUT_SELECTIONS);
3569
+ }
3570
+ return candidateSelections;
3571
+ }
3572
+ function packetSelectionsFromValues(values) {
3573
+ if (!Array.isArray(values)) {
3574
+ return [];
3575
+ }
3576
+ return mergePacketSelections(values
3577
+ .slice(0, MAX_DELEGATE_MINIMUM_OUTPUT_SELECTIONS)
3578
+ .map((value) => packetSelectionFromValue(value, "candidate_id"))
3579
+ .filter((selection) => selection != null));
3580
+ }
3581
+ function packetCandidateSelectionsFromValues(values) {
3582
+ if (!Array.isArray(values)) {
3583
+ return [];
3584
+ }
3585
+ return mergePacketSelections(values
3586
+ .slice(0, MAX_DELEGATE_MINIMUM_OUTPUT_SELECTIONS)
3587
+ .map((value) => packetSelectionFromValue(value, "id"))
3588
+ .filter((selection) => selection != null));
3589
+ }
3590
+ function mergePacketSelections(selections) {
3591
+ const merged = new Map();
3592
+ for (const selection of selections) {
3593
+ const ranges = merged.get(selection.candidate_id) ?? [];
3594
+ ranges.push(...selection.ranges);
3595
+ merged.set(selection.candidate_id, ranges);
3596
+ }
3597
+ return [...merged].map(([candidate_id, ranges]) => ({
3598
+ candidate_id,
3599
+ ranges,
3600
+ }));
3601
+ }
3602
+ function packetSelectionFromValue(value, candidateIdKey) {
3603
+ if (value == null || typeof value !== "object") {
3604
+ return null;
3605
+ }
3606
+ const record = value;
3607
+ const candidateId = record[candidateIdKey];
3608
+ const ranges = record["ranges"];
3609
+ const validRanges = Array.isArray(ranges)
3610
+ ? ranges.map(packetRangeBounds).filter((range) => range != null)
3611
+ : [];
3612
+ return typeof candidateId === "string" && validRanges.length > 0
3613
+ ? { candidate_id: candidateId, ranges: validRanges }
3614
+ : null;
3615
+ }
3616
+ function packetRangeBounds(value) {
3617
+ if (value == null || typeof value !== "object") {
3618
+ return null;
3619
+ }
3620
+ const record = value;
3621
+ const startLine = record["start_line"];
3622
+ const endLine = record["end_line"];
3623
+ if (typeof startLine !== "number" || typeof endLine !== "number") {
3624
+ return null;
3625
+ }
3626
+ return Number.isInteger(startLine) &&
3627
+ Number.isInteger(endLine) &&
3628
+ startLine > 0 &&
3629
+ endLine >= startLine
3630
+ ? { start_line: startLine, end_line: endLine }
3631
+ : null;
3632
+ }
3633
+ function delegatePromptDiagnostic(packet) {
3634
+ if (packet == null || typeof packet !== "object") {
3635
+ return `prompt_version=${CONTEXT_BUILDER_DELEGATE_PROMPT_VERSION}; packet=invalid`;
3636
+ }
3637
+ const record = packet;
3638
+ const candidateCount = Array.isArray(record["candidates"])
3639
+ ? record["candidates"].length
3640
+ : 0;
3641
+ const deterministic = record["deterministic_selection"];
3642
+ const deterministicSelected = deterministic != null && typeof deterministic === "object"
3643
+ ? deterministic["selected"]
3644
+ : undefined;
3645
+ const deterministicCount = Array.isArray(deterministicSelected)
3646
+ ? deterministicSelected.length
3647
+ : 0;
3648
+ const proposal = record["curator_proposal"];
3649
+ const proposalSelected = proposal != null && typeof proposal === "object"
3650
+ ? proposal["selected"]
3651
+ : undefined;
3652
+ const curatorProposalCount = Array.isArray(proposalSelected)
3653
+ ? proposalSelected.length
3654
+ : 0;
3655
+ const minimumSelection = packetMinimumSelections("curator", packet);
3656
+ return [
3657
+ `pv=${CONTEXT_BUILDER_DELEGATE_PROMPT_VERSION}`,
3658
+ `candidates=${candidateCount}`,
3659
+ `det=${deterministicCount}`,
3660
+ `curator_selected=${curatorProposalCount}`,
3661
+ `min=${minimumSelection.length > 0}`,
3662
+ ].join("; ");
3663
+ }
3664
+ function failureReasonFromCall(stage, call) {
3665
+ return `${stage} ${call.reason}: ${call.message}`;
3666
+ }
3667
+ function failureReasonFromError(stage, err, diagnostic) {
3668
+ const message = err instanceof Error ? err.message : "unknown delegate error";
3669
+ return diagnostic == null
3670
+ ? `${stage}: ${message}`
3671
+ : `${stage}: ${diagnostic}; ${message}`;
3672
+ }
3673
+ function delegateWarning(code, message) {
3674
+ return {
3675
+ code: sanitizeDiagnosticText(code),
3676
+ message: sanitizeDiagnosticText(message),
3677
+ };
3678
+ }
3679
+ function reconcileContextBuilderWarnings(input) {
3680
+ if (input.warnings.length === 0) {
3681
+ return [];
3682
+ }
3683
+ return input.warnings.filter((warning) => {
3684
+ const text = warning.message.toLowerCase();
3685
+ if (isStaleTruncationWarning(text, input)) {
3686
+ return false;
3687
+ }
3688
+ if (isStaleSelectedContextOmissionWarning(text, input.selected)) {
3689
+ return false;
3690
+ }
3691
+ if (isStaleSelectedContextRangeWarning(text, input.selected)) {
3692
+ return false;
3693
+ }
3694
+ return true;
3695
+ });
3696
+ }
3697
+ function isStaleTruncationWarning(text, input) {
3698
+ if (!isTruncationWarning(text)) {
3699
+ return false;
3700
+ }
3701
+ return !contextBuilderPacketIsDegraded(input);
3702
+ }
3703
+ function contextBuilderPacketIsDegraded(input) {
3704
+ return (input.metrics.truncated ||
3705
+ input.omissions.some(isMaterialWarningOmission) ||
3706
+ input.delegate?.fallback_used === true ||
3707
+ input.delegate?.status === "partial");
3708
+ }
3709
+ function isMaterialWarningOmission(omission) {
3710
+ if (omission.reason === "excluded" ||
3711
+ omission.reason === "exclude_glob" ||
3712
+ omission.reason === "caller_include_glob" ||
3713
+ omission.reason === "content_secret" ||
3714
+ omission.reason === "secret_path" ||
3715
+ omission.reason === "symlink_omitted" ||
3716
+ omission.reason === "symlink_file" ||
3717
+ omission.reason === "binary_file" ||
3718
+ omission.reason === "duplicate_root" ||
3719
+ omission.reason === "noisy_file" ||
3720
+ omission.reason === "default_exclude" ||
3721
+ omission.reason === "default_noisy_exclude") {
3722
+ return false;
3723
+ }
3724
+ return true;
3725
+ }
3726
+ function isTruncationWarning(text) {
3727
+ return /\b(?:truncat(?:ed|ion)|token[- ]?truncated|token budget|budget[- ]limited|budget limited)\b/.test(text);
3728
+ }
3729
+ function isStaleSelectedContextOmissionWarning(text, selected) {
3730
+ if (selected.length === 0 ||
3731
+ !isOmissionWarning(text) ||
3732
+ isPathOrSecretOmissionWarning(text)) {
3733
+ return false;
3734
+ }
3735
+ const references = selectedContextWarningReferences(selected);
3736
+ const groupedRefs = concreteWarningReferenceGroups(text);
3737
+ if (groupedRefs.length > 0) {
3738
+ if (groupedRefs.some((group) => group.every((ref) => references.tokens.has(ref)))) {
3739
+ return true;
3740
+ }
3741
+ }
3742
+ return warningReferencesSelectedContext(text, references);
3743
+ }
3744
+ function isStaleSelectedContextRangeWarning(text, selected) {
3745
+ if (selected.length === 0 ||
3746
+ !/\b(?:available as|available only|only available|only includes|only selected|partial|range|ranges|slice|slices|line|lines|clipped|narrow)\b/.test(text)) {
3747
+ return false;
3748
+ }
3749
+ return warningReferencesSelectedContext(text, selectedContextWarningReferences(selected));
3750
+ }
3751
+ function isOmissionWarning(text) {
3752
+ return /\b(?:missing|missed|omission|omissions|omit|omits|omitted|not selected|not be selected|not present|unavailable|insufficient)\b/.test(text);
3753
+ }
3754
+ function isPathOrSecretOmissionWarning(text) {
3755
+ return /\b(?:secret|sensitive|credential|private key|api key|redacted|allowed roots?|outside allowed|unsafe path|path traversal|symlink|permission denied|eacces|enoent|not readable)\b/.test(text);
3756
+ }
3757
+ function selectedContextWarningReferences(selected) {
3758
+ const compactTextRefs = new Set();
3759
+ const tokens = new Set();
3760
+ for (const file of selected) {
3761
+ const normalizedPath = normalizeWarningReference(file.path);
3762
+ if (normalizedPath.length > 0) {
3763
+ compactTextRefs.add(normalizedPath);
3764
+ }
3765
+ const basename = file.path.split("/").at(-1) ?? file.path;
3766
+ const basenameRef = normalizeWarningReference(basename);
3767
+ if (basenameRef.length > 0) {
3768
+ compactTextRefs.add(basenameRef);
3769
+ }
3770
+ const stem = basename.split(".")[0] ?? basename;
3771
+ const stemRef = normalizeWarningReference(stem);
3772
+ if (isConcreteWarningReference(stemRef)) {
3773
+ compactTextRefs.add(stemRef);
3774
+ tokens.add(stemRef);
3775
+ }
3776
+ }
3777
+ return { compactTextRefs, tokens };
3778
+ }
3779
+ function warningReferencesSelectedContext(text, references) {
3780
+ const compactText = normalizeWarningReference(text);
3781
+ for (const ref of references.compactTextRefs) {
3782
+ if (isConcreteWarningReference(ref) && compactText.includes(ref)) {
3783
+ return true;
3784
+ }
3785
+ }
3786
+ return false;
3787
+ }
3788
+ function concreteWarningReferenceGroups(text) {
3789
+ const groups = [];
3790
+ const groupPatterns = [
3791
+ /\b([a-z0-9_.-]+(?:\/[a-z0-9_.-]+)+)\s+(?:schemas?|tests?|files?)\b/g,
3792
+ /\b([a-z0-9_.-]+)\s+and\s+([a-z0-9_.-]+)\s+(?:schemas?|tests?|files?)\b/g,
3793
+ ];
3794
+ for (const pattern of groupPatterns) {
3795
+ for (const match of text.matchAll(pattern)) {
3796
+ const refs = match
3797
+ .slice(1)
3798
+ .flatMap((value) => value.split("/"))
3799
+ .map(normalizeWarningReference)
3800
+ .filter(isConcreteWarningReference);
3801
+ if (refs.length > 0) {
3802
+ groups.push(refs);
3803
+ }
3804
+ }
3805
+ }
3806
+ return groups;
3807
+ }
3808
+ function normalizeWarningReference(value) {
3809
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "");
3810
+ }
3811
+ function isConcreteWarningReference(value) {
3812
+ if (value.length < 4) {
3813
+ return false;
3814
+ }
3815
+ return !new Set([
3816
+ "backend",
3817
+ "frontend",
3818
+ "schema",
3819
+ "schemas",
3820
+ "service",
3821
+ "services",
3822
+ "source",
3823
+ "test",
3824
+ "tests",
3825
+ "types",
3826
+ ]).has(value);
3827
+ }
3828
+ function buildContextBuilderMetrics(input) {
3829
+ return {
3830
+ files_seen: input.discovery.files_seen,
3831
+ files_considered: input.discovery.files_considered,
3832
+ files_selected: input.selection.files_selected,
3833
+ files_omitted: input.omissionCount,
3834
+ scan_cap_hit: input.discovery.scan_cap_hit,
3835
+ search_cap_hit: input.discovery.search_cap_hit,
3836
+ discovery_byte_cap_hit: input.discovery.discovery_byte_cap_hit,
3837
+ discovery_candidate_cap_hit: input.discovery.discovery_candidate_cap_hit,
3838
+ candidate_cap_hit: input.discovery.candidate_cap_hit,
3839
+ bytes_read: input.discovery.bytes_read,
3840
+ bytes_written: 0,
3841
+ estimated_tokens: input.selection.estimated_tokens,
3842
+ truncated: input.selection.truncated ||
3843
+ input.discovery.scan_cap_hit ||
3844
+ input.discovery.discovery_byte_cap_hit ||
3845
+ input.discovery.discovery_candidate_cap_hit,
3846
+ };
3847
+ }
3848
+ //# sourceMappingURL=handler.js.map