@thegitai/cli 1.0.0-beta.9 → 1.0.0-preview.1

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 (55) hide show
  1. package/README.md +36 -2
  2. package/dist/bin/ai.js +134 -18
  3. package/dist/parsers/NOTICE +18 -0
  4. package/dist/src/agent-mode.js +5 -0
  5. package/dist/src/api/auth.js +3 -3
  6. package/dist/src/api/browser-login.js +0 -16
  7. package/dist/src/api/chat.js +57 -11
  8. package/dist/src/api/http.js +49 -1
  9. package/dist/src/api/models.js +26 -20
  10. package/dist/src/artifact-policy.js +3 -0
  11. package/dist/src/background-jobs.js +410 -0
  12. package/dist/src/cli-args.js +0 -5
  13. package/dist/src/client-environment.js +2 -0
  14. package/dist/src/colors.js +50 -0
  15. package/dist/src/core/clipboard.js +19 -0
  16. package/dist/src/core/image-path-extractor.js +144 -0
  17. package/dist/src/executor.js +48 -12
  18. package/dist/src/help-text.js +11 -6
  19. package/dist/src/markdown-renderer.js +1 -1
  20. package/dist/src/patcher.js +1 -3
  21. package/dist/src/scanner.js +50 -12
  22. package/dist/src/scratch-dir.js +57 -0
  23. package/dist/src/secret-preview.js +0 -10
  24. package/dist/src/session-safety.js +0 -19
  25. package/dist/src/session-store.js +0 -1
  26. package/dist/src/todo-list.js +106 -0
  27. package/dist/src/tool-executor.js +159 -18
  28. package/dist/src/tools/delete-file.js +1 -1
  29. package/dist/src/tools/index.js +6 -0
  30. package/dist/src/tools/patch-file.js +3 -2
  31. package/dist/src/tools/path-suggest.js +81 -8
  32. package/dist/src/tools/read-document.js +2 -2
  33. package/dist/src/tools/read-file.js +14 -7
  34. package/dist/src/tools/replace-document-text.js +3 -11
  35. package/dist/src/tools/restore-checkpoint.js +1 -1
  36. package/dist/src/tools/run-command.js +83 -16
  37. package/dist/src/tools/run-node-script.js +3 -1
  38. package/dist/src/tools/shell-job-kill.js +48 -0
  39. package/dist/src/tools/shell-job-output.js +51 -0
  40. package/dist/src/tools/str-replace.js +3 -2
  41. package/dist/src/tools/undo-edit.js +1 -1
  42. package/dist/src/tools/update-todos.js +27 -0
  43. package/dist/src/tools/write-file.js +1 -1
  44. package/dist/src/tree-sitter-runtime.js +8 -1
  45. package/dist/src/ui/repl.js +313 -23
  46. package/dist/src/ui/tui/bridge.js +0 -4
  47. package/dist/src/ui/tui/build-frame.js +220 -24
  48. package/dist/src/ui/tui/shell-input.js +33 -4
  49. package/dist/src/ui/tui/terminal-title.js +81 -0
  50. package/dist/src/version.js +0 -6
  51. package/dist/vendor/web-tree-sitter/LICENSE +21 -0
  52. package/dist/vendor/web-tree-sitter/NOTICE +13 -0
  53. package/dist/vendor/web-tree-sitter/web-tree-sitter.cjs +4063 -0
  54. package/dist/vendor/web-tree-sitter/web-tree-sitter.wasm +0 -0
  55. package/package.json +14 -15
@@ -1,8 +1,9 @@
1
- import chalk from 'chalk';
1
+ import chalk from '../colors.js';
2
2
  import { execFileSync, spawn } from 'node:child_process';
3
3
  import { syncIndexFromDisk } from '../project-index.js';
4
4
  import { isTuiMode } from '../runtime-mode.js';
5
5
  import { buildDeferredShellDiagnostics, invalidateShellDiagnosticsCache, } from './shell-diagnostics.js';
6
+ import { ensureSessionScratchDir } from '../scratch-dir.js';
6
7
  const DEFAULT_TIMEOUT = 5 * 60 * 1000;
7
8
  const MAX_OUTPUT_CHARS = 4000;
8
9
  const MAX_CAPTURE_CHARS = 1024 * 1024;
@@ -99,6 +100,7 @@ function executeNodeScript(rootDir, script, timeout) {
99
100
  npm_config_progress: 'false',
100
101
  npm_config_fund: 'false',
101
102
  npm_config_audit: 'false',
103
+ THEGITAI_SCRATCH_DIR: ensureSessionScratchDir(),
102
104
  },
