@thegitai/cli 1.0.0-preview.5 → 1.0.0-preview.50
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 +93 -4
- package/dist/bin/ai.js +142 -112
- package/dist/bin/browser-host.js +265 -0
- package/dist/src/agent-mode.js +32 -7
- package/dist/src/api/auth.js +10 -4
- package/dist/src/api/browser-login.js +149 -37
- package/dist/src/api/chat.js +680 -166
- package/dist/src/api/contracts.js +55 -1
- package/dist/src/api/default-host.js +1 -0
- package/dist/src/api/http.js +151 -7
- package/dist/src/api/models.js +29 -10
- package/dist/src/api/startup-handshake.js +36 -0
- package/dist/src/api/turn-recovery.js +189 -0
- package/dist/src/background-jobs.js +4 -2
- package/dist/src/browser/bridge.js +262 -0
- package/dist/src/browser/framing.js +42 -0
- package/dist/src/browser/native-host.js +219 -0
- package/dist/src/browser/protocol.js +46 -0
- package/dist/src/browser/session-bridge.js +130 -0
- package/dist/src/cli-args.js +19 -5
- package/dist/src/client-environment.js +2 -0
- package/dist/src/core/clipboard.js +7 -13
- package/dist/src/core/image-limits.js +56 -0
- package/dist/src/core/image-path-extractor.js +70 -3
- package/dist/src/core/session-image-store.js +246 -0
- package/dist/src/edit-journal.js +33 -2
- package/dist/src/executor.js +25 -3
- package/dist/src/help-text.js +112 -21
- package/dist/src/patcher.js +43 -4
- package/dist/src/permissions.js +288 -0
- package/dist/src/preferences.js +39 -0
- package/dist/src/quota-notice.js +35 -0
- package/dist/src/session-safety.js +0 -12
- package/dist/src/session-store.js +121 -20
- package/dist/src/session.js +19 -4
- package/dist/src/signin.js +58 -0
- package/dist/src/tool-executor.js +13 -46
- package/dist/src/tools/browser.js +628 -0
- package/dist/src/tools/delete-file.js +20 -4
- package/dist/src/tools/index.js +32 -10
- package/dist/src/tools/patch-file.js +12 -26
- package/dist/src/tools/read-image-file.js +85 -0
- package/dist/src/tools/replace-document-text.js +28 -18
- package/dist/src/tools/restore-checkpoint.js +0 -1
- package/dist/src/tools/run-command.js +14 -71
- package/dist/src/tools/run-node-script.js +12 -81
- package/dist/src/tools/save-generated-image.js +120 -0
- package/dist/src/tools/str-replace.js +12 -26
- package/dist/src/tools/undo-edit.js +1 -6
- package/dist/src/tools/write-file.js +67 -11
- package/dist/src/ui/prompt-history-store.js +1 -1
- package/dist/src/ui/repl.js +949 -279
- package/dist/src/ui/slash-commands.js +121 -0
- package/dist/src/ui/tui/attention.js +25 -0
- package/dist/src/ui/tui/bridge.js +38 -5
- package/dist/src/ui/tui/build-frame.js +686 -223
- package/dist/src/ui/tui/composer-layout.js +76 -0
- package/dist/src/ui/tui/desktop-notification.js +118 -0
- package/dist/src/ui/tui/markdown-render.js +11 -2
- package/dist/src/ui/tui/shell-input.js +256 -73
- package/dist/src/ui/tui/shortcuts.js +61 -0
- package/dist/src/ui/tui/terminal-theme.js +28 -0
- package/dist/src/ui/tui/user-input.js +593 -0
- package/dist/src/update-check.js +205 -0
- package/dist/src/usage.js +5 -2
- package/dist/src/utils.js +13 -0
- package/dist/src/version.js +52 -2
- package/package.json +22 -9
- package/dist/src/project-index.js +0 -233
- package/dist/src/tools/code-intel.js +0 -472
- package/dist/src/tools/find-symbol.js +0 -70
- package/dist/src/tools/hover-symbol.js +0 -95
- package/dist/src/tools/list-symbols.js +0 -55
- package/dist/src/tools/search-code.js +0 -37
- package/dist/src/tools/signature-help.js +0 -118
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
export const SLASH_COMMANDS = [
|
|
2
|
+
{ command: '/model', description: 'Switch the active model' },
|
|
3
|
+
{ command: '/help', description: 'Show available chat commands' },
|
|
4
|
+
{ command: '/usage', description: 'Show account usage percentage and reset times' },
|
|
5
|
+
{
|
|
6
|
+
command: '/resume',
|
|
7
|
+
description: 'Open the session picker to resume a previous session',
|
|
8
|
+
},
|
|
9
|
+
{ command: '/new', description: 'start a new conversation; this session remains saved' },
|
|
10
|
+
{ command: '/jobs', description: 'Background jobs: pick to view output or kill' },
|
|
11
|
+
{
|
|
12
|
+
command: '/notify',
|
|
13
|
+
description: 'Toggle desktop notifications when a turn ends (Ctrl+G)',
|
|
14
|
+
},
|
|
15
|
+
{ command: '/report', description: 'Report a bug privately on the TheGitAI website' },
|
|
16
|
+
{ command: '/about', description: 'Show version and platform info' },
|
|
17
|
+
{ command: '/logout', description: 'Sign out and quit' },
|
|
18
|
+
{ command: '/exit', description: 'Quit the current session', aliases: ['/quit'] },
|
|
19
|
+
];
|
|
20
|
+
export const SLASH_COMMAND_SUGGESTION_LIMIT = 5;
|
|
21
|
+
export function getInputCommandToken(input) {
|
|
22
|
+
const trimmed = String(input ?? '').trimStart();
|
|
23
|
+
const match = trimmed.match(/^\/[^\s]*/);
|
|
24
|
+
const token = match?.[0] ?? '';
|
|
25
|
+
if (token.indexOf('/', 1) !== -1)
|
|
26
|
+
return '';
|
|
27
|
+
return token;
|
|
28
|
+
}
|
|
29
|
+
export function slashCommandMatchesToken(option, token) {
|
|
30
|
+
return option.command === token || (option.aliases?.includes(token) ?? false);
|
|
31
|
+
}
|
|
32
|
+
const MATCH_EXACT = 0;
|
|
33
|
+
const MATCH_PREFIX = 100;
|
|
34
|
+
const MATCH_OVERTYPED = 200;
|
|
35
|
+
const MATCH_TYPO = 300;
|
|
36
|
+
const MATCH_IN_NAME = 400;
|
|
37
|
+
const MATCH_IN_DESCRIPTION = 500;
|
|
38
|
+
const MATCH_NONE = 600;
|
|
39
|
+
function typoBudget(body) {
|
|
40
|
+
if (body.length <= 3)
|
|
41
|
+
return 0;
|
|
42
|
+
if (body.length <= 5)
|
|
43
|
+
return 1;
|
|
44
|
+
return 2;
|
|
45
|
+
}
|
|
46
|
+
function editDistanceWithin(a, b, max) {
|
|
47
|
+
if (a === b)
|
|
48
|
+
return 0;
|
|
49
|
+
if (max <= 0)
|
|
50
|
+
return null;
|
|
51
|
+
if (Math.abs(a.length - b.length) > max)
|
|
52
|
+
return null;
|
|
53
|
+
const width = b.length + 1;
|
|
54
|
+
let beforePrevious = [];
|
|
55
|
+
let previous = Array.from({ length: width }, (_, index) => index);
|
|
56
|
+
for (let i = 1; i <= a.length; i += 1) {
|
|
57
|
+
const current = new Array(width);
|
|
58
|
+
current[0] = i;
|
|
59
|
+
let best = i;
|
|
60
|
+
for (let j = 1; j < width; j += 1) {
|
|
61
|
+
const substitution = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
62
|
+
let cost = Math.min(previous[j] + 1, current[j - 1] + 1, previous[j - 1] + substitution);
|
|
63
|
+
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
|
|
64
|
+
cost = Math.min(cost, beforePrevious[j - 2] + 1);
|
|
65
|
+
}
|
|
66
|
+
current[j] = cost;
|
|
67
|
+
if (cost < best)
|
|
68
|
+
best = cost;
|
|
69
|
+
}
|
|
70
|
+
if (best > max)
|
|
71
|
+
return null;
|
|
72
|
+
beforePrevious = previous;
|
|
73
|
+
previous = current;
|
|
74
|
+
}
|
|
75
|
+
const distance = previous[b.length];
|
|
76
|
+
return distance <= max ? distance : null;
|
|
77
|
+
}
|
|
78
|
+
function scoreSlashCommand(option, token) {
|
|
79
|
+
const command = option.command;
|
|
80
|
+
const body = token.slice(1);
|
|
81
|
+
if (!body)
|
|
82
|
+
return MATCH_PREFIX;
|
|
83
|
+
const spellings = [command, ...(option.aliases ?? [])];
|
|
84
|
+
if (slashCommandMatchesToken(option, token))
|
|
85
|
+
return MATCH_EXACT;
|
|
86
|
+
if (spellings.some((spelling) => spelling.startsWith(token)))
|
|
87
|
+
return MATCH_PREFIX;
|
|
88
|
+
const overtyped = spellings.find((spelling) => token.startsWith(spelling));
|
|
89
|
+
if (overtyped) {
|
|
90
|
+
return MATCH_OVERTYPED + Math.min(token.length - overtyped.length, 99);
|
|
91
|
+
}
|
|
92
|
+
const distances = spellings
|
|
93
|
+
.map((spelling) => editDistanceWithin(body, spelling.slice(1), typoBudget(body)))
|
|
94
|
+
.filter((distance) => distance !== null);
|
|
95
|
+
if (distances.length)
|
|
96
|
+
return MATCH_TYPO + Math.min(...distances);
|
|
97
|
+
if (command.includes(body))
|
|
98
|
+
return MATCH_IN_NAME;
|
|
99
|
+
if (option.description.toLowerCase().includes(body))
|
|
100
|
+
return MATCH_IN_DESCRIPTION;
|
|
101
|
+
return MATCH_NONE;
|
|
102
|
+
}
|
|
103
|
+
function rankSlashCommands(input) {
|
|
104
|
+
const token = getInputCommandToken(input).toLowerCase();
|
|
105
|
+
if (!token)
|
|
106
|
+
return [];
|
|
107
|
+
return SLASH_COMMANDS.map((option, order) => ({
|
|
108
|
+
option,
|
|
109
|
+
order,
|
|
110
|
+
score: scoreSlashCommand(option, token),
|
|
111
|
+
}))
|
|
112
|
+
.filter((entry) => entry.score < MATCH_NONE)
|
|
113
|
+
.sort((a, b) => a.score - b.score || a.order - b.order)
|
|
114
|
+
.map((entry) => entry.option);
|
|
115
|
+
}
|
|
116
|
+
export function getSlashCommandSuggestions(input) {
|
|
117
|
+
return rankSlashCommands(input).slice(0, SLASH_COMMAND_SUGGESTION_LIMIT);
|
|
118
|
+
}
|
|
119
|
+
export function getHiddenSlashCommandCount(input) {
|
|
120
|
+
return Math.max(0, rankSlashCommands(input).length - SLASH_COMMAND_SUGGESTION_LIMIT);
|
|
121
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const INITIAL_TERMINAL_FOCUS = true;
|
|
2
|
+
export function createAttentionController(options) {
|
|
3
|
+
let previous = null;
|
|
4
|
+
let outstanding = false;
|
|
5
|
+
return {
|
|
6
|
+
sync(state, enabled) {
|
|
7
|
+
const last = previous;
|
|
8
|
+
previous = { ...state };
|
|
9
|
+
if (last && !last.focused && state.focused && outstanding) {
|
|
10
|
+
outstanding = false;
|
|
11
|
+
options.withdraw();
|
|
12
|
+
}
|
|
13
|
+
if (!last || !enabled)
|
|
14
|
+
return;
|
|
15
|
+
if (state.focused)
|
|
16
|
+
return;
|
|
17
|
+
const turnFinished = last.busy && !state.busy;
|
|
18
|
+
const nowBlocked = !last.awaitingAnswer && state.awaitingAnswer;
|
|
19
|
+
if (nowBlocked || turnFinished) {
|
|
20
|
+
outstanding = true;
|
|
21
|
+
options.notify(nowBlocked ? 'blocked' : 'finished');
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { createInterface } from 'node:readline';
|
|
3
|
-
import { existsSync } from 'node:fs';
|
|
3
|
+
import { existsSync, statSync } from 'node:fs';
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
@@ -51,6 +51,9 @@ function normalizeChildMessage(raw) {
|
|
|
51
51
|
url: String(raw.url ?? ''),
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
+
if (raw.kind === 'focus') {
|
|
55
|
+
return { op: 'event', kind: 'focus', focused: raw.focused === true };
|
|
56
|
+
}
|
|
54
57
|
if (raw.kind === 'contextMenu') {
|
|
55
58
|
return { op: 'event', kind: 'contextMenu' };
|
|
56
59
|
}
|
|
@@ -61,6 +64,13 @@ function normalizeChildMessage(raw) {
|
|
|
61
64
|
deltaLines: Number(raw.deltaLines ?? raw.delta_lines ?? 0),
|
|
62
65
|
};
|
|
63
66
|
}
|
|
67
|
+
if (raw.kind === 'transcriptScrollTo') {
|
|
68
|
+
return {
|
|
69
|
+
op: 'event',
|
|
70
|
+
kind: 'transcriptScrollTo',
|
|
71
|
+
offset: Number(raw.offset ?? 0),
|
|
72
|
+
};
|
|
73
|
+
}
|
|
64
74
|
if (raw.kind !== 'key') {
|
|
65
75
|
return null;
|
|
66
76
|
}
|
|
@@ -88,13 +98,18 @@ function normalizeChildMessage(raw) {
|
|
|
88
98
|
pageDown: bool(raw.pageDown ?? raw.page_down),
|
|
89
99
|
};
|
|
90
100
|
}
|
|
101
|
+
function isRepoCheckout(moduleDir) {
|
|
102
|
+
return [
|
|
103
|
+
path.join(moduleDir, '../../../../thegitai-tui/Cargo.toml'),
|
|
104
|
+
path.join(moduleDir, '../../../../../thegitai-tui/Cargo.toml'),
|
|
105
|
+
].some((candidate) => existsSync(candidate));
|
|
106
|
+
}
|
|
91
107
|
export function resolveTuiBinaryPath() {
|
|
92
108
|
const binaryName = process.platform === 'win32' ? 'thegitai-tui.exe' : 'thegitai-tui';
|
|
93
109
|
const platformPackage = `@thegitai/tui-${process.platform}-${process.arch}`;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
catch {
|
|
110
|
+
const override = String(process.env.THEGITAI_TUI_BINARY ?? '').trim();
|
|
111
|
+
if (override && existsSync(override)) {
|
|
112
|
+
return override;
|
|
98
113
|
}
|
|
99
114
|
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
100
115
|
const devCandidates = [
|
|
@@ -102,6 +117,24 @@ export function resolveTuiBinaryPath() {
|
|
|
102
117
|
path.join(moduleDir, '../../../../bin', binaryName),
|
|
103
118
|
];
|
|
104
119
|
const devBinary = devCandidates.find((candidate) => existsSync(candidate));
|
|
120
|
+
let publishedBinary = null;
|
|
121
|
+
try {
|
|
122
|
+
publishedBinary = requireFromHere.resolve(`${platformPackage}/${binaryName}`);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
}
|
|
126
|
+
if (publishedBinary && devBinary && isRepoCheckout(moduleDir)) {
|
|
127
|
+
try {
|
|
128
|
+
if (statSync(devBinary).mtimeMs > statSync(publishedBinary).mtimeMs) {
|
|
129
|
+
return devBinary;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (publishedBinary) {
|
|
136
|
+
return publishedBinary;
|
|
137
|
+
}
|
|
105
138
|
if (devBinary) {
|
|
106
139
|
return devBinary;
|
|
107
140
|
}
|