@thegitai/cli 1.0.0-preview.33 → 1.0.0-preview.35

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.
@@ -7,6 +7,7 @@ import { isUserInputQuestionArray } from './contracts.js';
7
7
  import { createTraceContext, gatewayFailureCategory, normalizeServerUrl, readErrorResponse, } from './http.js';
8
8
  import { collectClientEnvironment } from '../client-environment.js';
9
9
  import { collectProjectOrientation } from '../project-orientation.js';
10
+ import { describeSessionImageStore } from '../core/session-image-store.js';
10
11
  import { autoAttachImages } from '../core/image-path-extractor.js';
11
12
  import { formatTurnFailureMarker } from '../turn-failure-marker.js';
12
13
  export class TurnCancelledError extends Error {
@@ -546,6 +547,7 @@ export async function sendServerUserMessage({ config, session, input, imageAttac
546
547
  backgroundJobUpdate: backgroundJobUpdate || undefined,
547
548
  clientEnvironment: collectClientEnvironment({ env: session.env }),
548
549
  projectOrientation: collectProjectOrientation(session.rootDir) ?? undefined,
550
+ sessionImageStore: describeSessionImageStore(session.env) ?? undefined,
549
551
  imageAttachments: imageAttachmentsForServer(requestImageAttachments),
550
552
  maxToolSteps: session.maxToolSteps,
551
553
  autoYes: session.autoYes,
@@ -111,6 +111,53 @@ export function readSessionImageByIndex(index, env = process.env) {
111
111
  }
112
112
  return null;
113
113
  }
114
+ export function describeSessionImageStore(env = process.env) {
115
+ if (!activeSessionId)
116
+ return null;
117
+ const dir = getSessionImageDir(activeSessionId, env);
118
+ if (!existsSync(dir))
119
+ return null;
120
+ const indices = [];
121
+ try {
122
+ for (const name of readdirSync(dir)) {
123
+ const parsed = Number.parseInt(path.basename(name, path.extname(name)), 10);
124
+ if (Number.isInteger(parsed) && parsed >= 1)
125
+ indices.push(parsed);
126
+ }
127
+ }
128
+ catch {
129
+ return null;
130
+ }
131
+ if (indices.length === 0)
132
+ return null;
133
+ return { dir, indices: indices.sort((a, b) => a - b) };
134
+ }
135
+ const MAX_STORE_DIR_CHARS = 512;
136
+ const MAX_STORE_INDICES = 200;
137
+ const STORE_CONTROL_CHARS = /[\u0000-\u001f\u007f]/g;
138
+ export function normalizeSessionImageStore(value) {
139
+ if (!value || typeof value !== 'object')
140
+ return null;
141
+ const record = value;
142
+ const dir = String(record.dir ?? '')
143
+ .replace(STORE_CONTROL_CHARS, ' ')
144
+ .trim()
145
+ .slice(0, MAX_STORE_DIR_CHARS);
146
+ if (!dir)
147
+ return null;
148
+ const seen = new Set();
149
+ for (const raw of Array.isArray(record.indices) ? record.indices : []) {
150
+ const parsed = Number(raw);
151
+ if (!Number.isInteger(parsed) || parsed < 1)
152
+ continue;
153
+ seen.add(parsed);
154
+ if (seen.size >= MAX_STORE_INDICES)
155
+ break;
156
+ }
157
+ if (seen.size === 0)
158
+ return null;
159
+ return { dir, indices: [...seen].sort((a, b) => a - b) };
160
+ }
114
161
  export class SessionImageError extends Error {
115
162
  code;
116
163
  constructor(message, code) {
@@ -4,6 +4,7 @@ import { approvalScrollLimit, buildTuiFrame, formatJobElapsed, formatTodoProgres
4
4
  import { createTerminalTitleController } from './tui/terminal-title.js';
5
5
  import { captureTerminalWrites, releaseTerminalWrites, } from './tui/terminal-writes.js';
6
6
  export { getSlashCommandSuggestions } from './tui/build-frame.js';
7
+ import { composerInputWidth, frameContentWidth } from './tui/composer-layout.js';
7
8
  import { agentModeLabel, nextAgentMode, } from '../agent-mode.js';
8
9
  import { chat, models } from '../api/index.js';
9
10
  import { isTurnCancelledError } from '../api/chat.js';
@@ -147,6 +148,17 @@ export const SLASH_COMMANDS = [
147
148
  description: 'Quit the current session',
148
149
  },
149
150
  ];
151
+ export function composerAttachmentsAfterCancel(queuedAttachments, inFlightAttachments) {
152
+ const seen = new Set();
153
+ const kept = [];
154
+ for (const attachment of [...queuedAttachments, ...inFlightAttachments]) {
155
+ if (seen.has(attachment.index))
156
+ continue;
157
+ seen.add(attachment.index);
158
+ kept.push(attachment);
159
+ }
160
+ return kept;
161
+ }
150
162
  function getShellWidth(columns) {
151
163
  const safeColumns = Math.max(columns, 20);
152
164
  const targetWidth = Math.floor(safeColumns * TUI_WIDTH_RATIO);
@@ -1413,6 +1425,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
1413
1425
  let latestUsageSummary = null;
1414
1426
  let pendingTurnEntries = [];
1415
1427
  let activeTurnAbort = null;
1428
+ let activeTurnImageAttachments = [];
1416
1429
  let activeServerTurnId = null;
1417
1430
  let unacknowledged = new Map();
1418
1431
  const blockedRows = new WeakMap();
@@ -1674,6 +1687,8 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
1674
1687
  activeTurnAbort = null;
1675
1688
  cancelActiveCommand();
1676
1689
  const queued = store.getState().queuedMessage;
1690
+ const restoredAttachments = composerAttachmentsAfterCancel(queued ? queued.imageAttachments : [], activeTurnImageAttachments);
1691
+ activeTurnImageAttachments = [];
1677
1692
  const cancelledEntries = [
1678
1693
  ...takePendingTurnEntries(),
1679
1694
  {
@@ -1691,7 +1706,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
1691
1706
  busySince: null,
1692
1707
  commandLog: [],
1693
1708
  cursor: queued ? queued.body.length : current.cursor,
1694
- imageAttachments: queued ? queued.imageAttachments : [],
1709
+ imageAttachments: restoredAttachments,
1695
1710
  input: queued ? queued.body : current.input,
1696
1711
  pastedChunks: queued ? queued.pastedChunks : current.pastedChunks,
1697
1712
  promptHistoryCursor: queued ? null : current.promptHistoryCursor,
@@ -2672,6 +2687,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
2672
2687
  pendingTurnEntries = [];
2673
2688
  queueTurnEntry(userEntry);
2674
2689
  resetThinkingPacer();
2690
+ activeTurnImageAttachments = imageAttachments;
2675
2691
  store.update((current) => ({
2676
2692
  ...current,
2677
2693
  activeTurnInput: input,
@@ -2725,6 +2741,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
2725
2741
  if (!(await saveActiveSession()))
2726
2742
  return;
2727
2743
  syncShellStateFromSession();
2744
+ activeTurnImageAttachments = [];
2728
2745
  store.update((current) => ({
2729
2746
  ...current,
2730
2747
  activeTurnInput: '',
@@ -2778,6 +2795,8 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
2778
2795
  const cancelled = isTurnCancelledError(error);
2779
2796
  if (exitForAuthenticationError(error))
2780
2797
  return;
2798
+ const failedTurnAttachments = activeTurnImageAttachments;
2799
+ activeTurnImageAttachments = [];
2781
2800
  store.update((current) => ({
2782
2801
  ...current,
2783
2802
  activeTurnInput: '',
@@ -2786,7 +2805,7 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
2786
2805
  busyPausedAt: null,
2787
2806
  busySince: null,
2788
2807
  commandLog: [],
2789
- imageAttachments: [],
2808
+ imageAttachments: failedTurnAttachments,
2790
2809
  status: cancelled ? 'Ready' : 'Turn failed',
2791
2810
  thinkingTitle: '',
2792
2811
  thinkingNotes: [],
@@ -2951,11 +2970,12 @@ export async function runClientInteractive({ appendPromptHistory, authConfig, de
2951
2970
  };
2952
2971
  const shellInputHandlers = {
2953
2972
  getApprovalScrollLimit: () => {
2954
- const contentWidth = Math.max(20, Math.floor(terminalCols * 0.95) - 2);
2973
+ const contentWidth = frameContentWidth(terminalCols);
2955
2974
  return approvalScrollLimit(store.getState().approvalPrompt, contentWidth, terminalRows);
2956
2975
  },
2976
+ getComposerInputWidth: () => composerInputWidth(terminalCols, store.getState()),
2957
2977
  getTranscriptScrollLimit: () => {
2958
- const contentWidth = Math.max(20, Math.floor(terminalCols * 0.95) - 2);
2978
+ const contentWidth = frameContentWidth(terminalCols);
2959
2979
  const blocks = store.getState().transcript.map((entry) => renderTranscriptEntryLines(entry, contentWidth));
2960
2980
  return blocks.reduce((total, block, index) => total + block.length + (index > 0 ? 1 : 0), 0);
2961
2981
  },
@@ -5,6 +5,7 @@ import { renderFormattedBodyLines, renderPreformattedBodyLines, } from './markdo
5
5
  import { displayWidth, line, padToWidth, plainLine, sliceToWidth, span, wrapText, } from './text.js';
6
6
  import { isDarkTerminalBackground, mutedColor, mutedStyle } from './terminal-theme.js';
7
7
  import { buildUserInputOverlayLines, } from './user-input.js';
8
+ import { composerPromptLabel, frameContentWidth, splitComposerInput, } from './composer-layout.js';
8
9
  const WORKING_CLOCK_ICON = '◷';
9
10
  const BRAILLE_SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴'];
10
11
  const TODO_PANEL_MAX_ROWS = 12;
@@ -40,50 +41,47 @@ const MODEL_PICKER_BORDER_COLOR = 'cyan';
40
41
  const MODEL_PICKER_ACCENT_COLOR = 'cyan';
41
42
  const MODEL_PICKER_HIGHLIGHT_BG = 'ansi256(87)';
42
43
  const MODEL_PICKER_META_INDENT = ' ';
43
- function splitComposerInput(input, cursor, width) {
44
- const safeWidth = Math.max(1, width);
45
- const normalizedCursor = Math.min(Math.max(cursor, 0), input.length);
46
- const rows = [''];
47
- let cursorRow = 0;
48
- let cursorCol = 0;
49
- let capturedCursor = false;
50
- const captureCursor = () => {
51
- if (capturedCursor)
52
- return;
53
- const current = rows[rows.length - 1] ?? '';
54
- if (current.length >= safeWidth) {
55
- rows.push('');
56
- cursorRow = rows.length - 1;
57
- cursorCol = 0;
58
- }
59
- else {
60
- cursorRow = rows.length - 1;
61
- cursorCol = current.length;
44
+ const COMPOSER_MARKER_PATTERN = /\[Image #\d+\]|\[Pasted Text: [^\]\n]*\]/g;
45
+ function composerMarkerMask(text) {
46
+ const mask = new Array(text.length).fill(false);
47
+ for (const match of text.matchAll(COMPOSER_MARKER_PATTERN)) {
48
+ const start = match.index ?? 0;
49
+ for (let offset = start; offset < start + match[0].length; offset += 1) {
50
+ mask[offset] = true;
62
51
  }
63
- capturedCursor = true;
52
+ }
53
+ return mask;
54
+ }
55
+ function composerRowSpans(text, mask, cursorCol) {
56
+ const spans = [];
57
+ const push = (value, marker, cursor) => {
58
+ if (!value)
59
+ return;
60
+ spans.push(span(value, {
61
+ ...(marker ? { color: 'cyan' } : {}),
62
+ ...(cursor ? { inverse: true } : {}),
63
+ }));
64
64
  };
65
- for (let index = 0; index < input.length; index += 1) {
66
- const char = input[index] ?? '';
67
- if (char !== '\n' &&
68
- char !== '\r' &&
69
- (rows[rows.length - 1]?.length ?? 0) >= safeWidth) {
70
- rows.push('');
71
- }
72
- if (index === normalizedCursor) {
73
- captureCursor();
65
+ let cut = 0;
66
+ const flushTo = (end) => {
67
+ while (cut < end) {
68
+ const marker = mask[cut] ?? false;
69
+ let runEnd = cut + 1;
70
+ while (runEnd < end && (mask[runEnd] ?? false) === marker)
71
+ runEnd += 1;
72
+ push(text.slice(cut, runEnd), marker, false);
73
+ cut = runEnd;
74
74
  }
75
- if (char === '\r')
76
- continue;
77
- if (char === '\n') {
78
- rows.push('');
79
- continue;
80
- }
81
- rows[rows.length - 1] = `${rows[rows.length - 1] ?? ''}${char}`;
82
- }
83
- if (!capturedCursor) {
84
- captureCursor();
75
+ };
76
+ if (cursorCol === null) {
77
+ flushTo(text.length);
78
+ return spans;
85
79
  }
86
- return { cursorCol, cursorRow, rows };
80
+ flushTo(Math.min(cursorCol, text.length));
81
+ push(text[cursorCol] ?? ' ', mask[cursorCol] ?? false, true);
82
+ cut = Math.min(cursorCol + 1, text.length);
83
+ flushTo(text.length);
84
+ return spans;
87
85
  }
88
86
  function buildComposerInputLines(input, cursor, promptLabel, placeholder, width) {
89
87
  if (!input) {
@@ -95,20 +93,22 @@ function buildComposerInputLines(input, cursor, promptLabel, placeholder, width)
95
93
  const inputWidth = Math.max(1, width - labelWidth);
96
94
  const { cursorCol, cursorRow, rows } = splitComposerInput(input, cursor, inputWidth);
97
95
  const firstRow = Math.min(Math.max(cursorRow - COMPOSER_INPUT_MAX_ROWS + 1, 0), Math.max(rows.length - COMPOSER_INPUT_MAX_ROWS, 0));
96
+ const rowOffsets = [];
97
+ let consumed = 0;
98
+ for (const row of rows) {
99
+ rowOffsets.push(consumed);
100
+ consumed += row.length;
101
+ }
102
+ const mask = composerMarkerMask(rows.join(''));
98
103
  return rows
99
104
  .slice(firstRow, firstRow + COMPOSER_INPUT_MAX_ROWS)
100
105
  .map((text, index) => {
101
106
  const absoluteRow = firstRow + index;
107
+ const rowStart = rowOffsets[absoluteRow] ?? 0;
102
108
  const label = index === 0
103
109
  ? span(promptLabel, { color: 'cyan' })
104
110
  : span(' '.repeat(labelWidth));
105
- if (absoluteRow !== cursorRow) {
106
- return line(label, span(text));
107
- }
108
- const before = text.slice(0, cursorCol);
109
- const cursorChar = text[cursorCol] ?? ' ';
110
- const after = text.slice(cursorCol + 1);
111
- return line(label, span(before), span(cursorChar, { inverse: true }), span(after));
111
+ return line(label, ...composerRowSpans(text, mask.slice(rowStart, rowStart + text.length), absoluteRow === cursorRow ? cursorCol : null));
112
112
  });
113
113
  }
114
114
  function getEntryColor(kind) {
@@ -1190,7 +1190,7 @@ function countSectionLines(sections) {
1190
1190
  return sections.reduce((sum, section) => sum + section.lines.length, 0);
1191
1191
  }
1192
1192
  export function userInputViewportForFrame(state, cols, rows, spinnerFrame, elapsedSeconds, nowMs = 0) {
1193
- const contentWidth = Math.max(20, Math.floor(cols * 0.95) - 2);
1193
+ const contentWidth = frameContentWidth(cols);
1194
1194
  const liveRows = buildLiveLines(state, contentWidth, spinnerFrame, elapsedSeconds, nowMs).length;
1195
1195
  const overlayHeight = Math.max(0, rows - liveRows - composerFooterLines(state).length);
1196
1196
  return {
@@ -1208,7 +1208,7 @@ function sliceTranscriptLines(lines, maxLines, scrollOffset) {
1208
1208
  return lines.slice(start, start + maxLines);
1209
1209
  }
1210
1210
  export function buildTuiFrame(state, cols, rows, spinnerFrame, elapsedSeconds, nowMs = 0) {
1211
- const contentWidth = Math.max(20, Math.floor(cols * 0.95) - 2);
1211
+ const contentWidth = frameContentWidth(cols);
1212
1212
  const gutter = Math.max(Math.floor((cols - contentWidth) / 2), 0);
1213
1213
  const buildTranscriptLines = (wrapWidth) => {
1214
1214
  const blocks = state.transcript.map((entry) => cachedTranscriptEntryLines(entry, wrapWidth));
@@ -1240,7 +1240,7 @@ export function buildTuiFrame(state, cols, rows, spinnerFrame, elapsedSeconds, n
1240
1240
  : ' sends it to the agent now', { color: 'gray' }), span(' · ↑', { color: 'cyan', bold: true }), span(' edit', { color: 'gray' }), span(' · Esc', { color: 'cyan', bold: true }), span(' discard', { color: 'gray' })));
1241
1241
  }
1242
1242
  else {
1243
- const promptLabel = state.busy ? 'queue> ' : '❯ ';
1243
+ const promptLabel = composerPromptLabel(state);
1244
1244
  const placeholder = state.busy
1245
1245
  ? 'Type to queue the next message'
1246
1246
  : 'Type a request or /help';
@@ -0,0 +1,76 @@
1
+ export const COMPOSER_PROMPT_LABEL_IDLE = '❯ ';
2
+ export const COMPOSER_PROMPT_LABEL_BUSY = 'queue> ';
3
+ export function composerPromptLabel(state) {
4
+ return state.busy ? COMPOSER_PROMPT_LABEL_BUSY : COMPOSER_PROMPT_LABEL_IDLE;
5
+ }
6
+ export function frameContentWidth(cols) {
7
+ return Math.max(20, Math.floor(cols * 0.95) - 2);
8
+ }
9
+ export function composerInputWidth(cols, state) {
10
+ return Math.max(1, frameContentWidth(cols) - composerPromptLabel(state).length);
11
+ }
12
+ function buildComposerLayout(input, cursor, width) {
13
+ const safeWidth = Math.max(1, width);
14
+ const normalizedCursor = Math.min(Math.max(cursor, 0), input.length);
15
+ const rows = [{ cursorOffsets: [0], text: '' }];
16
+ let cursorRow = 0;
17
+ let cursorCol = 0;
18
+ let capturedCursor = false;
19
+ const currentRow = () => rows[rows.length - 1];
20
+ const addRow = (offset) => {
21
+ rows.push({ cursorOffsets: [offset], text: '' });
22
+ };
23
+ const captureCursor = () => {
24
+ if (capturedCursor)
25
+ return;
26
+ if (currentRow().text.length >= safeWidth) {
27
+ addRow(normalizedCursor);
28
+ }
29
+ cursorRow = rows.length - 1;
30
+ cursorCol = currentRow().text.length;
31
+ capturedCursor = true;
32
+ };
33
+ for (let index = 0; index < input.length; index += 1) {
34
+ const char = input[index] ?? '';
35
+ if (char !== '\n' &&
36
+ char !== '\r' &&
37
+ currentRow().text.length >= safeWidth) {
38
+ addRow(index);
39
+ }
40
+ if (index === normalizedCursor) {
41
+ captureCursor();
42
+ }
43
+ if (char === '\r') {
44
+ currentRow().cursorOffsets[currentRow().text.length] = index + 1;
45
+ continue;
46
+ }
47
+ if (char === '\n') {
48
+ currentRow().cursorOffsets[currentRow().text.length] =
49
+ input[index - 1] === '\r' ? index - 1 : index;
50
+ addRow(index + 1);
51
+ continue;
52
+ }
53
+ currentRow().text += char;
54
+ currentRow().cursorOffsets.push(index + 1);
55
+ }
56
+ if (!capturedCursor) {
57
+ captureCursor();
58
+ }
59
+ return { cursorCol, cursorRow, rows };
60
+ }
61
+ export function splitComposerInput(input, cursor, width) {
62
+ const layout = buildComposerLayout(input, cursor, width);
63
+ return {
64
+ cursorCol: layout.cursorCol,
65
+ cursorRow: layout.cursorRow,
66
+ rows: layout.rows.map((row) => row.text),
67
+ };
68
+ }
69
+ export function moveComposerCursorVertically(input, cursor, width, direction) {
70
+ const layout = buildComposerLayout(input, cursor, width);
71
+ const targetRow = layout.rows[layout.cursorRow + direction];
72
+ if (!targetRow)
73
+ return null;
74
+ const targetCol = Math.min(layout.cursorCol, targetRow.text.length);
75
+ return targetRow.cursorOffsets[targetCol] ?? null;
76
+ }
@@ -1,3 +1,4 @@
1
+ import { moveComposerCursorVertically } from './composer-layout.js';
1
2
  import { readClipboardImage, readClipboardText } from '../../core/clipboard.js';
2
3
  import { MAX_IMAGES_PER_MESSAGE, MAX_TOTAL_IMAGE_BYTES_PER_MESSAGE, approximateBase64DecodedBytes, totalAttachmentBytes, } from '../../core/image-limits.js';
3
4
  import { tryCacheAttachmentBytes } from '../../core/session-image-store.js';
@@ -479,9 +480,13 @@ export function handleShellKeyEvent(store, handlers, event) {
479
480
  });
480
481
  return;
481
482
  }
482
- if (state.busy)
483
+ const nextCursor = moveComposerCursorVertically(state.input, state.cursor, handlers.getComposerInputWidth?.() ?? Number.POSITIVE_INFINITY, -1);
484
+ if (nextCursor === null && state.busy)
483
485
  return;
484
486
  store.update((current) => {
487
+ if (nextCursor !== null) {
488
+ return { ...current, commandCursor: 0, cursor: nextCursor };
489
+ }
485
490
  const next = navigatePromptHistory(current, 'previous');
486
491
  prepareForComposerInputChange(current, next.input);
487
492
  return next;
@@ -489,9 +494,13 @@ export function handleShellKeyEvent(store, handlers, event) {
489
494
  return;
490
495
  }
491
496
  if (key.downArrow) {
492
- if (state.busy)
497
+ const nextCursor = moveComposerCursorVertically(state.input, state.cursor, handlers.getComposerInputWidth?.() ?? Number.POSITIVE_INFINITY, 1);
498
+ if (nextCursor === null && state.busy)
493
499
  return;
494
500
  store.update((current) => {
501
+ if (nextCursor !== null) {
502
+ return { ...current, commandCursor: 0, cursor: nextCursor };
503
+ }
495
504
  const next = navigatePromptHistory(current, 'next');
496
505
  prepareForComposerInputChange(current, next.input);
497
506
  return next;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thegitai/cli",
3
- "version": "1.0.0-preview.33",
3
+ "version": "1.0.0-preview.35",
4
4
  "description": "TheGitAI is an agentic AI coding tool for your terminal. It reads and searches your repository, writes and edits files, runs your tests, and verifies the change before handing it back.",
5
5
  "keywords": [
6
6
  "agentic-ai",
@@ -44,11 +44,11 @@
44
44
  "@lydell/node-pty-linux-x64": "1.1.0",
45
45
  "@lydell/node-pty-win32-arm64": "1.1.0",
46
46
  "@lydell/node-pty-win32-x64": "1.1.0",
47
- "@thegitai/tui-darwin-arm64": "1.0.0-preview.33",
48
- "@thegitai/tui-darwin-x64": "1.0.0-preview.33",
49
- "@thegitai/tui-linux-arm64": "1.0.0-preview.33",
50
- "@thegitai/tui-linux-x64": "1.0.0-preview.33",
51
- "@thegitai/tui-win32-x64": "1.0.0-preview.33",
47
+ "@thegitai/tui-darwin-arm64": "1.0.0-preview.35",
48
+ "@thegitai/tui-darwin-x64": "1.0.0-preview.35",
49
+ "@thegitai/tui-linux-arm64": "1.0.0-preview.35",
50
+ "@thegitai/tui-linux-x64": "1.0.0-preview.35",
51
+ "@thegitai/tui-win32-x64": "1.0.0-preview.35",
52
52
  "@vscode/ripgrep": "1.18.0"
53
53
  },
54
54
  "repository": {