103
105
  stdio: ['pipe', 'pipe', 'pipe'],
104
106
  });
@@ -0,0 +1,48 @@
1
+ import { killBackgroundJob } from '../background-jobs.js';
2
+ import { redactConnectionStringCredentials } from '../secret-preview.js';
3
+ const MAX_JOB_TOOL_OUTPUT_CHARS = 64 * 1024;
4
+ function boundJobToolOutput(output) {
5
+ if (output.length <= MAX_JOB_TOOL_OUTPUT_CHARS)
6
+ return output;
7
+ const headSize = Math.floor(MAX_JOB_TOOL_OUTPUT_CHARS * 0.2);
8
+ const tailSize = MAX_JOB_TOOL_OUTPUT_CHARS - headSize;
9
+ return (output.slice(0, headSize) +
10
+ `\n\n... (${output.length - headSize - tailSize} chars truncated) ...\n\n` +
11
+ output.slice(-tailSize));
12
+ }
13
+ export async function shellJobKill(context, args) {
14
+ const jobId = String(args.job_id ?? '').trim();
15
+ if (!jobId) {
16
+ return {
17
+ ok: false,
18
+ error: 'job_id is required',
19
+ failureCategory: 'missing_required_argument',
20
+ };
21
+ }
22
+ const result = await killBackgroundJob(jobId, {
23
+ sessionId: context.sessionId,
24
+ });
25
+ if (!result.ok || !result.snapshot) {
26
+ return {
27
+ ok: false,
28
+ error: result.error ?? 'Background job lookup failed.',
29
+ failureCategory: 'not_found',
30
+ };
31
+ }
32
+ const snapshot = result.snapshot;
33
+ let finalOutput = redactConnectionStringCredentials(result.finalOutput ?? '');
34
+ if (result.droppedChars) {
35
+ finalOutput = `... (${result.droppedChars} chars of older output dropped) ...\n${finalOutput}`;
36
+ }
37
+ finalOutput = boundJobToolOutput(finalOutput);
38
+ return {
39
+ ok: true,
40
+ jobId: snapshot.id,
41
+ command: snapshot.command,
42
+ status: snapshot.status,
43
+ exitCode: snapshot.exitCode,
44
+ alreadyFinished: result.alreadyFinished === true,
45
+ ranMs: (snapshot.endedAt ?? Date.now()) - snapshot.startedAt,
46
+ finalOutput,
47
+ };
48
+ }
@@ -0,0 +1,51 @@
1
+ import { MAX_JOB_WAIT_MS, readBackgroundJobOutput, } from '../background-jobs.js';
2
+ import { redactConnectionStringCredentials } from '../secret-preview.js';
3
+ const MAX_JOB_TOOL_OUTPUT_CHARS = 64 * 1024;
4
+ function boundJobToolOutput(output) {
5
+ if (output.length <= MAX_JOB_TOOL_OUTPUT_CHARS)
6
+ return output;
7
+ const headSize = Math.floor(MAX_JOB_TOOL_OUTPUT_CHARS * 0.2);
8
+ const tailSize = MAX_JOB_TOOL_OUTPUT_CHARS - headSize;
9
+ return (output.slice(0, headSize) +
10
+ `\n\n... (${output.length - headSize - tailSize} chars truncated) ...\n\n` +
11
+ output.slice(-tailSize));
12
+ }
13
+ export async function shellJobOutput(context, args) {
14
+ const jobId = String(args.job_id ?? '').trim();
15
+ if (!jobId) {
16
+ return {
17
+ ok: false,
18
+ error: 'job_id is required',
19
+ failureCategory: 'missing_required_argument',
20
+ };
21
+ }
22
+ const waitMs = typeof args.wait_ms === 'number' && args.wait_ms > 0
23
+ ? Math.min(args.wait_ms, MAX_JOB_WAIT_MS)
24
+ : 0;
25
+ const result = await readBackgroundJobOutput(jobId, {
26
+ waitMs,
27
+ sessionId: context.sessionId,
28
+ });
29
+ if (!result.ok || !result.snapshot) {
30
+ return {
31
+ ok: false,
32
+ error: result.error ?? 'Background job lookup failed.',
33
+ failureCategory: 'not_found',
34
+ };
35
+ }
36
+ const snapshot = result.snapshot;
37
+ let newOutput = redactConnectionStringCredentials(result.newOutput ?? '');
38
+ if (result.droppedChars) {
39
+ newOutput = `... (${result.droppedChars} chars of older output dropped) ...\n${newOutput}`;
40
+ }
41
+ newOutput = boundJobToolOutput(newOutput);
42
+ return {
43
+ ok: true,
44
+ jobId: snapshot.id,
45
+ command: snapshot.command,
46
+ status: snapshot.status,
47
+ exitCode: snapshot.exitCode,
48
+ elapsedMs: (snapshot.endedAt ?? Date.now()) - snapshot.startedAt,
49
+ newOutput,
50
+ };
51
+ }
@@ -1,7 +1,8 @@
1
- import chalk from 'chalk';
1
+ import chalk from '../colors.js';
2
2
  import path from 'node:path';
