@thegitai/cli 1.0.0-preview.27 → 1.0.0-preview.29

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # TheGitAI — AI coding agent for your terminal
2
2
 
3
- TheGitAI is an AI coding agent for your terminal. It indexes your repository,
3
+ TheGitAI is an AI coding agent for your terminal. It reads and searches your repository,
4
4
  writes and edits files, runs commands, and builds features with you.
5
5
 
6
6
  Talk to your repo in plain English. TheGitAI can keep long-running processes
@@ -37,7 +37,7 @@ also be listed while signed out or offline.
37
37
  Signing in opens your browser. The same screen also prints a URL you can open on
38
38
  any other device and a box for an authorization code, so SSH and headless
39
39
  machines need no separate command: open the URL wherever you have a browser,
40
- choose "Not on this machine?" on that page, and paste the code it shows.
40
+ choose "On another computer" on that page, and paste the code it shows.
41
41
 
42
42
  CLI login tokens use a rolling 48-hour inactivity timeout. If one expires during
43
43
  any server request, the CLI removes the expired credential and signs you in
package/dist/bin/ai.js CHANGED
@@ -6,7 +6,6 @@ import { isSignInCancelled } from '../src/api/browser-login.js';
6
6
  import { runSignIn } from '../src/signin.js';
7
7
  import { STARTUP_RETRY_BUDGET, authenticationErrorMessage, isAuthenticationError, isTransientNetworkError, } from '../src/api/http.js';
8
8
  import { formatCliHelpText } from '../src/help-text.js';
9
- import { createIndex } from '../src/project-index.js';
10
9
  import { createSession } from '../src/session.js';
11
10
  import { applySessionSnapshot, listSessionMetadata, loadSessionSnapshot, saveSessionState, sessionHasUserMessage, } from '../src/session-store.js';
12
11
  import { runClientInteractive } from '../src/ui/repl.js';
