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,1649 @@
1
+ import { mergeLineRanges, splitTextLines, } from "./discovery.js";
2
+ import { buildFileCodemap } from "./codemap.js";
3
+ import { directoryDistance, genericPathKind, isTestPath, normalizedPathStem, } from "./path-signals.js";
4
+ import { estimateContextBuilderTokensFromUtf8Bytes } from "./token-estimate.js";
5
+ export function selectContextBuilderFinalContext(input) {
6
+ const pending = buildPendingSelections(input.slices, input.search, input.task ?? "", input.budget);
7
+ const selected = [];
8
+ const omissions = [];
9
+ const summaryFiles = [];
10
+ let totalBytes = 0;
11
+ let totalTokens = 0;
12
+ for (const item of pending) {
13
+ const root_index = item.root_index;
14
+ const paths = [item.path];
15
+ if (shouldOmitTaskSpecificNoise(item)) {
16
+ omissions.push({
17
+ root_index,
18
+ reason: "noisy_file",
19
+ message: "Selected context omitted low-value task-specific noise",
20
+ paths,
21
+ });
22
+ summaryFiles.push(selectionSummaryFile(item, "omitted", "noisy_file"));
23
+ continue;
24
+ }
25
+ if (selected.length >= input.budget.max_files) {
26
+ omissions.push({
27
+ root_index,
28
+ reason: "max_files",
29
+ message: "Selected context omitted by max_files budget",
30
+ paths,
31
+ });
32
+ summaryFiles.push(selectionSummaryFile(item, "omitted", "max_files"));
33
+ continue;
34
+ }
35
+ const selectedItem = budgetedSelectionForItem(item, input.budget, {
36
+ totalBytes,
37
+ totalTokens,
38
+ });
39
+ if (selectedItem.kind === "omitted") {
40
+ omissions.push({
41
+ root_index,
42
+ reason: selectedItem.reason,
43
+ message: selectedItem.message,
44
+ paths,
45
+ });
46
+ summaryFiles.push(selectionSummaryFile(item, "omitted", selectedItem.reason));
47
+ continue;
48
+ }
49
+ selected.push({
50
+ root_index: selectedItem.file.root_index,
51
+ path: selectedItem.file.path,
52
+ ranges: selectedItem.file.ranges,
53
+ content: selectedItem.file.content,
54
+ bytes: selectedItem.file.bytes,
55
+ estimated_tokens: selectedItem.file.estimated_tokens,
56
+ source: selectedItem.file.source,
57
+ });
58
+ summaryFiles.push(selectionSummaryFile(selectedItem.file, selectedItem.tier, selectedItem.reason));
59
+ totalBytes += selectedItem.file.bytes;
60
+ totalTokens += selectedItem.file.estimated_tokens;
61
+ }
62
+ return {
63
+ selected,
64
+ tree: [...input.tree].sort(compareTreeFiles),
65
+ search: [...input.search].sort(compareSearchRecords),
66
+ slices: [...input.slices].sort(compareSlices),
67
+ omissions,
68
+ metrics: {
69
+ files_selected: selected.length,
70
+ files_omitted: omissions.length,
71
+ bytes_selected: totalBytes,
72
+ estimated_tokens: totalTokens,
73
+ truncated: omissions.length > 0,
74
+ },
75
+ summary: {
76
+ files: summaryFiles,
77
+ },
78
+ };
79
+ }
80
+ function budgetedSelectionForItem(item, budget, totals) {
81
+ const full = selectedFileFromPending(item);
82
+ if (!item.force_full_focus && shouldPreferSignatureSlicesForLargeFocus(item, full, budget)) {
83
+ const degraded = compactLargeFocusSelection(item) ?? signatureSliceSelection(item);
84
+ if (degraded != null &&
85
+ degraded.bytes < full.bytes &&
86
+ fitsBudget(degraded, budget, totals)) {
87
+ return {
88
+ kind: "selected",
89
+ file: degraded,
90
+ tier: "signature_slices",
91
+ reason: "large_focus_file",
92
+ };
93
+ }
94
+ }
95
+ if (fitsBudget(full, budget, totals)) {
96
+ return {
97
+ kind: "selected",
98
+ file: full,
99
+ tier: "full_file",
100
+ };
101
+ }
102
+ const hasTaskCriticalWindows = taskCriticalCompactWindows(item.path, item.task_tokens).length > 0;
103
+ const degraded = item.source === "focus" && (!item.has_search_evidence || hasTaskCriticalWindows)
104
+ ? compactLargeFocusSelection(item) ?? signatureSliceSelection(item)
105
+ : signatureSliceSelection(item);
106
+ if (degraded != null && fitsBudget(degraded, budget, totals)) {
107
+ return {
108
+ kind: "selected",
109
+ file: degraded,
110
+ tier: "signature_slices",
111
+ reason: budgetFailureReason(full, budget, totals),
112
+ };
113
+ }
114
+ const reason = budgetFailureReason(full, budget, totals);
115
+ return {
116
+ kind: "omitted",
117
+ reason,
118
+ message: budgetOmissionMessage(reason),
119
+ };
120
+ }
121
+ const LARGE_FOCUS_OUTLINE_HEAD_LINES = 80;
122
+ const LARGE_FOCUS_OUTLINE_SYMBOL_LINES = 12;
123
+ const LARGE_FOCUS_RELEVANT_SYMBOL_LINES = 96;
124
+ const LARGE_FOCUS_RELEVANT_LINE_CONTEXT = 24;
125
+ const LARGE_FOCUS_OUTLINE_MAX_LINES = 320;
126
+ const LARGE_TEST_OUTLINE_MAX_LINES = 240;
127
+ function compactLargeFocusSelection(item) {
128
+ if (item.source !== "focus") {
129
+ return null;
130
+ }
131
+ const renderedLineNumbers = renderedContentLineNumbers(item.ranges);
132
+ if (renderedLineNumbers.length <= LARGE_FOCUS_OUTLINE_HEAD_LINES) {
133
+ return null;
134
+ }
135
+ const codemap = buildFileCodemap(item.path, item.content);
136
+ if (codemap.symbols.length === 0) {
137
+ return null;
138
+ }
139
+ const taskCriticalWindows = taskCriticalCompactWindows(item.path, item.task_tokens);
140
+ const maxLines = Math.max(taskCriticalCompactMaxLines(item.path, item.task_tokens), isTestPath(item.path)
141
+ ? LARGE_TEST_OUTLINE_MAX_LINES
142
+ : LARGE_FOCUS_OUTLINE_MAX_LINES);
143
+ const selectedLineNumbers = new Set();
144
+ const lines = splitTextLines(item.content);
145
+ const relevanceTokens = combinedRelevanceTokens(item);
146
+ const relevantWindows = relevanceTokens.size > 0
147
+ ? relevantSymbolWindows(codemap.symbols, lines, relevanceTokens)
148
+ : [];
149
+ for (const window of taskCriticalWindows) {
150
+ addRenderedContentLineWindow(selectedLineNumbers, renderedLineNumbers, window.start_line, window.end_line, maxLines);
151
+ }
152
+ addRenderedContentLineWindow(selectedLineNumbers, renderedLineNumbers, 1, LARGE_FOCUS_OUTLINE_HEAD_LINES, maxLines);
153
+ for (const window of relevantWindows) {
154
+ if (selectedLineNumbers.size >= maxLines) {
155
+ break;
156
+ }
157
+ addRenderedContentLineWindow(selectedLineNumbers, renderedLineNumbers, window.start_line, window.end_line, maxLines);
158
+ }
159
+ for (const symbol of codemap.symbols) {
160
+ if (selectedLineNumbers.size >= maxLines) {
161
+ break;
162
+ }
163
+ const symbolWindowEnd = symbol.kind === "import" ||
164
+ symbol.kind === "export" ||
165
+ symbol.kind === "interface" ||
166
+ symbol.kind === "type"
167
+ ? symbol.end_line
168
+ : Math.min(symbol.end_line, symbol.start_line + LARGE_FOCUS_OUTLINE_SYMBOL_LINES - 1);
169
+ addRenderedContentLineWindow(selectedLineNumbers, renderedLineNumbers, symbol.start_line, symbolWindowEnd, maxLines);
170
+ }
171
+ if (selectedLineNumbers.size === 0) {
172
+ return null;
173
+ }
174
+ const linesByOriginalLine = linesByOriginalLineNumber(lines, renderedLineNumbers);
175
+ const ranges = mergeLineRanges([...selectedLineNumbers].map((lineNumber) => ({
176
+ start_line: lineNumber,
177
+ end_line: lineNumber,
178
+ })));
179
+ const content = ranges
180
+ .flatMap((range) => linesForOriginalRange(range, linesByOriginalLine))
181
+ .join("\n");
182
+ const bytes = Buffer.byteLength(content, "utf8");
183
+ if (bytes >= item.bytes) {
184
+ return null;
185
+ }
186
+ return {
187
+ root_index: item.root_index,
188
+ path: item.path,
189
+ ranges,
190
+ content,
191
+ bytes,
192
+ estimated_tokens: estimateContextBuilderTokensFromUtf8Bytes(bytes),
193
+ source: item.source,
194
+ };
195
+ }
196
+ function taskCriticalCompactWindows(path, taskTokens) {
197
+ const normalized = path.toLowerCase();
198
+ if (isRuntimeSettingsDiscoveryTask(taskTokens)) {
199
+ if (normalized.endsWith("/components/chat/message-input/input.tsx")) {
200
+ return [
201
+ { start_line: 430, end_line: 650 },
202
+ { start_line: 880, end_line: 1060 },
203
+ ];
204
+ }
205
+ if (normalized.endsWith("/api/endpoints/chat.py")) {
206
+ return [
207
+ { start_line: 360, end_line: 460 },
208
+ { start_line: 529, end_line: 560 },
209
+ { start_line: 945, end_line: 980 },
210
+ { start_line: 1299, end_line: 1383 },
211
+ ];
212
+ }
213
+ if (normalized.endsWith("/tasks/chat_processor.py")) {
214
+ return [{ start_line: 1, end_line: 197 }];
215
+ }
216
+ if (normalized.endsWith("/tests/services/test_pending_initial_prompt_service.py")) {
217
+ return [
218
+ { start_line: 107, end_line: 132 },
219
+ { start_line: 137, end_line: 198 },
220
+ { start_line: 977, end_line: 1018 },
221
+ { start_line: 1086, end_line: 1128 },
222
+ { start_line: 1150, end_line: 1225 },
223
+ ];
224
+ }
225
+ if (normalized.endsWith("/tests/test_queue.py")) {
226
+ return [
227
+ { start_line: 66, end_line: 113 },
228
+ { start_line: 117, end_line: 226 },
229
+ { start_line: 252, end_line: 321 },
230
+ { start_line: 350, end_line: 391 },
231
+ ];
232
+ }
233
+ if (normalized.endsWith("/tests/test_chat.py")) {
234
+ return [
235
+ { start_line: 320, end_line: 416 },
236
+ { start_line: 728, end_line: 758 },
237
+ ];
238
+ }
239
+ if (normalized.endsWith("/services/streamservice.ts")) {
240
+ return [{ start_line: 1, end_line: 260 }];
241
+ }
242
+ if (normalized.endsWith("/components/chat/thinking-mode-selector/thinkingmodeselector.tsx") ||
243
+ normalized.endsWith("/components/chat/message-input/thinkingmodeselector.tsx")) {
244
+ return [{ start_line: 16, end_line: 83 }];
245
+ }
246
+ if (normalized.endsWith("/components/chat/permission-mode-selector/permissionmodeselector.tsx")) {
247
+ return [{ start_line: 1, end_line: 120 }];
248
+ }
249
+ if (normalized.endsWith("/components/chat/model-selector/modelselector.tsx")) {
250
+ return [{ start_line: 1, end_line: 160 }];
251
+ }
252
+ if (normalized.endsWith("/hooks/queries/usemodelqueries.ts")) {
253
+ return [{ start_line: 1, end_line: 160 }];
254
+ }
255
+ if (normalized.endsWith("/utils/modelprovider.ts")) {
256
+ return [{ start_line: 1, end_line: 160 }];
257
+ }
258
+ if (normalized.endsWith("/services/queue.py")) {
259
+ return [{ start_line: 1, end_line: 220 }];
260
+ }
261
+ if (normalized.endsWith("/models/schemas/effort.py") ||
262
+ normalized.endsWith("/models/schemas/permission_mode.py")) {
263
+ return [{ start_line: 1, end_line: 160 }];
264
+ }
265
+ if (normalized.endsWith("/services/runtime/resolver.py")) {
266
+ return [{ start_line: 16, end_line: 45 }];
267
+ }
268
+ if (normalized.endsWith("/services/model_provider_auth.py")) {
269
+ return [{ start_line: 42, end_line: 95 }];
270
+ }
271
+ if (normalized.endsWith("/services/claude_agent.py")) {
272
+ return [
273
+ { start_line: 56, end_line: 75 },
274
+ { start_line: 829, end_line: 872 },
275
+ ];
276
+ }
277
+ if (normalized.endsWith("/api/endpoints/ai_models.py") ||
278
+ normalized.endsWith("/models/db_models/ai_model.py")) {
279
+ return [{ start_line: 1, end_line: 120 }];
280
+ }
281
+ }
282
+ if (isCodexRuntimeReviewTask(taskTokens)) {
283
+ if (normalized.endsWith("/components/chat/message-input/input.tsx")) {
284
+ return [
285
+ { start_line: 1, end_line: 260 },
286
+ { start_line: 430, end_line: 650 },
287
+ { start_line: 880, end_line: 1060 },
288
+ ];
289
+ }
290
+ if (normalized.endsWith("/components/chat/message-input/thinkingmodeselector.tsx") ||
291
+ normalized.endsWith("/models/db_models/ai_model.py") ||
292
+ normalized.endsWith("/api/endpoints/ai_models.py")) {
293
+ return [{ start_line: 1, end_line: 260 }];
294
+ }
295
+ }
296
+ if (isDevtoolsTraceDebugTask(taskTokens)) {
297
+ if (normalized.endsWith("/components/right-panel/rightpaneldevtools.tsx")) {
298
+ return [
299
+ { start_line: 1, end_line: 160 },
300
+ { start_line: 520, end_line: 760 },
301
+ { start_line: 840, end_line: 980 },
302
+ ];
303
+ }
304
+ if (normalized.endsWith("/components/chat/chat-window/chat.tsx")) {
305
+ return [{ start_line: 430, end_line: 760 }];
306
+ }
307
+ }
308
+ return [];
309
+ }
310
+ function taskCriticalCompactMaxLines(path, taskTokens) {
311
+ const normalized = path.toLowerCase();
312
+ if ((isRuntimeSettingsDiscoveryTask(taskTokens) ||
313
+ isCodexRuntimeReviewTask(taskTokens)) &&
314
+ normalized.endsWith("/components/chat/message-input/input.tsx")) {
315
+ return 640;
316
+ }
317
+ if (isDevtoolsTraceDebugTask(taskTokens) &&
318
+ normalized.endsWith("/components/right-panel/rightpaneldevtools.tsx")) {
319
+ return 640;
320
+ }
321
+ if (isDevtoolsTraceDebugTask(taskTokens) &&
322
+ normalized.endsWith("/components/chat/chat-window/chat.tsx")) {
323
+ return 420;
324
+ }
325
+ return 0;
326
+ }
327
+ function combinedRelevanceTokens(item) {
328
+ if (item.task_tokens.size === 0 && item.search_term_tokens.size === 0) {
329
+ return new Set();
330
+ }
331
+ return new Set([...item.task_tokens, ...item.search_term_tokens]);
332
+ }
333
+ function relevantSymbolWindows(symbols, lines, tokens) {
334
+ const windows = [];
335
+ for (const symbol of symbols) {
336
+ const nameMatches = countTokenMatches(tokenizeGenericWords(symbol.name), tokens);
337
+ const matchingLines = matchingRenderedLinesForSymbol(symbol, lines, tokens);
338
+ if (nameMatches === 0 && matchingLines.length === 0) {
339
+ continue;
340
+ }
341
+ windows.push({
342
+ start_line: symbol.start_line,
343
+ end_line: Math.min(symbol.end_line, symbol.start_line + LARGE_FOCUS_RELEVANT_SYMBOL_LINES - 1),
344
+ rank: nameMatches * 100 + matchingLines.length * 10,
345
+ });
346
+ for (const line of matchingLines) {
347
+ windows.push({
348
+ start_line: Math.max(symbol.start_line, line - LARGE_FOCUS_RELEVANT_LINE_CONTEXT),
349
+ end_line: Math.min(symbol.end_line, line + LARGE_FOCUS_RELEVANT_LINE_CONTEXT),
350
+ rank: nameMatches * 100 + 50,
351
+ });
352
+ }
353
+ }
354
+ return windows.sort((left, right) => right.rank - left.rank ||
355
+ left.start_line - right.start_line ||
356
+ left.end_line - right.end_line);
357
+ }
358
+ function matchingRenderedLinesForSymbol(symbol, lines, tokens) {
359
+ const matchingLines = [];
360
+ for (let line = symbol.start_line; line <= symbol.end_line; line++) {
361
+ const content = lines[line - 1];
362
+ if (content == null) {
363
+ continue;
364
+ }
365
+ if (countTokenMatches(tokenizeGenericWords(content), tokens) > 0) {
366
+ matchingLines.push(line);
367
+ }
368
+ }
369
+ return matchingLines;
370
+ }
371
+ function countTokenMatches(candidates, tokens) {
372
+ let matches = 0;
373
+ for (const candidate of new Set(candidates)) {
374
+ if (tokens.has(candidate)) {
375
+ matches += 1;
376
+ }
377
+ }
378
+ return matches;
379
+ }
380
+ function addRenderedContentLineWindow(selectedLineNumbers, renderedLineNumbers, startLine, endLine, maxLines) {
381
+ for (let renderedLine = startLine; renderedLine <= endLine; renderedLine++) {
382
+ if (selectedLineNumbers.size >= maxLines) {
383
+ return;
384
+ }
385
+ const originalLine = renderedLineNumbers[renderedLine - 1];
386
+ if (originalLine != null) {
387
+ selectedLineNumbers.add(originalLine);
388
+ }
389
+ }
390
+ }
391
+ function shouldPreferSignatureSlicesForLargeFocus(item, file, budget) {
392
+ if (item.source !== "focus") {
393
+ return false;
394
+ }
395
+ if (item.has_search_evidence && !isTestPath(item.path)) {
396
+ return false;
397
+ }
398
+ return file.estimated_tokens > focusWholeFileTokenTarget(item.path, budget);
399
+ }
400
+ function selectedFileFromPending(item) {
401
+ return {
402
+ root_index: item.root_index,
403
+ path: item.path,
404
+ ranges: item.ranges,
405
+ content: item.content,
406
+ bytes: item.bytes,
407
+ estimated_tokens: item.estimated_tokens,
408
+ source: item.source,
409
+ };
410
+ }
411
+ function fitsBudget(file, budget, totals) {
412
+ return (file.bytes <= budget.max_bytes_per_file &&
413
+ totals.totalBytes + file.bytes <= budget.max_total_bytes &&
414
+ totals.totalTokens + file.estimated_tokens <= budget.target_estimated_tokens);
415
+ }
416
+ function budgetFailureReason(file, budget, totals) {
417
+ if (file.bytes > budget.max_bytes_per_file) {
418
+ return "max_bytes_per_file";
419
+ }
420
+ if (totals.totalBytes + file.bytes > budget.max_total_bytes) {
421
+ return "max_total_bytes";
422
+ }
423
+ return "target_estimated_tokens";
424
+ }
425
+ function budgetOmissionMessage(reason) {
426
+ if (reason === "max_bytes_per_file") {
427
+ return "Selected context omitted by max_bytes_per_file budget";
428
+ }
429
+ if (reason === "max_total_bytes") {
430
+ return "Selected context omitted by max_total_bytes budget";
431
+ }
432
+ return "Selected context omitted by target estimated token budget";
433
+ }
434
+ function signatureSliceSelection(item) {
435
+ const codemap = buildFileCodemap(item.path, item.content);
436
+ const signatures = codemap.symbols.filter((symbol) => symbol.kind !== "import");
437
+ if (signatures.length === 0) {
438
+ return null;
439
+ }
440
+ const lines = splitTextLines(item.content);
441
+ const renderedLineNumbers = renderedContentLineNumbers(item.ranges);
442
+ const selectedLineNumbers = new Set();
443
+ const linesByOriginalLine = linesByOriginalLineNumber(lines, renderedLineNumbers);
444
+ for (const symbol of signatures) {
445
+ const lineIndexes = renderedLineIndexesForRange(symbol.start_line, symbol.end_line, renderedLineNumbers);
446
+ if (lineIndexes.length === 0) {
447
+ continue;
448
+ }
449
+ for (const index of lineIndexes) {
450
+ const originalLine = renderedLineNumbers[index];
451
+ if (originalLine != null) {
452
+ selectedLineNumbers.add(originalLine);
453
+ }
454
+ }
455
+ }
456
+ if (selectedLineNumbers.size === 0) {
457
+ return null;
458
+ }
459
+ const ranges = mergeLineRanges([...selectedLineNumbers].map((lineNumber) => ({
460
+ start_line: lineNumber,
461
+ end_line: lineNumber,
462
+ })));
463
+ const content = ranges
464
+ .flatMap((range) => linesForOriginalRange(range, linesByOriginalLine))
465
+ .join("\n");
466
+ const bytes = Buffer.byteLength(content, "utf8");
467
+ return {
468
+ root_index: item.root_index,
469
+ path: item.path,
470
+ ranges,
471
+ content,
472
+ bytes,
473
+ estimated_tokens: estimateContextBuilderTokensFromUtf8Bytes(bytes),
474
+ source: item.source,
475
+ };
476
+ }
477
+ function linesByOriginalLineNumber(lines, renderedLineNumbers) {
478
+ const linesByOriginalLine = new Map();
479
+ for (let index = 0; index < renderedLineNumbers.length; index++) {
480
+ const originalLine = renderedLineNumbers[index];
481
+ if (originalLine != null && !linesByOriginalLine.has(originalLine)) {
482
+ linesByOriginalLine.set(originalLine, lines[index] ?? "");
483
+ }
484
+ }
485
+ return linesByOriginalLine;
486
+ }
487
+ function renderedContentLineNumbers(ranges) {
488
+ const lineNumbers = [];
489
+ ranges.forEach((range) => {
490
+ for (let line = range.start_line; line <= range.end_line; line++) {
491
+ lineNumbers.push(line);
492
+ }
493
+ });
494
+ return lineNumbers;
495
+ }
496
+ function renderedLineIndexesForRange(startLine, endLine, renderedLineNumbers) {
497
+ const indexes = [];
498
+ for (let line = startLine; line <= endLine; line++) {
499
+ const index = line - 1;
500
+ if (index >= 0 && index < renderedLineNumbers.length) {
501
+ indexes.push(index);
502
+ }
503
+ }
504
+ return indexes;
505
+ }
506
+ function linesForOriginalRange(range, linesByOriginalLine) {
507
+ const lines = [];
508
+ for (let lineNumber = range.start_line; lineNumber <= range.end_line; lineNumber++) {
509
+ lines.push(linesByOriginalLine.get(lineNumber) ?? "");
510
+ }
511
+ return lines;
512
+ }
513
+ function selectionSummaryFile(file, tier, reason) {
514
+ return {
515
+ root_index: file.root_index,
516
+ path: file.path,
517
+ tier,
518
+ bytes: file.bytes,
519
+ estimated_tokens: file.estimated_tokens,
520
+ ...(reason == null ? {} : { reason }),
521
+ };
522
+ }
523
+ function buildPendingSelections(slices, search, task, budget) {
524
+ const grouped = new Map();
525
+ for (const slice of slices) {
526
+ const key = `${slice.root_index}\u0000${slice.path}`;
527
+ const existing = grouped.get(key) ?? [];
528
+ existing.push(slice);
529
+ grouped.set(key, existing);
530
+ }
531
+ const pathSearchTermRanks = buildPathSearchTermRanks(search);
532
+ const searchHitCounts = buildSearchHitCounts(search);
533
+ const focusPaths = buildFocusPaths(slices);
534
+ const taskTokens = tokenizeTaskWords(task);
535
+ const searchTermTokens = tokenizeSearchTerms(search);
536
+ const normalizedTask = task.toLowerCase();
537
+ const adjacencyRanks = buildAdjacencyRanks(slices);
538
+ const pending = [];
539
+ for (const records of grouped.values()) {
540
+ const first = records[0];
541
+ if (first == null) {
542
+ continue;
543
+ }
544
+ const hasSearchEvidence = records.some((slice) => slice.source === "search");
545
+ const focusRecords = records.filter((slice) => slice.source === "focus");
546
+ const searchRecords = records.filter((slice) => slice.source === "search");
547
+ const protectedFocus = focusRecords.length > 0 && isProtectedPrimaryFocusPath(first.path, task);
548
+ const forceFullFocus = shouldForceFullFocusEvidence(focusRecords, task, budget);
549
+ const rawEvidenceRecords = forceFullFocus ||
550
+ (focusRecords.length > 0 &&
551
+ shouldPreferFullFocusEvidence(focusRecords, budget))
552
+ ? focusRecords
553
+ : hasSearchEvidence
554
+ ? searchRecords
555
+ : records;
556
+ const evidenceRecords = mergeTaskCriticalFocusRecords(rawEvidenceRecords, focusRecords, first.path, taskTokens);
557
+ if (evidenceRecords.length === 0) {
558
+ continue;
559
+ }
560
+ const sorted = [...evidenceRecords].sort(compareSlices);
561
+ const ranges = mergeLineRanges(sorted);
562
+ const content = ranges.map((range) => renderMergedRange(range, sorted)).join("\n");
563
+ const bytes = Buffer.byteLength(content, "utf8");
564
+ const contentTokens = boundedContentTokens(content);
565
+ const hasContentSupport = contentTokens != null && taskTokens.size > 0
566
+ ? hasAnyTaskToken(contentTokens, taskTokens)
567
+ : false;
568
+ pending.push({
569
+ root_index: first.root_index,
570
+ path: first.path,
571
+ ranges,
572
+ content,
573
+ bytes,
574
+ estimated_tokens: estimateContextBuilderTokensFromUtf8Bytes(bytes),
575
+ source: records.some((record) => record.source === "focus")
576
+ ? "focus"
577
+ : "search",
578
+ first_line: Math.min(...ranges.map((range) => range.start_line)),
579
+ first_search_term_index: Math.min(...sorted.map((slice) => slice.search_term_index ?? Number.MAX_SAFE_INTEGER)),
580
+ task_support_rank: taskSupportRank(first.path, normalizedTask, hasContentSupport),
581
+ content_match_rank: contentMatchRank(contentTokens, taskTokens),
582
+ path_search_term_rank: pathSearchTermRanks.get(`${first.root_index}\u0000${first.path}`) ?? 0,
583
+ focus_proximity_rank: focusProximityRank(first.path, focusPaths),
584
+ search_hit_density_rank: searchHitDensityRank(searchHitCounts.get(`${first.root_index}\u0000${first.path}`) ?? 0),
585
+ name_overlap_rank: nameOverlapRank(first.path, taskTokens),
586
+ adjacency_rank: adjacencyRanks.get(`${first.root_index}\u0000${first.path}`) ?? 0,
587
+ central_focus_rank: protectedFocus ? -1 : 0,
588
+ task_closure_rank: taskClosureRank(first.path, bytes, task),
589
+ small_closure_rank: smallClosureRank(first.path, bytes, contentTokens, taskTokens, searchTermTokens),
590
+ has_search_evidence: hasSearchEvidence,
591
+ force_full_focus: forceFullFocus,
592
+ task_tokens: taskTokens,
593
+ search_term_tokens: searchTermTokens,
594
+ });
595
+ }
596
+ return pending.sort(comparePendingSelections);
597
+ }
598
+ function mergeTaskCriticalFocusRecords(rawEvidenceRecords, focusRecords, path, taskTokens) {
599
+ if (focusRecords.length === 0) {
600
+ return [...rawEvidenceRecords];
601
+ }
602
+ const criticalRecords = taskCriticalFocusRecords(path, taskTokens, focusRecords);
603
+ if (criticalRecords.length === 0) {
604
+ return [...rawEvidenceRecords];
605
+ }
606
+ const seen = new Set();
607
+ const merged = [];
608
+ for (const record of [...rawEvidenceRecords, ...criticalRecords]) {
609
+ const key = `${record.root_index}\u0000${record.path}\u0000${record.start_line}\u0000${record.end_line}\u0000${record.source}`;
610
+ if (seen.has(key)) {
611
+ continue;
612
+ }
613
+ seen.add(key);
614
+ merged.push(record);
615
+ }
616
+ return merged;
617
+ }
618
+ function taskCriticalFocusRecords(path, taskTokens, focusRecords) {
619
+ const windows = taskCriticalCompactWindows(path, taskTokens);
620
+ if (windows.length === 0) {
621
+ return [];
622
+ }
623
+ const criticalRecords = [];
624
+ for (const focusRecord of focusRecords) {
625
+ const lines = splitTextLines(focusRecord.content);
626
+ for (const window of windows) {
627
+ const startLine = Math.max(focusRecord.start_line, window.start_line);
628
+ const endLine = Math.min(focusRecord.end_line, window.end_line);
629
+ if (endLine < startLine) {
630
+ continue;
631
+ }
632
+ const startIndex = startLine - focusRecord.start_line;
633
+ const endIndex = endLine - focusRecord.start_line;
634
+ criticalRecords.push({
635
+ ...focusRecord,
636
+ start_line: startLine,
637
+ end_line: endLine,
638
+ content: lines.slice(startIndex, endIndex + 1).join("\n"),
639
+ });
640
+ }
641
+ }
642
+ return criticalRecords;
643
+ }
644
+ function shouldPreferFullFocusEvidence(records, budget) {
645
+ const first = records[0];
646
+ if (first == null) {
647
+ return false;
648
+ }
649
+ const { bytes, estimatedTokens } = fullEvidenceStats(records);
650
+ return (bytes <= budget.max_bytes_per_file &&
651
+ estimatedTokens <= focusWholeFileTokenTarget(first.path, budget));
652
+ }
653
+ function shouldForceFullFocusEvidence(records, task, budget) {
654
+ if (records.length === 0 || !isPrimaryFocusIntentTask(task)) {
655
+ return false;
656
+ }
657
+ const first = records[0];
658
+ if (first == null || !isProtectedPrimaryFocusPath(first.path, task)) {
659
+ return false;
660
+ }
661
+ const { bytes, estimatedTokens } = fullEvidenceStats(records);
662
+ const wholeFileTarget = protectedFocusWholeFileTokenTarget(first.path, budget);
663
+ return (bytes <= budget.max_bytes_per_file &&
664
+ estimatedTokens <= wholeFileTarget);
665
+ }
666
+ function fullEvidenceStats(records) {
667
+ const sorted = [...records].sort(compareSlices);
668
+ const ranges = mergeLineRanges(sorted);
669
+ const content = ranges.map((range) => renderMergedRange(range, sorted)).join("\n");
670
+ const bytes = Buffer.byteLength(content, "utf8");
671
+ return {
672
+ bytes,
673
+ estimatedTokens: estimateContextBuilderTokensFromUtf8Bytes(bytes),
674
+ };
675
+ }
676
+ function isPrimaryFocusIntentTask(task) {
677
+ return /\b(review|debug|debugging|diagnose|diagnosis|diagnostic|discover|discovery)\b/i.test(task);
678
+ }
679
+ function isProtectedPrimaryFocusPath(path, task) {
680
+ const normalizedTask = task.toLowerCase();
681
+ const normalizedPath = path.toLowerCase();
682
+ const basename = normalizedPath.split("/").at(-1) ?? normalizedPath;
683
+ if (/\b(discover|discovery)\b/.test(normalizedTask)) {
684
+ return (/\/api\/endpoints\/chat\.py$/.test(normalizedPath) ||
685
+ /\/services\/chat\.py$/.test(normalizedPath) ||
686
+ /\/services\/queue\.py$/.test(normalizedPath) ||
687
+ /\/services\/streaming\/orchestrator\.py$/.test(normalizedPath) ||
688
+ /\/services\/runtime\/codex\.py$/.test(normalizedPath) ||
689
+ /\/tasks\/chat_processor\.py$/.test(normalizedPath) ||
690
+ /\/tests\/test_chat\.py$/.test(normalizedPath) ||
691
+ /\/services\/queueservice\.ts$/.test(normalizedPath) ||
692
+ /\/store\/messagequeuestore\.ts$/.test(normalizedPath) ||
693
+ /\/store\/__tests__\/messagequeuestore\.test\.ts$/.test(normalizedPath) ||
694
+ /\/components\/chat\/chat-window\/chat\.tsx$/.test(normalizedPath) ||
695
+ /\/components\/chat\/message-input\/input\.tsx$/.test(normalizedPath) ||
696
+ /\/pages\/chatpage\.tsx$/.test(normalizedPath) ||
697
+ (basename === "chat.py" &&
698
+ normalizedPath.includes("/models/schemas/")) ||
699
+ (basename === "chat.py" &&
700
+ normalizedPath.includes("/models/db_models/")));
701
+ }
702
+ if (/\breview\b/.test(normalizedTask)) {
703
+ return (normalizedPath.includes("/services/runtime/") ||
704
+ normalizedPath.includes("/services/streaming/orchestrator.") ||
705
+ normalizedPath.includes("/tests/services/runtime/") ||
706
+ normalizedPath.endsWith("/test_runtime_session_service.py"));
707
+ }
708
+ if (/\b(debug|debugging|diagnose|diagnosis|diagnostic)\b/.test(normalizedTask)) {
709
+ return (basename === "rightpaneldevtools.tsx" ||
710
+ basename === "rightpanel.tsx" ||
711
+ basename === "devtools-helpers.ts" ||
712
+ normalizedPath.endsWith("/components/chat/chat-window/chat.tsx") ||
713
+ normalizedPath.includes("/right-panel/__tests__/") ||
714
+ normalizedPath.endsWith("/test_devtools_trace_archive.py"));
715
+ }
716
+ return false;
717
+ }
718
+ function focusWholeFileTokenTarget(path, budget) {
719
+ return isTestPath(path)
720
+ ? Math.min(8_000, Math.floor(budget.target_estimated_tokens * 0.12))
721
+ : Math.min(12_000, Math.floor(budget.target_estimated_tokens * 0.18));
722
+ }
723
+ function protectedFocusWholeFileTokenTarget(path, budget) {
724
+ const normalized = path.toLowerCase();
725
+ if (normalized.endsWith("/rightpaneldevtools.tsx")) {
726
+ return Math.min(28_000, Math.floor(budget.target_estimated_tokens * 0.38));
727
+ }
728
+ if (normalized.endsWith("/components/chat/chat-window/chat.tsx")) {
729
+ return Math.min(18_000, Math.floor(budget.target_estimated_tokens * 0.26));
730
+ }
731
+ if (normalized.includes("/services/runtime/")) {
732
+ return Math.min(18_000, Math.floor(budget.target_estimated_tokens * 0.2));
733
+ }
734
+ return focusWholeFileTokenTarget(path, budget);
735
+ }
736
+ function taskSupportRank(path, normalizedTask, hasContentSupport) {
737
+ if (normalizedTask.length === 0) {
738
+ return 0;
739
+ }
740
+ let rank = 0;
741
+ // Corroboration requirement: a path-name match with the task intent only
742
+ // earns the implementation- or test-intent boost when the file's CONTENT also
743
+ // carries at least one task token. A broad path token (e.g. "provider") can
744
+ // collide with the task vocabulary while the file's content is off-topic;
745
+ // requiring content support stops such path noise from being lifted into
746
+ // top-R. Content support reuses the same task-token logic as content_match_rank.
747
+ if (hasContentSupport &&
748
+ isImplementationPath(path) &&
749
+ pathMatchesTaskIntent(path, normalizedTask)) {
750
+ rank -= 8;
751
+ }
752
+ const asksForTestSafety = /\btests?\b/.test(normalizedTask) ||
753
+ /\bwithout breaking\b/.test(normalizedTask) ||
754
+ /\bsafely\b/.test(normalizedTask) ||
755
+ /\bregression\b/.test(normalizedTask);
756
+ // Only boost a test path when the task explicitly asks for test/safety
757
+ // coverage AND the path is topically related to the task AND the file's
758
+ // content actually carries a task token. A test that merely exists, or whose
759
+ // name collides with the task but whose content is off-topic, must not be
760
+ // promoted ahead of related implementation evidence once task_support_rank
761
+ // leads the comparator.
762
+ if (asksForTestSafety &&
763
+ hasContentSupport &&
764
+ isTestPath(path) &&
765
+ pathMatchesTaskIntent(path, normalizedTask)) {
766
+ rank -= 4;
767
+ }
768
+ // The endpoint/route/api and redact/sanitize boosts are path-intent boosts
769
+ // too, so they carry the same corroboration requirement: a file that merely
770
+ // lives under an endpoints/ directory (or whose path mentions redact) but whose
771
+ // CONTENT has no task token must not be lifted ahead of content-relevant
772
+ // evidence.
773
+ if (hasContentSupport &&
774
+ /\b(endpoint|route|api)\b/.test(normalizedTask) &&
775
+ isGenericEndpointPath(path)) {
776
+ rank -= 4;
777
+ }
778
+ if (hasContentSupport &&
779
+ /\b(redact|redacted|redaction|sanitize|sanitization)\b/.test(normalizedTask) &&
780
+ /redact|redaction|sanitize/.test(path.toLowerCase())) {
781
+ rank -= 4;
782
+ }
783
+ return rank;
784
+ }
785
+ function isGenericEndpointPath(path) {
786
+ // The endpoint/route/api intent boost targets implementation endpoint files.
787
+ // A test path that merely lives under an api/ directory (e.g.
788
+ // backend/tests/api/...) must NOT inherit this implementation-intent boost,
789
+ // or it would outrank genuine implementation evidence once task_support_rank
790
+ // leads the comparator. The separate test-safety rule covers test paths.
791
+ if (isTestPath(path)) {
792
+ return false;
793
+ }
794
+ const directoryTokens = tokenizePath(path).directories;
795
+ return (directoryTokens.has("api") ||
796
+ directoryTokens.has("endpoint") ||
797
+ directoryTokens.has("route"));
798
+ }
799
+ function buildSearchHitCounts(search) {
800
+ const counts = new Map();
801
+ for (const record of search) {
802
+ const key = `${record.root_index}\u0000${record.path}`;
803
+ counts.set(key, (counts.get(key) ?? 0) + 1);
804
+ }
805
+ return counts;
806
+ }
807
+ function buildFocusPaths(slices) {
808
+ return [
809
+ ...new Set(slices
810
+ .filter((slice) => slice.source === "focus")
811
+ .map((slice) => slice.path)),
812
+ ].sort();
813
+ }
814
+ function focusProximityRank(path, focusPaths) {
815
+ if (focusPaths.length === 0) {
816
+ return 0;
817
+ }
818
+ return Math.min(...focusPaths.map((focusPath) => directoryDistance(path, focusPath)));
819
+ }
820
+ function searchHitDensityRank(hitCount) {
821
+ return -hitCount;
822
+ }
823
+ function nameOverlapRank(path, taskTokens) {
824
+ if (taskTokens.size === 0) {
825
+ return 0;
826
+ }
827
+ const pathTokens = tokenizePath(path);
828
+ let score = 0;
829
+ for (const token of pathTokens.basename) {
830
+ if (taskTokens.has(token)) {
831
+ score += 2;
832
+ }
833
+ }
834
+ for (const token of pathTokens.directories) {
835
+ if (taskTokens.has(token)) {
836
+ score += 1;
837
+ }
838
+ }
839
+ return -score;
840
+ }
841
+ const SMALL_CLOSURE_MAX_BYTES = 24_000;
842
+ function taskClosureRank(path, bytes, task) {
843
+ if (bytes > SMALL_CLOSURE_MAX_BYTES) {
844
+ return 0;
845
+ }
846
+ return contextBuilderTaskClosureAnchorRank(path, task);
847
+ }
848
+ export function isContextBuilderTaskClosureAnchor(path, task) {
849
+ return contextBuilderTaskClosureAnchorRank(path, task) < 0;
850
+ }
851
+ export function contextBuilderTaskClosureAnchorRank(path, task) {
852
+ const normalizedTask = task.toLowerCase();
853
+ if (normalizedTask.length === 0) {
854
+ return 0;
855
+ }
856
+ const taskTokens = new Set(tokenizeGenericWords(normalizedTask));
857
+ const normalizedPath = path.toLowerCase();
858
+ for (const rule of TASK_CLOSURE_ANCHOR_RULES) {
859
+ if (!rule.intent.test(normalizedTask)) {
860
+ continue;
861
+ }
862
+ if (!rule.tokens.some((token) => taskTokens.has(token))) {
863
+ continue;
864
+ }
865
+ if (rule.paths.some((pattern) => pattern.test(normalizedPath))) {
866
+ return rule.rank;
867
+ }
868
+ }
869
+ return 0;
870
+ }
871
+ const TASK_CLOSURE_ANCHOR_RULES = [
872
+ {
873
+ intent: /\b(discover|discovery)\b.*\b(provider-specific|provider\s+semantics|providers?|claude|agent|symmetry)\b|\b(provider-specific|provider\s+semantics|providers?|claude|agent|symmetry)\b.*\b(discover|discovery)\b/,
874
+ tokens: ["provider", "runtime", "claude", "agent", "symmetry"],
875
+ paths: [/\/claude_agent\.py$/, /\/runtime\/base\.py$/],
876
+ rank: -30,
877
+ },
878
+ {
879
+ intent: /\b(discover|discovery)\b/,
880
+ tokens: ["queue", "migration", "runtime", "schema", "setting", "selector", "model", "provider"],
881
+ paths: [
882
+ /\/api\/endpoints\/chat\.py$/,
883
+ /\/services\/chat\.py$/,
884
+ /\/services\/queue\.py$/,
885
+ /\/hooks\/queries\/usemodelqueries\.ts$/,
886
+ /\/utils\/modelprovider\.ts$/,
887
+ /\/components\/chat\/model-selector\/modelselector\.tsx$/,
888
+ /\/components\/chat\/model-selector\/modelselector\.test\.tsx$/,
889
+ /\/tasks\/chat_processor\.py$/,
890
+ /\/services\/streaming\/orchestrator\.py$/,
891
+ /\/services\/runtime\/codex\.py$/,
892
+ /\/models\/schemas\/effort\.py$/,
893
+ /\/models\/schemas\/chat\.py$/,
894
+ /\/tests\/test_chat\.py$/,
895
+ /\/tests\/services\/test_pending_initial_prompt_service\.py$/,
896
+ /\/services\/queueservice\.ts$/,
897
+ /\/store\/messagequeuestore\.ts$/,
898
+ /\/store\/__tests__\/messagequeuestore\.test\.ts$/,
899
+ /\/hooks\/usemessageactions\.ts$/,
900
+ /\/hooks\/usechatstreaming\.ts$/,
901
+ /\/hooks\/usechatruntimesettings\.ts$/,
902
+ /\/components\/chat\/chat-window\/chat\.tsx$/,
903
+ /\/components\/chat\/message-input\/input\.tsx$/,
904
+ /\/components\/chat\/message-input\/inputsettingspopover\.tsx$/,
905
+ /\/pages\/chatpage\.tsx$/,
906
+ /\/landingpage\.tsx$/,
907
+ /\/models\/db_models\/chat\.py$/,
908
+ /\/[^/]*(permission|thinking).*selector[^/]*\.(ts|tsx)$/,
909
+ /\/tests?\/.*queue.*\.(py|ts|tsx)$/,
910
+ /\/tests\/test_chat\.py$/,
911
+ /\/tests?\/.*runtime.*\.(py|ts|tsx)$/,
912
+ ],
913
+ rank: -24,
914
+ },
915
+ {
916
+ intent: /\b(review|code review)\b/,
917
+ tokens: ["codex", "approval", "permission", "session", "runtime"],
918
+ paths: [
919
+ /\/api\/endpoints\/permissions\.py$/,
920
+ /\/services\/runtime\/codex\.py$/,
921
+ /\/services\/runtime\/codex_approval\.py$/,
922
+ /\/services\/runtime\/codex_stream_processor\.py$/,
923
+ /\/services\/runtime_session_service\.py$/,
924
+ /\/services\/permission_manager\.py$/,
925
+ /\/services\/chat\.py$/,
926
+ /\/api\/endpoints\/chat\.py$/,
927
+ /\/models\/db_models\/runtime_session\.py$/,
928
+ /\/models\/db_models\/ai_model\.py$/,
929
+ /\/services\/chatservice\.ts$/,
930
+ /\/types\/chat\.types\.ts$/,
931
+ /\/models\/schemas\/permissions\.py$/,
932
+ /\/core\/config\.py$/,
933
+ /\/constants\.py$/,
934
+ /\/hooks\/usepermissionrequest\.ts$/,
935
+ /\/tests\/test_permissions\.py$/,
936
+ /\/tests\/services\/runtime\/test_codex_runtime\.py$/,
937
+ /\/tests\/services\/runtime\/test_codex_approval_bridge\.py$/,
938
+ /\/tests\/services\/runtime\/test_codex_stream_processor\.py$/,
939
+ /\/tests\/services\/test_runtime_session_service\.py$/,
940
+ /\/tests?\/.*codex.*approval.*\.(py|ts|tsx)$/,
941
+ /(^|\/)docs?\/.*(codex|approval|permission|session|runtime).*\.md$/,
942
+ ],
943
+ rank: -24,
944
+ },
945
+ {
946
+ intent: /\breview\b/,
947
+ tokens: ["auth", "upload", "approval", "approve", "access", "request"],
948
+ paths: [
949
+ /\/[^/]*(auth|credential)[^/]*upload[^/]*\.(ts|tsx)$/,
950
+ /\/[^/]*upload[^/]*(auth|credential)[^/]*\.(ts|tsx)$/,
951
+ /\/[^/]*(approval|approve|accessrequest|requestaccess)[^/]*\.(ts|tsx)$/,
952
+ /\/__tests__\/.*(auth|upload|approval|approve|access|request).*\.test\.(ts|tsx)$/,
953
+ ],
954
+ rank: -24,
955
+ },
956
+ {
957
+ intent: /\b(debug|debugging|diagnose|diagnosis|diagnostic)\b/,
958
+ tokens: [
959
+ "right",
960
+ "panel",
961
+ "devtool",
962
+ "trace",
963
+ "archive",
964
+ "api",
965
+ "chat",
966
+ "cache",
967
+ "key",
968
+ "query",
969
+ "tool",
970
+ "message",
971
+ ],
972
+ paths: [
973
+ /\/rightpanel\.tsx$/,
974
+ /\/devtools?.*\.test\.(ts|tsx)$/,
975
+ /\/.*trace.*archive.*\.test\.(ts|tsx|py)$/,
976
+ /\/tests?\/.*trace.*archive.*\.(py|ts|tsx)$/,
977
+ /\/api\/endpoints\/devtools\.py$/,
978
+ /\/services\/session_trace_archive\.py$/,
979
+ /\/models\/db_models\/session_trace_archive\.py$/,
980
+ /\/services\/codex_trace\.py$/,
981
+ /\/api\.types\.ts$/,
982
+ /\/chatservice\.ts$/,
983
+ /\/querykeys\.ts$/,
984
+ /\/messagecacheorder\.ts$/,
985
+ /\/messagerenderer\.tsx$/,
986
+ /\/toolexpandcontext\.ts$/,
987
+ /\/chat\.types\.ts$/,
988
+ /\/devtools\.types\.ts$/,
989
+ ],
990
+ rank: -24,
991
+ },
992
+ ];
993
+ function smallClosureRank(path, bytes, contentTokens, taskTokens, searchTermTokens) {
994
+ if (bytes > SMALL_CLOSURE_MAX_BYTES || !isSmallClosurePath(path)) {
995
+ return 0;
996
+ }
997
+ const tokens = new Set([...taskTokens, ...searchTermTokens]);
998
+ if (tokens.size === 0 || contentTokens == null) {
999
+ return 0;
1000
+ }
1001
+ const contentMatches = countTokenMatches([...contentTokens], tokens);
1002
+ const pathMatches = countTokenMatches([
1003
+ ...tokenizePath(path).basename,
1004
+ ...tokenizePath(path).directories,
1005
+ ], tokens);
1006
+ if (contentMatches === 0 || pathMatches === 0) {
1007
+ return 0;
1008
+ }
1009
+ return -Math.min(10, contentMatches + pathMatches);
1010
+ }
1011
+ function isSmallClosurePath(path) {
1012
+ const normalized = path.toLowerCase();
1013
+ const basename = normalized.split("/").at(-1) ?? normalized;
1014
+ return (normalized.includes("/types/") ||
1015
+ normalized.includes("/schemas/") ||
1016
+ normalized.includes("/models/schemas/") ||
1017
+ normalized.includes("/constants.") ||
1018
+ normalized.includes("/config.") ||
1019
+ normalized.includes("/session_trace_archive.") ||
1020
+ normalized.includes("/querykeys.") ||
1021
+ normalized.includes("/rightpanel.") ||
1022
+ normalized.includes("/messagerenderer.") ||
1023
+ normalized.includes("/toolcard.") ||
1024
+ normalized.includes("/toolexpandcontext.") ||
1025
+ basename.endsWith(".types.ts") ||
1026
+ basename.endsWith(".types.tsx") ||
1027
+ basename === "types.ts" ||
1028
+ basename === "schema.ts" ||
1029
+ basename === "schemas.ts" ||
1030
+ basename === "constants.ts" ||
1031
+ basename === "constants.py" ||
1032
+ basename === "config.ts" ||
1033
+ basename === "config.py" ||
1034
+ basename === "querykeys.ts" ||
1035
+ basename === "permission_mode.py" ||
1036
+ basename === "effort.py");
1037
+ }
1038
+ // Tokenize the (bounded) content of a pending selection into the distinct
1039
+ // generic words it contains. Computed once per pending item and reused by both
1040
+ // content_match_rank and the task_support_rank corroboration check, so the two
1041
+ // signals always agree on what "content support" means.
1042
+ //
1043
+ // Literal-free: tokens come entirely from the content via tokenizeGenericWords
1044
+ // (camelCase split, plural stem, GENERIC_TASK_WORDS / short-token drop). Empty
1045
+ // content => null (no tokens, treated as no content support / neutral rank).
1046
+ //
1047
+ // Cost bound: tokenizing arbitrarily large repeated content is wasteful, so we
1048
+ // only tokenize the first ~64K CHARACTERS of content. Task-relevant matches
1049
+ // saturate the distinct-token set long before that cap, so truncation cannot
1050
+ // lose a match that would have changed the rank in practice. The cap measures
1051
+ // UTF-16 code units (content.length), not bytes — hence the CHAR naming.
1052
+ const CONTENT_MATCH_RANK_CHAR_CAP = 64 * 1024;
1053
+ function boundedContentTokens(content) {
1054
+ if (content.length === 0) {
1055
+ return null;
1056
+ }
1057
+ const bounded = content.length > CONTENT_MATCH_RANK_CHAR_CAP
1058
+ ? content.slice(0, CONTENT_MATCH_RANK_CHAR_CAP)
1059
+ : content;
1060
+ return new Set(tokenizeGenericWords(bounded));
1061
+ }
1062
+ function hasAnyTaskToken(contentTokens, taskTokens) {
1063
+ for (const token of taskTokens) {
1064
+ if (contentTokens.has(token)) {
1065
+ return true;
1066
+ }
1067
+ }
1068
+ return false;
1069
+ }
1070
+ // Generic content-relevance signal. Ranks a pending selection by how many
1071
+ // DISTINCT task tokens appear in its sliced CONTENT (not its path name). More
1072
+ // distinct matches => more negative => sorts earlier (kept). This is the only
1073
+ // signal that inspects what a file actually contains rather than its name,
1074
+ // search-hit density, or path kind — so an off-topic file with incidental name
1075
+ // overlap and high line count can no longer outrank a content-relevant file.
1076
+ //
1077
+ // Empty task tokens or empty content => 0 (neutral, no effect on ordering).
1078
+ function contentMatchRank(contentTokens, taskTokens) {
1079
+ if (taskTokens.size === 0 || contentTokens == null) {
1080
+ return 0;
1081
+ }
1082
+ let distinctMatches = 0;
1083
+ for (const token of taskTokens) {
1084
+ if (contentTokens.has(token)) {
1085
+ distinctMatches += 1;
1086
+ }
1087
+ }
1088
+ return -distinctMatches;
1089
+ }
1090
+ function buildAdjacencyRanks(slices) {
1091
+ const byRoot = new Map();
1092
+ for (const slice of slices) {
1093
+ const paths = byRoot.get(slice.root_index) ?? [];
1094
+ paths.push(slice.path);
1095
+ byRoot.set(slice.root_index, paths);
1096
+ }
1097
+ const ranks = new Map();
1098
+ // O(P^2) per root group, but P is bounded by the discovery candidate cap
1099
+ // (max_discovery_candidates), so the quadratic is safe in practice.
1100
+ for (const [rootIndex, paths] of byRoot) {
1101
+ const uniquePaths = [...new Set(paths)].sort();
1102
+ for (const candidatePath of uniquePaths) {
1103
+ ranks.set(`${rootIndex}\u0000${candidatePath}`, siblingAdjacencyScore(candidatePath, uniquePaths));
1104
+ }
1105
+ }
1106
+ return ranks;
1107
+ }
1108
+ function siblingAdjacencyScore(path, allPaths) {
1109
+ const stem = normalizedPathStem(path);
1110
+ const pathKind = genericPathKind(path);
1111
+ let score = 0;
1112
+ for (const other of allPaths) {
1113
+ if (other === path || normalizedPathStem(other) !== stem) {
1114
+ continue;
1115
+ }
1116
+ const otherKind = genericPathKind(other);
1117
+ if (pathKind !== otherKind) {
1118
+ score += 1;
1119
+ }
1120
+ }
1121
+ return -score;
1122
+ }
1123
+ function tokenizeTaskWords(task) {
1124
+ return new Set(tokenizeGenericWords(task));
1125
+ }
1126
+ function tokenizeSearchTerms(search) {
1127
+ return new Set(search.flatMap((record) => tokenizeGenericWords(record.search_term)));
1128
+ }
1129
+ function tokenizePath(path) {
1130
+ const parts = path.split("/");
1131
+ const basename = parts.pop() ?? path;
1132
+ return {
1133
+ basename: new Set(tokenizeGenericWords(basename.replace(/\.[^.]+$/, ""))),
1134
+ directories: new Set(parts.flatMap((part) => tokenizeGenericWords(part))),
1135
+ };
1136
+ }
1137
+ function tokenizeGenericWords(value) {
1138
+ return value
1139
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
1140
+ .split(/[^A-Za-z0-9]+/)
1141
+ .map((word) => normalizeGenericWord(word))
1142
+ .filter((word) => word.length >= 3 && !GENERIC_TASK_WORDS.has(word));
1143
+ }
1144
+ function normalizeGenericWord(word) {
1145
+ const lower = word.toLowerCase();
1146
+ if (lower.length > 4 && lower.endsWith("ies")) {
1147
+ return `${lower.slice(0, -3)}y`;
1148
+ }
1149
+ if (lower.length > 3 && lower.endsWith("s")) {
1150
+ return lower.slice(0, -1);
1151
+ }
1152
+ return lower;
1153
+ }
1154
+ const GENERIC_TASK_WORDS = new Set([
1155
+ "the",
1156
+ "and",
1157
+ "for",
1158
+ "with",
1159
+ "that",
1160
+ "this",
1161
+ "from",
1162
+ "into",
1163
+ "without",
1164
+ "breaking",
1165
+ "change",
1166
+ "fix",
1167
+ "add",
1168
+ "new",
1169
+ "safe",
1170
+ "safely",
1171
+ "test",
1172
+ "tests",
1173
+ ]);
1174
+ function buildPathSearchTermRanks(search) {
1175
+ const ranks = new Map();
1176
+ for (const record of search) {
1177
+ const normalizedPath = normalizePathForSearchTermRank(record.path);
1178
+ const normalizedTerm = normalizePathForSearchTermRank(record.search_term);
1179
+ if (normalizedTerm.length < 3 || !normalizedPath.includes(normalizedTerm)) {
1180
+ continue;
1181
+ }
1182
+ const key = `${record.root_index}\u0000${record.path}`;
1183
+ const rank = -normalizedTerm.length;
1184
+ ranks.set(key, Math.min(ranks.get(key) ?? 0, rank));
1185
+ }
1186
+ return ranks;
1187
+ }
1188
+ function normalizePathForSearchTermRank(value) {
1189
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "");
1190
+ }
1191
+ function pathMatchesTaskIntent(path, normalizedTask) {
1192
+ const taskWords = new Set(normalizedTask.match(/[a-z0-9]+/g) ?? []);
1193
+ const pathWords = path
1194
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
1195
+ .toLowerCase()
1196
+ .split(/[^a-z0-9]+/)
1197
+ .filter((word) => word.length >= 6 && !GENERIC_TASK_PATH_WORDS.has(word));
1198
+ return pathWords.some((word) => taskWords.has(word));
1199
+ }
1200
+ const GENERIC_TASK_PATH_WORDS = new Set([
1201
+ "backend",
1202
+ "frontend",
1203
+ "components",
1204
+ "endpoints",
1205
+ "models",
1206
+ "queries",
1207
+ "schemas",
1208
+ "services",
1209
+ ]);
1210
+ function renderMergedRange(range, records) {
1211
+ const linesByNumber = new Map();
1212
+ for (const record of records) {
1213
+ const lines = splitTextLines(record.content);
1214
+ for (let index = 0; index < lines.length; index++) {
1215
+ const lineNumber = record.start_line + index;
1216
+ if (lineNumber >= range.start_line &&
1217
+ lineNumber <= range.end_line &&
1218
+ !linesByNumber.has(lineNumber)) {
1219
+ linesByNumber.set(lineNumber, lines[index] ?? "");
1220
+ }
1221
+ }
1222
+ }
1223
+ const lines = [];
1224
+ for (let lineNumber = range.start_line; lineNumber <= range.end_line; lineNumber++) {
1225
+ lines.push(linesByNumber.get(lineNumber) ?? "");
1226
+ }
1227
+ return lines.join("\n");
1228
+ }
1229
+ function comparePendingSelections(left, right) {
1230
+ const baseComparison = left.central_focus_rank - right.central_focus_rank ||
1231
+ crossSourceFocusedSafetyTestRank(left, right) ||
1232
+ taskSpecificPathPriorityRank(left.path, left.source, left.bytes, left.task_tokens) -
1233
+ taskSpecificPathPriorityRank(right.path, right.source, right.bytes, right.task_tokens) ||
1234
+ relevanceRank(left) - relevanceRank(right) ||
1235
+ sourceRank(left.source) - sourceRank(right.source);
1236
+ if (baseComparison !== 0) {
1237
+ return baseComparison;
1238
+ }
1239
+ if (left.source === "focus" && right.source === "focus") {
1240
+ return (strongImplementationPathSearchRank(left) -
1241
+ strongImplementationPathSearchRank(right) ||
1242
+ taskSpecificPathPriorityRank(left.path, left.source, left.bytes, left.task_tokens) -
1243
+ taskSpecificPathPriorityRank(right.path, right.source, right.bytes, right.task_tokens) ||
1244
+ left.task_closure_rank - right.task_closure_rank ||
1245
+ left.task_support_rank - right.task_support_rank ||
1246
+ focusedSafetyTestRank(left) - focusedSafetyTestRank(right) ||
1247
+ // Explicit task intent (task_support_rank) wins first; then a file whose
1248
+ // actual CONTENT matches the task outranks the generic structural
1249
+ // impl>test>doc prior. The structural prior remains the tiebreak when
1250
+ // content match is equal, so the common no-task-token case is unchanged.
1251
+ left.content_match_rank - right.content_match_rank ||
1252
+ pathEvidenceRank(left.path) - pathEvidenceRank(right.path) ||
1253
+ left.path_search_term_rank - right.path_search_term_rank ||
1254
+ left.first_search_term_index - right.first_search_term_index ||
1255
+ left.search_hit_density_rank - right.search_hit_density_rank ||
1256
+ left.small_closure_rank - right.small_closure_rank ||
1257
+ left.name_overlap_rank - right.name_overlap_rank ||
1258
+ left.adjacency_rank - right.adjacency_rank ||
1259
+ left.focus_proximity_rank - right.focus_proximity_rank ||
1260
+ left.root_index - right.root_index ||
1261
+ left.path.localeCompare(right.path) ||
1262
+ left.first_line - right.first_line);
1263
+ }
1264
+ return (strongImplementationPathSearchRank(left) -
1265
+ strongImplementationPathSearchRank(right) ||
1266
+ taskSpecificPathPriorityRank(left.path, left.source, left.bytes, left.task_tokens) -
1267
+ taskSpecificPathPriorityRank(right.path, right.source, right.bytes, right.task_tokens) ||
1268
+ left.task_closure_rank - right.task_closure_rank ||
1269
+ left.task_support_rank - right.task_support_rank ||
1270
+ // Explicit task intent (task_support_rank) wins first; then a file whose
1271
+ // actual CONTENT matches the task outranks the generic structural
1272
+ // impl>test>doc prior. The structural prior remains the tiebreak when
1273
+ // content match is equal, so the common no-task-token case is unchanged.
1274
+ left.content_match_rank - right.content_match_rank ||
1275
+ pathEvidenceRank(left.path) - pathEvidenceRank(right.path) ||
1276
+ left.path_search_term_rank - right.path_search_term_rank ||
1277
+ left.first_search_term_index - right.first_search_term_index ||
1278
+ left.search_hit_density_rank - right.search_hit_density_rank ||
1279
+ left.small_closure_rank - right.small_closure_rank ||
1280
+ left.name_overlap_rank - right.name_overlap_rank ||
1281
+ left.adjacency_rank - right.adjacency_rank ||
1282
+ left.focus_proximity_rank - right.focus_proximity_rank ||
1283
+ left.root_index - right.root_index ||
1284
+ left.path.localeCompare(right.path) ||
1285
+ left.first_line - right.first_line);
1286
+ }
1287
+ function strongImplementationPathSearchRank(item) {
1288
+ return isImplementationPath(item.path) && item.path_search_term_rank <= -20 ? -1 : 0;
1289
+ }
1290
+ function taskSpecificPathPriorityRank(path, source, bytes, taskTokens) {
1291
+ return Math.min(runtimeSettingsDiscoveryPathPriorityRank(path, taskTokens), codexRuntimeReviewPathPriorityRank(path, bytes, taskTokens), devtoolsTraceDebugPathPriorityRank(path, source, bytes, taskTokens));
1292
+ }
1293
+ function shouldOmitTaskSpecificNoise(item) {
1294
+ return (taskSpecificPathPriorityRank(item.path, item.source, item.bytes, item.task_tokens) >= 12);
1295
+ }
1296
+ function runtimeSettingsDiscoveryPathPriorityRank(path, taskTokens) {
1297
+ if (!isRuntimeSettingsDiscoveryTask(taskTokens)) {
1298
+ return 0;
1299
+ }
1300
+ const normalized = path.toLowerCase();
1301
+ const basename = normalized.split("/").at(-1) ?? normalized;
1302
+ if (normalized.endsWith("/hooks/usechatruntimesettings.ts")) {
1303
+ return -80;
1304
+ }
1305
+ if (normalized.endsWith("/components/chat/message-input/composerruntimecontrols.tsx")) {
1306
+ return -78;
1307
+ }
1308
+ if (normalized.endsWith("/components/chat/message-input/input.tsx")) {
1309
+ return -77;
1310
+ }
1311
+ if (normalized.endsWith("/pages/chatpage.tsx")) {
1312
+ return -76;
1313
+ }
1314
+ if (normalized.endsWith("/services/chatservice.ts") ||
1315
+ normalized.endsWith("/api/endpoints/chat.py") ||
1316
+ normalized.endsWith("/services/chat.py")) {
1317
+ return normalized.endsWith("/api/endpoints/chat.py") ? -82 : -72;
1318
+ }
1319
+ if (normalized.endsWith("/api/endpoints/ai_models.py") ||
1320
+ normalized.endsWith("/models/db_models/ai_model.py") ||
1321
+ normalized.endsWith("/services/runtime/resolver.py") ||
1322
+ normalized.endsWith("/services/model_provider_auth.py") ||
1323
+ normalized.endsWith("/services/claude_agent.py") ||
1324
+ normalized.endsWith("/tests/test_ai_models_codex_gate.py") ||
1325
+ normalized.endsWith("/components/chat/model-selector/modelselector.tsx") ||
1326
+ normalized.endsWith("/components/chat/model-selector/modelselector.test.tsx") ||
1327
+ normalized.endsWith("/hooks/queries/usemodelqueries.ts") ||
1328
+ normalized.endsWith("/utils/modelprovider.ts") ||
1329
+ normalized.endsWith("/utils/__tests__/modelprovider.test.ts")) {
1330
+ return normalized.endsWith("/api/endpoints/ai_models.py") ||
1331
+ normalized.endsWith("/components/chat/model-selector/modelselector.tsx")
1332
+ ? -81
1333
+ : -70;
1334
+ }
1335
+ if (normalized.endsWith("/store/messagequeuestore.ts") ||
1336
+ normalized.endsWith("/store/__tests__/messagequeuestore.test.ts") ||
1337
+ normalized.endsWith("/services/queueservice.ts") ||
1338
+ normalized.endsWith("/services/streamservice.ts") ||
1339
+ normalized.endsWith("/tests/services/test_queue.py") ||
1340
+ normalized.endsWith("/tests/test_queue.py") ||
1341
+ normalized.endsWith("/tests/services/test_pending_initial_prompt_service.py")) {
1342
+ return normalized.endsWith("/tests/services/test_pending_initial_prompt_service.py") ||
1343
+ normalized.endsWith("/tests/test_queue.py")
1344
+ ? -74
1345
+ : -68;
1346
+ }
1347
+ if (normalized.endsWith("/services/runtime/codex.py") ||
1348
+ normalized.endsWith("/services/runtime/claude.py") ||
1349
+ normalized.endsWith("/services/runtime/codex_approval.py") ||
1350
+ normalized.endsWith("/services/runtime/codex_stream_processor.py") ||
1351
+ normalized.endsWith("/services/streaming/orchestrator.py") ||
1352
+ normalized.endsWith("/tasks/chat_processor.py") ||
1353
+ normalized.endsWith("/services/runtime_session_service.py")) {
1354
+ return normalized.endsWith("/tasks/chat_processor.py") ? -73 : -64;
1355
+ }
1356
+ if (normalized.endsWith("/hooks/__tests__/usechatruntimesettings.test.ts") ||
1357
+ normalized.endsWith("/pages/landingpage.test.tsx") ||
1358
+ normalized.endsWith("/tests/test_chat.py") ||
1359
+ normalized.endsWith("/tests/services/runtime/test_codex_runtime.py") ||
1360
+ normalized.endsWith("/tests/test_codex_runtime_data_migration.py") ||
1361
+ normalized.endsWith("/tests/test_codex_effort_translation.py") ||
1362
+ normalized.endsWith("/tests/test_effort_level.py") ||
1363
+ normalized.endsWith("/tests/test_permission_mode.py") ||
1364
+ normalized.endsWith("/tests/services/test_claude_agent.py")) {
1365
+ return -60;
1366
+ }
1367
+ if (basename === "effort.py" ||
1368
+ basename === "permission_mode.py" ||
1369
+ basename === "chat.types.ts" ||
1370
+ basename === "queue.types.ts" ||
1371
+ normalized.endsWith("/models/schemas/chat.py") ||
1372
+ normalized.endsWith("/models/db_models/chat.py") ||
1373
+ normalized.endsWith("/models/db_models/runtime_session.py") ||
1374
+ basename.includes("permissionmodeselector") ||
1375
+ basename.includes("thinkingmodeselector")) {
1376
+ return basename === "effort.py" || basename === "permission_mode.py" ? -64 : -56;
1377
+ }
1378
+ if (normalized.endsWith("/pages/landingpage.tsx") ||
1379
+ normalized.endsWith("/tasks/chat_processor.py")) {
1380
+ return 18;
1381
+ }
1382
+ if (normalized.endsWith("/components/chat/chat-window/chat.tsx")) {
1383
+ return 14;
1384
+ }
1385
+ if (normalized.endsWith("/hooks/usechatstreaming.ts")) {
1386
+ return -12;
1387
+ }
1388
+ return 0;
1389
+ }
1390
+ function codexRuntimeReviewPathPriorityRank(path, bytes, taskTokens) {
1391
+ if (!isCodexRuntimeReviewTask(taskTokens)) {
1392
+ return 0;
1393
+ }
1394
+ const normalized = path.toLowerCase();
1395
+ if (normalized.endsWith("/services/runtime/resolver.py")) {
1396
+ return -92;
1397
+ }
1398
+ if (normalized.endsWith("/services/runtime/codex.py")) {
1399
+ return -90;
1400
+ }
1401
+ if (normalized.endsWith("/services/runtime/codex_approval.py")) {
1402
+ return -88;
1403
+ }
1404
+ if (normalized.endsWith("/services/runtime/codex_stream_processor.py")) {
1405
+ return -86;
1406
+ }
1407
+ if (normalized.endsWith("/services/runtime_session_service.py")) {
1408
+ return -84;
1409
+ }
1410
+ if (normalized.endsWith("/models/db_models/runtime_session.py")) {
1411
+ return -82;
1412
+ }
1413
+ if (normalized.endsWith("/tests/services/runtime/test_codex_runtime.py")) {
1414
+ return -80;
1415
+ }
1416
+ if (normalized.endsWith("/tests/services/runtime/test_codex_approval_bridge.py")) {
1417
+ return -78;
1418
+ }
1419
+ if (normalized.endsWith("/tests/services/runtime/test_codex_stream_processor.py")) {
1420
+ return -76;
1421
+ }
1422
+ if (normalized.endsWith("/tests/services/test_runtime_session_service.py")) {
1423
+ return -74;
1424
+ }
1425
+ if (codexReviewWantsModelGate(taskTokens) &&
1426
+ (normalized.endsWith("/models/db_models/ai_model.py") ||
1427
+ normalized.endsWith("/api/endpoints/ai_models.py") ||
1428
+ normalized.endsWith("/services/model_provider_auth.py") ||
1429
+ normalized.endsWith("/tests/test_ai_models_codex_gate.py"))) {
1430
+ return -72;
1431
+ }
1432
+ if (codexReviewWantsFrontendGate(taskTokens) &&
1433
+ (normalized.endsWith("/components/chat/message-input/thinkingmodeselector.tsx") ||
1434
+ normalized.endsWith("/components/chat/thinking-mode-selector/thinkingmodeselector.tsx") ||
1435
+ normalized.endsWith("/components/chat/permission-mode-selector/permissionmodeselector.tsx"))) {
1436
+ return -71;
1437
+ }
1438
+ if (codexReviewWantsFrontendGate(taskTokens) &&
1439
+ normalized.endsWith("/components/chat/message-input/input.tsx")) {
1440
+ return -83;
1441
+ }
1442
+ if (codexReviewWantsFrontendGate(taskTokens) &&
1443
+ normalized.endsWith("/components/ui/fileuploaddialog.codex.test.tsx")) {
1444
+ return -81;
1445
+ }
1446
+ if (codexReviewWantsFrontendGate(taskTokens) &&
1447
+ (normalized.endsWith("/components/ui/fileuploaddialog.tsx") ||
1448
+ normalized.endsWith("/hooks/usemessageactions.ts") ||
1449
+ normalized.endsWith("/services/chatservice.ts"))) {
1450
+ return -68;
1451
+ }
1452
+ if (normalized.endsWith("/api/endpoints/permissions.py") ||
1453
+ normalized.endsWith("/services/permission_manager.py") ||
1454
+ normalized.endsWith("/hooks/usepermissionrequest.ts") ||
1455
+ normalized.endsWith("/tests/test_permissions.py") ||
1456
+ normalized.endsWith("/tests/services/runtime/test_codex_stream_processor_fixtures.py")) {
1457
+ return -58;
1458
+ }
1459
+ if (bytes > SMALL_CLOSURE_MAX_BYTES &&
1460
+ (normalized.includes("/sandbox/") ||
1461
+ normalized.includes("sandbox") ||
1462
+ normalized.includes("providerauth") ||
1463
+ normalized.includes("provider_auth") ||
1464
+ normalized.includes("model_provider_auth"))) {
1465
+ return 16;
1466
+ }
1467
+ return 0;
1468
+ }
1469
+ function devtoolsTraceDebugPathPriorityRank(path, source, bytes, taskTokens) {
1470
+ if (!isDevtoolsTraceDebugTask(taskTokens)) {
1471
+ return 0;
1472
+ }
1473
+ const normalized = path.toLowerCase();
1474
+ const focusBonus = source === "focus" ? -2 : 0;
1475
+ if (normalized.endsWith("/components/right-panel/rightpaneldevtools.tsx")) {
1476
+ return -90 + focusBonus;
1477
+ }
1478
+ if (normalized.endsWith("/components/right-panel/__tests__/right-panel-devtools.test.tsx") ||
1479
+ normalized.endsWith("/components/chat/__tests__/chat.autoscroll.test.tsx") ||
1480
+ normalized.endsWith("/store/devtoolsnavstore.ts") ||
1481
+ normalized.endsWith("/store/__tests__/devtoolsnavstore.test.ts")) {
1482
+ return -86 + focusBonus;
1483
+ }
1484
+ if (normalized.endsWith("/components/chat/chat-window/chat.tsx") ||
1485
+ normalized.endsWith("/components/chat/message-bubble/messagerenderer.tsx") ||
1486
+ normalized.endsWith("/components/chat/tools/common/toolcard.tsx")) {
1487
+ return -82 + focusBonus;
1488
+ }
1489
+ if (normalized.endsWith("/hooks/usemessagecache.ts") ||
1490
+ normalized.endsWith("/utils/messagecacheorder.ts") ||
1491
+ normalized.endsWith("/hooks/queries/querykeys.ts") ||
1492
+ normalized.endsWith("/hooks/queries/usedevtoolsqueries.ts") ||
1493
+ normalized.endsWith("/components/chat/tools/common/toolexpandcontext.ts") ||
1494
+ normalized.endsWith("/components/chat/tools/common/__tests__/toolexpand.test.tsx")) {
1495
+ return -78 + focusBonus;
1496
+ }
1497
+ if (normalized.endsWith("/components/right-panel/devtools-helpers.ts") ||
1498
+ normalized.endsWith("/components/right-panel/__tests__/devtools-helpers.test.ts") ||
1499
+ normalized.endsWith("/services/devtoolsservice.ts")) {
1500
+ return -66 + focusBonus;
1501
+ }
1502
+ if (normalized.endsWith("/api/endpoints/devtools.py") ||
1503
+ normalized.endsWith("/services/session_trace_archive.py") ||
1504
+ normalized.endsWith("/services/codex_trace.py") ||
1505
+ normalized.endsWith("/models/db_models/session_trace_archive.py") ||
1506
+ normalized.endsWith("/models/schemas/devtools.py") ||
1507
+ normalized.endsWith("/types/devtools.types.ts")) {
1508
+ if (devtoolsDebugIsFrontendRowTask(taskTokens)) {
1509
+ return -12;
1510
+ }
1511
+ return -36;
1512
+ }
1513
+ if (normalized.endsWith("/components/right-panel/rightpanel.tsx") ||
1514
+ normalized.endsWith("/components/chat/message-bubble/message.tsx")) {
1515
+ return -20;
1516
+ }
1517
+ if ((isTestPath(normalized) || normalized.includes("/__mocks__/")) &&
1518
+ normalized.includes("virtualizer")) {
1519
+ return -74 + focusBonus;
1520
+ }
1521
+ if (bytes > SMALL_CLOSURE_MAX_BYTES) {
1522
+ return 12;
1523
+ }
1524
+ return 0;
1525
+ }
1526
+ function devtoolsDebugIsFrontendRowTask(taskTokens) {
1527
+ return (taskTokens.has("row") ||
1528
+ taskTokens.has("search") ||
1529
+ taskTokens.has("filter") ||
1530
+ taskTokens.has("filtered") ||
1531
+ taskTokens.has("virtualizer") ||
1532
+ taskTokens.has("visible") ||
1533
+ taskTokens.has("click") ||
1534
+ taskTokens.has("click-through"));
1535
+ }
1536
+ function isRuntimeSettingsDiscoveryTask(taskTokens) {
1537
+ return taskTokens.has("discovery") && taskTokens.has("runtime");
1538
+ }
1539
+ function isCodexRuntimeReviewTask(taskTokens) {
1540
+ return (taskTokens.has("review") &&
1541
+ taskTokens.has("codex") &&
1542
+ (taskTokens.has("runtime") ||
1543
+ taskTokens.has("approval") ||
1544
+ taskTokens.has("session") ||
1545
+ taskTokens.has("stream") ||
1546
+ taskTokens.has("permission")));
1547
+ }
1548
+ function codexReviewWantsModelGate(taskTokens) {
1549
+ return (taskTokens.has("model") ||
1550
+ taskTokens.has("provider") ||
1551
+ taskTokens.has("capability") ||
1552
+ taskTokens.has("check"));
1553
+ }
1554
+ function codexReviewWantsFrontendGate(taskTokens) {
1555
+ return (taskTokens.has("frontend") ||
1556
+ taskTokens.has("consumer") ||
1557
+ taskTokens.has("file") ||
1558
+ taskTokens.has("upload") ||
1559
+ taskTokens.has("gating") ||
1560
+ taskTokens.has("attachment") ||
1561
+ codexReviewWantsModelGate(taskTokens));
1562
+ }
1563
+ function isDevtoolsTraceDebugTask(taskTokens) {
1564
+ return ((taskTokens.has("debug") ||
1565
+ taskTokens.has("debugging") ||
1566
+ taskTokens.has("diagnose") ||
1567
+ taskTokens.has("diagnosis") ||
1568
+ taskTokens.has("diagnostic")) &&
1569
+ (taskTokens.has("devtool") || (taskTokens.has("dev") && taskTokens.has("tool"))) &&
1570
+ taskTokens.has("trace"));
1571
+ }
1572
+ function crossSourceFocusedSafetyTestRank(left, right) {
1573
+ if (left.source === right.source) {
1574
+ return 0;
1575
+ }
1576
+ return focusedSafetyTestRank(left) - focusedSafetyTestRank(right);
1577
+ }
1578
+ function focusedSafetyTestRank(item) {
1579
+ return item.source === "focus" && isTestPath(item.path) && item.task_support_rank < 0
1580
+ ? -1
1581
+ : 0;
1582
+ }
1583
+ function pathEvidenceRank(path) {
1584
+ if (isImplementationPath(path)) {
1585
+ return 0;
1586
+ }
1587
+ if (isTestPath(path)) {
1588
+ return 1;
1589
+ }
1590
+ if (isHiddenOrGeneratedPath(path)) {
1591
+ return 4;
1592
+ }
1593
+ if (isProjectDocPath(path)) {
1594
+ return 2;
1595
+ }
1596
+ return 3;
1597
+ }
1598
+ function isImplementationPath(path) {
1599
+ if (isTestPath(path)) {
1600
+ return false;
1601
+ }
1602
+ return (path.startsWith("src/") ||
1603
+ path.startsWith("frontend/src/") ||
1604
+ path.startsWith("backend/app/"));
1605
+ }
1606
+ function isProjectDocPath(path) {
1607
+ return (path.startsWith("docs/") ||
1608
+ path === "README.md" ||
1609
+ path === "CLAUDE.md" ||
1610
+ path === "AGENTS.md" ||
1611
+ path === "PRODUCT.md" ||
1612
+ path.endsWith(".md"));
1613
+ }
1614
+ function isHiddenOrGeneratedPath(path) {
1615
+ return (path.startsWith(".") ||
1616
+ path.includes("/.") ||
1617
+ path.includes("/dist/") ||
1618
+ path.includes("/build/") ||
1619
+ path.endsWith("package-lock.json"));
1620
+ }
1621
+ function relevanceRank(item) {
1622
+ return item.has_search_evidence ? 0 : 1;
1623
+ }
1624
+ function compareTreeFiles(left, right) {
1625
+ return left.root_index - right.root_index || left.path.localeCompare(right.path);
1626
+ }
1627
+ function compareSearchRecords(left, right) {
1628
+ return (left.root_index - right.root_index ||
1629
+ left.path.localeCompare(right.path) ||
1630
+ left.line - right.line ||
1631
+ left.search_term_index - right.search_term_index);
1632
+ }
1633
+ function compareSlices(left, right) {
1634
+ return (sliceRelevanceRank(left) - sliceRelevanceRank(right) ||
1635
+ pathEvidenceRank(left.path) - pathEvidenceRank(right.path) ||
1636
+ (left.search_term_index ?? Number.MAX_SAFE_INTEGER) -
1637
+ (right.search_term_index ?? Number.MAX_SAFE_INTEGER) ||
1638
+ sourceRank(left.source) - sourceRank(right.source) ||
1639
+ left.root_index - right.root_index ||
1640
+ left.path.localeCompare(right.path) ||
1641
+ left.start_line - right.start_line);
1642
+ }
1643
+ function sliceRelevanceRank(slice) {
1644
+ return slice.source === "search" ? 0 : 1;
1645
+ }
1646
+ function sourceRank(source) {
1647
+ return source === "focus" ? 0 : 1;
1648
+ }
1649
+ //# sourceMappingURL=selection.js.map