3
3
  import { normalizeProjectRelativePath } from '../artifact-policy.js';
4
4
  import { readProjectFile, writeProjectFile } from '../patcher.js';
5
+ import { repairFilePath } from './path-suggest.js';
5
6
  import { upsertIndexFile } from '../project-index.js';
6
7
  import { isTuiMode } from '../runtime-mode.js';
7
8
  import { getCurrentFileHash, resolveRedactionTokens } from '../session-safety.js';
@@ -76,7 +77,7 @@ function buildStrReplacePreview(oldString, newString) {
76
77
  }
77
78
  export async function strReplace(context, args) {
78
79
  const { rootDir, projectIndex, autoYes, confirmPatch } = context;
79
- const filePath = String(args.filePath ?? args.file_path ?? '').trim();
80
+ const filePath = repairFilePath(rootDir, String(args.filePath ?? args.file_path ?? '').trim());
80
81
  let oldString = typeof args.old_string === 'string'
81
82
  ? args.old_string
82
83
  : typeof args.oldString === 'string'
@@ -1,4 +1,4 @@
1
- import chalk from 'chalk';
1
+ import chalk from '../colors.js';
2
2
  import { hashStoredContent, readFileEditSnapshot, storedContentBuffer, } from '../edit-journal.js';
3
3
  import { deleteProjectFile, writeProjectFile, writeProjectFileBuffer, } from '../patcher.js';
4
4
  import { removeIndexFile, upsertIndexFile, } from '../project-index.js';
@@ -0,0 +1,27 @@
1
+ import { extractTodosArg, replaceTodos } from '../todo-list.js';
2
+ export function updateTodos(_context, args) {
3
+ const rawTodos = extractTodosArg(args);
4
+ if (rawTodos === undefined) {
5
+ return {
6
+ ok: false,
7
+ error: 'todos is required (pass [] to clear the list).',
8
+ failureCategory: 'missing_required_argument',
9
+ };
10
+ }
11
+ const result = replaceTodos(rawTodos);
12
+ if (!result.ok) {
13
+ return {
14
+ ok: false,
15
+ error: result.error,
16
+ failureCategory: 'invalid_argument',
17
+ };
18
+ }
19
+ const { snapshot, normalizations } = result;
20
+ return {
21
+ ok: true,
22
+ todos: snapshot.items,
23
+ completedCount: snapshot.completedCount,
24
+ totalCount: snapshot.totalCount,
25
+ ...(normalizations.length ? { normalizations } : {}),
26
+ };
27
+ }
@@ -1,4 +1,4 @@
1
- import chalk from 'chalk';
1
+ import chalk from '../colors.js';
2
2
  import path from 'node:path';
3
3
  import { normalizeProjectRelativePath } from '../artifact-policy.js';
4
4
  import { writeProjectFile } from '../patcher.js';
@@ -5,8 +5,15 @@ import { fileURLToPath } from 'node:url';
5
5
  import { addSignatureForNode } from './extractors/index.js';
6
6
  import { getRepoMapLanguageForFile, } from './repo-map-languages.js';
7
7
  const require = createRequire(import.meta.url);
8
- const TreeSitter = require('web-tree-sitter');
9
8
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ function resolveVendoredTreeSitter() {
10
+ const candidates = [
11
+ path.resolve(__dirname, '..', 'vendor', 'web-tree-sitter', 'web-tree-sitter.cjs'),
12
+ path.resolve(__dirname, '..', '..', 'vendor', 'web-tree-sitter', 'web-tree-sitter.cjs'),
13
+ ];
14
+ return candidates.find((candidate) => existsSync(candidate)) ?? candidates[0];
15
+ }
16
+ const TreeSitter = require(resolveVendoredTreeSitter());
10
17
  let parserInitPromise = null;
11
18
  const parserCache = Object.create(null);
12
19
  const languageCache = Object.create(null);