@@ -238,25 +237,11 @@ export async function main() {
238
237
  if (sourceSnapshot) {
239
238
  applySessionSnapshot(session, sourceSnapshot);
240
239
  }
241
- const projectIndex = createIndex({
242
- rootDir,
243
- onStatus: (message) => {
244
- if (message.trim()) {
245
- console.log(chalk.dim(` ${message}`));
246
- }
247
- },
248
- onContextLog: (message) => {
249
- if (message.trim()) {
250
- console.log(chalk.cyan(` ${message}`));
251
- }
252
- },
253
- });
254
240
  const initialPrompt = prompt || undefined;
255
241
  const outcome = await runClientInteractive({
256
242
  appendPromptHistory: (value) => appendPromptHistory(value, session.env),
257
243
  authConfig,
258
244
  debugUi: whoami.debugUi,
259
- projectIndex,
260
245
  serverModels,
261
246
  serverSessionClient,
262
247
  session,
@@ -1,14 +1,9 @@
1
1
  export const AGENT_MODES = ['default', 'auto-accept', 'plan'];
2
2
  const PLAN_MODE_TOOL_NAMES = new Set([
3
- 'search_code',
4
3
  'list_files',
5
4
  'list_directories',
6
5
  'read_file',
7
6
  'grep_code',
8
- 'find_symbol',
9
- 'list_symbols',
10
- 'hover_symbol',
11
- 'signature_help',
12
7
  'read_document',
13
8
  'analyze_image',
14
9
  'run_command',
@@ -6,7 +6,7 @@ import os from 'node:os';
6
6
  import { openUrl } from '../core/open-url.js';
7
7
  import { ServerApiError, createTraceContext, failureCode, failureMessage, normalizeServerUrl, readJsonResponse, } from './http.js';
8
8
  import { DEFAULT_THEGITAI_HOST } from './default-host.js';
9
- const DEFAULT_TIMEOUT_MS = 15 * 60 * 1000;
9
+ const DEFAULT_TIMEOUT_MS = 10 * 60 * 1000;
10
10
  function shutDownServer(server) {
11
11
  server.closeAllConnections?.();
12
12
  server.close();
@@ -179,7 +179,7 @@ export async function loginViaBrowser(options) {
179
179
  const codePromise = new Promise((resolve, reject) => {
180
180
  timer = setTimeout(() => {
181
181
  shutDownServer(server);
182
- reject(new Error('Timed out waiting for the login to complete.'));
182
+ reject(new Error('Sign-in timed out. Authorization codes last 10 minutes — run `ai` again to start over.'));
183
183
  }, options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
184
184
  server.on('request', (req, res) => {
185
185
  const requestUrl = new URL(req.url ?? '/', 'http://127.0.0.1');
@@ -299,7 +299,7 @@ function exitServerTurnId(session) {
299
299
  turnIdOverrides.delete(session);
300
300
  }
301
301
  }
302
- async function executeAndPostToolResult({ config, projectIndex, session, event, input, fetchImpl, signal, traceId, }) {
302
+ async function executeAndPostToolResult({ config, session, event, input, fetchImpl, signal, traceId, }) {
303
303
  const turnId = String(event?.turnId ?? '').trim();
304
304
  if (!turnId || !event?.call?.id || !event.call.name) {
305
305
  throw new Error('Server emitted an invalid tool-call event.');
@@ -323,7 +323,7 @@ async function executeAndPostToolResult({ config, projectIndex, session, event,
323
323
  suggestedFilename: event.generatedImage.suggestedFilename ||
324
324
  String(call.args?.filename ?? call.args?.file_name ?? ''),
325
325
  })
326
- : await executeLocalToolCall({ projectIndex }, session, call);
326
+ : await executeLocalToolCall(session, call);
327
327
  preserveCancelledTurnToolResult(session, input, { ...event, call }, rawResult);
328
328
  if (signal?.aborted) {
329
329
  throw new TurnCancelledError();
@@ -344,7 +344,7 @@ async function executeAndPostToolResult({ config, projectIndex, session, event,
344
344
  }
345
345
  }
346
346
  }
347
- async function consumeTurnStream({ response, config, projectIndex, session, input, fetchImpl, signal, traceId, onTurnStart, onInterjectionDelivered, }) {
347
+ async function consumeTurnStream({ response, config, session, input, fetchImpl, signal, traceId, onTurnStart, onInterjectionDelivered, }) {
348
348
  if (!response.body) {
349
349
  throw new Error('Server returned an empty chat stream.');
350
350
  }
@@ -417,7 +417,6 @@ async function consumeTurnStream({ response, config, projectIndex, session, inpu
417
417
  if (data?.parallelSafe === true) {
418
418
  pendingParallelTools.push(executeAndPostToolResult({
419
419
  config,
420
- projectIndex,
421
420
  session,
422
421
  event: data,
423
422
  input,
@@ -430,7 +429,6 @@ async function consumeTurnStream({ response, config, projectIndex, session, inpu
430
429
  await drainParallelTools();
431
430
  await executeAndPostToolResult({
432
431
  config,
433
- projectIndex,
434
432
  session,
435
433
  event: data,
436
434
  input,
@@ -529,7 +527,7 @@ async function consumeTurnStream({ response, config, projectIndex, session, inpu
529
527
  }
530
528
  return finalResult.current;
531
529
  }
532
- export async function sendServerUserMessage({ config, projectIndex, session, input, imageAttachments = [], fetchImpl = globalThis.fetch, signal, onTurnStart, onInterjectionDelivered, }) {
530
+ export async function sendServerUserMessage({ config, session, input, imageAttachments = [], fetchImpl = globalThis.fetch, signal, onTurnStart, onInterjectionDelivered, }) {
533
531
  const autoAttach = autoAttachImages(input, session.rootDir, imageAttachments);
534
532
  const requestImageAttachments = autoAttach.attachments.length > 0
535
533
  ? [...imageAttachments, ...autoAttach.attachments]
@@ -580,7 +578,6 @@ export async function sendServerUserMessage({ config, projectIndex, session, inp
580
578
  const result = await consumeTurnStream({
581
579
  response,
582
580
  config,
583
- projectIndex,
584
581
  session,
585
582
  input: requestInputBase,
586
583
  fetchImpl,
@@ -14,7 +14,7 @@ const PASTE_SHORTCUT = pasteShortcutForPlatform();
14
14
  const HELP_MARKDOWN = [
15
15
  '# TheGitAI',
16
16
  '',
17
- 'Interactive terminal coding agent. Local repo indexing, file edits, and',
17
+ 'Interactive terminal coding agent. Local repo search, file edits, and',
18
18
  'shell commands run on your machine. Model inference and server-executed',
19
19
  'tools run on the server.',
20
20
  '',
@@ -132,7 +132,7 @@ const HELP_MARKDOWN = [
132
132
  ' ends.',
133
133
  '- File and shell operations are confined to the target repo root.',
134
134
  '- Sensitive directories (`.git`, `node_modules`, build output) are',
135
- ' never indexed.',
135
+ ' excluded from search and listing.',
136
136
  '',
137
137
  '## Troubleshooting',
138
138
  '',
@@ -142,8 +142,8 @@ const HELP_MARKDOWN = [
142
142
  '- Signed in with the wrong account → `/logout` (or `ai logout`), then run',
143
143
  ' `ai` and sign in as the account you intended to use.',
144
144
  '- The browser did not open, or opened on the wrong machine → open the URL',
145
- " printed on the sign-in screen anywhere you like, choose \"Not on this",
146
- ' machine?" on that page, and paste the code back into the terminal.',
145
+ ' printed on the sign-in screen anywhere you like, choose "On another',
146
+ ' computer" on that page, and paste the code back into the terminal.',
147
147
  '- A local session was used with a different sign-in → sign in with the',
148
148
  ' account you used for that session or start a new session.',
149
149
  '- For anything else, re-run the command and report the printed error',
@@ -4,7 +4,6 @@ import path from 'node:path';
4
4
  import { ARTIFACT_IGNORE_DIRS, normalizeProjectRelativePath, shouldIgnoreArtifactPath, } from './artifact-policy.js';
5
5
  import { hashBytes, readFileEditSnapshot, storedContentBuffer, } from './edit-journal.js';
6
6
  import { deleteProjectFile, resolveProjectPath, writeProjectFile, writeProjectFileBuffer, } from './patcher.js';
7
- import { removeIndexFile, upsertIndexFile } from './project-index.js';
8
7
  const MAX_CHECKPOINTS = 20;
9
8
  const MAX_SESSION_EDITS = 500;
10
9
  const MAX_READ_RECORDS = 200;
@@ -672,7 +671,6 @@ export async function restoreCheckpointFiles(args) {
672
671
  const restored = [];
673
672
  const applied = [];
674
673
  let changed = false;
675
- const syncPolicy = args.projectIndex.initialized;
676
674
  for (const snapshot of targets) {
677
675
  const before = readFileEditSnapshot(args.rootDir, snapshot.filePath);
678
676
  try {
@@ -680,15 +678,11 @@ export async function restoreCheckpointFiles(args) {
680
678
  const result = writeStoredProjectFile(args.rootDir, snapshot.filePath, snapshot.content ?? '', snapshot.contentEncoding);
681
679
  if (result.changed)
682
680
  changed = true;
683
- if (syncPolicy)
684
- await upsertIndexFile(args.projectIndex, snapshot.filePath);
685
681
  }
686
682
  else {
687
683
  const result = deleteProjectFile(args.rootDir, snapshot.filePath);
688
684
  if (result.deleted)
689
685
  changed = true;
690
- if (syncPolicy)
691
- await removeIndexFile(args.projectIndex, snapshot.filePath);
692
686
  }
693
687
  const after = readFileEditSnapshot(args.rootDir, snapshot.filePath);
694
688
  applied.push({ snapshot, before, after });
@@ -710,15 +704,9 @@ export async function restoreCheckpointFiles(args) {
710
704
  throw new Error('previous file content is unavailable');
711
705
  }
712
706
  writeStoredProjectFile(args.rootDir, item.snapshot.filePath, item.before.content, item.before.contentEncoding);
713
- if (syncPolicy) {
714
- await upsertIndexFile(args.projectIndex, item.snapshot.filePath);
715
- }
716
707
  }
717
708
  else {
718
709
  deleteProjectFile(args.rootDir, item.snapshot.filePath);
719
- if (syncPolicy) {
720
- await removeIndexFile(args.projectIndex, item.snapshot.filePath);
721
- }
722
710
  }
723
711
  rolledBack.push({ filePath: item.snapshot.filePath });
724
712
  }
@@ -21,8 +21,8 @@ export function formatSignInScreen({ url }) {
21
21
  '',
22
22
  ` ${hyperlink(url, chalk.cyan('→ Click here to authenticate'))}`,
23
23
  '',
24
- chalk.dim(" Signing in on a different machine? Choose \"Not on this machine?\""),
25
- chalk.dim(' on that page, authorize, and paste the code it gives you below.'),
24
+ ' If this terminal is not on the computer where that page opened, choose',
25
+ ` ${chalk.bold('"On another computer"')} there and paste the code it gives you below.`,
26
26
  '',
27
27
  ].join('\n');
28
28
  }
@@ -46,7 +46,9 @@ export async function runSignIn({ env = process.env, login = loginViaBrowser, wr
46
46
  }
47
47
  },
48
48
  promptCode: promptForCode,
49
- onPasteRejected: (message) => log(chalk.red(` ✖ ${message}`) + chalk.dim(' Try pasting it again.')),
49
+ onPasteRejected: (message) => log(` ${chalk.red('')} ${message}\n` +
50
+ ' Codes last 10 minutes. If that page has been open a while, run `ai`\n' +
51
+ ' again for a fresh one.'),
50
52
  });
51
53
  write(result, env);
52
54
  log('');
@@ -4,7 +4,6 @@ import { clearEditFailure, collectCommandMutations, captureMutationBaseline, ens
4
4
  import { buildAgentModeToolBlockedResult, } from './agent-mode.js';
5
5
  import { classifyProjectPath } from './patcher.js';
6
6
  import { dispatchTool } from './tools/index.js';
7
- import { syncIndexFromDisk } from './project-index.js';
8
7
  import { PATH_REPAIRING_EDIT_TOOLS, repairFilePath } from './tools/path-suggest.js';
9
8
  import { invalidateShellDiagnosticsCache, runShellDiagnostics, } from './tools/shell-diagnostics.js';
10
9
  import { extractTodosArg } from './todo-list.js';
@@ -69,7 +68,7 @@ function editToolWritesSeparateOutput(call) {
69
68
  const output = args.outputPath ?? args.output_path;
70
69
  return typeof output === 'string' && output.trim().length > 0;
71
70
  }
72
- async function collectTrackedCommandMutations({ session, projectIndex, result, tracker, toolName, toolCallId, turnId, }) {
71
+ async function collectTrackedCommandMutations({ session, result, tracker, toolName, toolCallId, turnId, }) {
73
72
  const checkpoint = ensureActiveCheckpoint(session.clientState.safety, turnId);
74
73
  const records = collectCommandMutations({
75
74
  state: session.clientState.safety,
@@ -84,40 +83,11 @@ async function collectTrackedCommandMutations({ session, projectIndex, result, t
84
83
  return;
85
84
  invalidateShellDiagnosticsCache(session.rootDir);
86
85
  rememberCheckpointFiles(session.clientState.safety, session.rootDir, records.map((record) => record.filePath), turnId);
87
- const priorSync = result.repoSync;
88
- if (!(priorSync && (priorSync.added || priorSync.modified || priorSync.removed))) {
89
- const mutationCounts = {
90
- added: records.filter((record) => record.operation === 'create').length,
91
- modified: records.filter((record) => record.operation === 'update').length,
92
- removed: records.filter((record) => record.operation === 'delete').length,
93
- indexedChunks: 0,
94
- retrievalTokensUsed: 0,
95
- };
96
- if (priorSync?.error) {
97
- result.repoSync = {
98
- ...mutationCounts,
99
- indexSyncError: priorSync.error,
100
- skipped: true,
101
- reason: 'local index sync failed after command execution',
102
- };
103
- }
104
- else {
105
- try {
106
- const repoSync = await syncIndexFromDisk(projectIndex);
107
- result.repoSync = {
108
- ...repoSync,
109
- added: Math.max(repoSync.added, mutationCounts.added),
110
- modified: Math.max(repoSync.modified, mutationCounts.modified),
111
- removed: Math.max(repoSync.removed, mutationCounts.removed),
112
- };
113
- }
114
- catch (error) {
115
- const indexSyncError = error instanceof Error ? error.message : String(error);
116
- result.repoSync = { ...mutationCounts, indexSyncError };
117
- session.onStatus(`Repository changes were recorded, but local index sync failed: ${indexSyncError}`);
118
- }
119
- }
120
- }
86
+ result.repoSync = {
87
+ added: records.filter((record) => record.operation === 'create').length,
88
+ modified: records.filter((record) => record.operation === 'update').length,
89
+ removed: records.filter((record) => record.operation === 'delete').length,
90
+ };
121
91
  result.sessionEdits = records.map((record) => ({
122
92
  id: record.id,
123
93
  filePath: record.filePath,
@@ -127,7 +97,7 @@ async function collectTrackedCommandMutations({ session, projectIndex, result, t
127
97
  }));
128
98
  result.diagnostics = runShellDiagnostics(session.rootDir);
129
99
  }
130
- export async function collectBackgroundJobUiKillMutations({ session, projectIndex, jobId, result, }) {
100
+ export async function collectBackgroundJobUiKillMutations({ session, jobId, result, }) {
131
101
  const normalizedJobId = String(jobId ?? result.snapshot?.id ?? '').trim();
132
102
  if (!normalizedJobId || !result.ok)
133
103
  return;
@@ -137,7 +107,6 @@ export async function collectBackgroundJobUiKillMutations({ session, projectInde
137
107
  const mutationResult = result;
138
108
  await collectTrackedCommandMutations({
139
109
  session,
140
- projectIndex,
141
110
  result: mutationResult,
142
111
  tracker: tracked.tracker,
143
112
  toolName: tracked.toolName,
@@ -151,7 +120,7 @@ export async function collectBackgroundJobUiKillMutations({ session, projectInde
151
120
  backgroundCommandTrackers.delete(normalizedJobId);
152
121
  }
153
122
  }
154
- export async function collectBackgroundJobUiOutputMutations({ session, projectIndex, jobId, }) {
123
+ export async function collectBackgroundJobUiOutputMutations({ session, jobId, }) {
155
124
  const normalizedJobId = String(jobId ?? '').trim();
156
125
  if (!normalizedJobId)
157
126
  return;
@@ -165,7 +134,6 @@ export async function collectBackgroundJobUiOutputMutations({ session, projectIn
165
134
  return;
166
135
  await collectTrackedCommandMutations({
167
136
  session,
168
- projectIndex,
169
137
  result: {},
170
138
  tracker: tracked.tracker,
171
139
  toolName: tracked.toolName,
@@ -244,7 +212,7 @@ function recordAssistantEdit(session, call, result, before) {
244
212
  });
245
213
  clearEditFailure(session.clientState.safety, filePath);
246
214
  }
247
- export async function executeLocalToolCall(toolContext, session, call) {
215
+ export async function executeLocalToolCall(session, call) {
248
216
  session.onStatus(formatToolCallForStatus(call));
249
217
  try {
250
218
  const agentModeBlocked = buildAgentModeToolBlockedResult(session.agentMode, call);
@@ -275,7 +243,6 @@ export async function executeLocalToolCall(toolContext, session, call) {
275
243
  const context = {
276
244
  rootDir: session.rootDir,
277
245
  sessionId: session.sessionId,
278
- projectIndex: toolContext.projectIndex,
279
246
  autoYes: session.autoYes,
280
247
  grants: session.grants,
281
248
  requestPermission: session.requestPermission,
@@ -299,7 +266,6 @@ export async function executeLocalToolCall(toolContext, session, call) {
299
266
  if (result && typeof result === 'object' && commandTracker) {
300
267
  await collectTrackedCommandMutations({
301
268
  session,
302
- projectIndex: toolContext.projectIndex,
303
269
  result,
304
270
  tracker: commandTracker,
305
271
  toolName: call.name,
@@ -326,7 +292,6 @@ export async function executeLocalToolCall(toolContext, session, call) {
326
292
  if (tracked) {
327
293
  await collectTrackedCommandMutations({
328
294
  session,
329
- projectIndex: toolContext.projectIndex,
330
295
  result,
331
296
  tracker: tracked.tracker,
332
297
  toolName: tracked.toolName,
@@ -1,11 +1,10 @@
1
1
  import chalk from '../colors.js';
2
2
  import { classifyProjectPath, deleteProjectFile } from '../patcher.js';
3
3
  import { isTuiMode } from '../runtime-mode.js';
4
- import { removeIndexFile } from '../project-index.js';
5
4
  import { invalidateShellDiagnosticsCache, runShellDiagnostics, } from './shell-diagnostics.js';
6
5
  import { ensurePermission } from '../permissions.js';
7
6
  export async function deleteFile(context, args) {
8
- const { rootDir, projectIndex } = context;
7
+ const { rootDir } = context;
9
8
  const filePath = String(args.filePath ?? '').trim();
10
9
  if (!filePath) {
11
10
  return { ok: false, error: 'filePath is required' };
@@ -41,7 +40,6 @@ export async function deleteFile(context, args) {
41
40
  const result = deleteProjectFile(rootDir, filePath);
42
41
  if (result.deleted) {
43
42
  if (!scratchPath) {
44
- await removeIndexFile(projectIndex, filePath);
45
43
  invalidateShellDiagnosticsCache(rootDir, filePath);
46
44
  }
47
45
  if (!isTuiMode())
@@ -1,14 +1,11 @@
1
1
  import { shellJobOutput } from './shell-job-output.js';
2
2
  import { deleteFile } from './delete-file.js';
3
- import { findSymbol } from './find-symbol.js';
4
3
  import { getDiagnostics } from './get-diagnostics.js';
5
4
  import { grepCode } from './grep-code.js';
6
- import { hoverSymbol } from './hover-symbol.js';
7
5
  import { listDirectories } from './list-directories.js';
8
6
  import { listCheckpoints } from './list-checkpoints.js';
9
7
  import { listFiles } from './list-files.js';
10
8
  import { listSessionEdits } from './list-session-edits.js';
11
- import { listSymbols } from './list-symbols.js';
12
9
  import { patchFile } from './patch-file.js';
13
10
  import { readDocument } from './read-document.js';
14
11
  import { readFile } from './read-file.js';
@@ -16,8 +13,6 @@ import { replaceDocumentText } from './replace-document-text.js';
16
13
  import { runShellCommand } from './run-command.js';
17
14
  import { runNodeScript } from './run-node-script.js';
18
15
  import { restoreFilesToCheckpoint, restoreToCheckpoint, } from './restore-checkpoint.js';
19
- import { searchCode } from './search-code.js';
20
- import { getSignatureHelp } from './signature-help.js';
21
16
  import { shellJobKill } from './shell-job-kill.js';
22
17
  import { strReplace } from './str-replace.js';
23
18
  import { undoEdit } from './undo-edit.js';
@@ -26,17 +21,12 @@ import { readImageFile } from './read-image-file.js';
26
21
  import { saveGeneratedImage } from './save-generated-image.js';
27
22
  import { writeFile } from './write-file.js';
28
23
  export const TOOL_MAP = {
29
- search_code: (context, args) => searchCode(context.projectIndex, args),
30
24
  list_files: (context, args) => listFiles(context, args),
31
25
  list_directories: (context, args) => listDirectories(context, args),
32
26
  read_file: (context, args) => readFile(context, args),
33
27
  read_document: (context, args) => readDocument(context.rootDir, args, context.env),
34
28
  replace_document_text: replaceDocumentText,
35
29
  grep_code: (context, args) => grepCode(context.rootDir, args),
36
- find_symbol: (context, args) => findSymbol(context, args),
37
- list_symbols: (context, args) => listSymbols(context, args),
38
- hover_symbol: (context, args) => hoverSymbol(context, args),
39
- signature_help: (context, args) => getSignatureHelp(context, args),
40
30
  get_diagnostics: (context, args) => getDiagnostics(context, args),
41
31
  list_checkpoints: (context) => listCheckpoints(context),
42
32
  list_session_edits: (context) => listSessionEdits(context),
@@ -2,7 +2,6 @@ import chalk from '../colors.js';
2
2
  import path from 'node:path';
3
3
  import { normalizeProjectRelativePath } from '../artifact-policy.js';
4
4
  import { applyUnifiedPatch, classifyProjectPath, readProjectFile, renderDiffPreview, writeProjectFile, } from '../patcher.js';
5
- import { upsertIndexFile } from '../project-index.js';
6
5
  import { repairFilePath } from './path-suggest.js';
7
6
  import { isTuiMode } from '../runtime-mode.js';
8
7
  import { getCurrentFileHash, resolveRedactionTokens } from '../session-safety.js';
@@ -10,7 +9,7 @@ import { invalidateShellDiagnosticsCache, runShellDiagnostics, } from './shell-d
10
9
  import { ensurePermission } from '../permissions.js';
11
10
  const DOCUMENT_EXTENSIONS = new Set(['.pdf', '.xlsx', '.docx']);
12
11
  export async function patchFile(context, args) {
13
- const { rootDir, projectIndex } = context;
12
+ const { rootDir } = context;
14
13
  const filePath = repairFilePath(rootDir, String(args.filePath ?? '').trim());
15
14
  let patch = typeof args.patch === 'string' ? args.patch : '';
16
15
  if (!filePath) {
@@ -90,13 +89,6 @@ export async function patchFile(context, args) {
90
89
  }
91
90
  }
92
91
  const { changed } = writeProjectFile(rootDir, filePath, patchedContent);
93
- let indexedChunks = 0;
94
- let retrievalTokensUsed = 0;
95
- if (changed && !scratchPath) {
96
- const indexResult = await upsertIndexFile(projectIndex, filePath);
97
- indexedChunks = indexResult.indexedChunks;
98
- retrievalTokensUsed = indexResult.retrievalTokensUsed ?? 0;
99
- }
100
92
  let diagnostics;
101
93
  if (!scratchPath) {
102
94
  invalidateShellDiagnosticsCache(rootDir, filePath);
@@ -115,8 +107,6 @@ export async function patchFile(context, args) {
115
107
  changed,
116
108
  operation: 'patch',
117
109
  ...(scratchPath ? { scratch: true } : {}),
118
- indexedChunks,
119
- retrievalTokensUsed,
120
110
  bytesWritten: Buffer.byteLength(patchedContent, 'utf-8'),
121
111
  diagnostics,
122
112
  };
@@ -54,7 +54,6 @@ export async function restoreToCheckpoint(context, args) {
54
54
  const result = await restoreCheckpointFiles({
55
55
  state: context.safety,
56
56
  rootDir: context.rootDir,
57
- projectIndex: context.projectIndex,
58
57
  checkpointId,
59
58
  filePaths,
60
59
  currentTurnId: context.currentTurnId ?? null,
@@ -1,7 +1,6 @@
1
1
  import chalk from '../colors.js';
2
2
  import { startBackgroundJob } from '../background-jobs.js';
3
3
  import { getBlockedCommandReason, runCommand, } from '../executor.js';
4
- import { syncIndexFromDisk } from '../project-index.js';
5
4
  import { ensurePermission } from '../permissions.js';
6
5
  import { isTuiMode } from '../runtime-mode.js';
7
6
  import { redactConnectionStringCredentials } from '../secret-preview.js';
@@ -9,7 +8,7 @@ import { buildNestedGitHint } from '../session-safety.js';
9
8
  import { buildDeferredShellDiagnostics, invalidateShellDiagnosticsCache, } from './shell-diagnostics.js';
10
9
  const MAX_OUTPUT_CHARS = 4000;
11
10
  export async function runShellCommand(context, args) {
12
- const { rootDir, projectIndex, requestSudoPassword, onStatus, } = context;
11
+ const { rootDir, requestSudoPassword, onStatus, } = context;
13
12
  const command = String(args.command ?? '').trim();
14
13
  if (!command) {
15
14
  return { ok: false, error: 'command is required' };
@@ -52,12 +51,8 @@ export async function runShellCommand(context, args) {
52
51
  requestSudoPassword,
53
52
  timeout: typeof args.timeout_ms === 'number' && args.timeout_ms > 0 ? args.timeout_ms : undefined,
54
53
  });
55
- const repoSync = await syncRepoIndex(projectIndex, onStatus);
56
54
  invalidateShellDiagnosticsCache(rootDir);
57
55
  const diagnostics = buildDeferredShellDiagnostics('run_command');
58
- if (repoSync.added || repoSync.modified || repoSync.removed) {
59
- onStatus(`Synced repo state after command (${repoSync.added} added, ${repoSync.modified} modified, ${repoSync.removed} removed).`);
60
- }
61
56
  const output = typeof result.output === 'string'
62
57
  ? boundCommandOutput(redactConnectionStringCredentials(result.output))
63
58
  : result.output;
@@ -67,8 +62,6 @@ export async function runShellCommand(context, args) {
67
62
  exitCode: result.exitCode,
68
63
  timedOut: result.timedOut,
69
64
  output,
70
- repoSync,
71
- retrievalTokensUsed: repoSync.retrievalTokensUsed,
72
65
  diagnostics,
73
66
  repoHint,
74
67
  };
@@ -82,36 +75,8 @@ export function boundCommandOutput(output) {
82
75
  `\n\n... (${output.length - headSize - tailSize} chars truncated) ...\n\n` +
83
76
  output.slice(-tailSize));
84
77
  }
85
- async function syncRepoIndex(projectIndex, onStatus) {
86
- if (!projectIndex.initialized) {
87
- return {
88
- added: 0,
89
- modified: 0,
90
- removed: 0,
91
- indexedChunks: 0,
92
- retrievalTokensUsed: 0,
93
- };
94
- }
95
- try {
96
- return await syncIndexFromDisk(projectIndex);
97
- }
98
- catch (error) {
99
- const message = error instanceof Error ? error.message : String(error);
100
- onStatus(`Command completed, but local index sync failed: ${message}`);
101
- return {
102
- added: 0,
103
- modified: 0,
104
- removed: 0,
105
- indexedChunks: 0,
106
- retrievalTokensUsed: 0,
107
- skipped: true,
108
- reason: 'local index sync failed after command execution',
109
- error: message,
110
- };
111
- }
112
- }
113
78
  async function runBackgroundCommand(context, command, timeoutMs, repoHint) {
114
- const { rootDir, projectIndex, onStatus } = context;
79
+ const { rootDir, onStatus } = context;
115
80
  const started = await startBackgroundJob(command, rootDir, {
116
81
  startupWaitMs: typeof timeoutMs === 'number' && timeoutMs > 0 ? timeoutMs : undefined,
117
82
  sessionId: context.sessionId,
@@ -128,11 +93,7 @@ async function runBackgroundCommand(context, command, timeoutMs, repoHint) {
128
93
  };
129
94
  }
130
95
  const snapshot = started.snapshot;
131
- const repoSync = await syncRepoIndex(projectIndex, onStatus);
132
96
  invalidateShellDiagnosticsCache(rootDir);
133
- if (repoSync.added || repoSync.modified || repoSync.removed) {
134
- onStatus(`Synced repo state after command (${repoSync.added} added, ${repoSync.modified} modified, ${repoSync.removed} removed).`);
135
- }
136
97
  const output = boundCommandOutput(redactConnectionStringCredentials(started.startupOutput ?? '').trim());
137
98
  if (snapshot.status === 'running') {
138
99
  return {
@@ -144,8 +105,6 @@ async function runBackgroundCommand(context, command, timeoutMs, repoHint) {
144
105
  pid: snapshot.pid,
145
106
  output,
146
107
  note: `Background job ${snapshot.id} is running. Use shell_job_output to poll status and new output, and shell_job_kill to stop it.`,
147
- repoSync,
148
- retrievalTokensUsed: repoSync.retrievalTokensUsed,
149
108
  repoHint,
150
109
  };
151
110
  }
@@ -158,8 +117,6 @@ async function runBackgroundCommand(context, command, timeoutMs, repoHint) {
158
117
  exitCode: snapshot.exitCode,
159
118
  output,
160
119
  note: `Background job ${snapshot.id} finished during the startup window.`,
161
- repoSync,
162
- retrievalTokensUsed: repoSync.retrievalTokensUsed,
163
120
  repoHint,
164
121
  };
165
122
  }