indusagi-coding-agent 0.2.12 → 0.2.14
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/.env.review.example +25 -0
- package/README.md +30 -0
- package/REVIEW_AGENT.md +137 -0
- package/dist/entry.js +1861 -979
- package/dist/guardrails.js +212 -36
- package/dist/index.js +2829 -1057
- package/dist/review-agent.js +4461 -0
- package/dist/review-server.js +4633 -0
- package/package.json +24 -7
- package/src/boot/auth-vault.ts +4 -5
- package/src/boot/contract.ts +1 -1
- package/src/boot/runners/addon-wiring.ts +111 -3
- package/src/boot/runners/benchmark-integrity.ts +107 -0
- package/src/boot/runners/repl-runner.ts +2 -1
- package/src/boot/runners/session.ts +26 -12
- package/src/boot/server-token.ts +20 -11
- package/src/boot/stages.ts +3 -6
- package/src/briefing/context-docs.ts +144 -12
- package/src/channels/oneshot.ts +6 -0
- package/src/conductor/catalog/catalog.ts +3 -1
- package/src/conductor/conductor.ts +77 -17
- package/src/conductor/contract.ts +9 -7
- package/src/conductor/index.ts +1 -1
- package/src/conductor/transcript-store/store.ts +4 -8
- package/src/console/auth-status.ts +9 -4
- package/src/console/components/AgentsView.ts +2 -2
- package/src/console/components/BackgroundAgents.ts +15 -2
- package/src/console/components/Banner.ts +20 -9
- package/src/console/components/Composer.ts +57 -82
- package/src/console/components/ScrollViewport.ts +46 -0
- package/src/console/components/TerminalConsole.ts +165 -162
- package/src/console/components/WorkingIndicator.ts +6 -5
- package/src/console/components/banner-sweep.ts +5 -1
- package/src/console/components/welcome.ts +3 -3
- package/src/console/contract.ts +10 -5
- package/src/console/index.ts +7 -7
- package/src/console/input/complete.ts +2 -2
- package/src/console/input/dir-reader.ts +3 -1
- package/src/console/input/graphemes.ts +22 -0
- package/src/console/input/keymap.ts +6 -4
- package/src/console/mount.ts +45 -3
- package/src/console/overlays/auth.ts +28 -8
- package/src/console/overlays/boards.ts +13 -40
- package/src/console/overlays/host.ts +10 -0
- package/src/console/overlays/pickers.ts +35 -30
- package/src/console/reducer.ts +12 -5
- package/src/console/slash/builtins.ts +4 -3
- package/src/console/slash/commands/integrations.ts +13 -14
- package/src/console/slash/commands/transcript.ts +3 -8
- package/src/console/slash/commands/workbench.ts +4 -4
- package/src/console/test-support.ts +48 -0
- package/src/index.ts +1 -0
- package/src/integrations/sarvam/config.ts +15 -13
- package/src/kit/external-editor.ts +17 -1
- package/src/kit/run-shell.ts +31 -0
- package/src/launch/catalog.ts +4 -2
- package/src/launch/contract.ts +1 -0
- package/src/launch/invocation/flags.ts +13 -1
- package/src/launch/invocation/read.ts +4 -3
- package/src/launch/login.ts +23 -10
- package/src/launch/oauth.ts +3 -0
- package/src/models.ts +166 -0
- package/src/review-agent/config.ts +75 -0
- package/src/review-agent/contract.ts +59 -0
- package/src/review-agent/github.ts +242 -0
- package/src/review-agent/index.ts +8 -0
- package/src/review-agent/prompt.ts +132 -0
- package/src/review-agent/reviewer.ts +118 -0
- package/src/review-agent/server.ts +221 -0
- package/src/review-agent/service.ts +165 -0
- package/src/review-agent/supabase.ts +209 -0
- package/src/review-agent/webhook.ts +76 -0
- package/src/security/private-state.ts +122 -0
- package/src/window-budget/summarize/condense.ts +4 -1
- package/src/workspace/brand.ts +1 -1
- package/src/workspace/locator.ts +2 -2
- package/supabase/migrations/20260827031803_indusagi_review_agent.sql +109 -0
- package/supabase/migrations/20260827035747_atomic_webhook_enqueue.sql +75 -0
- package/supabase/migrations/20260827040104_check_run_reconciliation.sql +8 -0
- package/supabase/migrations/20260827041049_owned_job_leases.sql +80 -0
- package/supabase/migrations/20260827042500_static_token_webhooks.sql +75 -0
package/dist/entry.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/entry.ts
|
|
4
4
|
import { argv as processArgv, env as processEnv } from "node:process";
|
|
5
|
-
import { realpathSync as
|
|
5
|
+
import { realpathSync as realpathSync4 } from "node:fs";
|
|
6
6
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
7
7
|
|
|
8
8
|
// src/workspace/brand.ts
|
|
@@ -18,7 +18,7 @@ var BRAND = Object.freeze({
|
|
|
18
18
|
envShareViewer: "INDUSAGI_SHARE_VIEWER_URL",
|
|
19
19
|
shareViewerUrl: "https://buildwithindusagi.ai/session/"
|
|
20
20
|
});
|
|
21
|
-
var VERSION = "0.2.
|
|
21
|
+
var VERSION = "0.2.14";
|
|
22
22
|
|
|
23
23
|
// src/launch/credentials.ts
|
|
24
24
|
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
@@ -31,7 +31,8 @@ var THINKING_EFFORTS = [
|
|
|
31
31
|
"low",
|
|
32
32
|
"medium",
|
|
33
33
|
"high",
|
|
34
|
-
"xhigh"
|
|
34
|
+
"xhigh",
|
|
35
|
+
"max"
|
|
35
36
|
];
|
|
36
37
|
function isThinkingEffort(value) {
|
|
37
38
|
return THINKING_EFFORTS.includes(value);
|
|
@@ -76,26 +77,153 @@ import {
|
|
|
76
77
|
|
|
77
78
|
// src/launch/login.ts
|
|
78
79
|
import { createInterface } from "node:readline/promises";
|
|
80
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
79
81
|
import chalk from "chalk";
|
|
80
82
|
|
|
81
83
|
// src/boot/server-token.ts
|
|
82
|
-
import {
|
|
84
|
+
import { unlink } from "node:fs/promises";
|
|
83
85
|
import os from "node:os";
|
|
84
86
|
import path from "node:path";
|
|
87
|
+
|
|
88
|
+
// src/security/private-state.ts
|
|
89
|
+
import {
|
|
90
|
+
chmodSync,
|
|
91
|
+
closeSync,
|
|
92
|
+
constants,
|
|
93
|
+
fchmodSync,
|
|
94
|
+
fstatSync,
|
|
95
|
+
lstatSync,
|
|
96
|
+
mkdirSync,
|
|
97
|
+
openSync,
|
|
98
|
+
readFileSync,
|
|
99
|
+
renameSync,
|
|
100
|
+
rmSync,
|
|
101
|
+
writeFileSync
|
|
102
|
+
} from "node:fs";
|
|
103
|
+
import { randomUUID } from "node:crypto";
|
|
104
|
+
import { dirname } from "node:path";
|
|
105
|
+
var PRIVATE_DIRECTORY_MODE = 448;
|
|
106
|
+
var PRIVATE_FILE_MODE = 384;
|
|
107
|
+
var NO_FOLLOW = constants.O_NOFOLLOW ?? 0;
|
|
108
|
+
function isPosix() {
|
|
109
|
+
return process.platform !== "win32";
|
|
110
|
+
}
|
|
111
|
+
function assertOwned(uid, path5) {
|
|
112
|
+
if (!isPosix() || process.getuid === void 0) return;
|
|
113
|
+
if (uid !== process.getuid()) {
|
|
114
|
+
throw new Error(`Refusing sensitive path not owned by the current user: ${path5}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function ensurePrivateDirectorySync(path5) {
|
|
118
|
+
try {
|
|
119
|
+
const current = lstatSync(path5);
|
|
120
|
+
if (current.isSymbolicLink() || !current.isDirectory()) {
|
|
121
|
+
throw new Error(`Refusing non-directory sensitive state path: ${path5}`);
|
|
122
|
+
}
|
|
123
|
+
assertOwned(current.uid, path5);
|
|
124
|
+
} catch (error) {
|
|
125
|
+
if (error.code !== "ENOENT") throw error;
|
|
126
|
+
mkdirSync(path5, { recursive: true, mode: PRIVATE_DIRECTORY_MODE });
|
|
127
|
+
}
|
|
128
|
+
if (isPosix()) chmodSync(path5, PRIVATE_DIRECTORY_MODE);
|
|
129
|
+
}
|
|
130
|
+
function validateExistingFile(path5) {
|
|
131
|
+
try {
|
|
132
|
+
const current = lstatSync(path5);
|
|
133
|
+
if (current.isSymbolicLink() || !current.isFile()) {
|
|
134
|
+
throw new Error(`Refusing non-regular sensitive file: ${path5}`);
|
|
135
|
+
}
|
|
136
|
+
assertOwned(current.uid, path5);
|
|
137
|
+
} catch (error) {
|
|
138
|
+
if (error.code === "ENOENT") return;
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function readPrivateFileSync(path5) {
|
|
143
|
+
ensurePrivateDirectorySync(dirname(path5));
|
|
144
|
+
try {
|
|
145
|
+
validateExistingFile(path5);
|
|
146
|
+
const fd = openSync(path5, constants.O_RDONLY | NO_FOLLOW);
|
|
147
|
+
try {
|
|
148
|
+
const current = fstatSync(fd);
|
|
149
|
+
if (!current.isFile()) throw new Error(`Refusing non-regular sensitive file: ${path5}`);
|
|
150
|
+
assertOwned(current.uid, path5);
|
|
151
|
+
if (isPosix()) fchmodSync(fd, PRIVATE_FILE_MODE);
|
|
152
|
+
return readFileSync(fd, "utf8");
|
|
153
|
+
} finally {
|
|
154
|
+
closeSync(fd);
|
|
155
|
+
}
|
|
156
|
+
} catch (error) {
|
|
157
|
+
if (error.code === "ENOENT") return null;
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function atomicWritePrivateFileSync(path5, content) {
|
|
162
|
+
const parent = dirname(path5);
|
|
163
|
+
ensurePrivateDirectorySync(parent);
|
|
164
|
+
validateExistingFile(path5);
|
|
165
|
+
const temporary = `${path5}.tmp-${process.pid}-${randomUUID()}`;
|
|
166
|
+
let fd;
|
|
167
|
+
try {
|
|
168
|
+
fd = openSync(
|
|
169
|
+
temporary,
|
|
170
|
+
constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | NO_FOLLOW,
|
|
171
|
+
PRIVATE_FILE_MODE
|
|
172
|
+
);
|
|
173
|
+
writeFileSync(fd, content, "utf8");
|
|
174
|
+
if (isPosix()) fchmodSync(fd, PRIVATE_FILE_MODE);
|
|
175
|
+
closeSync(fd);
|
|
176
|
+
fd = void 0;
|
|
177
|
+
renameSync(temporary, path5);
|
|
178
|
+
if (isPosix()) chmodSync(path5, PRIVATE_FILE_MODE);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
if (fd !== void 0) closeSync(fd);
|
|
181
|
+
try {
|
|
182
|
+
rmSync(temporary, { force: true });
|
|
183
|
+
} catch {
|
|
184
|
+
}
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function appendPrivateFileSync(path5, content) {
|
|
189
|
+
ensurePrivateDirectorySync(dirname(path5));
|
|
190
|
+
validateExistingFile(path5);
|
|
191
|
+
const fd = openSync(
|
|
192
|
+
path5,
|
|
193
|
+
constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | NO_FOLLOW,
|
|
194
|
+
PRIVATE_FILE_MODE
|
|
195
|
+
);
|
|
196
|
+
try {
|
|
197
|
+
const current = fstatSync(fd);
|
|
198
|
+
if (!current.isFile()) throw new Error(`Refusing non-regular sensitive file: ${path5}`);
|
|
199
|
+
assertOwned(current.uid, path5);
|
|
200
|
+
if (isPosix()) fchmodSync(fd, PRIVATE_FILE_MODE);
|
|
201
|
+
writeFileSync(fd, content, "utf8");
|
|
202
|
+
} finally {
|
|
203
|
+
closeSync(fd);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// src/boot/server-token.ts
|
|
85
208
|
var INDUS_SERVER_URL = process.env.INDUS_SERVER_URL?.replace(/\/+$/, "") ?? "https://indus-server.vercel.app";
|
|
86
209
|
var CONFIG_DIR = path.join(os.homedir(), ".indusagi", "agent");
|
|
87
210
|
var TOKEN_FILE = path.join(CONFIG_DIR, "server-token.json");
|
|
88
|
-
|
|
211
|
+
function resolveTokenPaths(paths = {}) {
|
|
212
|
+
const configDir = paths.configDir ?? CONFIG_DIR;
|
|
213
|
+
return { configDir, tokenFile: paths.tokenFile ?? path.join(configDir, "server-token.json") };
|
|
214
|
+
}
|
|
215
|
+
async function getServerToken(paths = {}) {
|
|
89
216
|
try {
|
|
90
|
-
const data =
|
|
217
|
+
const data = readPrivateFileSync(resolveTokenPaths(paths).tokenFile);
|
|
218
|
+
if (data === null) return null;
|
|
91
219
|
return JSON.parse(data);
|
|
92
220
|
} catch {
|
|
93
221
|
return null;
|
|
94
222
|
}
|
|
95
223
|
}
|
|
96
|
-
async function storeServerToken(token) {
|
|
224
|
+
async function storeServerToken(token, paths = {}) {
|
|
97
225
|
try {
|
|
98
|
-
|
|
226
|
+
const { tokenFile } = resolveTokenPaths(paths);
|
|
99
227
|
const tokenData = {
|
|
100
228
|
access_token: token.access_token,
|
|
101
229
|
refresh_token: token.refresh_token,
|
|
@@ -104,20 +232,17 @@ async function storeServerToken(token) {
|
|
|
104
232
|
expires_at: token.expires_in !== void 0 ? new Date(Date.now() + token.expires_in * 1e3).toISOString() : null,
|
|
105
233
|
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
106
234
|
};
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
encoding: "utf8",
|
|
110
|
-
mode: 384
|
|
111
|
-
});
|
|
235
|
+
atomicWritePrivateFileSync(tokenFile, `${JSON.stringify(tokenData, null, 2)}
|
|
236
|
+
`);
|
|
112
237
|
return true;
|
|
113
238
|
} catch (error) {
|
|
114
239
|
console.error("Failed to store server token:", error.message);
|
|
115
240
|
return false;
|
|
116
241
|
}
|
|
117
242
|
}
|
|
118
|
-
async function clearServerToken() {
|
|
243
|
+
async function clearServerToken(paths = {}) {
|
|
119
244
|
try {
|
|
120
|
-
await unlink(
|
|
245
|
+
await unlink(resolveTokenPaths(paths).tokenFile);
|
|
121
246
|
return true;
|
|
122
247
|
} catch {
|
|
123
248
|
return false;
|
|
@@ -154,10 +279,10 @@ function err(line) {
|
|
|
154
279
|
process.stderr.write(`${line}
|
|
155
280
|
`);
|
|
156
281
|
}
|
|
157
|
-
function sleep(ms) {
|
|
158
|
-
return
|
|
282
|
+
function sleep(ms, signal) {
|
|
283
|
+
return delay(ms, void 0, { signal });
|
|
159
284
|
}
|
|
160
|
-
async function postJson(url, body) {
|
|
285
|
+
async function postJson(url, body, signal) {
|
|
161
286
|
const res = await fetch(url, {
|
|
162
287
|
method: "POST",
|
|
163
288
|
headers: {
|
|
@@ -165,7 +290,8 @@ async function postJson(url, body) {
|
|
|
165
290
|
accept: "application/json",
|
|
166
291
|
"user-agent": USER_AGENT
|
|
167
292
|
},
|
|
168
|
-
body: JSON.stringify(body)
|
|
293
|
+
body: JSON.stringify(body),
|
|
294
|
+
signal: signal ? AbortSignal.any([signal, AbortSignal.timeout(3e4)]) : AbortSignal.timeout(3e4)
|
|
169
295
|
});
|
|
170
296
|
const data = await res.json().catch(() => ({}));
|
|
171
297
|
return { status: res.status, data };
|
|
@@ -201,11 +327,11 @@ async function confirm(prompt, defaultValue) {
|
|
|
201
327
|
rl.close();
|
|
202
328
|
}
|
|
203
329
|
}
|
|
204
|
-
async function requestDeviceCode(serverUrl, clientId) {
|
|
330
|
+
async function requestDeviceCode(serverUrl, clientId, signal) {
|
|
205
331
|
const { status, data } = await postJson(`${serverUrl}/api/auth/device/code`, {
|
|
206
332
|
client_id: clientId,
|
|
207
333
|
scope: DEVICE_SCOPE
|
|
208
|
-
});
|
|
334
|
+
}, signal);
|
|
209
335
|
if (status >= 400 || typeof data.device_code !== "string") {
|
|
210
336
|
throw new LoginError(
|
|
211
337
|
`Authorization request failed: ${data.error_description ?? data.error ?? data.message ?? `HTTP ${status}`}`
|
|
@@ -213,18 +339,18 @@ async function requestDeviceCode(serverUrl, clientId) {
|
|
|
213
339
|
}
|
|
214
340
|
return data;
|
|
215
341
|
}
|
|
216
|
-
async function pollForToken(serverUrl, clientId, device) {
|
|
342
|
+
async function pollForToken(serverUrl, clientId, device, signal) {
|
|
217
343
|
let intervalMs = Math.max(1, device.interval ?? 5) * 1e3;
|
|
218
344
|
const deadline = Date.now() + (device.expires_in ?? 0) * 1e3;
|
|
219
345
|
while (Date.now() < deadline) {
|
|
220
|
-
await sleep(intervalMs);
|
|
346
|
+
await sleep(intervalMs, signal);
|
|
221
347
|
const { data } = await postJson(`${serverUrl}/api/auth/device/token`, {
|
|
222
348
|
grant_type: DEVICE_GRANT_TYPE,
|
|
223
349
|
device_code: device.device_code,
|
|
224
350
|
client_id: clientId
|
|
225
|
-
});
|
|
351
|
+
}, signal);
|
|
226
352
|
if (typeof data.access_token === "string") {
|
|
227
|
-
return data;
|
|
353
|
+
return { ...data, access_token: data.access_token };
|
|
228
354
|
}
|
|
229
355
|
const code = data.error;
|
|
230
356
|
switch (code) {
|
|
@@ -247,14 +373,17 @@ async function pollForToken(serverUrl, clientId, device) {
|
|
|
247
373
|
throw new LoginError("Timed out waiting for authorization. Run `indus login` again.");
|
|
248
374
|
}
|
|
249
375
|
async function runServerTierLogin(callbacks, serverUrl = INDUS_SERVER_URL, clientId = INDUS_CLIENT_ID) {
|
|
250
|
-
|
|
376
|
+
callbacks.signal?.throwIfAborted();
|
|
377
|
+
const device = await requestDeviceCode(serverUrl, clientId, callbacks.signal);
|
|
378
|
+
callbacks.signal?.throwIfAborted();
|
|
251
379
|
callbacks.onAuth({
|
|
252
380
|
url: device.verification_uri_complete ?? device.verification_uri ?? "",
|
|
253
381
|
instructions: `Enter code ${device.user_code} to authorize this device.`
|
|
254
382
|
});
|
|
255
383
|
callbacks.onProgress?.("Waiting for authorization...");
|
|
256
|
-
const token = await pollForToken(serverUrl, clientId, device);
|
|
257
|
-
|
|
384
|
+
const token = await pollForToken(serverUrl, clientId, device, callbacks.signal);
|
|
385
|
+
callbacks.signal?.throwIfAborted();
|
|
386
|
+
if (!await storeServerToken(token)) throw new LoginError("Could not save the server token.");
|
|
258
387
|
callbacks.onProgress?.("Server sign-in complete.");
|
|
259
388
|
}
|
|
260
389
|
async function doLogin(args) {
|
|
@@ -465,12 +594,12 @@ function openLoginUrl(url) {
|
|
|
465
594
|
const tryAt = (index) => {
|
|
466
595
|
if (index >= attempts.length) return Promise.resolve(false);
|
|
467
596
|
const { command, args } = attempts[index];
|
|
468
|
-
return new Promise((
|
|
597
|
+
return new Promise((resolve11) => {
|
|
469
598
|
let settled = false;
|
|
470
599
|
const finish = (ok) => {
|
|
471
600
|
if (settled) return;
|
|
472
601
|
settled = true;
|
|
473
|
-
|
|
602
|
+
resolve11(ok);
|
|
474
603
|
};
|
|
475
604
|
try {
|
|
476
605
|
const child = spawn(command, [...args], {
|
|
@@ -503,8 +632,11 @@ async function startOAuthLogin(providerId, callbacks, vault, account = "default"
|
|
|
503
632
|
const hint = envVar !== void 0 ? `set ${envVar} and restart` : "configure its OAuth client id";
|
|
504
633
|
throw new Error(`Browser sign-in for "${providerId}" is not configured: ${hint}.`);
|
|
505
634
|
}
|
|
635
|
+
callbacks.signal?.throwIfAborted();
|
|
506
636
|
const credentials = await provider.login(callbacks);
|
|
637
|
+
callbacks.signal?.throwIfAborted();
|
|
507
638
|
const existing = await vault.listAccounts(providerId);
|
|
639
|
+
callbacks.signal?.throwIfAborted();
|
|
508
640
|
const madeDefault = existing.length === 0;
|
|
509
641
|
await vault.putOAuth(providerId, account, credentials, madeDefault);
|
|
510
642
|
return { provider: providerId, account, madeDefault };
|
|
@@ -1157,7 +1289,7 @@ var FLAG_GROUPS = [
|
|
|
1157
1289
|
{ id: "tools", title: "Tools" },
|
|
1158
1290
|
{ id: "meta", title: "Meta" }
|
|
1159
1291
|
];
|
|
1160
|
-
var THINKING_CHOICES = ["off", "minimal", "low", "medium", "high", "xhigh"];
|
|
1292
|
+
var THINKING_CHOICES = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
1161
1293
|
var FLAG_SPECS = [
|
|
1162
1294
|
/* ---- Output ---------------------------------------------------------- */
|
|
1163
1295
|
{
|
|
@@ -1246,6 +1378,18 @@ var FLAG_SPECS = [
|
|
|
1246
1378
|
group: "context",
|
|
1247
1379
|
describe: "Continue the most recent session in this directory."
|
|
1248
1380
|
},
|
|
1381
|
+
{
|
|
1382
|
+
name: "--trust-project-addons",
|
|
1383
|
+
kind: "boolean",
|
|
1384
|
+
group: "context",
|
|
1385
|
+
describe: "Trust executable project addons for the canonical workspace and their current content digest."
|
|
1386
|
+
},
|
|
1387
|
+
{
|
|
1388
|
+
name: "--allow-context-import",
|
|
1389
|
+
kind: "list",
|
|
1390
|
+
group: "context",
|
|
1391
|
+
describe: "Explicitly approve an exact external context file (comma-separated or repeated). Secret-like files remain blocked."
|
|
1392
|
+
},
|
|
1249
1393
|
/* ---- Tools ----------------------------------------------------------- */
|
|
1250
1394
|
{
|
|
1251
1395
|
name: "--tools",
|
|
@@ -1330,6 +1474,150 @@ var FLAG_SPECS = [
|
|
|
1330
1474
|
}
|
|
1331
1475
|
];
|
|
1332
1476
|
|
|
1477
|
+
// src/models.ts
|
|
1478
|
+
import { ModelRegistry } from "indusagi/ai";
|
|
1479
|
+
var GPT_6_ASTRA_BASE = {
|
|
1480
|
+
id: "gpt-6-astra",
|
|
1481
|
+
name: "GPT-6 Astra",
|
|
1482
|
+
api: "openai-responses",
|
|
1483
|
+
reasoning: true,
|
|
1484
|
+
reasoningEfforts: ["low", "medium", "high", "xhigh", "max"],
|
|
1485
|
+
input: ["text", "image"],
|
|
1486
|
+
cost: {
|
|
1487
|
+
input: 10,
|
|
1488
|
+
cacheRead: 1,
|
|
1489
|
+
cacheWrite: 12.5,
|
|
1490
|
+
output: 50
|
|
1491
|
+
},
|
|
1492
|
+
contextWindow: 105e4,
|
|
1493
|
+
maxTokens: 128e3,
|
|
1494
|
+
longContextPricing: {
|
|
1495
|
+
threshold: 272e3,
|
|
1496
|
+
multipliers: {
|
|
1497
|
+
input: 2,
|
|
1498
|
+
cacheRead: 2,
|
|
1499
|
+
cacheWrite: 2,
|
|
1500
|
+
output: 1.5
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
};
|
|
1504
|
+
var GPT_6_SOL_BASE = {
|
|
1505
|
+
id: "gpt-6-sol",
|
|
1506
|
+
name: "GPT-6 Sol",
|
|
1507
|
+
api: "openai-responses",
|
|
1508
|
+
reasoning: true,
|
|
1509
|
+
reasoningEfforts: ["high"],
|
|
1510
|
+
input: ["text", "image"],
|
|
1511
|
+
cost: {
|
|
1512
|
+
input: 10,
|
|
1513
|
+
cacheRead: 1,
|
|
1514
|
+
cacheWrite: 12.5,
|
|
1515
|
+
output: 50
|
|
1516
|
+
},
|
|
1517
|
+
contextWindow: 105e4,
|
|
1518
|
+
maxTokens: 128e3,
|
|
1519
|
+
longContextPricing: {
|
|
1520
|
+
threshold: 272e3,
|
|
1521
|
+
multipliers: {
|
|
1522
|
+
input: 2,
|
|
1523
|
+
cacheRead: 2,
|
|
1524
|
+
cacheWrite: 2,
|
|
1525
|
+
output: 1.5
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
};
|
|
1529
|
+
var GPT_6_LUNA_BASE = {
|
|
1530
|
+
id: "gpt-6-luna",
|
|
1531
|
+
name: "GPT-6 Luna",
|
|
1532
|
+
api: "openai-responses",
|
|
1533
|
+
reasoning: true,
|
|
1534
|
+
reasoningEfforts: ["low", "medium", "high", "xhigh", "max"],
|
|
1535
|
+
input: ["text", "image"],
|
|
1536
|
+
cost: {
|
|
1537
|
+
input: 0.1,
|
|
1538
|
+
cacheRead: 0.01,
|
|
1539
|
+
cacheWrite: 0.125,
|
|
1540
|
+
output: 0.5
|
|
1541
|
+
},
|
|
1542
|
+
contextWindow: 105e4,
|
|
1543
|
+
maxTokens: 128e3,
|
|
1544
|
+
longContextPricing: {
|
|
1545
|
+
threshold: 272e3,
|
|
1546
|
+
multipliers: { input: 2, cacheRead: 2, cacheWrite: 2, output: 1.5 }
|
|
1547
|
+
}
|
|
1548
|
+
};
|
|
1549
|
+
var CODING_AGENT_MODELS = [
|
|
1550
|
+
{
|
|
1551
|
+
...GPT_6_SOL_BASE,
|
|
1552
|
+
provider: "openai",
|
|
1553
|
+
baseUrl: "https://api.openai.com/v1"
|
|
1554
|
+
},
|
|
1555
|
+
{
|
|
1556
|
+
...GPT_6_SOL_BASE,
|
|
1557
|
+
api: "openai-codex-responses",
|
|
1558
|
+
provider: "openai-codex",
|
|
1559
|
+
baseUrl: "https://chatgpt.com/backend-api"
|
|
1560
|
+
},
|
|
1561
|
+
{
|
|
1562
|
+
...GPT_6_LUNA_BASE,
|
|
1563
|
+
provider: "openai",
|
|
1564
|
+
baseUrl: "https://api.openai.com/v1"
|
|
1565
|
+
},
|
|
1566
|
+
{
|
|
1567
|
+
...GPT_6_LUNA_BASE,
|
|
1568
|
+
api: "openai-codex-responses",
|
|
1569
|
+
provider: "openai-codex",
|
|
1570
|
+
baseUrl: "https://chatgpt.com/backend-api"
|
|
1571
|
+
},
|
|
1572
|
+
{
|
|
1573
|
+
...GPT_6_ASTRA_BASE,
|
|
1574
|
+
provider: "openai",
|
|
1575
|
+
baseUrl: "https://api.openai.com/v1"
|
|
1576
|
+
},
|
|
1577
|
+
{
|
|
1578
|
+
...GPT_6_ASTRA_BASE,
|
|
1579
|
+
api: "openai-codex-responses",
|
|
1580
|
+
provider: "openai-codex",
|
|
1581
|
+
baseUrl: "https://chatgpt.com/backend-api"
|
|
1582
|
+
},
|
|
1583
|
+
{
|
|
1584
|
+
...GPT_6_ASTRA_BASE,
|
|
1585
|
+
provider: "codex-cli",
|
|
1586
|
+
baseUrl: "bridge:codex-cli"
|
|
1587
|
+
},
|
|
1588
|
+
{
|
|
1589
|
+
...GPT_6_ASTRA_BASE,
|
|
1590
|
+
id: "openai/gpt-6-astra",
|
|
1591
|
+
provider: "indusagi-cli",
|
|
1592
|
+
baseUrl: "bridge:indusagi-cli"
|
|
1593
|
+
},
|
|
1594
|
+
{
|
|
1595
|
+
...GPT_6_ASTRA_BASE,
|
|
1596
|
+
id: "openai-codex/gpt-6-astra",
|
|
1597
|
+
api: "openai-codex-responses",
|
|
1598
|
+
provider: "indusagi-cli",
|
|
1599
|
+
baseUrl: "bridge:indusagi-cli"
|
|
1600
|
+
}
|
|
1601
|
+
];
|
|
1602
|
+
function applyCodingAgentModelOverlay(registry) {
|
|
1603
|
+
for (const model of CODING_AGENT_MODELS) registry.registerCustomModel(model);
|
|
1604
|
+
return registry;
|
|
1605
|
+
}
|
|
1606
|
+
function createCodingAgentModelRegistry() {
|
|
1607
|
+
return applyCodingAgentModelOverlay(new ModelRegistry());
|
|
1608
|
+
}
|
|
1609
|
+
function isReasoningEffortSupported(modelId, effort) {
|
|
1610
|
+
const id = modelId?.split("/").at(-1);
|
|
1611
|
+
if (id === "gpt-6-astra") {
|
|
1612
|
+
return GPT_6_ASTRA_BASE.reasoningEfforts.includes(effort);
|
|
1613
|
+
}
|
|
1614
|
+
if (id === "gpt-6-sol") return effort === "high";
|
|
1615
|
+
if (id === "gpt-6-luna") {
|
|
1616
|
+
return GPT_6_LUNA_BASE.reasoningEfforts.includes(effort);
|
|
1617
|
+
}
|
|
1618
|
+
return true;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1333
1621
|
// src/launch/invocation/read.ts
|
|
1334
1622
|
function isFlagToken(token) {
|
|
1335
1623
|
return token.length > 1 && token.startsWith("-");
|
|
@@ -1445,9 +1733,9 @@ function deriveMode(flags) {
|
|
|
1445
1733
|
if (readBool(flags, "json")) return "rpc";
|
|
1446
1734
|
return "text";
|
|
1447
1735
|
}
|
|
1448
|
-
function resolveThinking(flags) {
|
|
1736
|
+
function resolveThinking(flags, modelId) {
|
|
1449
1737
|
const raw = readString(flags, "thinking");
|
|
1450
|
-
return raw !== void 0 && isThinkingEffort(raw) ? raw : void 0;
|
|
1738
|
+
return raw !== void 0 && isThinkingEffort(raw) && isReasoningEffortSupported(modelId, raw) ? raw : void 0;
|
|
1451
1739
|
}
|
|
1452
1740
|
function resolveTools(flags) {
|
|
1453
1741
|
const raw = readList(flags, "tools");
|
|
@@ -1496,7 +1784,7 @@ function readInvocation(argv2) {
|
|
|
1496
1784
|
const cwd = readString(flags, "cwd");
|
|
1497
1785
|
const system = readString(flags, "system");
|
|
1498
1786
|
const appendSystem = readString(flags, "append-system");
|
|
1499
|
-
const thinking = resolveThinking(flags);
|
|
1787
|
+
const thinking = resolveThinking(flags, model);
|
|
1500
1788
|
const tools = resolveTools(flags);
|
|
1501
1789
|
return {
|
|
1502
1790
|
mode,
|
|
@@ -1580,7 +1868,7 @@ var MAX_TEXT_BYTES = 10 * 1024 * 1024;
|
|
|
1580
1868
|
var MAX_IMAGE_BYTES = 20 * 1024 * 1024;
|
|
1581
1869
|
|
|
1582
1870
|
// src/launch/catalog.ts
|
|
1583
|
-
import { ModelRegistry } from "indusagi/ai";
|
|
1871
|
+
import { ModelRegistry as ModelRegistry2 } from "indusagi/ai";
|
|
1584
1872
|
function defaultCatalogIo() {
|
|
1585
1873
|
return {
|
|
1586
1874
|
print(line) {
|
|
@@ -1589,10 +1877,11 @@ function defaultCatalogIo() {
|
|
|
1589
1877
|
}
|
|
1590
1878
|
};
|
|
1591
1879
|
}
|
|
1592
|
-
function registrySource(registry = new
|
|
1880
|
+
function registrySource(registry = new ModelRegistry2()) {
|
|
1881
|
+
const overlaid = applyCodingAgentModelOverlay(registry);
|
|
1593
1882
|
return {
|
|
1594
|
-
providers: () =>
|
|
1595
|
-
models: (provider) =>
|
|
1883
|
+
providers: () => overlaid.getProviders(),
|
|
1884
|
+
models: (provider) => overlaid.getModels(provider)
|
|
1596
1885
|
};
|
|
1597
1886
|
}
|
|
1598
1887
|
var HEADERS = [
|
|
@@ -1699,13 +1988,13 @@ function defaultResumeDeps() {
|
|
|
1699
1988
|
},
|
|
1700
1989
|
mountPicker(sessions, totalCount) {
|
|
1701
1990
|
const byPath = new Map(sessions.map((s) => [s.path, s]));
|
|
1702
|
-
return new Promise((
|
|
1991
|
+
return new Promise((resolve11, reject) => {
|
|
1703
1992
|
let settled = false;
|
|
1704
1993
|
const settle = (value) => {
|
|
1705
1994
|
if (settled) return;
|
|
1706
1995
|
settled = true;
|
|
1707
1996
|
instance.unmount();
|
|
1708
|
-
|
|
1997
|
+
resolve11(value);
|
|
1709
1998
|
};
|
|
1710
1999
|
let instance;
|
|
1711
2000
|
try {
|
|
@@ -1724,7 +2013,7 @@ function defaultResumeDeps() {
|
|
|
1724
2013
|
void instance.waitUntilExit().then(() => {
|
|
1725
2014
|
if (!settled) {
|
|
1726
2015
|
settled = true;
|
|
1727
|
-
|
|
2016
|
+
resolve11(null);
|
|
1728
2017
|
}
|
|
1729
2018
|
});
|
|
1730
2019
|
});
|
|
@@ -1829,7 +2118,7 @@ import { join as join2 } from "node:path";
|
|
|
1829
2118
|
|
|
1830
2119
|
// src/boot/upgrade/upgrades.ts
|
|
1831
2120
|
import { promises as fs, constants as fsConstants } from "node:fs";
|
|
1832
|
-
import { join, dirname, basename } from "node:path";
|
|
2121
|
+
import { join, dirname as dirname2, basename } from "node:path";
|
|
1833
2122
|
var SECURE_FILE_MODE = 384;
|
|
1834
2123
|
var RETIRED_SUFFIX = ".retired";
|
|
1835
2124
|
async function pathExists(target) {
|
|
@@ -1862,7 +2151,7 @@ async function readJsonOrUndefined(target) {
|
|
|
1862
2151
|
}
|
|
1863
2152
|
}
|
|
1864
2153
|
async function writeJsonWithMode(target, value, mode) {
|
|
1865
|
-
await fs.mkdir(
|
|
2154
|
+
await fs.mkdir(dirname2(target), { recursive: true });
|
|
1866
2155
|
await fs.writeFile(target, `${JSON.stringify(value, null, 2)}
|
|
1867
2156
|
`, { mode });
|
|
1868
2157
|
await fs.chmod(target, mode);
|
|
@@ -1870,7 +2159,7 @@ async function writeJsonWithMode(target, value, mode) {
|
|
|
1870
2159
|
async function relocateWithoutClobber(from, into) {
|
|
1871
2160
|
if (!await pathExists(from)) return false;
|
|
1872
2161
|
if (await pathExists(into)) return false;
|
|
1873
|
-
await fs.mkdir(
|
|
2162
|
+
await fs.mkdir(dirname2(into), { recursive: true });
|
|
1874
2163
|
await fs.rename(from, into);
|
|
1875
2164
|
return true;
|
|
1876
2165
|
}
|
|
@@ -2027,7 +2316,6 @@ async function applyUpgrades(ws) {
|
|
|
2027
2316
|
}
|
|
2028
2317
|
|
|
2029
2318
|
// src/workspace/locator.ts
|
|
2030
|
-
import { mkdirSync } from "node:fs";
|
|
2031
2319
|
import { homedir } from "node:os";
|
|
2032
2320
|
import { isAbsolute, join as join3, resolve } from "node:path";
|
|
2033
2321
|
var LAYOUT = {
|
|
@@ -2091,7 +2379,7 @@ function createWorkspace(overrides = {}) {
|
|
|
2091
2379
|
}
|
|
2092
2380
|
function ensureDirs(workspace) {
|
|
2093
2381
|
for (const key of DIRECTORY_KEYS) {
|
|
2094
|
-
|
|
2382
|
+
ensurePrivateDirectorySync(workspace[key]);
|
|
2095
2383
|
}
|
|
2096
2384
|
return workspace;
|
|
2097
2385
|
}
|
|
@@ -2139,11 +2427,7 @@ async function loadDefaultSettings() {
|
|
|
2139
2427
|
}
|
|
2140
2428
|
}
|
|
2141
2429
|
async function loadModelRegistry() {
|
|
2142
|
-
|
|
2143
|
-
if (typeof mod.ModelRegistry === "function") {
|
|
2144
|
-
return new mod.ModelRegistry();
|
|
2145
|
-
}
|
|
2146
|
-
return mod.modelRegistry;
|
|
2430
|
+
return createCodingAgentModelRegistry();
|
|
2147
2431
|
}
|
|
2148
2432
|
var selectRunnerStage = {
|
|
2149
2433
|
name: "select-runner",
|
|
@@ -2192,6 +2476,30 @@ var EMPTY_CONSOLE_STATE = {
|
|
|
2192
2476
|
tick: 0
|
|
2193
2477
|
};
|
|
2194
2478
|
|
|
2479
|
+
// src/console/input/graphemes.ts
|
|
2480
|
+
var segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
2481
|
+
function previousGrapheme(text, at) {
|
|
2482
|
+
let previous = 0;
|
|
2483
|
+
for (const part of segmenter.segment(text)) {
|
|
2484
|
+
if (part.index >= at) break;
|
|
2485
|
+
previous = part.index;
|
|
2486
|
+
}
|
|
2487
|
+
return previous;
|
|
2488
|
+
}
|
|
2489
|
+
function nextGrapheme(text, at) {
|
|
2490
|
+
for (const part of segmenter.segment(text)) if (part.index > at) return part.index;
|
|
2491
|
+
return text.length;
|
|
2492
|
+
}
|
|
2493
|
+
function moveGrapheme(text, at, delta) {
|
|
2494
|
+
let next = Math.max(0, Math.min(at, text.length));
|
|
2495
|
+
for (let i = 0; i < Math.abs(delta); i++) next = delta < 0 ? previousGrapheme(text, next) : nextGrapheme(text, next);
|
|
2496
|
+
return next;
|
|
2497
|
+
}
|
|
2498
|
+
function snapGrapheme(text, at) {
|
|
2499
|
+
const clamped = Math.max(0, Math.min(at, text.length));
|
|
2500
|
+
return clamped === text.length ? clamped : previousGrapheme(text, clamped + 1);
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2195
2503
|
// src/console/reducer.ts
|
|
2196
2504
|
function clamp(offset, max) {
|
|
2197
2505
|
if (offset < 0) return 0;
|
|
@@ -2215,13 +2523,14 @@ function insertBuffer(state, text) {
|
|
|
2215
2523
|
function erasePrev(state) {
|
|
2216
2524
|
const at = clamp(state.caret, state.buffer.length);
|
|
2217
2525
|
if (at === 0) return state;
|
|
2218
|
-
const
|
|
2219
|
-
|
|
2526
|
+
const previous = previousGrapheme(state.buffer, at);
|
|
2527
|
+
const next = state.buffer.slice(0, previous) + state.buffer.slice(at);
|
|
2528
|
+
return withBuffer(state, next, previous);
|
|
2220
2529
|
}
|
|
2221
2530
|
function eraseNext(state) {
|
|
2222
2531
|
const at = clamp(state.caret, state.buffer.length);
|
|
2223
2532
|
if (at >= state.buffer.length) return state;
|
|
2224
|
-
const next = state.buffer.slice(0, at) + state.buffer.slice(at
|
|
2533
|
+
const next = state.buffer.slice(0, at) + state.buffer.slice(nextGrapheme(state.buffer, at));
|
|
2225
2534
|
return withBuffer(state, next, at);
|
|
2226
2535
|
}
|
|
2227
2536
|
function pushHistory(state, text) {
|
|
@@ -2264,6 +2573,10 @@ function patchRow(state, id, text) {
|
|
|
2264
2573
|
}
|
|
2265
2574
|
function consoleReducer(state, event) {
|
|
2266
2575
|
switch (event.type) {
|
|
2576
|
+
case "view:reset":
|
|
2577
|
+
return { ...state, rows: [], blocks: [], buffer: "", caret: 0, historyAt: null, stash: "", modal: NO_MODAL, busy: false };
|
|
2578
|
+
case "display:set":
|
|
2579
|
+
return { ...state, [event.key]: event.value };
|
|
2267
2580
|
// Composer buffer & caret
|
|
2268
2581
|
case "buffer:set":
|
|
2269
2582
|
return setBuffer(state, event.text);
|
|
@@ -2282,9 +2595,9 @@ function consoleReducer(state, event) {
|
|
|
2282
2595
|
case "buffer:eraseNext":
|
|
2283
2596
|
return eraseNext(state);
|
|
2284
2597
|
case "caret:move":
|
|
2285
|
-
return { ...state, caret:
|
|
2598
|
+
return { ...state, caret: moveGrapheme(state.buffer, state.caret, event.delta) };
|
|
2286
2599
|
case "caret:jump":
|
|
2287
|
-
return { ...state, caret:
|
|
2600
|
+
return { ...state, caret: snapGrapheme(state.buffer, event.offset) };
|
|
2288
2601
|
// History ring
|
|
2289
2602
|
case "history:push":
|
|
2290
2603
|
return pushHistory(state, event.text);
|
|
@@ -2514,7 +2827,7 @@ function resolveTheme(scheme) {
|
|
|
2514
2827
|
var THEME_SCHEMES = Object.keys(THEMES);
|
|
2515
2828
|
|
|
2516
2829
|
// src/console/slash/builtins.ts
|
|
2517
|
-
import { homedir as
|
|
2830
|
+
import { homedir as homedir2 } from "node:os";
|
|
2518
2831
|
import { join as join12 } from "node:path";
|
|
2519
2832
|
|
|
2520
2833
|
// src/briefing/contract.ts
|
|
@@ -2699,7 +3012,7 @@ function composeBriefing(input) {
|
|
|
2699
3012
|
}
|
|
2700
3013
|
|
|
2701
3014
|
// src/briefing/macros.ts
|
|
2702
|
-
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
3015
|
+
import { readFileSync as readFileSync2, readdirSync, statSync } from "node:fs";
|
|
2703
3016
|
import { basename as basename2, join as join4 } from "node:path";
|
|
2704
3017
|
var decimal = (ch) => ch.charCodeAt(0) >= 48 && ch.charCodeAt(0) <= 57;
|
|
2705
3018
|
var bareword = (ch) => {
|
|
@@ -2911,13 +3224,13 @@ function loadMacros(dir, opts = {}) {
|
|
|
2911
3224
|
const macros = [];
|
|
2912
3225
|
for (const entry of entries.sort()) {
|
|
2913
3226
|
if (entry.startsWith(".") || !entry.toLowerCase().endsWith(".md")) continue;
|
|
2914
|
-
const
|
|
3227
|
+
const path5 = join4(dir, entry);
|
|
2915
3228
|
try {
|
|
2916
|
-
if (!statSync(
|
|
3229
|
+
if (!statSync(path5).isFile()) continue;
|
|
2917
3230
|
} catch {
|
|
2918
3231
|
continue;
|
|
2919
3232
|
}
|
|
2920
|
-
const macro = readMacroFile(
|
|
3233
|
+
const macro = readMacroFile(path5, origin, label);
|
|
2921
3234
|
if (!seen.has(macro.name)) {
|
|
2922
3235
|
seen.add(macro.name);
|
|
2923
3236
|
macros.push(macro);
|
|
@@ -2925,17 +3238,17 @@ function loadMacros(dir, opts = {}) {
|
|
|
2925
3238
|
}
|
|
2926
3239
|
return macros;
|
|
2927
3240
|
}
|
|
2928
|
-
function readMacroFile(
|
|
3241
|
+
function readMacroFile(path5, origin, label) {
|
|
2929
3242
|
let text;
|
|
2930
3243
|
try {
|
|
2931
|
-
text =
|
|
3244
|
+
text = readFileSync2(path5, "utf8");
|
|
2932
3245
|
} catch (cause) {
|
|
2933
|
-
throw briefingFault("macro_invalid", `could not read macro file at ${
|
|
3246
|
+
throw briefingFault("macro_invalid", `could not read macro file at ${path5}`, cause);
|
|
2934
3247
|
}
|
|
2935
3248
|
const { frontmatter, body } = splitFrontmatter(text);
|
|
2936
|
-
const name = basename2(
|
|
3249
|
+
const name = basename2(path5).replace(/\.md$/i, "");
|
|
2937
3250
|
const declared = typeof frontmatter.description === "string" ? frontmatter.description.trim() : "";
|
|
2938
|
-
return { name, description: declared ? `${declared} (${label})` : deriveDescription(body, label), body, origin, source:
|
|
3251
|
+
return { name, description: declared ? `${declared} (${label})` : deriveDescription(body, label), body, origin, source: path5 };
|
|
2939
3252
|
}
|
|
2940
3253
|
function deriveDescription(body, label) {
|
|
2941
3254
|
const first = body.split("\n").find((line) => line.trim())?.trim() ?? "";
|
|
@@ -2961,8 +3274,8 @@ function unquoteScalar(value) {
|
|
|
2961
3274
|
}
|
|
2962
3275
|
|
|
2963
3276
|
// src/briefing/skills.ts
|
|
2964
|
-
import { readFileSync as
|
|
2965
|
-
import { basename as basename3, dirname as
|
|
3277
|
+
import { readFileSync as readFileSync3, readdirSync as readdirSync2, realpathSync, statSync as statSync2 } from "node:fs";
|
|
3278
|
+
import { basename as basename3, dirname as dirname3, join as join5 } from "node:path";
|
|
2966
3279
|
var SKILL_MANIFEST = "SKILL.md";
|
|
2967
3280
|
var PRUNED_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git"]);
|
|
2968
3281
|
var KNOWN_FRONTMATTER_KEYS = /* @__PURE__ */ new Set(["name", "description", "license", "compatibility", "metadata", "allowed-tools", "disable-model-invocation"]);
|
|
@@ -2997,7 +3310,7 @@ function* walkLevel(dir, atRoot, seen) {
|
|
|
2997
3310
|
seen.add(real);
|
|
2998
3311
|
yield* walkLevel(full, false, seen);
|
|
2999
3312
|
}
|
|
3000
|
-
} else if (stats.isFile() && (atRoot && entry.toLowerCase().endsWith(".md") || !atRoot && entry === SKILL_MANIFEST)) yield { path: full, dirName: basename3(
|
|
3313
|
+
} else if (stats.isFile() && (atRoot && entry.toLowerCase().endsWith(".md") || !atRoot && entry === SKILL_MANIFEST)) yield { path: full, dirName: basename3(dirname3(full)) };
|
|
3001
3314
|
}
|
|
3002
3315
|
}
|
|
3003
3316
|
function checkName(name, dirName, fromDir) {
|
|
@@ -3036,7 +3349,7 @@ function describeCause(cause) {
|
|
|
3036
3349
|
function parseCandidate(candidate, origin) {
|
|
3037
3350
|
let text;
|
|
3038
3351
|
try {
|
|
3039
|
-
text =
|
|
3352
|
+
text = readFileSync3(candidate.path, "utf8");
|
|
3040
3353
|
} catch (cause) {
|
|
3041
3354
|
return { card: null, diagnostic: diag("invalid", candidate.path, `could not read the skill file (${describeCause(cause)})`) };
|
|
3042
3355
|
}
|
|
@@ -3087,49 +3400,52 @@ function modelInvocableCards(cards) {
|
|
|
3087
3400
|
}
|
|
3088
3401
|
|
|
3089
3402
|
// src/briefing/context-docs.ts
|
|
3090
|
-
import {
|
|
3091
|
-
import { dirname as
|
|
3403
|
+
import { closeSync as closeSync2, constants as constants2, fstatSync as fstatSync2, lstatSync as lstatSync2, openSync as openSync2, readFileSync as readFileSync4, realpathSync as realpathSync2 } from "node:fs";
|
|
3404
|
+
import { basename as basename4, dirname as dirname4, extname, isAbsolute as isAbsolute2, join as join6, parse, resolve as resolve2, sep } from "node:path";
|
|
3092
3405
|
var DEFAULT_MAX_IMPORT_DEPTH = 5;
|
|
3093
3406
|
var DEFAULT_MAX_BYTES_PER_DOC = 4e4;
|
|
3094
3407
|
var CANDIDATE_FILES = ["AGENTS.md", "CLAUDE.md", "INDUSAGI.md", "CLAUDE.local.md", "AGENTS.local.md", join6(".indusagi", "CLAUDE.md"), join6(".claude", "CLAUDE.md")];
|
|
3095
|
-
var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".markdown", ".txt", ".text", ".json", ".jsonc", ".yaml", ".yml", ".toml", ".xml", ".csv", ".html", ".htm", ".css", ".js", ".ts", ".tsx", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".py", ".rb", ".go", ".rs", ".sh"
|
|
3408
|
+
var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".md", ".markdown", ".txt", ".text", ".json", ".jsonc", ".yaml", ".yml", ".toml", ".xml", ".csv", ".html", ".htm", ".css", ".js", ".ts", ".tsx", ".jsx", ".mjs", ".cjs", ".mts", ".cts", ".py", ".rb", ".go", ".rs", ".sh"]);
|
|
3096
3409
|
var IMPORT_REGEX = /(?:^|\s)@((?:[^\s\\]|\\ )+)/g;
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3410
|
+
var NO_FOLLOW2 = constants2.O_NOFOLLOW ?? 0;
|
|
3411
|
+
var SECRET_BASENAMES = /* @__PURE__ */ new Set([
|
|
3412
|
+
".env",
|
|
3413
|
+
"credentials",
|
|
3414
|
+
"credentials.json",
|
|
3415
|
+
"id_rsa",
|
|
3416
|
+
"id_dsa",
|
|
3417
|
+
"id_ecdsa",
|
|
3418
|
+
"id_ed25519"
|
|
3419
|
+
]);
|
|
3420
|
+
var SECRET_EXTENSIONS = /* @__PURE__ */ new Set([".key", ".pem", ".p12", ".pfx"]);
|
|
3421
|
+
function shortenPath(path5, cwd, home) {
|
|
3422
|
+
if (cwd && (path5 === cwd || path5.startsWith(`${cwd}${sep}`))) {
|
|
3423
|
+
const rest = path5.slice(cwd.length).replace(/^[/\\]+/, "");
|
|
3100
3424
|
return rest ? `./${rest}` : ".";
|
|
3101
3425
|
}
|
|
3102
|
-
return home &&
|
|
3103
|
-
}
|
|
3104
|
-
function dirChain(cwd) {
|
|
3105
|
-
const chain = [];
|
|
3106
|
-
let current = cwd;
|
|
3107
|
-
for (let i = 0; i < 256; i++) {
|
|
3108
|
-
chain.push(current);
|
|
3109
|
-
const parent = dirname3(current);
|
|
3110
|
-
if (parent === current || current === parse(current).root) break;
|
|
3111
|
-
current = parent;
|
|
3112
|
-
}
|
|
3113
|
-
return chain.reverse();
|
|
3114
|
-
}
|
|
3115
|
-
function safeRealpath(path4) {
|
|
3116
|
-
try {
|
|
3117
|
-
return realpathSync2(path4);
|
|
3118
|
-
} catch {
|
|
3119
|
-
return path4;
|
|
3120
|
-
}
|
|
3426
|
+
return home && (path5 === home || path5.startsWith(`${home}${sep}`)) ? `~${path5.slice(home.length)}` : path5;
|
|
3121
3427
|
}
|
|
3122
|
-
function isTextFile(
|
|
3123
|
-
const extension = extname(
|
|
3428
|
+
function isTextFile(path5) {
|
|
3429
|
+
const extension = extname(path5).toLowerCase();
|
|
3124
3430
|
return !extension || TEXT_FILE_EXTENSIONS.has(extension);
|
|
3125
3431
|
}
|
|
3126
|
-
function
|
|
3127
|
-
|
|
3432
|
+
function isLikelySecretFile(path5) {
|
|
3433
|
+
const name = basename4(path5).toLowerCase();
|
|
3434
|
+
return SECRET_BASENAMES.has(name) || name.startsWith(".env.") || SECRET_EXTENSIONS.has(extname(name));
|
|
3435
|
+
}
|
|
3436
|
+
function readFileBody(path5) {
|
|
3437
|
+
let fd;
|
|
3128
3438
|
try {
|
|
3129
|
-
const
|
|
3439
|
+
const before = lstatSync2(path5);
|
|
3440
|
+
if (before.isSymbolicLink() || !before.isFile()) return null;
|
|
3441
|
+
fd = openSync2(path5, constants2.O_RDONLY | NO_FOLLOW2);
|
|
3442
|
+
if (!fstatSync2(fd).isFile()) return null;
|
|
3443
|
+
const body = readFileSync4(fd, "utf8").trim();
|
|
3130
3444
|
return body || null;
|
|
3131
3445
|
} catch {
|
|
3132
3446
|
return null;
|
|
3447
|
+
} finally {
|
|
3448
|
+
if (fd !== void 0) closeSync2(fd);
|
|
3133
3449
|
}
|
|
3134
3450
|
}
|
|
3135
3451
|
function extractImports(body, baseDir, home) {
|
|
@@ -3148,23 +3464,46 @@ function extractImports(body, baseDir, home) {
|
|
|
3148
3464
|
}
|
|
3149
3465
|
return out2;
|
|
3150
3466
|
}
|
|
3151
|
-
function
|
|
3152
|
-
|
|
3153
|
-
|
|
3467
|
+
function canonicalExistingFile(path5) {
|
|
3468
|
+
try {
|
|
3469
|
+
const before = lstatSync2(path5);
|
|
3470
|
+
if (before.isSymbolicLink() || !before.isFile()) return null;
|
|
3471
|
+
return realpathSync2(path5);
|
|
3472
|
+
} catch {
|
|
3473
|
+
return null;
|
|
3474
|
+
}
|
|
3475
|
+
}
|
|
3476
|
+
function isWithin(root, candidate) {
|
|
3477
|
+
return candidate === root || candidate.startsWith(`${root}${sep}`);
|
|
3478
|
+
}
|
|
3479
|
+
function loadTrustedDocTree(path5, cwd, home, seen, depth, maxDepth, maxBytes, out2, policy) {
|
|
3480
|
+
if (isLikelySecretFile(path5)) return;
|
|
3481
|
+
const real = canonicalExistingFile(path5);
|
|
3482
|
+
if (real === null || seen.has(real) || isLikelySecretFile(real)) return;
|
|
3483
|
+
if (!isWithin(policy.root, real) && !policy.approvedExternal.has(real)) return;
|
|
3154
3484
|
seen.add(real);
|
|
3155
|
-
const body = readFileBody(
|
|
3485
|
+
const body = readFileBody(real);
|
|
3156
3486
|
if (body === null) return;
|
|
3157
|
-
out2.push({ path: shortenPath(
|
|
3487
|
+
out2.push({ path: shortenPath(real, cwd, home), body: body.length > maxBytes ? body.slice(0, maxBytes) : body });
|
|
3158
3488
|
if (depth >= maxDepth) return;
|
|
3159
|
-
for (const child of extractImports(body,
|
|
3489
|
+
for (const child of extractImports(body, dirname4(real), home)) {
|
|
3490
|
+
loadTrustedDocTree(child, cwd, home, seen, depth + 1, maxDepth, maxBytes, out2, policy);
|
|
3491
|
+
}
|
|
3160
3492
|
}
|
|
3161
|
-
function gatherContextDocs(cwd, home, opts) {
|
|
3493
|
+
function gatherContextDocs(cwd, home, opts = {}) {
|
|
3162
3494
|
const out2 = [];
|
|
3163
3495
|
try {
|
|
3496
|
+
const root = realpathSync2(cwd);
|
|
3497
|
+
const approvedExternal = /* @__PURE__ */ new Set();
|
|
3498
|
+
for (const path5 of opts.approvedExternalPaths ?? []) {
|
|
3499
|
+
const real = canonicalExistingFile(path5);
|
|
3500
|
+
if (real !== null && !isLikelySecretFile(real)) approvedExternal.add(real);
|
|
3501
|
+
}
|
|
3502
|
+
const policy = { root, approvedExternal };
|
|
3164
3503
|
const seen = /* @__PURE__ */ new Set();
|
|
3165
|
-
const
|
|
3166
|
-
|
|
3167
|
-
|
|
3504
|
+
for (const name of CANDIDATE_FILES) {
|
|
3505
|
+
loadTrustedDocTree(join6(root, name), root, home, seen, 0, opts.maxImportDepth ?? DEFAULT_MAX_IMPORT_DEPTH, opts.maxBytesPerDoc ?? DEFAULT_MAX_BYTES_PER_DOC, out2, policy);
|
|
3506
|
+
}
|
|
3168
3507
|
} catch {
|
|
3169
3508
|
return out2;
|
|
3170
3509
|
}
|
|
@@ -3277,9 +3616,9 @@ function buildDynamicCommands(sources = {}) {
|
|
|
3277
3616
|
|
|
3278
3617
|
// src/console/slash/commands/integrations.ts
|
|
3279
3618
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
3280
|
-
import {
|
|
3281
|
-
import {
|
|
3282
|
-
import {
|
|
3619
|
+
import { getEnvApiKey as getEnvApiKey2 } from "indusagi/ai";
|
|
3620
|
+
import { writeFileSync as writeFileSync4 } from "node:fs";
|
|
3621
|
+
import { resolve as resolve5 } from "node:path";
|
|
3283
3622
|
import { createMCPAgentToolFactory, loadMCPConfig, MCPClientPool } from "indusagi/mcp";
|
|
3284
3623
|
import { createComposioGateway } from "indusagi/connectors-saas";
|
|
3285
3624
|
|
|
@@ -4399,14 +4738,14 @@ var DaemonTable = class {
|
|
|
4399
4738
|
if (handle.state !== "running") return;
|
|
4400
4739
|
const child = handle.child;
|
|
4401
4740
|
child.kill("SIGTERM");
|
|
4402
|
-
await new Promise((
|
|
4741
|
+
await new Promise((resolve11) => {
|
|
4403
4742
|
const timer = setTimeout(() => {
|
|
4404
4743
|
if (handle.state === "running") child.kill("SIGKILL");
|
|
4405
|
-
|
|
4744
|
+
resolve11();
|
|
4406
4745
|
}, graceMs);
|
|
4407
4746
|
child.once("exit", () => {
|
|
4408
4747
|
clearTimeout(timer);
|
|
4409
|
-
|
|
4748
|
+
resolve11();
|
|
4410
4749
|
});
|
|
4411
4750
|
});
|
|
4412
4751
|
}
|
|
@@ -5150,7 +5489,7 @@ function createLimiter(limit) {
|
|
|
5150
5489
|
queue.shift()?.();
|
|
5151
5490
|
};
|
|
5152
5491
|
return async (fn) => {
|
|
5153
|
-
if (active >= limit) await new Promise((
|
|
5492
|
+
if (active >= limit) await new Promise((resolve11) => queue.push(resolve11));
|
|
5154
5493
|
active++;
|
|
5155
5494
|
try {
|
|
5156
5495
|
return await fn();
|
|
@@ -5216,9 +5555,59 @@ import { Agent } from "indusagi/agent";
|
|
|
5216
5555
|
import { createZeroUsage as createZeroUsage2 } from "indusagi/ai";
|
|
5217
5556
|
import * as path3 from "node:path";
|
|
5218
5557
|
|
|
5558
|
+
// src/kit/run-shell.ts
|
|
5559
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
5560
|
+
function runShell(command, cwd, signal) {
|
|
5561
|
+
if (signal?.aborted) return Promise.resolve({ output: "Command cancelled.", exitCode: 130 });
|
|
5562
|
+
return new Promise((resolve11) => {
|
|
5563
|
+
let output = "", truncated = false, settled = false;
|
|
5564
|
+
let forceKill;
|
|
5565
|
+
const child = spawn3(command, { cwd, shell: true, detached: process.platform !== "win32" });
|
|
5566
|
+
const capture = (chunk) => {
|
|
5567
|
+
output += String(chunk);
|
|
5568
|
+
if (output.length > 1024 * 1024) {
|
|
5569
|
+
output = output.slice(-1024 * 1024);
|
|
5570
|
+
truncated = true;
|
|
5571
|
+
}
|
|
5572
|
+
};
|
|
5573
|
+
const kill = (signalName) => {
|
|
5574
|
+
try {
|
|
5575
|
+
if (process.platform !== "win32" && child.pid) process.kill(-child.pid, signalName);
|
|
5576
|
+
else child.kill(signalName);
|
|
5577
|
+
} catch {
|
|
5578
|
+
try {
|
|
5579
|
+
child.kill(signalName);
|
|
5580
|
+
} catch {
|
|
5581
|
+
}
|
|
5582
|
+
}
|
|
5583
|
+
};
|
|
5584
|
+
const abort = () => {
|
|
5585
|
+
kill("SIGTERM");
|
|
5586
|
+
forceKill = setTimeout(() => kill("SIGKILL"), 1e3);
|
|
5587
|
+
forceKill.unref();
|
|
5588
|
+
};
|
|
5589
|
+
const finish = (exitCode) => {
|
|
5590
|
+
if (settled) return;
|
|
5591
|
+
settled = true;
|
|
5592
|
+
signal?.removeEventListener("abort", abort);
|
|
5593
|
+
if (forceKill) clearTimeout(forceKill);
|
|
5594
|
+
resolve11({ output: (truncated ? "[older output truncated]\n" : "") + output, exitCode: signal?.aborted ? 130 : exitCode });
|
|
5595
|
+
};
|
|
5596
|
+
child.stdout?.on("data", capture);
|
|
5597
|
+
child.stderr?.on("data", capture);
|
|
5598
|
+
child.once("error", (error) => {
|
|
5599
|
+
capture(error.message);
|
|
5600
|
+
finish(1);
|
|
5601
|
+
});
|
|
5602
|
+
child.once("close", (code) => finish(code ?? 1));
|
|
5603
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
5604
|
+
if (signal?.aborted) abort();
|
|
5605
|
+
});
|
|
5606
|
+
}
|
|
5607
|
+
|
|
5219
5608
|
// src/conductor/catalog/catalog.ts
|
|
5220
5609
|
import { z } from "zod";
|
|
5221
|
-
import { getModels, getProviders } from "indusagi/ai";
|
|
5610
|
+
import { getModels, getProviders, modelRegistry } from "indusagi/ai";
|
|
5222
5611
|
var rawModelGate = z.object({
|
|
5223
5612
|
id: z.string().min(1),
|
|
5224
5613
|
name: z.string().min(1),
|
|
@@ -5228,6 +5617,7 @@ var rawModelGate = z.object({
|
|
|
5228
5617
|
contextWindow: z.number().optional()
|
|
5229
5618
|
});
|
|
5230
5619
|
var EXCLUDED_PROVIDERS = /* @__PURE__ */ new Set(["mock"]);
|
|
5620
|
+
applyCodingAgentModelOverlay(modelRegistry);
|
|
5231
5621
|
var frameworkSource = {
|
|
5232
5622
|
providers: () => getProviders().filter((provider) => !EXCLUDED_PROVIDERS.has(String(provider))),
|
|
5233
5623
|
models: (provider) => getModels(provider)
|
|
@@ -5642,30 +6032,21 @@ function memoryBackend() {
|
|
|
5642
6032
|
}
|
|
5643
6033
|
function fsBackend(dir) {
|
|
5644
6034
|
const fileOf = async (sessionId) => {
|
|
5645
|
-
const
|
|
5646
|
-
return
|
|
6035
|
+
const path5 = await import("node:path");
|
|
6036
|
+
return path5.join(dir, `${sessionId}.ndjson`);
|
|
5647
6037
|
};
|
|
5648
6038
|
return {
|
|
5649
6039
|
locate: (sessionId) => `${dir}/${sessionId}.ndjson`,
|
|
5650
6040
|
read: async (sessionId) => {
|
|
5651
|
-
|
|
5652
|
-
try {
|
|
5653
|
-
return await fs3.readFile(await fileOf(sessionId), "utf8");
|
|
5654
|
-
} catch {
|
|
5655
|
-
return null;
|
|
5656
|
-
}
|
|
6041
|
+
return readPrivateFileSync(await fileOf(sessionId));
|
|
5657
6042
|
},
|
|
5658
6043
|
append: async (sessionId, line) => {
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
await fs3.appendFile(await fileOf(sessionId), `${line}
|
|
5662
|
-
`, "utf8");
|
|
6044
|
+
appendPrivateFileSync(await fileOf(sessionId), `${line}
|
|
6045
|
+
`);
|
|
5663
6046
|
},
|
|
5664
6047
|
rewrite: async (sessionId, text) => {
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
await fs3.writeFile(await fileOf(sessionId), text.length === 0 ? "" : `${text}
|
|
5668
|
-
`, "utf8");
|
|
6048
|
+
atomicWritePrivateFileSync(await fileOf(sessionId), text.length === 0 ? "" : `${text}
|
|
6049
|
+
`);
|
|
5669
6050
|
}
|
|
5670
6051
|
};
|
|
5671
6052
|
}
|
|
@@ -6303,7 +6684,10 @@ async function summarize(messages, deps = {}) {
|
|
|
6303
6684
|
const digest2 = localFallbackDigest(messages, deps.priorDigest);
|
|
6304
6685
|
return { message: toSummaryMessage(digest2, scope), coveredCount };
|
|
6305
6686
|
}
|
|
6306
|
-
const prompt = buildSummaryPrompt(messages, scope, deps.priorDigest)
|
|
6687
|
+
const prompt = buildSummaryPrompt(messages, scope, deps.priorDigest) + (deps.instructions ? `
|
|
6688
|
+
|
|
6689
|
+
User compaction guidance:
|
|
6690
|
+
${deps.instructions}` : "");
|
|
6307
6691
|
const context = {
|
|
6308
6692
|
systemPrompt: CONDENSER_BRIEF,
|
|
6309
6693
|
messages: [{ role: "user", content: prompt, timestamp: Date.now() }]
|
|
@@ -6427,8 +6811,8 @@ function collectVisibleReadPaths(kept, readToolName) {
|
|
|
6427
6811
|
if (!isRecord4(block2) || block2.type !== "toolCall") continue;
|
|
6428
6812
|
if (block2.name !== readToolName) continue;
|
|
6429
6813
|
const args = isRecord4(block2.arguments) ? block2.arguments : void 0;
|
|
6430
|
-
const
|
|
6431
|
-
if (
|
|
6814
|
+
const path5 = args && typeof args.path === "string" ? args.path : "";
|
|
6815
|
+
if (path5.length > 0) paths.add(path5);
|
|
6432
6816
|
}
|
|
6433
6817
|
}
|
|
6434
6818
|
return paths;
|
|
@@ -6444,8 +6828,8 @@ function collectDroppedReads(dropped, readToolName) {
|
|
|
6444
6828
|
if (block2.name !== readToolName) continue;
|
|
6445
6829
|
const id = typeof block2.id === "string" ? block2.id : "";
|
|
6446
6830
|
const args = isRecord4(block2.arguments) ? block2.arguments : void 0;
|
|
6447
|
-
const
|
|
6448
|
-
if (id.length > 0 &&
|
|
6831
|
+
const path5 = args && typeof args.path === "string" ? args.path : "";
|
|
6832
|
+
if (id.length > 0 && path5.length > 0) calls.set(id, { path: path5, order: i });
|
|
6449
6833
|
}
|
|
6450
6834
|
}
|
|
6451
6835
|
if (calls.size === 0) return [];
|
|
@@ -6496,7 +6880,7 @@ ${read.body}`,
|
|
|
6496
6880
|
|
|
6497
6881
|
// src/conductor/diagnostics.ts
|
|
6498
6882
|
import * as path2 from "node:path";
|
|
6499
|
-
import { existsSync
|
|
6883
|
+
import { existsSync } from "node:fs";
|
|
6500
6884
|
var MAX_PER_FILE = 10;
|
|
6501
6885
|
var MAX_TOTAL = 30;
|
|
6502
6886
|
var DELIVERED_KEYS_CAP = 500;
|
|
@@ -6553,18 +6937,18 @@ async function loadSpawn() {
|
|
|
6553
6937
|
return void 0;
|
|
6554
6938
|
}
|
|
6555
6939
|
}
|
|
6556
|
-
function captureOutput(
|
|
6557
|
-
return new Promise((
|
|
6940
|
+
function captureOutput(spawn4, bin, args, cwd, signal) {
|
|
6941
|
+
return new Promise((resolve11) => {
|
|
6558
6942
|
let settled = false;
|
|
6559
6943
|
const finish = (value) => {
|
|
6560
6944
|
if (!settled) {
|
|
6561
6945
|
settled = true;
|
|
6562
|
-
|
|
6946
|
+
resolve11(value);
|
|
6563
6947
|
}
|
|
6564
6948
|
};
|
|
6565
6949
|
let child;
|
|
6566
6950
|
try {
|
|
6567
|
-
child =
|
|
6951
|
+
child = spawn4(bin, args, { cwd, shell: false });
|
|
6568
6952
|
} catch {
|
|
6569
6953
|
finish();
|
|
6570
6954
|
return;
|
|
@@ -6593,9 +6977,9 @@ function captureOutput(spawn3, bin, args, cwd, signal) {
|
|
|
6593
6977
|
});
|
|
6594
6978
|
}
|
|
6595
6979
|
async function runTscDiagnostics(cwd, signal) {
|
|
6596
|
-
const
|
|
6597
|
-
if (!
|
|
6598
|
-
const output = await captureOutput(
|
|
6980
|
+
const spawn4 = await loadSpawn();
|
|
6981
|
+
if (!spawn4 || signal?.aborted) return [];
|
|
6982
|
+
const output = await captureOutput(spawn4, path2.join(cwd, "node_modules", ".bin", "tsc"), ["--noEmit", "--pretty", "false"], cwd, signal);
|
|
6599
6983
|
return output === void 0 ? [] : parseTscOutput(output, cwd);
|
|
6600
6984
|
}
|
|
6601
6985
|
function parseTscOutput(output, cwd) {
|
|
@@ -6615,9 +6999,9 @@ function parseTscOutput(output, cwd) {
|
|
|
6615
6999
|
}
|
|
6616
7000
|
async function runEslintDiagnostics(files, cwd, signal) {
|
|
6617
7001
|
if (files.length === 0) return [];
|
|
6618
|
-
const
|
|
6619
|
-
if (!
|
|
6620
|
-
const output = await captureOutput(
|
|
7002
|
+
const spawn4 = await loadSpawn();
|
|
7003
|
+
if (!spawn4 || signal?.aborted) return [];
|
|
7004
|
+
const output = await captureOutput(spawn4, path2.join(cwd, "node_modules", ".bin", "eslint"), ["--format", "json", ...files], cwd, signal);
|
|
6621
7005
|
return output === void 0 ? [] : parseEslintOutput(output, cwd);
|
|
6622
7006
|
}
|
|
6623
7007
|
function parseEslintOutput(output, cwd) {
|
|
@@ -6724,14 +7108,14 @@ function isTypeScriptOrJs(filePath) {
|
|
|
6724
7108
|
}
|
|
6725
7109
|
function hasTsConfig(cwd) {
|
|
6726
7110
|
try {
|
|
6727
|
-
return
|
|
7111
|
+
return existsSync(path2.join(cwd, "tsconfig.json"));
|
|
6728
7112
|
} catch {
|
|
6729
7113
|
return false;
|
|
6730
7114
|
}
|
|
6731
7115
|
}
|
|
6732
7116
|
function hasEslintConfig(cwd) {
|
|
6733
7117
|
try {
|
|
6734
|
-
return ["eslint.config.js", "eslint.config.mjs", "eslint.config.cjs", ".eslintrc", ".eslintrc.js", ".eslintrc.cjs", ".eslintrc.json", ".eslintrc.yml", ".eslintrc.yaml"].some((name) =>
|
|
7118
|
+
return ["eslint.config.js", "eslint.config.mjs", "eslint.config.cjs", ".eslintrc", ".eslintrc.js", ".eslintrc.cjs", ".eslintrc.json", ".eslintrc.yml", ".eslintrc.yaml"].some((name) => existsSync(path2.join(cwd, name)));
|
|
6735
7119
|
} catch {
|
|
6736
7120
|
return false;
|
|
6737
7121
|
}
|
|
@@ -6758,7 +7142,7 @@ function reduceState(prev, action) {
|
|
|
6758
7142
|
}
|
|
6759
7143
|
}
|
|
6760
7144
|
var DEFAULT_RETRY = { maxAttempts: 2, baseDelayMs: 250 };
|
|
6761
|
-
var
|
|
7145
|
+
var DEFAULT_THINKING_LADDER = ["off", "low", "medium", "high"];
|
|
6762
7146
|
var PERMISSION_CYCLE = ["default", "acceptEdits", "plan", "bypass"];
|
|
6763
7147
|
function newSessionId() {
|
|
6764
7148
|
return `s_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
@@ -6780,6 +7164,10 @@ function isOverloadFault(error) {
|
|
|
6780
7164
|
const text = errorText(error).toLowerCase();
|
|
6781
7165
|
return text.includes("529") || text.includes("overload");
|
|
6782
7166
|
}
|
|
7167
|
+
function thinkingLadderForModel(model) {
|
|
7168
|
+
const efforts = model?.reasoningEfforts;
|
|
7169
|
+
return efforts?.length ? efforts : DEFAULT_THINKING_LADDER;
|
|
7170
|
+
}
|
|
6783
7171
|
function withGatewayBaseUrl(model, gatewayBaseUrls) {
|
|
6784
7172
|
const url = gatewayBaseUrls?.[model.provider];
|
|
6785
7173
|
return url ? { ...model, baseUrl: url } : model;
|
|
@@ -6878,6 +7266,8 @@ var SessionConductorImpl = class {
|
|
|
6878
7266
|
#matcher;
|
|
6879
7267
|
#state;
|
|
6880
7268
|
#busy = false;
|
|
7269
|
+
#activeWork;
|
|
7270
|
+
#shellAbort;
|
|
6881
7271
|
#draining = false;
|
|
6882
7272
|
#queue = [];
|
|
6883
7273
|
#boundModel;
|
|
@@ -6937,6 +7327,7 @@ var SessionConductorImpl = class {
|
|
|
6937
7327
|
abort() {
|
|
6938
7328
|
this.clearQueue();
|
|
6939
7329
|
this.#condenseAbort?.abort();
|
|
7330
|
+
this.#shellAbort?.abort();
|
|
6940
7331
|
this.agent.abort();
|
|
6941
7332
|
const fault = conductorFault("aborted", "turn aborted by caller");
|
|
6942
7333
|
this.#dispatch({ type: "fault", fault });
|
|
@@ -6949,13 +7340,22 @@ var SessionConductorImpl = class {
|
|
|
6949
7340
|
return this.#state;
|
|
6950
7341
|
}
|
|
6951
7342
|
this.#busy = true;
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
7343
|
+
const work = (async () => {
|
|
7344
|
+
try {
|
|
7345
|
+
await this.#runTurn(input);
|
|
7346
|
+
await this.#drainQueue();
|
|
7347
|
+
return this.#state;
|
|
7348
|
+
} finally {
|
|
7349
|
+
this.#busy = false;
|
|
7350
|
+
}
|
|
7351
|
+
})();
|
|
7352
|
+
this.#activeWork = work;
|
|
7353
|
+
return work;
|
|
7354
|
+
}
|
|
7355
|
+
async #stopWork() {
|
|
7356
|
+
if (!this.#busy) return;
|
|
7357
|
+
this.abort();
|
|
7358
|
+
await this.#activeWork;
|
|
6959
7359
|
}
|
|
6960
7360
|
async #drainQueue() {
|
|
6961
7361
|
if (this.#draining) return;
|
|
@@ -6993,7 +7393,7 @@ var SessionConductorImpl = class {
|
|
|
6993
7393
|
}
|
|
6994
7394
|
if (attempt < (this.deps.retry ?? DEFAULT_RETRY).maxAttempts && isTransient(error)) {
|
|
6995
7395
|
this.#hub.emit({ kind: "fault", fault: conductorFault("model", `transient model fault; retry ${attempt + 1}`, error), transient: true });
|
|
6996
|
-
await (this.deps.sleep ?? ((ms) => new Promise((
|
|
7396
|
+
await (this.deps.sleep ?? ((ms) => new Promise((resolve11) => setTimeout(resolve11, ms))))((this.deps.retry ?? DEFAULT_RETRY).baseDelayMs * 2 ** attempt);
|
|
6997
7397
|
continue;
|
|
6998
7398
|
}
|
|
6999
7399
|
if (isOverloadFault(error) && this.options.fallbackModelId) this.selectModel(this.options.fallbackModelId);
|
|
@@ -7044,8 +7444,16 @@ var SessionConductorImpl = class {
|
|
|
7044
7444
|
}
|
|
7045
7445
|
this.#applyModel(card);
|
|
7046
7446
|
}
|
|
7047
|
-
cycleModel(id) {
|
|
7048
|
-
|
|
7447
|
+
cycleModel(id, direction = 1) {
|
|
7448
|
+
if (id.trim()) {
|
|
7449
|
+
this.selectModel(id);
|
|
7450
|
+
return;
|
|
7451
|
+
}
|
|
7452
|
+
const cards = this.availableModels();
|
|
7453
|
+
if (!cards.length) return;
|
|
7454
|
+
const at = cards.findIndex((card) => card.id === this.#state.modelId);
|
|
7455
|
+
const index = at < 0 ? 0 : (at + direction + cards.length) % cards.length;
|
|
7456
|
+
this.selectModel(cards[index].id);
|
|
7049
7457
|
}
|
|
7050
7458
|
#applyModel(card) {
|
|
7051
7459
|
const model = withGatewayBaseUrl(card.model, this.#gatewayBaseUrls);
|
|
@@ -7060,28 +7468,36 @@ var SessionConductorImpl = class {
|
|
|
7060
7468
|
registerTools(tools) {
|
|
7061
7469
|
this.agent.setTools([...this.#deckTools, ...tools]);
|
|
7062
7470
|
}
|
|
7063
|
-
async condense() {
|
|
7471
|
+
async condense(instructions) {
|
|
7064
7472
|
if (this.#busy) return "busy";
|
|
7065
7473
|
this.#busy = true;
|
|
7066
7474
|
this.#condenseAbort = new AbortController();
|
|
7067
|
-
|
|
7068
|
-
|
|
7069
|
-
|
|
7070
|
-
|
|
7071
|
-
|
|
7072
|
-
|
|
7073
|
-
|
|
7074
|
-
|
|
7475
|
+
const work = (async () => {
|
|
7476
|
+
try {
|
|
7477
|
+
const result = await this.#runCondense(true, this.#condenseAbort.signal, instructions);
|
|
7478
|
+
await this.#drainQueue();
|
|
7479
|
+
return result;
|
|
7480
|
+
} finally {
|
|
7481
|
+
this.#busy = false;
|
|
7482
|
+
this.#condenseAbort = void 0;
|
|
7483
|
+
}
|
|
7484
|
+
})();
|
|
7485
|
+
this.#activeWork = work;
|
|
7486
|
+
return work;
|
|
7075
7487
|
}
|
|
7076
7488
|
cancelCondense() {
|
|
7077
7489
|
this.#condenseAbort?.abort();
|
|
7078
7490
|
}
|
|
7079
|
-
async #runCondense(force, signal) {
|
|
7491
|
+
async #runCondense(force, signal, instructions) {
|
|
7080
7492
|
const before = [...this.agent.state.messages];
|
|
7081
7493
|
this.#dispatch({ type: "phase", phase: "condensing" });
|
|
7082
7494
|
try {
|
|
7083
|
-
const after = await (this.deps.condense ?? noopCondense)(before, { force, model: this.#boundModel, contextTokens: this.#state.contextTokens, signal });
|
|
7084
|
-
if (signal?.aborted)
|
|
7495
|
+
const after = await (this.deps.condense ?? noopCondense)(before, { force, model: this.#boundModel, contextTokens: this.#state.contextTokens, signal, instructions });
|
|
7496
|
+
if (signal?.aborted) {
|
|
7497
|
+
this.#dispatch({ type: "settled" });
|
|
7498
|
+
this.#hub.emit({ kind: "idle" });
|
|
7499
|
+
return "cancelled";
|
|
7500
|
+
}
|
|
7085
7501
|
if (after.length >= before.length) {
|
|
7086
7502
|
this.#dispatch({ type: "settled" });
|
|
7087
7503
|
return "nothing";
|
|
@@ -7108,10 +7524,12 @@ var SessionConductorImpl = class {
|
|
|
7108
7524
|
}
|
|
7109
7525
|
async #move(id, message) {
|
|
7110
7526
|
try {
|
|
7527
|
+
await this.#stopWork();
|
|
7111
7528
|
await this.store.branchAt(id);
|
|
7112
7529
|
this.agent.replaceMessages(this.store.messages());
|
|
7113
7530
|
this.#dispatch({ type: "head", head: this.store.head });
|
|
7114
7531
|
this.#dispatch({ type: "settled" });
|
|
7532
|
+
this.#hub.emit({ kind: "reset" });
|
|
7115
7533
|
this.#hub.emit({ kind: "idle" });
|
|
7116
7534
|
} catch (error) {
|
|
7117
7535
|
const fault = conductorFault("persistence", message, error);
|
|
@@ -7126,18 +7544,33 @@ var SessionConductorImpl = class {
|
|
|
7126
7544
|
return { canRestore: this.options.checkpoint?.hasSnapshot(id) ?? false };
|
|
7127
7545
|
}
|
|
7128
7546
|
async executeBash(command, opts = {}) {
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
${outcome.output}`.trimEnd(), timestamp: Date.now() }
|
|
7140
|
-
|
|
7547
|
+
if (this.#busy) throw new Error("A turn is running \u2014 stop it before running a shell command.");
|
|
7548
|
+
this.#busy = true;
|
|
7549
|
+
this.#shellAbort = new AbortController();
|
|
7550
|
+
const signal = opts.signal ? AbortSignal.any([opts.signal, this.#shellAbort.signal]) : this.#shellAbort.signal;
|
|
7551
|
+
const work = (async () => {
|
|
7552
|
+
try {
|
|
7553
|
+
this.#dispatch({ type: "phase", phase: "tooling" });
|
|
7554
|
+
const outcome = await runShell(command, this.#workspace, signal);
|
|
7555
|
+
if (!opts.excludeFromContext) {
|
|
7556
|
+
const message = { role: "user", content: `$ ${command}
|
|
7557
|
+
${outcome.output}`.trimEnd(), timestamp: Date.now() };
|
|
7558
|
+
const entry = await this.store.append(message, "note");
|
|
7559
|
+
this.agent.replaceMessages([...this.agent.state.messages, message]);
|
|
7560
|
+
this.#dispatch({ type: "head", head: this.store.head });
|
|
7561
|
+
this.#hub.emit({ kind: "persisted", entryId: entry.id });
|
|
7562
|
+
}
|
|
7563
|
+
this.#dispatch({ type: "settled" });
|
|
7564
|
+
this.#hub.emit({ kind: "idle" });
|
|
7565
|
+
await this.#drainQueue();
|
|
7566
|
+
return outcome;
|
|
7567
|
+
} finally {
|
|
7568
|
+
this.#busy = false;
|
|
7569
|
+
this.#shellAbort = void 0;
|
|
7570
|
+
}
|
|
7571
|
+
})();
|
|
7572
|
+
this.#activeWork = work;
|
|
7573
|
+
return work;
|
|
7141
7574
|
}
|
|
7142
7575
|
stats() {
|
|
7143
7576
|
const messages = this.agent.state.messages;
|
|
@@ -7160,11 +7593,13 @@ ${outcome.output}`.trimEnd(), timestamp: Date.now() }, "note");
|
|
|
7160
7593
|
return this.#thinking;
|
|
7161
7594
|
}
|
|
7162
7595
|
setThinkingLevel(level) {
|
|
7596
|
+
if (!isReasoningEffortSupported(this.#boundModel?.id, level)) return;
|
|
7163
7597
|
this.#thinking = level;
|
|
7164
7598
|
this.agent.setThinkingLevel?.(level);
|
|
7165
7599
|
}
|
|
7166
7600
|
cycleThinkingLevel() {
|
|
7167
|
-
const
|
|
7601
|
+
const ladder = thinkingLadderForModel(this.#boundModel);
|
|
7602
|
+
const next = ladder[(ladder.indexOf(this.#thinking) + 1) % ladder.length];
|
|
7168
7603
|
this.setThinkingLevel(next);
|
|
7169
7604
|
return next;
|
|
7170
7605
|
}
|
|
@@ -7205,6 +7640,7 @@ ${outcome.output}`.trimEnd(), timestamp: Date.now() }, "note");
|
|
|
7205
7640
|
this.#sessionName = name;
|
|
7206
7641
|
}
|
|
7207
7642
|
async resume(id) {
|
|
7643
|
+
await this.#stopWork();
|
|
7208
7644
|
if (!await this.store.load(id)) {
|
|
7209
7645
|
const fault = conductorFault("persistence", `no session "${id}" to resume`);
|
|
7210
7646
|
this.#dispatch({ type: "fault", fault });
|
|
@@ -7213,19 +7649,23 @@ ${outcome.output}`.trimEnd(), timestamp: Date.now() }, "note");
|
|
|
7213
7649
|
}
|
|
7214
7650
|
this.agent.replaceMessages(this.store.messages());
|
|
7215
7651
|
this.#state = { ...this.#state, head: this.store.head, usage: this.store.usage ?? createZeroUsage2(), phase: "idle" };
|
|
7652
|
+
this.#hub.emit({ kind: "reset" });
|
|
7216
7653
|
this.#hub.emit({ kind: "idle" });
|
|
7217
7654
|
}
|
|
7218
7655
|
async newSession() {
|
|
7219
|
-
this
|
|
7656
|
+
await this.#stopWork();
|
|
7220
7657
|
this.agent.replaceMessages([]);
|
|
7221
7658
|
this.store.startNewSession(newSessionId());
|
|
7222
7659
|
this.#queue.length = 0;
|
|
7223
7660
|
this.#sessionName = void 0;
|
|
7224
7661
|
this.#state = { phase: "idle", head: this.store.head, usage: createZeroUsage2(), contextTokens: 0, modelId: this.#state.modelId };
|
|
7662
|
+
this.#hub.emit({ kind: "reset" });
|
|
7225
7663
|
this.#hub.emit({ kind: "idle" });
|
|
7226
7664
|
}
|
|
7227
7665
|
#dispatch(action) {
|
|
7666
|
+
const phase = this.#state.phase;
|
|
7228
7667
|
this.#state = reduceState(this.#state, action);
|
|
7668
|
+
if (phase !== this.#state.phase) this.#hub.emit({ kind: "phase", phase: this.#state.phase });
|
|
7229
7669
|
}
|
|
7230
7670
|
};
|
|
7231
7671
|
|
|
@@ -7993,7 +8433,7 @@ var SETTING_KEYS = Object.freeze(
|
|
|
7993
8433
|
|
|
7994
8434
|
// src/kit/clipboard-image.ts
|
|
7995
8435
|
import { spawnSync } from "node:child_process";
|
|
7996
|
-
import { readFileSync as
|
|
8436
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "node:fs";
|
|
7997
8437
|
import { tmpdir } from "node:os";
|
|
7998
8438
|
import { join as join8 } from "node:path";
|
|
7999
8439
|
var READ_TIMEOUT_MS = 3e3;
|
|
@@ -8038,10 +8478,10 @@ function captureViaOsascript() {
|
|
|
8038
8478
|
{ timeout: READ_TIMEOUT_MS, encoding: "utf8" }
|
|
8039
8479
|
);
|
|
8040
8480
|
if (result.error || result.status !== 0) return null;
|
|
8041
|
-
const
|
|
8042
|
-
if (
|
|
8481
|
+
const path5 = String(result.stdout ?? "").trim();
|
|
8482
|
+
if (path5.length === 0) return null;
|
|
8043
8483
|
try {
|
|
8044
|
-
const bytes =
|
|
8484
|
+
const bytes = readFileSync5(path5);
|
|
8045
8485
|
return bytes.length > 0 ? bytes : null;
|
|
8046
8486
|
} catch {
|
|
8047
8487
|
return null;
|
|
@@ -8072,10 +8512,10 @@ function readClipboardImage(options = {}) {
|
|
|
8072
8512
|
if (bytes === null) return null;
|
|
8073
8513
|
const dir = options.dir ?? tmpdir();
|
|
8074
8514
|
const name = `indus-clipboard-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}.png`;
|
|
8075
|
-
const
|
|
8515
|
+
const path5 = join8(dir, name);
|
|
8076
8516
|
try {
|
|
8077
|
-
|
|
8078
|
-
return
|
|
8517
|
+
writeFileSync2(path5, bytes);
|
|
8518
|
+
return path5;
|
|
8079
8519
|
} catch {
|
|
8080
8520
|
return null;
|
|
8081
8521
|
}
|
|
@@ -8083,7 +8523,7 @@ function readClipboardImage(options = {}) {
|
|
|
8083
8523
|
|
|
8084
8524
|
// src/kit/external-editor.ts
|
|
8085
8525
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
8086
|
-
import { readFileSync as
|
|
8526
|
+
import { readFileSync as readFileSync6, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
8087
8527
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
8088
8528
|
import { join as join9 } from "node:path";
|
|
8089
8529
|
var FALLBACK_EDITOR = "vi";
|
|
@@ -8096,18 +8536,28 @@ function openInExternalEditor(buffer, options = {}) {
|
|
|
8096
8536
|
const env2 = options.env ?? process.env;
|
|
8097
8537
|
const dir = options.dir ?? tmpdir2();
|
|
8098
8538
|
const name = `indus-editor-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}.md`;
|
|
8099
|
-
const
|
|
8539
|
+
const path5 = join9(dir, name);
|
|
8100
8540
|
const [editor, ...editorArgs] = resolveEditor(env2);
|
|
8101
8541
|
try {
|
|
8102
|
-
|
|
8103
|
-
const
|
|
8542
|
+
writeFileSync3(path5, buffer, "utf8");
|
|
8543
|
+
const terminal = options.terminal ?? { stdin: process.stdin, stdout: process.stdout };
|
|
8544
|
+
const wasRaw = terminal.stdin.isRaw === true;
|
|
8545
|
+
let result;
|
|
8546
|
+
try {
|
|
8547
|
+
terminal.stdin.setRawMode?.(false);
|
|
8548
|
+
if (terminal.stdout.isTTY) terminal.stdout.write("\x1B[?1049h\x1B[?25h");
|
|
8549
|
+
result = spawnSync2(editor, [...editorArgs, path5], { stdio: "inherit" });
|
|
8550
|
+
} finally {
|
|
8551
|
+
if (terminal.stdout.isTTY) terminal.stdout.write("\x1B[?1049l\x1B[?25l");
|
|
8552
|
+
terminal.stdin.setRawMode?.(wasRaw);
|
|
8553
|
+
}
|
|
8104
8554
|
if (result.error || result.status !== 0) return null;
|
|
8105
|
-
return
|
|
8555
|
+
return readFileSync6(path5, "utf8").replace(/\n$/, "");
|
|
8106
8556
|
} catch {
|
|
8107
8557
|
return null;
|
|
8108
8558
|
} finally {
|
|
8109
8559
|
try {
|
|
8110
|
-
unlinkSync(
|
|
8560
|
+
unlinkSync(path5);
|
|
8111
8561
|
} catch {
|
|
8112
8562
|
}
|
|
8113
8563
|
}
|
|
@@ -8757,6 +9207,7 @@ function lastAssistantText(messages) {
|
|
|
8757
9207
|
return "";
|
|
8758
9208
|
}
|
|
8759
9209
|
function toPublishRole(role) {
|
|
9210
|
+
if (role === "toolResult") return "tool";
|
|
8760
9211
|
return PUBLISH_ROLES.has(role) ? role : "note";
|
|
8761
9212
|
}
|
|
8762
9213
|
function toPublishEntries(messages) {
|
|
@@ -8787,7 +9238,7 @@ function exportTranscriptHtml(ctx, target) {
|
|
|
8787
9238
|
const html = publishTranscript(toPublishEntries(messages), {
|
|
8788
9239
|
title: "Session Transcript"
|
|
8789
9240
|
});
|
|
8790
|
-
|
|
9241
|
+
writeFileSync4(outPath, html, "utf-8");
|
|
8791
9242
|
return { ok: true, path: outPath };
|
|
8792
9243
|
} catch (cause) {
|
|
8793
9244
|
const message = cause instanceof Error ? cause.message : String(cause);
|
|
@@ -9178,13 +9629,11 @@ function runLogin2(ctx) {
|
|
|
9178
9629
|
}
|
|
9179
9630
|
return HANDLED;
|
|
9180
9631
|
}
|
|
9181
|
-
function hasLocalProviderKey(provider) {
|
|
9182
|
-
if (provider
|
|
9632
|
+
async function hasLocalProviderKey(provider, ctx) {
|
|
9633
|
+
if (!provider) return false;
|
|
9183
9634
|
try {
|
|
9184
|
-
|
|
9185
|
-
|
|
9186
|
-
const entry = vault[provider];
|
|
9187
|
-
return entry !== null && typeof entry === "object" && Object.keys(entry).length > 0;
|
|
9635
|
+
if (getEnvApiKey2(provider)) return true;
|
|
9636
|
+
return (await ctx.services?.vault.listAccounts(provider) ?? []).length > 0;
|
|
9188
9637
|
} catch {
|
|
9189
9638
|
return false;
|
|
9190
9639
|
}
|
|
@@ -9200,7 +9649,7 @@ function runStatus(ctx) {
|
|
|
9200
9649
|
signedIn = false;
|
|
9201
9650
|
}
|
|
9202
9651
|
const eligible = isGatewayEligibleProvider(provider);
|
|
9203
|
-
const localKey = hasLocalProviderKey(provider);
|
|
9652
|
+
const localKey = await hasLocalProviderKey(provider, ctx);
|
|
9204
9653
|
const viaServer = signedIn && eligible && !localKey;
|
|
9205
9654
|
if (viaServer) {
|
|
9206
9655
|
ctx.setStatus(info(`\u25CF server tier \u2014 ${modelId} routing via ${INDUS_SERVER_URL} (signed in)`));
|
|
@@ -9381,12 +9830,7 @@ var compactCommand = {
|
|
|
9381
9830
|
ctx.setStatus({ kind: "busy", text: busyText });
|
|
9382
9831
|
void (async () => {
|
|
9383
9832
|
try {
|
|
9384
|
-
|
|
9385
|
-
await ctx.conductor.executeBash(
|
|
9386
|
-
`printf '%s' ${JSON.stringify(`Compaction guidance: ${instructions}`)}`
|
|
9387
|
-
);
|
|
9388
|
-
}
|
|
9389
|
-
switch (await ctx.conductor.condense()) {
|
|
9833
|
+
switch (await ctx.conductor.condense(instructions || void 0)) {
|
|
9390
9834
|
case "condensed":
|
|
9391
9835
|
ctx.setStatus(
|
|
9392
9836
|
info(
|
|
@@ -9561,7 +10005,7 @@ var transcriptCommands = [
|
|
|
9561
10005
|
];
|
|
9562
10006
|
|
|
9563
10007
|
// src/console/slash/commands/workbench.ts
|
|
9564
|
-
import { mkdtempSync, readFileSync as
|
|
10008
|
+
import { mkdtempSync, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
9565
10009
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
9566
10010
|
import { join as join11 } from "node:path";
|
|
9567
10011
|
function block(slug, title, markdown) {
|
|
@@ -9597,7 +10041,7 @@ function hotkeysBlock() {
|
|
|
9597
10041
|
function readChangelog(cwd) {
|
|
9598
10042
|
for (const name of CHANGELOG_NAMES) {
|
|
9599
10043
|
try {
|
|
9600
|
-
const text =
|
|
10044
|
+
const text = readFileSync8(join11(cwd, name), "utf8");
|
|
9601
10045
|
if (text.trim().length > 0) return text;
|
|
9602
10046
|
} catch {
|
|
9603
10047
|
}
|
|
@@ -9635,9 +10079,9 @@ function runDebug(ctx) {
|
|
|
9635
10079
|
const jsonl = records.map((r) => JSON.stringify(r)).join("\n") + "\n";
|
|
9636
10080
|
try {
|
|
9637
10081
|
const dir = mkdtempSync(join11(tmpdir3(), "indus-debug-"));
|
|
9638
|
-
const
|
|
9639
|
-
|
|
9640
|
-
ctx.setStatus(info(`Diagnostics written to ${
|
|
10082
|
+
const path5 = join11(dir, `session-${stats.sessionId || "unknown"}.jsonl`);
|
|
10083
|
+
writeFileSync5(path5, jsonl, "utf8");
|
|
10084
|
+
ctx.setStatus(info(`Diagnostics written to ${path5}`));
|
|
9641
10085
|
} catch (cause) {
|
|
9642
10086
|
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
9643
10087
|
ctx.setStatus(warn(`Could not write the diagnostics log (${detail}).`));
|
|
@@ -9689,7 +10133,7 @@ var HOTKEYS = [
|
|
|
9689
10133
|
["Tab", "Accept the highlighted completion"],
|
|
9690
10134
|
["Ctrl+C", "Interrupt the running turn"],
|
|
9691
10135
|
["Ctrl+T", "Toggle reasoning / thinking rows"],
|
|
9692
|
-
["/thinking", "Cycle
|
|
10136
|
+
["/thinking", "Cycle the selected model's supported reasoning efforts"],
|
|
9693
10137
|
["Ctrl+V", "Attach an image from the clipboard"],
|
|
9694
10138
|
["Ctrl+G", "Edit the composer in your external editor"],
|
|
9695
10139
|
["Ctrl+O", "Expand or collapse full tool output"],
|
|
@@ -9761,7 +10205,7 @@ var workbenchCommands = [
|
|
|
9761
10205
|
{
|
|
9762
10206
|
name: "whats-new",
|
|
9763
10207
|
summary: "Show what changed in this build",
|
|
9764
|
-
aliases: ["changelog"],
|
|
10208
|
+
aliases: ["changelog", "release-notes"],
|
|
9765
10209
|
run: runChangelog
|
|
9766
10210
|
},
|
|
9767
10211
|
{
|
|
@@ -9771,7 +10215,7 @@ var workbenchCommands = [
|
|
|
9771
10215
|
},
|
|
9772
10216
|
{
|
|
9773
10217
|
name: "thinking",
|
|
9774
|
-
summary: "Cycle
|
|
10218
|
+
summary: "Cycle reasoning effort using the selected model's supported levels",
|
|
9775
10219
|
run: (ctx) => {
|
|
9776
10220
|
ctx.conductor.cycleThinkingLevel();
|
|
9777
10221
|
return HANDLED;
|
|
@@ -9787,7 +10231,7 @@ var workbenchCommands = [
|
|
|
9787
10231
|
// src/console/slash/builtins.ts
|
|
9788
10232
|
var PROJECT_DIR = ".indusagi";
|
|
9789
10233
|
function dynamicRoots() {
|
|
9790
|
-
const home =
|
|
10234
|
+
const home = homedir2();
|
|
9791
10235
|
const cwd = process.cwd();
|
|
9792
10236
|
return {
|
|
9793
10237
|
skills: [
|
|
@@ -9925,7 +10369,7 @@ function readKey(input, key) {
|
|
|
9925
10369
|
case "n":
|
|
9926
10370
|
return { verb: "flow:cycleModel" };
|
|
9927
10371
|
case "p":
|
|
9928
|
-
return { verb: "flow:cycleModel" };
|
|
10372
|
+
return { verb: "flow:cycleModel", direction: -1 };
|
|
9929
10373
|
case "t":
|
|
9930
10374
|
return { verb: "view:toggleReasoning" };
|
|
9931
10375
|
case "v":
|
|
@@ -9950,15 +10394,15 @@ function readKey(input, key) {
|
|
|
9950
10394
|
}
|
|
9951
10395
|
if (key.escape) return { verb: "flow:dismiss" };
|
|
9952
10396
|
if (key.tab) return key.shift ? { verb: "mode:cyclePermission" } : { verb: "flow:accept" };
|
|
9953
|
-
if (key.
|
|
10397
|
+
if (key.delete) return { verb: "edit:eraseNext" };
|
|
10398
|
+
if (key.backspace || input === "\x7F" || input === "\b") {
|
|
9954
10399
|
return { verb: "edit:erasePrev" };
|
|
9955
10400
|
}
|
|
9956
10401
|
if (key.leftArrow) return { verb: "nav:left" };
|
|
9957
10402
|
if (key.rightArrow) return { verb: "nav:right" };
|
|
9958
10403
|
if (key.upArrow) return { verb: "nav:up" };
|
|
9959
10404
|
if (key.downArrow) return { verb: "nav:down" };
|
|
9960
|
-
if (key.pageUp) return
|
|
9961
|
-
if (key.pageDown) return { verb: "nav:end" };
|
|
10405
|
+
if (key.pageUp || key.pageDown) return NO_INTENT;
|
|
9962
10406
|
return isPrintable(input) ? typed(input) : NO_INTENT;
|
|
9963
10407
|
}
|
|
9964
10408
|
var NO_CHORD = { armed: null };
|
|
@@ -10078,12 +10522,12 @@ function splitPathStem(stem) {
|
|
|
10078
10522
|
const body = stem.slice(sigil.length);
|
|
10079
10523
|
const slash = body.lastIndexOf("/");
|
|
10080
10524
|
if (slash < 0) return { dir: ".", leaf: body, sigil };
|
|
10081
|
-
return { dir: body.slice(0, slash) || "
|
|
10525
|
+
return { dir: body.slice(0, slash) || "/", leaf: body.slice(slash + 1), sigil };
|
|
10082
10526
|
}
|
|
10083
10527
|
function completePath(stem, readDir) {
|
|
10084
10528
|
const { dir, leaf, sigil } = splitPathStem(stem);
|
|
10085
10529
|
const lowerLeaf = leaf.toLowerCase();
|
|
10086
|
-
const prefix = dir === "." ? "" : `${dir}/`;
|
|
10530
|
+
const prefix = dir === "." ? "" : dir === "/" ? "/" : `${dir}/`;
|
|
10087
10531
|
const matches = readDir(dir).filter((e) => e.name.toLowerCase().startsWith(lowerLeaf)).sort((a, b) => {
|
|
10088
10532
|
if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;
|
|
10089
10533
|
return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
|
|
@@ -10119,6 +10563,7 @@ function applySuggestion(buffer, span, suggestion) {
|
|
|
10119
10563
|
// src/console/input/dir-reader.ts
|
|
10120
10564
|
import { readdirSync as readdirSync3, statSync as statSync3 } from "node:fs";
|
|
10121
10565
|
import { resolve as resolve6 } from "node:path";
|
|
10566
|
+
import { homedir as homedir3 } from "node:os";
|
|
10122
10567
|
function entryIsDir(base, name, isDirent, isSymlink) {
|
|
10123
10568
|
if (isDirent) return true;
|
|
10124
10569
|
if (!isSymlink) return false;
|
|
@@ -10130,7 +10575,8 @@ function entryIsDir(base, name, isDirent, isSymlink) {
|
|
|
10130
10575
|
}
|
|
10131
10576
|
function createDirReader(cwd = process.cwd()) {
|
|
10132
10577
|
return (dirPath) => {
|
|
10133
|
-
const
|
|
10578
|
+
const expanded = dirPath === "~" ? homedir3() : dirPath.startsWith("~/") ? resolve6(homedir3(), dirPath.slice(2)) : dirPath;
|
|
10579
|
+
const target = resolve6(cwd, expanded);
|
|
10134
10580
|
try {
|
|
10135
10581
|
const dirents = readdirSync3(target, { withFileTypes: true });
|
|
10136
10582
|
return dirents.map((d) => ({
|
|
@@ -10145,11 +10591,12 @@ function createDirReader(cwd = process.cwd()) {
|
|
|
10145
10591
|
|
|
10146
10592
|
// src/console/components/TerminalConsole.ts
|
|
10147
10593
|
import { execFileSync } from "node:child_process";
|
|
10148
|
-
import { homedir as
|
|
10149
|
-
import
|
|
10150
|
-
import { Box as
|
|
10594
|
+
import { homedir as homedir6 } from "node:os";
|
|
10595
|
+
import React4, { useEffect as useEffect9, useMemo as useMemo2, useState as useState10 } from "indusagi/react-host";
|
|
10596
|
+
import { Box as Box12, Text as Text11, useInput as useInput6 } from "indusagi/react-host/ink";
|
|
10597
|
+
import { useStdin, useStdout as useStdout2 } from "ink";
|
|
10151
10598
|
import { MessageList, StreamingMarkdown, TaskPanel } from "indusagi/react-ink";
|
|
10152
|
-
import { Fragment as Fragment4, jsx as
|
|
10599
|
+
import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs10 } from "indusagi/react-host/jsx-runtime";
|
|
10153
10600
|
|
|
10154
10601
|
// src/workspace/runtime-detect.ts
|
|
10155
10602
|
var BUN_VIRTUAL_FS_MARKERS = ["$bunfs", "~BUN", "%7EBUN"];
|
|
@@ -10164,13 +10611,13 @@ function isPackagedBinary() {
|
|
|
10164
10611
|
}
|
|
10165
10612
|
|
|
10166
10613
|
// src/settings/manager.ts
|
|
10167
|
-
import { existsSync as
|
|
10168
|
-
import { dirname as
|
|
10614
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "node:fs";
|
|
10615
|
+
import { dirname as dirname5, join as join13 } from "node:path";
|
|
10169
10616
|
function loadTier(filePath) {
|
|
10170
|
-
if (!
|
|
10617
|
+
if (!existsSync2(filePath)) return {};
|
|
10171
10618
|
let raw;
|
|
10172
10619
|
try {
|
|
10173
|
-
raw =
|
|
10620
|
+
raw = readFileSync9(filePath, "utf-8");
|
|
10174
10621
|
} catch {
|
|
10175
10622
|
return {};
|
|
10176
10623
|
}
|
|
@@ -10186,9 +10633,9 @@ function loadTier(filePath) {
|
|
|
10186
10633
|
return { ...parsed };
|
|
10187
10634
|
}
|
|
10188
10635
|
function writeTier(filePath, tier) {
|
|
10189
|
-
const dir =
|
|
10190
|
-
if (!
|
|
10191
|
-
|
|
10636
|
+
const dir = dirname5(filePath);
|
|
10637
|
+
if (!existsSync2(dir)) mkdirSync2(dir, { recursive: true });
|
|
10638
|
+
writeFileSync6(filePath, `${JSON.stringify(tier, null, 2)}
|
|
10192
10639
|
`, "utf-8");
|
|
10193
10640
|
}
|
|
10194
10641
|
var PreferenceStore = class _PreferenceStore {
|
|
@@ -10261,14 +10708,14 @@ var IMAGE_SNIFF_BYTES = PNG_SIGNATURE.length;
|
|
|
10261
10708
|
|
|
10262
10709
|
// src/sessions/library.ts
|
|
10263
10710
|
import {
|
|
10264
|
-
mkdir
|
|
10265
|
-
readFile
|
|
10711
|
+
mkdir,
|
|
10712
|
+
readFile,
|
|
10266
10713
|
readdir,
|
|
10267
10714
|
rename,
|
|
10268
10715
|
rm,
|
|
10269
10716
|
stat
|
|
10270
10717
|
} from "node:fs/promises";
|
|
10271
|
-
import { basename as
|
|
10718
|
+
import { basename as basename5, join as join14 } from "node:path";
|
|
10272
10719
|
var SESSION_FILE_EXT = ".ndjson";
|
|
10273
10720
|
var PREVIEW_LIMIT = 72;
|
|
10274
10721
|
var SessionLibrary = class {
|
|
@@ -10300,14 +10747,14 @@ var SessionLibrary = class {
|
|
|
10300
10747
|
if (!await this.#missing(toPath)) {
|
|
10301
10748
|
throw new Error(`SessionLibrary.rename: session "${toId}" already exists`);
|
|
10302
10749
|
}
|
|
10303
|
-
await
|
|
10750
|
+
await mkdir(this.#dir, { recursive: true });
|
|
10304
10751
|
await rename(fromPath, toPath);
|
|
10305
10752
|
return toPath;
|
|
10306
10753
|
}
|
|
10307
10754
|
async remove(id) {
|
|
10308
|
-
const
|
|
10309
|
-
if (await this.#missing(
|
|
10310
|
-
await rm(
|
|
10755
|
+
const path5 = this.pathOf(id);
|
|
10756
|
+
if (await this.#missing(path5)) return false;
|
|
10757
|
+
await rm(path5, { force: true });
|
|
10311
10758
|
return true;
|
|
10312
10759
|
}
|
|
10313
10760
|
pathOf(id) {
|
|
@@ -10362,41 +10809,41 @@ var SessionLibrary = class {
|
|
|
10362
10809
|
} catch {
|
|
10363
10810
|
return [];
|
|
10364
10811
|
}
|
|
10365
|
-
return names.filter((name) => name.endsWith(SESSION_FILE_EXT)).map((name) =>
|
|
10812
|
+
return names.filter((name) => name.endsWith(SESSION_FILE_EXT)).map((name) => basename5(name, SESSION_FILE_EXT));
|
|
10366
10813
|
}
|
|
10367
10814
|
async #shallowRow(id) {
|
|
10368
|
-
const
|
|
10369
|
-
const meta = await this.#fileMeta(
|
|
10370
|
-
return { id, path:
|
|
10815
|
+
const path5 = this.pathOf(id);
|
|
10816
|
+
const meta = await this.#fileMeta(path5);
|
|
10817
|
+
return { id, path: path5, ...meta };
|
|
10371
10818
|
}
|
|
10372
10819
|
async #deepRow(id) {
|
|
10373
|
-
const
|
|
10374
|
-
const meta = await this.#fileMeta(
|
|
10820
|
+
const path5 = this.pathOf(id);
|
|
10821
|
+
const meta = await this.#fileMeta(path5);
|
|
10375
10822
|
const store = await this.open(id);
|
|
10376
|
-
if (store === null) return { id, path:
|
|
10823
|
+
if (store === null) return { id, path: path5, ...meta };
|
|
10377
10824
|
const branch = store.pathTo();
|
|
10378
10825
|
const conversational = branch.filter(isConversational);
|
|
10379
10826
|
const opener = conversational.find((entry) => entry.role === "user");
|
|
10380
10827
|
const preview2 = opener ? previewOf(messageText(opener.content)) : void 0;
|
|
10381
10828
|
return {
|
|
10382
10829
|
id,
|
|
10383
|
-
path:
|
|
10830
|
+
path: path5,
|
|
10384
10831
|
...meta,
|
|
10385
10832
|
messageCount: conversational.length,
|
|
10386
10833
|
...preview2 ? { preview: preview2, name: preview2 } : {}
|
|
10387
10834
|
};
|
|
10388
10835
|
}
|
|
10389
|
-
async #fileMeta(
|
|
10836
|
+
async #fileMeta(path5) {
|
|
10390
10837
|
try {
|
|
10391
|
-
const info2 = await stat(
|
|
10838
|
+
const info2 = await stat(path5);
|
|
10392
10839
|
return { size: info2.size, lastModified: info2.mtimeMs };
|
|
10393
10840
|
} catch {
|
|
10394
10841
|
return {};
|
|
10395
10842
|
}
|
|
10396
10843
|
}
|
|
10397
|
-
async #missing(
|
|
10844
|
+
async #missing(path5) {
|
|
10398
10845
|
try {
|
|
10399
|
-
await
|
|
10846
|
+
await readFile(path5);
|
|
10400
10847
|
return false;
|
|
10401
10848
|
} catch {
|
|
10402
10849
|
return true;
|
|
@@ -10555,9 +11002,9 @@ function resolveSpecifierPath(specifier) {
|
|
|
10555
11002
|
function buildAliasMap() {
|
|
10556
11003
|
const map = {};
|
|
10557
11004
|
for (const specifier of BUNDLED_NAMESPACES) {
|
|
10558
|
-
const
|
|
10559
|
-
if (
|
|
10560
|
-
map[specifier] =
|
|
11005
|
+
const path5 = resolveSpecifierPath(specifier);
|
|
11006
|
+
if (path5 !== void 0) {
|
|
11007
|
+
map[specifier] = path5;
|
|
10561
11008
|
}
|
|
10562
11009
|
}
|
|
10563
11010
|
return map;
|
|
@@ -10605,8 +11052,8 @@ function createJitiLoader(options = {}) {
|
|
|
10605
11052
|
const base = options.base ?? process.cwd();
|
|
10606
11053
|
const home = options.home ?? homedir4();
|
|
10607
11054
|
return {
|
|
10608
|
-
async load(
|
|
10609
|
-
const absolute = resolvePath(
|
|
11055
|
+
async load(path5) {
|
|
11056
|
+
const absolute = resolvePath(path5, base, home);
|
|
10610
11057
|
const specifier = pathToFileURL(absolute).href;
|
|
10611
11058
|
const imported = await jiti.import(specifier);
|
|
10612
11059
|
const manifest = toManifest(imported);
|
|
@@ -10621,8 +11068,8 @@ function createJitiLoader(options = {}) {
|
|
|
10621
11068
|
}
|
|
10622
11069
|
|
|
10623
11070
|
// src/addons/manifest.ts
|
|
10624
|
-
import { readFileSync as
|
|
10625
|
-
import { basename as
|
|
11071
|
+
import { readFileSync as readFileSync10, readdirSync as readdirSync4, statSync as statSync4 } from "node:fs";
|
|
11072
|
+
import { basename as basename6, extname as extname3, isAbsolute as isAbsolute5, join as join15, resolve as resolve8 } from "node:path";
|
|
10626
11073
|
var ENTRY_EXTENSIONS = [
|
|
10627
11074
|
".ts",
|
|
10628
11075
|
".tsx",
|
|
@@ -10639,9 +11086,9 @@ function isHidden(name) {
|
|
|
10639
11086
|
function hasEntryExtension(name) {
|
|
10640
11087
|
return ENTRY_EXTENSIONS.includes(extname3(name).toLowerCase());
|
|
10641
11088
|
}
|
|
10642
|
-
function entryKind(
|
|
11089
|
+
function entryKind(path5) {
|
|
10643
11090
|
try {
|
|
10644
|
-
const stat2 = statSync4(
|
|
11091
|
+
const stat2 = statSync4(path5);
|
|
10645
11092
|
if (stat2.isDirectory()) return "directory";
|
|
10646
11093
|
if (stat2.isFile()) return "file";
|
|
10647
11094
|
return void 0;
|
|
@@ -10662,7 +11109,7 @@ function readManifestEntry(packageDir) {
|
|
|
10662
11109
|
return void 0;
|
|
10663
11110
|
}
|
|
10664
11111
|
try {
|
|
10665
|
-
const parsed = JSON.parse(
|
|
11112
|
+
const parsed = JSON.parse(readFileSync10(manifestPath, "utf8"));
|
|
10666
11113
|
if (typeof parsed !== "object" || parsed === null) {
|
|
10667
11114
|
return void 0;
|
|
10668
11115
|
}
|
|
@@ -10694,13 +11141,13 @@ function resolveTopLevelEntry(dir, name) {
|
|
|
10694
11141
|
if (isHidden(name)) {
|
|
10695
11142
|
return void 0;
|
|
10696
11143
|
}
|
|
10697
|
-
const
|
|
10698
|
-
const kind = entryKind(
|
|
11144
|
+
const path5 = join15(dir, name);
|
|
11145
|
+
const kind = entryKind(path5);
|
|
10699
11146
|
if (kind === "file") {
|
|
10700
|
-
return hasEntryExtension(name) ?
|
|
11147
|
+
return hasEntryExtension(name) ? path5 : void 0;
|
|
10701
11148
|
}
|
|
10702
11149
|
if (kind === "directory") {
|
|
10703
|
-
return resolvePackageEntry(
|
|
11150
|
+
return resolvePackageEntry(path5);
|
|
10704
11151
|
}
|
|
10705
11152
|
return void 0;
|
|
10706
11153
|
}
|
|
@@ -10715,9 +11162,9 @@ function discoverAddons(dir) {
|
|
|
10715
11162
|
return entries.sort();
|
|
10716
11163
|
}
|
|
10717
11164
|
function deriveAddonId(entryPath) {
|
|
10718
|
-
const file =
|
|
11165
|
+
const file = basename6(entryPath);
|
|
10719
11166
|
const stem = file.slice(0, file.length - extname3(file).length);
|
|
10720
|
-
const label = INDEX_BASENAMES.includes(stem) ?
|
|
11167
|
+
const label = INDEX_BASENAMES.includes(stem) ? basename6(join15(entryPath, "..")) : stem;
|
|
10721
11168
|
return addonId(label.length > 0 ? label : entryPath);
|
|
10722
11169
|
}
|
|
10723
11170
|
function addonsDirFor(workspace, dir = ADDONS_DIR) {
|
|
@@ -10734,12 +11181,12 @@ function discoverSources(discovery) {
|
|
|
10734
11181
|
}
|
|
10735
11182
|
const seen = /* @__PURE__ */ new Set();
|
|
10736
11183
|
const sources = [];
|
|
10737
|
-
for (const
|
|
10738
|
-
if (seen.has(
|
|
11184
|
+
for (const path5 of paths) {
|
|
11185
|
+
if (seen.has(path5)) {
|
|
10739
11186
|
continue;
|
|
10740
11187
|
}
|
|
10741
|
-
seen.add(
|
|
10742
|
-
sources.push({ id: deriveAddonId(
|
|
11188
|
+
seen.add(path5);
|
|
11189
|
+
sources.push({ id: deriveAddonId(path5), path: path5 });
|
|
10743
11190
|
}
|
|
10744
11191
|
return sources;
|
|
10745
11192
|
}
|
|
@@ -11308,6 +11755,7 @@ function ndjsonStrategy() {
|
|
|
11308
11755
|
},
|
|
11309
11756
|
onSignal(signal, ctx) {
|
|
11310
11757
|
const s = signal;
|
|
11758
|
+
if (s.kind === "tool_update") return;
|
|
11311
11759
|
ctx.out.write(ctx.framer.encodeLine({ type: "signal", name: s.kind, body: s }));
|
|
11312
11760
|
},
|
|
11313
11761
|
finish(state, ctx) {
|
|
@@ -11414,16 +11862,16 @@ function createDialogBridge(deps) {
|
|
|
11414
11862
|
ask(kind, payload, fallback) {
|
|
11415
11863
|
const id = nextAskId(seq);
|
|
11416
11864
|
const frame = { type: "ask", id, kind, payload };
|
|
11417
|
-
return new Promise((
|
|
11865
|
+
return new Promise((resolve11) => {
|
|
11418
11866
|
const timer = setTimeout(() => {
|
|
11419
11867
|
pending.delete(id);
|
|
11420
|
-
|
|
11868
|
+
resolve11(fallback);
|
|
11421
11869
|
}, deps.timings.dialogMs);
|
|
11422
11870
|
if (typeof timer.unref === "function") {
|
|
11423
11871
|
timer.unref();
|
|
11424
11872
|
}
|
|
11425
11873
|
pending.set(id, {
|
|
11426
|
-
settle: (value) =>
|
|
11874
|
+
settle: (value) => resolve11(value),
|
|
11427
11875
|
timer
|
|
11428
11876
|
});
|
|
11429
11877
|
emit(frame);
|
|
@@ -12016,6 +12464,9 @@ var DEFAULT_REDACTOR = createRedactor();
|
|
|
12016
12464
|
// src/insight/replay.ts
|
|
12017
12465
|
var TEXT_DECODER3 = new TextDecoder();
|
|
12018
12466
|
|
|
12467
|
+
// src/review-agent/reviewer.ts
|
|
12468
|
+
import { Type as Type8 } from "@sinclair/typebox";
|
|
12469
|
+
|
|
12019
12470
|
// src/console/overlays/approval-queue.ts
|
|
12020
12471
|
var EMPTY_APPROVAL_QUEUE = { entries: [] };
|
|
12021
12472
|
function approvalQueueReducer(state, event) {
|
|
@@ -12049,6 +12500,7 @@ import { jsx as jsx2 } from "indusagi/react-host/jsx-runtime";
|
|
|
12049
12500
|
|
|
12050
12501
|
// src/console/auth-status.ts
|
|
12051
12502
|
import { useEffect, useState } from "indusagi/react-host";
|
|
12503
|
+
import { getEnvApiKey as getEnvApiKey3 } from "indusagi/ai";
|
|
12052
12504
|
function useAuthenticatedProviders(services, refreshKey) {
|
|
12053
12505
|
const [authed, setAuthed] = useState(null);
|
|
12054
12506
|
useEffect(() => {
|
|
@@ -12057,10 +12509,14 @@ function useAuthenticatedProviders(services, refreshKey) {
|
|
|
12057
12509
|
void (async () => {
|
|
12058
12510
|
const found = /* @__PURE__ */ new Set();
|
|
12059
12511
|
try {
|
|
12060
|
-
|
|
12512
|
+
const providers = /* @__PURE__ */ new Set([
|
|
12513
|
+
...services.listLoginProviders().map((provider) => provider.id),
|
|
12514
|
+
...services.conductor.availableModels().map((model) => model.provider)
|
|
12515
|
+
]);
|
|
12516
|
+
for (const provider of providers) {
|
|
12061
12517
|
try {
|
|
12062
|
-
if ((await services.vault.listAccounts(provider
|
|
12063
|
-
found.add(provider
|
|
12518
|
+
if (getEnvApiKey3(provider) || (await services.vault.listAccounts(provider)).length > 0) {
|
|
12519
|
+
found.add(provider);
|
|
12064
12520
|
}
|
|
12065
12521
|
} catch {
|
|
12066
12522
|
}
|
|
@@ -12078,15 +12534,12 @@ function useAuthenticatedProviders(services, refreshKey) {
|
|
|
12078
12534
|
return () => {
|
|
12079
12535
|
live3 = false;
|
|
12080
12536
|
};
|
|
12081
|
-
}, [refreshKey]);
|
|
12537
|
+
}, [services, refreshKey]);
|
|
12082
12538
|
return authed;
|
|
12083
12539
|
}
|
|
12084
12540
|
|
|
12085
12541
|
// src/console/overlays/boards.ts
|
|
12086
12542
|
import chalk2 from "chalk";
|
|
12087
|
-
import { readFileSync as readFileSync10 } from "node:fs";
|
|
12088
|
-
import { homedir as homedir5 } from "node:os";
|
|
12089
|
-
import { join as join16 } from "node:path";
|
|
12090
12543
|
import { useEffect as useEffect2, useMemo, useState as useState2 } from "indusagi/react-host";
|
|
12091
12544
|
import { Box, Text, useInput } from "indusagi/react-host/ink";
|
|
12092
12545
|
import {
|
|
@@ -12094,28 +12547,6 @@ import {
|
|
|
12094
12547
|
wrapSelectionIndex
|
|
12095
12548
|
} from "indusagi/react-ink";
|
|
12096
12549
|
import { Fragment, jsx, jsxs } from "indusagi/react-host/jsx-runtime";
|
|
12097
|
-
function readServerTierInfo() {
|
|
12098
|
-
let signedIn = false;
|
|
12099
|
-
try {
|
|
12100
|
-
const file = join16(homedir5(), ".indusagi", "agent", "server-token.json");
|
|
12101
|
-
const token = JSON.parse(readFileSync10(file, "utf8"));
|
|
12102
|
-
signedIn = typeof token.expires_at === "string" && new Date(token.expires_at).getTime() - Date.now() > 5 * 60 * 1e3;
|
|
12103
|
-
} catch {
|
|
12104
|
-
signedIn = false;
|
|
12105
|
-
}
|
|
12106
|
-
const localKeys = /* @__PURE__ */ new Set();
|
|
12107
|
-
try {
|
|
12108
|
-
const file = join16(homedir5(), ".indusagi", "agent", "auth.json");
|
|
12109
|
-
const vault = JSON.parse(readFileSync10(file, "utf8"));
|
|
12110
|
-
for (const [provider, entry] of Object.entries(vault)) {
|
|
12111
|
-
if (entry !== null && typeof entry === "object" && Object.keys(entry).length > 0) {
|
|
12112
|
-
localKeys.add(provider);
|
|
12113
|
-
}
|
|
12114
|
-
}
|
|
12115
|
-
} catch {
|
|
12116
|
-
}
|
|
12117
|
-
return { signedIn, localKeys };
|
|
12118
|
-
}
|
|
12119
12550
|
function truncate(text, width) {
|
|
12120
12551
|
if (text.length <= width) return text;
|
|
12121
12552
|
if (width <= 1) return text.slice(0, width);
|
|
@@ -12212,6 +12643,7 @@ function nextValue(values, current, direction) {
|
|
|
12212
12643
|
return values[(at + direction + values.length) % values.length];
|
|
12213
12644
|
}
|
|
12214
12645
|
function SettingsBoard({ theme, items, onClose }) {
|
|
12646
|
+
const [error, setError] = useState2();
|
|
12215
12647
|
const [query, setQuery] = useState2("");
|
|
12216
12648
|
const [selectedIndex, setSelectedIndex] = useState2(0);
|
|
12217
12649
|
const filtered = useMemo(
|
|
@@ -12228,7 +12660,15 @@ function SettingsBoard({ theme, items, onClose }) {
|
|
|
12228
12660
|
const item = filtered[selectedIndex];
|
|
12229
12661
|
if (!item) return;
|
|
12230
12662
|
const value = nextValue(item.values, item.value, direction);
|
|
12231
|
-
if (value && value !== item.value)
|
|
12663
|
+
if (value && value !== item.value) {
|
|
12664
|
+
setError(void 0);
|
|
12665
|
+
const failed = (error2) => setError(error2 instanceof Error ? error2.message : String(error2));
|
|
12666
|
+
try {
|
|
12667
|
+
void Promise.resolve(item.onChange(value)).catch(failed);
|
|
12668
|
+
} catch (error2) {
|
|
12669
|
+
failed(error2);
|
|
12670
|
+
}
|
|
12671
|
+
}
|
|
12232
12672
|
};
|
|
12233
12673
|
useInput((input, key) => {
|
|
12234
12674
|
if (key.escape) return onClose();
|
|
@@ -12243,7 +12683,7 @@ function SettingsBoard({ theme, items, onClose }) {
|
|
|
12243
12683
|
const { start, budget, below } = windowAround(filtered.length, selectedIndex);
|
|
12244
12684
|
const visible = filtered.slice(start, start + budget);
|
|
12245
12685
|
const selected = filtered[selectedIndex];
|
|
12246
|
-
const detail = selected ? `${selected.description} \xB7 ${selected.values.join(" / ")}` : void 0;
|
|
12686
|
+
const detail = error ?? (selected ? `${selected.description} \xB7 ${selected.values.join(" / ")}` : void 0);
|
|
12247
12687
|
const list = items.length === 0 ? jsx(Text, { children: theme.muted("No settings are available.") }) : filtered.length === 0 ? jsx(Text, { children: theme.muted("No settings matched the search.") }) : jsx(Box, {
|
|
12248
12688
|
flexDirection: "column",
|
|
12249
12689
|
children: visible.map((item, index) => {
|
|
@@ -12283,12 +12723,7 @@ function ModelBoard({ theme, models, onClose, onSelect, search }) {
|
|
|
12283
12723
|
const [query, setQuery] = useState2(search ?? "");
|
|
12284
12724
|
const [selectedIndex, setSelectedIndex] = useState2(0);
|
|
12285
12725
|
useEffect2(() => setQuery(search ?? ""), [search]);
|
|
12286
|
-
const
|
|
12287
|
-
const isServerTier = (provider) => serverTier.signedIn && isGatewayEligibleProvider(provider) && !serverTier.localKeys.has(provider);
|
|
12288
|
-
const available = useMemo(
|
|
12289
|
-
() => models.filter((model) => serverTier.localKeys.has(model.provider) || isServerTier(model.provider)),
|
|
12290
|
-
[models, serverTier]
|
|
12291
|
-
);
|
|
12726
|
+
const available = models;
|
|
12292
12727
|
const filtered = useMemo(() => available.filter((model) => modelMatches(model, query)), [available, query]);
|
|
12293
12728
|
useEffect2(() => setSelectedIndex(0), [query]);
|
|
12294
12729
|
useEffect2(() => {
|
|
@@ -12324,10 +12759,10 @@ function ModelBoard({ theme, models, onClose, onSelect, search }) {
|
|
|
12324
12759
|
jsx(Box, { width: 2, children: jsx(Text, { children: isSelected ? theme.color("accent", "\u203A") : " " }) }),
|
|
12325
12760
|
jsx(Text, { bold: isSelected, children: theme.color("text", model.id) }),
|
|
12326
12761
|
model.name ? jsx(Text, { children: theme.dim(` ${model.name}`) }) : null,
|
|
12327
|
-
|
|
12762
|
+
jsx(Text, { children: theme.dim(` ${model.provider}`) })
|
|
12328
12763
|
]
|
|
12329
12764
|
},
|
|
12330
|
-
model.id
|
|
12765
|
+
`${model.provider}/${model.id}`
|
|
12331
12766
|
);
|
|
12332
12767
|
})
|
|
12333
12768
|
});
|
|
@@ -12344,6 +12779,19 @@ function ModelBoard({ theme, models, onClose, onSelect, search }) {
|
|
|
12344
12779
|
|
|
12345
12780
|
// src/console/overlays/pickers.ts
|
|
12346
12781
|
var TOGGLE_VALUES = ["on", "off"];
|
|
12782
|
+
function saveSetting(settings, key, value) {
|
|
12783
|
+
const previous = settings.get(key);
|
|
12784
|
+
try {
|
|
12785
|
+
settings.set(key, value);
|
|
12786
|
+
settings.save();
|
|
12787
|
+
} catch (error) {
|
|
12788
|
+
settings.set(key, previous);
|
|
12789
|
+
throw error;
|
|
12790
|
+
}
|
|
12791
|
+
}
|
|
12792
|
+
function reportError(dispatch2, error) {
|
|
12793
|
+
dispatch2({ type: "status:set", status: { kind: "error", text: error instanceof Error ? error.message : String(error) } });
|
|
12794
|
+
}
|
|
12347
12795
|
function refToModel(ref) {
|
|
12348
12796
|
return {
|
|
12349
12797
|
id: ref.id,
|
|
@@ -12366,7 +12814,7 @@ function listModels(services) {
|
|
|
12366
12814
|
}
|
|
12367
12815
|
}
|
|
12368
12816
|
function ModelPicker(props) {
|
|
12369
|
-
const { services, theme, closeModal } = props;
|
|
12817
|
+
const { services, theme, closeModal, dispatch: dispatch2 } = props;
|
|
12370
12818
|
const authed = useAuthenticatedProviders(services);
|
|
12371
12819
|
if (!services) return null;
|
|
12372
12820
|
const all = listModels(services);
|
|
@@ -12377,7 +12825,8 @@ function ModelPicker(props) {
|
|
|
12377
12825
|
onSelect: (model) => {
|
|
12378
12826
|
try {
|
|
12379
12827
|
services.conductor.selectModel(model.id);
|
|
12380
|
-
} catch {
|
|
12828
|
+
} catch (error) {
|
|
12829
|
+
reportError(dispatch2, error);
|
|
12381
12830
|
}
|
|
12382
12831
|
closeModal();
|
|
12383
12832
|
},
|
|
@@ -12398,8 +12847,7 @@ function ScopedModelPicker(props) {
|
|
|
12398
12847
|
useEffect3(() => {
|
|
12399
12848
|
if (!services || payload.intent !== "reset") return;
|
|
12400
12849
|
try {
|
|
12401
|
-
services.settings
|
|
12402
|
-
services.settings.save();
|
|
12850
|
+
saveSetting(services.settings, "enabledModels", []);
|
|
12403
12851
|
dispatch2({
|
|
12404
12852
|
type: "status:set",
|
|
12405
12853
|
status: { kind: "info", text: "Per-scope model overrides cleared." }
|
|
@@ -12429,9 +12877,9 @@ function ScopedModelPicker(props) {
|
|
|
12429
12877
|
try {
|
|
12430
12878
|
const all = models.map((model) => model.id);
|
|
12431
12879
|
const next = ids.length === all.length ? [] : ids;
|
|
12432
|
-
services.settings
|
|
12433
|
-
|
|
12434
|
-
|
|
12880
|
+
saveSetting(services.settings, "enabledModels", next);
|
|
12881
|
+
} catch (error) {
|
|
12882
|
+
reportError(dispatch2, error);
|
|
12435
12883
|
}
|
|
12436
12884
|
closeModal();
|
|
12437
12885
|
},
|
|
@@ -12458,11 +12906,11 @@ function ThemePicker(props) {
|
|
|
12458
12906
|
themes: [...THEME_SCHEMES],
|
|
12459
12907
|
onSelect: (name) => {
|
|
12460
12908
|
if (isThemeScheme(name)) {
|
|
12461
|
-
dispatch2({ type: "scheme:set", scheme: name });
|
|
12462
12909
|
try {
|
|
12463
|
-
services.settings
|
|
12464
|
-
|
|
12465
|
-
} catch {
|
|
12910
|
+
saveSetting(services.settings, "colourScheme", name);
|
|
12911
|
+
dispatch2({ type: "scheme:set", scheme: name });
|
|
12912
|
+
} catch (error) {
|
|
12913
|
+
reportError(dispatch2, error);
|
|
12466
12914
|
}
|
|
12467
12915
|
}
|
|
12468
12916
|
closeModal();
|
|
@@ -12484,9 +12932,8 @@ function SettingsPicker(props) {
|
|
|
12484
12932
|
value: onOff(settings.get(key)),
|
|
12485
12933
|
values: [...TOGGLE_VALUES],
|
|
12486
12934
|
onChange: (value) => {
|
|
12487
|
-
settings
|
|
12488
|
-
|
|
12489
|
-
live3?.();
|
|
12935
|
+
saveSetting(settings, key, value === "on");
|
|
12936
|
+
live3?.(value === "on");
|
|
12490
12937
|
bump();
|
|
12491
12938
|
}
|
|
12492
12939
|
});
|
|
@@ -12498,8 +12945,7 @@ function SettingsPicker(props) {
|
|
|
12498
12945
|
values: [...DELIVERY_MODES],
|
|
12499
12946
|
onChange: (value) => {
|
|
12500
12947
|
if (isDeliveryMode(value)) {
|
|
12501
|
-
settings
|
|
12502
|
-
settings.save();
|
|
12948
|
+
saveSetting(settings, key, value);
|
|
12503
12949
|
}
|
|
12504
12950
|
bump();
|
|
12505
12951
|
}
|
|
@@ -12513,16 +12959,15 @@ function SettingsPicker(props) {
|
|
|
12513
12959
|
value: settings.get("colourScheme"),
|
|
12514
12960
|
values: [...THEME_SCHEMES],
|
|
12515
12961
|
onChange: (value) => {
|
|
12516
|
-
settings
|
|
12517
|
-
settings.save();
|
|
12962
|
+
saveSetting(settings, "colourScheme", value);
|
|
12518
12963
|
if (isThemeScheme(value)) dispatch2({ type: "scheme:set", scheme: value });
|
|
12519
12964
|
bump();
|
|
12520
12965
|
}
|
|
12521
12966
|
});
|
|
12522
|
-
items.push(toggleRow("show-images", "showImages", "Show images", "Render inline image content in the transcript.", () => dispatch2({ type: "
|
|
12967
|
+
items.push(toggleRow("show-images", "showImages", "Show images", "Render inline image content in the transcript.", (value) => dispatch2({ type: "display:set", key: "showImages", value })));
|
|
12523
12968
|
items.push(toggleRow("image-auto-resize", "imageAutoResize", "Auto-resize images", "Shrink oversized images to fit before handing them to a provider."));
|
|
12524
12969
|
items.push(toggleRow("block-images", "blockImages", "Block images", "Withhold image content from providers entirely."));
|
|
12525
|
-
items.push(toggleRow("show-reasoning", "showReasoning", "Show reasoning", "Stream the model's reasoning / thinking text as it arrives.", () => dispatch2({ type: "
|
|
12970
|
+
items.push(toggleRow("show-reasoning", "showReasoning", "Show reasoning", "Stream the model's reasoning / thinking text as it arrives.", (value) => dispatch2({ type: "display:set", key: "showReasoning", value })));
|
|
12526
12971
|
items.push(toggleRow("skill-commands", "enableSkillCommands", "Skill commands", "Surface discovered skills as their own slash commands."));
|
|
12527
12972
|
items.push(deliveryRow("steering-mode", "steeringMode", "Steering mode", "Whether queued steering corrections release one at a time or all at once."));
|
|
12528
12973
|
items.push(deliveryRow("follow-up-mode", "followUpMode", "Follow-up mode", "Whether queued follow-up prompts release one at a time or all at once."));
|
|
@@ -12531,7 +12976,6 @@ function SettingsPicker(props) {
|
|
|
12531
12976
|
items.push(toggleRow("quiet-startup", "quietStartup", "Quiet startup", "Suppress the banner and tips shown on a normal interactive launch."));
|
|
12532
12977
|
items.push(toggleRow("logo-sweep", "logoSweep", "Logo sweep", "Tint the startup wordmark and emblem along a static colour gradient."));
|
|
12533
12978
|
items.push(toggleRow("reduced-motion", "reducedMotion", "Reduced motion", "Suppress motion-flavoured flourishes such as the logo colour sweep."));
|
|
12534
|
-
items.push(toggleRow("hardware-cursor", "showHardwareCursor", "Hardware cursor", "Reveal the terminal's own cursor instead of the software-drawn caret."));
|
|
12535
12979
|
items.push({
|
|
12536
12980
|
id: "editor-padding",
|
|
12537
12981
|
label: "Editor padding",
|
|
@@ -12541,8 +12985,7 @@ function SettingsPicker(props) {
|
|
|
12541
12985
|
onChange: (value) => {
|
|
12542
12986
|
const parsed = Number.parseInt(value, 10);
|
|
12543
12987
|
if (Number.isFinite(parsed)) {
|
|
12544
|
-
settings
|
|
12545
|
-
settings.save();
|
|
12988
|
+
saveSetting(settings, "editorPaddingX", parsed);
|
|
12546
12989
|
}
|
|
12547
12990
|
bump();
|
|
12548
12991
|
}
|
|
@@ -12796,7 +13239,7 @@ function SignInDialog(props) {
|
|
|
12796
13239
|
var SERVER_TIER_ACCOUNT_ID = "server-session";
|
|
12797
13240
|
var SERVER_TIER_PROVIDER_ID2 = "indus-server";
|
|
12798
13241
|
function SignOutDialog(props) {
|
|
12799
|
-
const { services, closeModal } = props;
|
|
13242
|
+
const { services, closeModal, dispatch: dispatch2 } = props;
|
|
12800
13243
|
const [accounts, setAccounts] = useState5([]);
|
|
12801
13244
|
useEffect5(() => {
|
|
12802
13245
|
let live3 = true;
|
|
@@ -12848,7 +13291,10 @@ function SignOutDialog(props) {
|
|
|
12848
13291
|
} else {
|
|
12849
13292
|
await services.vault.remove(account.provider, account.accountId);
|
|
12850
13293
|
}
|
|
12851
|
-
|
|
13294
|
+
await services.refreshGatewayRouting();
|
|
13295
|
+
dispatch2({ type: "status:set", status: { kind: "info", text: "Signed out. Model routing refreshed." } });
|
|
13296
|
+
} catch (error) {
|
|
13297
|
+
dispatch2({ type: "status:set", status: { kind: "error", text: error instanceof Error ? error.message : "Sign-out failed." } });
|
|
12852
13298
|
}
|
|
12853
13299
|
closeModal();
|
|
12854
13300
|
}
|
|
@@ -12886,15 +13332,24 @@ function OAuthFlowDialog(props) {
|
|
|
12886
13332
|
})();
|
|
12887
13333
|
const [state, setState] = useState5(() => seedOAuthState(providerId, providerName, mode));
|
|
12888
13334
|
const pending = useRef(null);
|
|
13335
|
+
const cancelPrompt = useRef(null);
|
|
13336
|
+
const mounted = useRef(true);
|
|
13337
|
+
const saving = useRef(false);
|
|
13338
|
+
useEffect5(() => () => {
|
|
13339
|
+
mounted.current = false;
|
|
13340
|
+
}, []);
|
|
12889
13341
|
const merge = (next) => setState((prev) => ({ ...prev, ...next }));
|
|
12890
13342
|
useEffect5(() => {
|
|
12891
13343
|
if (mode !== "oauth") return;
|
|
12892
13344
|
let live3 = true;
|
|
13345
|
+
const controller = new AbortController();
|
|
12893
13346
|
const safeMerge = (next) => {
|
|
12894
13347
|
if (live3) merge(next);
|
|
12895
13348
|
};
|
|
12896
13349
|
const callbacks = {
|
|
13350
|
+
signal: controller.signal,
|
|
12897
13351
|
onAuth: (info2) => {
|
|
13352
|
+
if (!live3) return;
|
|
12898
13353
|
safeMerge({ authInfo: info2, progress: "Opening your browser to sign in\u2026" });
|
|
12899
13354
|
void services.openLoginUrl(info2.url).then((opened) => {
|
|
12900
13355
|
safeMerge({
|
|
@@ -12902,12 +13357,28 @@ function OAuthFlowDialog(props) {
|
|
|
12902
13357
|
});
|
|
12903
13358
|
});
|
|
12904
13359
|
},
|
|
12905
|
-
onPrompt: (prompt) => new Promise((
|
|
12906
|
-
|
|
13360
|
+
onPrompt: (prompt) => new Promise((resolve11, reject) => {
|
|
13361
|
+
if (!live3) {
|
|
13362
|
+
reject(new DOMException("Sign-in cancelled", "AbortError"));
|
|
13363
|
+
return;
|
|
13364
|
+
}
|
|
13365
|
+
cancelPrompt.current = () => reject(new DOMException("Sign-in cancelled", "AbortError"));
|
|
13366
|
+
pending.current = (value) => {
|
|
13367
|
+
cancelPrompt.current = null;
|
|
13368
|
+
resolve11(value);
|
|
13369
|
+
};
|
|
12907
13370
|
safeMerge({ prompt, inputLabel: prompt.message, inputValue: "" });
|
|
12908
13371
|
}),
|
|
12909
|
-
onManualCodeInput: () => new Promise((
|
|
12910
|
-
|
|
13372
|
+
onManualCodeInput: () => new Promise((resolve11, reject) => {
|
|
13373
|
+
if (!live3) {
|
|
13374
|
+
reject(new DOMException("Sign-in cancelled", "AbortError"));
|
|
13375
|
+
return;
|
|
13376
|
+
}
|
|
13377
|
+
cancelPrompt.current = () => reject(new DOMException("Sign-in cancelled", "AbortError"));
|
|
13378
|
+
pending.current = (value) => {
|
|
13379
|
+
cancelPrompt.current = null;
|
|
13380
|
+
resolve11(value);
|
|
13381
|
+
};
|
|
12911
13382
|
safeMerge({
|
|
12912
13383
|
prompt: { message: "Paste the authorization code or complete redirect URL:" },
|
|
12913
13384
|
inputLabel: "Authorization code or redirect URL",
|
|
@@ -12921,7 +13392,9 @@ function OAuthFlowDialog(props) {
|
|
|
12921
13392
|
void (async () => {
|
|
12922
13393
|
try {
|
|
12923
13394
|
await services.startOAuthLogin(providerId, callbacks, services.vault);
|
|
13395
|
+
if (!live3) return;
|
|
12924
13396
|
await services.refreshGatewayRouting();
|
|
13397
|
+
if (!live3) return;
|
|
12925
13398
|
selectProviderModel(services, providerId);
|
|
12926
13399
|
if (live3) {
|
|
12927
13400
|
dispatch2({
|
|
@@ -12936,15 +13409,23 @@ function OAuthFlowDialog(props) {
|
|
|
12936
13409
|
})();
|
|
12937
13410
|
return () => {
|
|
12938
13411
|
live3 = false;
|
|
13412
|
+
controller.abort();
|
|
13413
|
+
cancelPrompt.current?.();
|
|
13414
|
+
cancelPrompt.current = null;
|
|
13415
|
+
pending.current = null;
|
|
12939
13416
|
};
|
|
12940
13417
|
}, []);
|
|
12941
13418
|
const saveApiKey = () => {
|
|
12942
13419
|
const key = state.inputValue.trim();
|
|
12943
|
-
if (key.length === 0) return;
|
|
13420
|
+
if (key.length === 0 || saving.current) return;
|
|
13421
|
+
saving.current = true;
|
|
12944
13422
|
const account = state.accountId ?? "default";
|
|
12945
13423
|
void (async () => {
|
|
12946
13424
|
try {
|
|
12947
13425
|
await services.vault.putApiKey(providerId, account, key, true);
|
|
13426
|
+
if (!mounted.current) return;
|
|
13427
|
+
await services.refreshGatewayRouting();
|
|
13428
|
+
if (!mounted.current) return;
|
|
12948
13429
|
selectProviderModel(services, providerId);
|
|
12949
13430
|
dispatch2({
|
|
12950
13431
|
type: "status:set",
|
|
@@ -12967,12 +13448,12 @@ function OAuthFlowDialog(props) {
|
|
|
12967
13448
|
saveApiKey();
|
|
12968
13449
|
return;
|
|
12969
13450
|
}
|
|
12970
|
-
const
|
|
12971
|
-
if (
|
|
13451
|
+
const resolve11 = pending.current;
|
|
13452
|
+
if (resolve11 === null) return;
|
|
12972
13453
|
pending.current = null;
|
|
12973
13454
|
const value = state.inputValue;
|
|
12974
13455
|
merge({ inputValue: "", prompt: void 0 });
|
|
12975
|
-
|
|
13456
|
+
resolve11(value);
|
|
12976
13457
|
},
|
|
12977
13458
|
onClose: closeModal
|
|
12978
13459
|
});
|
|
@@ -13127,12 +13608,12 @@ function summarizeInput(input) {
|
|
|
13127
13608
|
}
|
|
13128
13609
|
function ApprovalDialog(props) {
|
|
13129
13610
|
const { payload, closeModal } = props;
|
|
13130
|
-
const { request, resolve:
|
|
13611
|
+
const { request, resolve: resolve11 } = payload;
|
|
13131
13612
|
let settled = false;
|
|
13132
13613
|
const settle = (choice) => {
|
|
13133
13614
|
if (settled) return;
|
|
13134
13615
|
settled = true;
|
|
13135
|
-
|
|
13616
|
+
resolve11(choice);
|
|
13136
13617
|
closeModal();
|
|
13137
13618
|
};
|
|
13138
13619
|
const args = summarizeInput(request.input);
|
|
@@ -13169,8 +13650,18 @@ function ApprovalOverlays(props) {
|
|
|
13169
13650
|
}
|
|
13170
13651
|
|
|
13171
13652
|
// src/console/overlays/host.ts
|
|
13653
|
+
import { Box as Box4, Text as Text4, useInput as useInput3 } from "indusagi/react-host/ink";
|
|
13654
|
+
function UnavailableOverlay({ closeModal }) {
|
|
13655
|
+
useInput3((_input, key) => {
|
|
13656
|
+
if (key.escape || key.return) closeModal();
|
|
13657
|
+
});
|
|
13658
|
+
return jsx6(Box4, { children: jsx6(Text4, { children: "This dialog is unavailable in this host. Esc / Enter to return." }) });
|
|
13659
|
+
}
|
|
13172
13660
|
function OverlayHost(props) {
|
|
13173
13661
|
if (props.modal.kind === "none") return null;
|
|
13662
|
+
if (!props.services && props.modal.kind !== "approval" && props.modal.kind !== "plugin") {
|
|
13663
|
+
return jsx6(UnavailableOverlay, { closeModal: props.closeModal });
|
|
13664
|
+
}
|
|
13174
13665
|
const forwarded = {
|
|
13175
13666
|
modal: props.modal,
|
|
13176
13667
|
services: props.services,
|
|
@@ -13189,31 +13680,31 @@ function OverlayHost(props) {
|
|
|
13189
13680
|
}
|
|
13190
13681
|
|
|
13191
13682
|
// src/console/startup.ts
|
|
13192
|
-
import { existsSync as
|
|
13193
|
-
import { join as
|
|
13683
|
+
import { existsSync as existsSync3, readFileSync as readFileSync11 } from "node:fs";
|
|
13684
|
+
import { join as join16 } from "node:path";
|
|
13194
13685
|
var PROFILE_DIR = ".indusagi";
|
|
13195
13686
|
var CONTEXT_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
13196
13687
|
function skillRoots(cwd, home) {
|
|
13197
13688
|
return [
|
|
13198
|
-
{ dir:
|
|
13199
|
-
{ dir:
|
|
13689
|
+
{ dir: join16(cwd, PROFILE_DIR, "skills"), origin: "project" },
|
|
13690
|
+
{ dir: join16(home, PROFILE_DIR, "skills"), origin: "user" }
|
|
13200
13691
|
];
|
|
13201
13692
|
}
|
|
13202
13693
|
function macroRoots(cwd, home) {
|
|
13203
13694
|
return [
|
|
13204
|
-
{ dir:
|
|
13205
|
-
{ dir:
|
|
13695
|
+
{ dir: join16(cwd, PROFILE_DIR, "commands"), origin: "project", label: "project" },
|
|
13696
|
+
{ dir: join16(home, PROFILE_DIR, "commands"), origin: "user", label: "user" }
|
|
13206
13697
|
];
|
|
13207
13698
|
}
|
|
13208
|
-
function shortenPath2(
|
|
13209
|
-
if (cwd.length > 0 &&
|
|
13210
|
-
const rest =
|
|
13699
|
+
function shortenPath2(path5, cwd, home) {
|
|
13700
|
+
if (cwd.length > 0 && path5.startsWith(cwd)) {
|
|
13701
|
+
const rest = path5.slice(cwd.length).replace(/^[/\\]+/, "");
|
|
13211
13702
|
return rest.length > 0 ? `./${rest}` : ".";
|
|
13212
13703
|
}
|
|
13213
|
-
if (home.length > 0 &&
|
|
13214
|
-
return `~${
|
|
13704
|
+
if (home.length > 0 && path5.startsWith(home)) {
|
|
13705
|
+
return `~${path5.slice(home.length)}`;
|
|
13215
13706
|
}
|
|
13216
|
-
return
|
|
13707
|
+
return path5;
|
|
13217
13708
|
}
|
|
13218
13709
|
var MAX_SECTION_LINES = 6;
|
|
13219
13710
|
function capLines(lines) {
|
|
@@ -13232,10 +13723,10 @@ function gatherContext(cwd, home) {
|
|
|
13232
13723
|
for (const root of [cwd, home]) {
|
|
13233
13724
|
if (root.length === 0) continue;
|
|
13234
13725
|
for (const name of CONTEXT_FILES) {
|
|
13235
|
-
const
|
|
13236
|
-
if (seen.has(
|
|
13237
|
-
seen.add(
|
|
13238
|
-
if (
|
|
13726
|
+
const path5 = join16(root, name);
|
|
13727
|
+
if (seen.has(path5)) continue;
|
|
13728
|
+
seen.add(path5);
|
|
13729
|
+
if (existsSync3(path5)) out2.push(shortenPath2(path5, cwd, home));
|
|
13239
13730
|
}
|
|
13240
13731
|
}
|
|
13241
13732
|
return out2;
|
|
@@ -13299,12 +13790,12 @@ function mascotRows(face) {
|
|
|
13299
13790
|
];
|
|
13300
13791
|
}
|
|
13301
13792
|
var TIPS = [
|
|
13302
|
-
"Run /
|
|
13793
|
+
"Run /help to explore commands and configured skill helpers",
|
|
13303
13794
|
'Ask in plain English \u2014 try "fix the failing tests" or "explain src/agent.ts"',
|
|
13304
|
-
"Shift+Tab cycles
|
|
13795
|
+
"Shift+Tab cycles: default \u2192 accept-edits \u2192 plan \u2192 bypass",
|
|
13305
13796
|
"Type @ to attach a file, or paste an image straight into the prompt",
|
|
13306
13797
|
"Run /status to check your model, account, and connectivity",
|
|
13307
|
-
"Use /
|
|
13798
|
+
"Use /help to discover specialized commands for the task at hand"
|
|
13308
13799
|
];
|
|
13309
13800
|
var WHATS_NEW = [
|
|
13310
13801
|
"Ctrl+X runs your newest queued message NOW \u2014 the current run stops cleanly",
|
|
@@ -13324,148 +13815,21 @@ function pickWelcomeVariant(seed) {
|
|
|
13324
13815
|
var PINNED_WELCOME_SEED = 12;
|
|
13325
13816
|
|
|
13326
13817
|
// src/console/components/AgentsView.ts
|
|
13327
|
-
import { useState as
|
|
13328
|
-
import { Box as
|
|
13818
|
+
import { useState as useState7 } from "indusagi/react-host";
|
|
13819
|
+
import { Box as Box6, Text as Text6, useInput as useInput4 } from "indusagi/react-host/ink";
|
|
13329
13820
|
import { wrapSelectionIndex as wrapSelectionIndex2 } from "indusagi/react-ink";
|
|
13821
|
+
import { jsx as jsx8, jsxs as jsxs5 } from "indusagi/react-host/jsx-runtime";
|
|
13822
|
+
|
|
13823
|
+
// src/console/components/BackgroundAgents.ts
|
|
13824
|
+
import { Box as Box5, Text as Text5 } from "indusagi/react-host/ink";
|
|
13825
|
+
import { useEffect as useEffect6, useState as useState6 } from "indusagi/react-host";
|
|
13826
|
+
import { splitAssistantMessage } from "indusagi/react-ink";
|
|
13330
13827
|
import { jsx as jsx7, jsxs as jsxs4 } from "indusagi/react-host/jsx-runtime";
|
|
13331
|
-
function
|
|
13332
|
-
|
|
13333
|
-
|
|
13334
|
-
|
|
13335
|
-
|
|
13336
|
-
if (flat.length <= width) return flat;
|
|
13337
|
-
if (width <= 1) return flat.slice(0, width);
|
|
13338
|
-
return `${flat.slice(0, width - 1)}\u2026`;
|
|
13339
|
-
}
|
|
13340
|
-
function runStatusLine(run, now, tokens) {
|
|
13341
|
-
let head;
|
|
13342
|
-
if (run.status === "error") head = "failed";
|
|
13343
|
-
else if (run.status === "done") head = "done";
|
|
13344
|
-
else if (run.startedAt > 0 && now >= run.startedAt) {
|
|
13345
|
-
head = `${Math.max(0, Math.round((now - run.startedAt) / 1e3))}s`;
|
|
13346
|
-
} else head = "working";
|
|
13347
|
-
const tok = tokens !== void 0 && tokens > 0 ? ` \xB7 \u2193 ${formatTokens2(tokens)} tokens` : "";
|
|
13348
|
-
return `${head}${tok}`;
|
|
13349
|
-
}
|
|
13350
|
-
var NAME_WIDTH = 12;
|
|
13351
|
-
function ActivityRow({ theme, line }) {
|
|
13352
|
-
if (line.tone === "tool") {
|
|
13353
|
-
return jsxs4(Box4, {
|
|
13354
|
-
children: [
|
|
13355
|
-
jsx7(Text4, { children: theme.color("success", "\u25CF ") }),
|
|
13356
|
-
jsx7(Text4, { children: theme.color("text", clampLine(line.text, 96)) })
|
|
13357
|
-
]
|
|
13358
|
-
});
|
|
13359
|
-
}
|
|
13360
|
-
if (line.tone === "result") {
|
|
13361
|
-
return jsx7(Box4, { marginLeft: 2, children: jsx7(Text4, { children: theme.dim(`\u2514 ${clampLine(line.text, 92)}`) }) });
|
|
13362
|
-
}
|
|
13363
|
-
return jsxs4(Box4, {
|
|
13364
|
-
children: [
|
|
13365
|
-
jsx7(Text4, { children: theme.color("accent", "\u25CF ") }),
|
|
13366
|
-
jsx7(Text4, { children: theme.color("text", clampLine(line.text, 96)) })
|
|
13367
|
-
]
|
|
13368
|
-
});
|
|
13369
|
-
}
|
|
13370
|
-
function AgentsView({ theme, runs, activity, tokens, now, onExit }) {
|
|
13371
|
-
const clock = now ?? Date.now();
|
|
13372
|
-
const [selectedIndex, setSelectedIndex] = useState6(runs.length > 0 ? 1 : 0);
|
|
13373
|
-
const rowCount = runs.length + 1;
|
|
13374
|
-
const index = Math.min(selectedIndex, rowCount - 1);
|
|
13375
|
-
const viewed = index > 0 ? runs[index - 1] : void 0;
|
|
13376
|
-
useInput3((input, key) => {
|
|
13377
|
-
if (key.escape || input === "x") return onExit();
|
|
13378
|
-
if (key.upArrow) return setSelectedIndex((i) => wrapSelectionIndex2(Math.min(i, rowCount - 1), -1, rowCount));
|
|
13379
|
-
if (key.downArrow) return setSelectedIndex((i) => wrapSelectionIndex2(Math.min(i, rowCount - 1), 1, rowCount));
|
|
13380
|
-
if (key.return && index === 0) onExit();
|
|
13381
|
-
});
|
|
13382
|
-
const lines = viewed ? activity[viewed.id] ?? [] : [];
|
|
13383
|
-
return jsxs4(Box4, {
|
|
13384
|
-
flexDirection: "column",
|
|
13385
|
-
marginTop: 1,
|
|
13386
|
-
children: [
|
|
13387
|
-
viewed ? jsxs4(Box4, {
|
|
13388
|
-
flexDirection: "column",
|
|
13389
|
-
children: [
|
|
13390
|
-
jsxs4(Box4, {
|
|
13391
|
-
marginBottom: 1,
|
|
13392
|
-
children: [
|
|
13393
|
-
jsx7(Text4, { children: theme.color("accent", "\u2736 ") }),
|
|
13394
|
-
jsx7(Text4, { bold: true, children: theme.color("accent", viewed.name) }),
|
|
13395
|
-
jsx7(Text4, { children: theme.dim(` ${runStatusLine(viewed, clock, tokens[viewed.id])}`) })
|
|
13396
|
-
]
|
|
13397
|
-
}),
|
|
13398
|
-
lines.length === 0 ? jsx7(Text4, { children: theme.muted(" Waiting for the first step\u2026") }) : lines.map((line, i) => jsx7(ActivityRow, { theme, line }, i)),
|
|
13399
|
-
jsx7(Box4, {
|
|
13400
|
-
marginTop: 1,
|
|
13401
|
-
children: jsx7(Text4, { wrap: "truncate", children: theme.muted(`\u2514 ${clampLine(viewed.objective, 100)}`) })
|
|
13402
|
-
})
|
|
13403
|
-
]
|
|
13404
|
-
}) : jsxs4(Box4, {
|
|
13405
|
-
children: [
|
|
13406
|
-
jsx7(Text4, { children: theme.muted("Select a sub-agent to view its live activity, or press Enter on ") }),
|
|
13407
|
-
jsx7(Text4, { bold: true, children: theme.color("text", "main") }),
|
|
13408
|
-
jsx7(Text4, { children: theme.muted(" to return.") })
|
|
13409
|
-
]
|
|
13410
|
-
}),
|
|
13411
|
-
jsxs4(Box4, {
|
|
13412
|
-
flexDirection: "column",
|
|
13413
|
-
marginTop: 1,
|
|
13414
|
-
borderStyle: "single",
|
|
13415
|
-
borderColor: theme.colors["borderMuted"],
|
|
13416
|
-
borderBottom: false,
|
|
13417
|
-
borderLeft: false,
|
|
13418
|
-
borderRight: false,
|
|
13419
|
-
paddingTop: 0,
|
|
13420
|
-
children: [
|
|
13421
|
-
jsxs4(Box4, {
|
|
13422
|
-
children: [
|
|
13423
|
-
jsx7(Text4, { children: index === 0 ? theme.color("accent", "\u203A ") : " " }),
|
|
13424
|
-
jsx7(Text4, { children: index === 0 ? theme.color("text", "\u25CF ") : theme.dim("\u25CB ") }),
|
|
13425
|
-
jsx7(Text4, { bold: index === 0, children: theme.color("text", "main") })
|
|
13426
|
-
]
|
|
13427
|
-
}),
|
|
13428
|
-
runs.map((run, i) => {
|
|
13429
|
-
const selected = index === i + 1;
|
|
13430
|
-
const dot = run.status === "running" ? theme.color("accent", "\u25D0") : run.status === "error" ? theme.color("error", "\u25CF") : theme.color("success", "\u25CF");
|
|
13431
|
-
return jsxs4(
|
|
13432
|
-
Box4,
|
|
13433
|
-
{
|
|
13434
|
-
children: [
|
|
13435
|
-
jsx7(Text4, { children: selected ? theme.color("accent", "\u203A ") : " " }),
|
|
13436
|
-
jsx7(Box4, { width: 2, flexShrink: 0, children: jsx7(Text4, { children: dot }) }),
|
|
13437
|
-
jsx7(Box4, {
|
|
13438
|
-
width: NAME_WIDTH,
|
|
13439
|
-
flexShrink: 0,
|
|
13440
|
-
children: jsx7(Text4, { bold: selected, children: theme.color("accent", clampLine(run.name, NAME_WIDTH - 1)) })
|
|
13441
|
-
}),
|
|
13442
|
-
jsx7(Box4, {
|
|
13443
|
-
flexGrow: 1,
|
|
13444
|
-
flexShrink: 1,
|
|
13445
|
-
children: jsx7(Text4, { wrap: "truncate", children: theme.muted(clampLine(run.objective, 56)) })
|
|
13446
|
-
}),
|
|
13447
|
-
jsx7(Text4, { children: theme.dim(` ${runStatusLine(run, clock, tokens[run.id])}`) })
|
|
13448
|
-
]
|
|
13449
|
-
},
|
|
13450
|
-
run.id
|
|
13451
|
-
);
|
|
13452
|
-
})
|
|
13453
|
-
]
|
|
13454
|
-
}),
|
|
13455
|
-
jsx7(Box4, { marginTop: 1, children: jsx7(Text4, { children: theme.dim("\u2191/\u2193 select \xB7 Enter to view \xB7 Enter on main / Esc to return") }) })
|
|
13456
|
-
]
|
|
13457
|
-
});
|
|
13458
|
-
}
|
|
13459
|
-
|
|
13460
|
-
// src/console/components/BackgroundAgents.ts
|
|
13461
|
-
import { Box as Box5, Text as Text5 } from "indusagi/react-host/ink";
|
|
13462
|
-
import { splitAssistantMessage } from "indusagi/react-ink";
|
|
13463
|
-
import { jsx as jsx8, jsxs as jsxs5 } from "indusagi/react-host/jsx-runtime";
|
|
13464
|
-
function readString2(args, key) {
|
|
13465
|
-
const value = args[key];
|
|
13466
|
-
if (typeof value !== "string") return void 0;
|
|
13467
|
-
const trimmed = value.trim();
|
|
13468
|
-
return trimmed.length > 0 ? trimmed : void 0;
|
|
13828
|
+
function readString2(args, key) {
|
|
13829
|
+
const value = args[key];
|
|
13830
|
+
if (typeof value !== "string") return void 0;
|
|
13831
|
+
const trimmed = value.trim();
|
|
13832
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
13469
13833
|
}
|
|
13470
13834
|
function deriveAgentRuns(messages) {
|
|
13471
13835
|
const runs = [];
|
|
@@ -13496,7 +13860,7 @@ function deriveAgentRuns(messages) {
|
|
|
13496
13860
|
return runs.map((run) => ({ ...run, status: status.get(run.id) ?? run.status }));
|
|
13497
13861
|
}
|
|
13498
13862
|
var MAX_VISIBLE_RUNS = 8;
|
|
13499
|
-
var
|
|
13863
|
+
var NAME_WIDTH = 12;
|
|
13500
13864
|
function clamp2(text, width) {
|
|
13501
13865
|
if (text.length <= width) return text;
|
|
13502
13866
|
if (width <= 1) return text.slice(0, width);
|
|
@@ -13506,7 +13870,7 @@ var OBJECTIVE_WIDTH = 64;
|
|
|
13506
13870
|
function oneLine(text) {
|
|
13507
13871
|
return text.replace(/\s+/g, " ").trim();
|
|
13508
13872
|
}
|
|
13509
|
-
function
|
|
13873
|
+
function formatTokens2(tokens) {
|
|
13510
13874
|
if (tokens >= 1e3) return `${(tokens / 1e3).toFixed(1)}k`;
|
|
13511
13875
|
return String(tokens);
|
|
13512
13876
|
}
|
|
@@ -13518,65 +13882,206 @@ function statusText(run, now, tokens) {
|
|
|
13518
13882
|
head = `${Math.max(0, Math.round((now - run.startedAt) / 1e3))}s`;
|
|
13519
13883
|
} else head = "running";
|
|
13520
13884
|
if (tokens !== void 0 && tokens > 0) {
|
|
13521
|
-
return `${head} \xB7 \u2193 ${
|
|
13885
|
+
return `${head} \xB7 \u2193 ${formatTokens2(tokens)} tokens`;
|
|
13522
13886
|
}
|
|
13523
13887
|
return head;
|
|
13524
13888
|
}
|
|
13889
|
+
function useAgentClock(active, supplied) {
|
|
13890
|
+
const [now, setNow] = useState6(Date.now);
|
|
13891
|
+
useEffect6(() => {
|
|
13892
|
+
if (!active || supplied !== void 0) return;
|
|
13893
|
+
const timer = setInterval(() => setNow(Date.now()), 1e3);
|
|
13894
|
+
return () => clearInterval(timer);
|
|
13895
|
+
}, [active, supplied]);
|
|
13896
|
+
return supplied ?? now;
|
|
13897
|
+
}
|
|
13525
13898
|
function BackgroundAgents({ theme, runs, tokens, now }) {
|
|
13526
|
-
const clock =
|
|
13899
|
+
const clock = useAgentClock(runs.some((run) => run.status === "running"), now);
|
|
13527
13900
|
const runningCount = runs.reduce((n, run) => run.status === "running" ? n + 1 : n, 0);
|
|
13528
13901
|
if (runningCount === 0) return null;
|
|
13529
|
-
const
|
|
13530
|
-
|
|
13902
|
+
const running = runs.filter((run) => run.status === "running");
|
|
13903
|
+
const recentDone = runs.filter((run) => run.status !== "running").slice(-Math.max(0, MAX_VISIBLE_RUNS - running.length));
|
|
13904
|
+
const visible = [...running, ...recentDone].slice(0, MAX_VISIBLE_RUNS);
|
|
13905
|
+
return jsxs4(Box5, {
|
|
13531
13906
|
flexDirection: "column",
|
|
13532
13907
|
marginTop: 1,
|
|
13533
13908
|
children: [
|
|
13534
|
-
|
|
13909
|
+
jsxs4(Box5, {
|
|
13535
13910
|
children: [
|
|
13536
|
-
|
|
13537
|
-
|
|
13911
|
+
jsx7(Text5, { children: theme.color("text", "\u25CF ") }),
|
|
13912
|
+
jsx7(Text5, { bold: true, children: theme.color("text", "main") })
|
|
13538
13913
|
]
|
|
13539
13914
|
}),
|
|
13540
13915
|
visible.map((run) => {
|
|
13541
13916
|
const dot = run.status === "running" ? theme.color("accent", "\u25D0") : run.status === "error" ? theme.color("error", "\u25CF") : theme.color("success", "\u25CF");
|
|
13542
|
-
return
|
|
13917
|
+
return jsxs4(
|
|
13543
13918
|
Box5,
|
|
13544
13919
|
{
|
|
13545
13920
|
children: [
|
|
13546
|
-
|
|
13547
|
-
|
|
13548
|
-
width:
|
|
13921
|
+
jsx7(Box5, { width: 2, flexShrink: 0, children: jsx7(Text5, { children: dot }) }),
|
|
13922
|
+
jsx7(Box5, {
|
|
13923
|
+
width: NAME_WIDTH,
|
|
13549
13924
|
flexShrink: 0,
|
|
13550
|
-
children:
|
|
13925
|
+
children: jsx7(Text5, { bold: true, children: theme.color("accent", clamp2(run.name, NAME_WIDTH - 1)) })
|
|
13551
13926
|
}),
|
|
13552
|
-
|
|
13927
|
+
jsx7(Box5, {
|
|
13553
13928
|
flexGrow: 1,
|
|
13554
13929
|
flexShrink: 1,
|
|
13555
|
-
children:
|
|
13930
|
+
children: jsx7(Text5, { wrap: "truncate", children: theme.muted(clamp2(oneLine(run.objective), OBJECTIVE_WIDTH)) })
|
|
13556
13931
|
}),
|
|
13557
|
-
|
|
13932
|
+
jsx7(Text5, { children: theme.dim(` ${statusText(run, clock, tokens?.[run.id])}`) })
|
|
13558
13933
|
]
|
|
13559
13934
|
},
|
|
13560
13935
|
run.id
|
|
13561
13936
|
);
|
|
13562
13937
|
}),
|
|
13563
|
-
|
|
13938
|
+
jsxs4(Box5, {
|
|
13564
13939
|
marginTop: 1,
|
|
13565
13940
|
children: [
|
|
13566
|
-
|
|
13567
|
-
|
|
13941
|
+
jsx7(Text5, { children: theme.color("accent", "\u2736 ") }),
|
|
13942
|
+
jsx7(Text5, { children: theme.muted(`Waiting for ${runningCount} background agent${runningCount === 1 ? "" : "s"} to finish`) })
|
|
13568
13943
|
]
|
|
13569
13944
|
})
|
|
13570
13945
|
]
|
|
13571
13946
|
});
|
|
13572
13947
|
}
|
|
13573
13948
|
|
|
13949
|
+
// src/console/components/AgentsView.ts
|
|
13950
|
+
function formatTokens3(tokens) {
|
|
13951
|
+
return tokens >= 1e3 ? `${(tokens / 1e3).toFixed(1)}k` : String(tokens);
|
|
13952
|
+
}
|
|
13953
|
+
function clampLine(text, width) {
|
|
13954
|
+
const flat = text.replace(/\s+/g, " ").trim();
|
|
13955
|
+
if (flat.length <= width) return flat;
|
|
13956
|
+
if (width <= 1) return flat.slice(0, width);
|
|
13957
|
+
return `${flat.slice(0, width - 1)}\u2026`;
|
|
13958
|
+
}
|
|
13959
|
+
function runStatusLine(run, now, tokens) {
|
|
13960
|
+
let head;
|
|
13961
|
+
if (run.status === "error") head = "failed";
|
|
13962
|
+
else if (run.status === "done") head = "done";
|
|
13963
|
+
else if (run.startedAt > 0 && now >= run.startedAt) {
|
|
13964
|
+
head = `${Math.max(0, Math.round((now - run.startedAt) / 1e3))}s`;
|
|
13965
|
+
} else head = "working";
|
|
13966
|
+
const tok = tokens !== void 0 && tokens > 0 ? ` \xB7 \u2193 ${formatTokens3(tokens)} tokens` : "";
|
|
13967
|
+
return `${head}${tok}`;
|
|
13968
|
+
}
|
|
13969
|
+
var NAME_WIDTH2 = 12;
|
|
13970
|
+
function ActivityRow({ theme, line }) {
|
|
13971
|
+
if (line.tone === "tool") {
|
|
13972
|
+
return jsxs5(Box6, {
|
|
13973
|
+
children: [
|
|
13974
|
+
jsx8(Text6, { children: theme.color("success", "\u25CF ") }),
|
|
13975
|
+
jsx8(Text6, { children: theme.color("text", clampLine(line.text, 96)) })
|
|
13976
|
+
]
|
|
13977
|
+
});
|
|
13978
|
+
}
|
|
13979
|
+
if (line.tone === "result") {
|
|
13980
|
+
return jsx8(Box6, { marginLeft: 2, children: jsx8(Text6, { children: theme.dim(`\u2514 ${clampLine(line.text, 92)}`) }) });
|
|
13981
|
+
}
|
|
13982
|
+
return jsxs5(Box6, {
|
|
13983
|
+
children: [
|
|
13984
|
+
jsx8(Text6, { children: theme.color("accent", "\u25CF ") }),
|
|
13985
|
+
jsx8(Text6, { children: theme.color("text", clampLine(line.text, 96)) })
|
|
13986
|
+
]
|
|
13987
|
+
});
|
|
13988
|
+
}
|
|
13989
|
+
function AgentsView({ theme, runs, activity, tokens, now, onExit }) {
|
|
13990
|
+
const clock = useAgentClock(runs.some((run) => run.status === "running"), now);
|
|
13991
|
+
const [selectedIndex, setSelectedIndex] = useState7(runs.length > 0 ? 1 : 0);
|
|
13992
|
+
const rowCount = runs.length + 1;
|
|
13993
|
+
const index = Math.min(selectedIndex, rowCount - 1);
|
|
13994
|
+
const viewed = index > 0 ? runs[index - 1] : void 0;
|
|
13995
|
+
useInput4((input, key) => {
|
|
13996
|
+
if (key.escape || input === "x") return onExit();
|
|
13997
|
+
if (key.upArrow) return setSelectedIndex((i) => wrapSelectionIndex2(Math.min(i, rowCount - 1), -1, rowCount));
|
|
13998
|
+
if (key.downArrow) return setSelectedIndex((i) => wrapSelectionIndex2(Math.min(i, rowCount - 1), 1, rowCount));
|
|
13999
|
+
if (key.return && index === 0) onExit();
|
|
14000
|
+
});
|
|
14001
|
+
const lines = viewed ? activity[viewed.id] ?? [] : [];
|
|
14002
|
+
return jsxs5(Box6, {
|
|
14003
|
+
flexDirection: "column",
|
|
14004
|
+
marginTop: 1,
|
|
14005
|
+
children: [
|
|
14006
|
+
viewed ? jsxs5(Box6, {
|
|
14007
|
+
flexDirection: "column",
|
|
14008
|
+
children: [
|
|
14009
|
+
jsxs5(Box6, {
|
|
14010
|
+
marginBottom: 1,
|
|
14011
|
+
children: [
|
|
14012
|
+
jsx8(Text6, { children: theme.color("accent", "\u2736 ") }),
|
|
14013
|
+
jsx8(Text6, { bold: true, children: theme.color("accent", viewed.name) }),
|
|
14014
|
+
jsx8(Text6, { children: theme.dim(` ${runStatusLine(viewed, clock, tokens[viewed.id])}`) })
|
|
14015
|
+
]
|
|
14016
|
+
}),
|
|
14017
|
+
lines.length === 0 ? jsx8(Text6, { children: theme.muted(" Waiting for the first step\u2026") }) : lines.map((line, i) => jsx8(ActivityRow, { theme, line }, i)),
|
|
14018
|
+
jsx8(Box6, {
|
|
14019
|
+
marginTop: 1,
|
|
14020
|
+
children: jsx8(Text6, { wrap: "truncate", children: theme.muted(`\u2514 ${clampLine(viewed.objective, 100)}`) })
|
|
14021
|
+
})
|
|
14022
|
+
]
|
|
14023
|
+
}) : jsxs5(Box6, {
|
|
14024
|
+
children: [
|
|
14025
|
+
jsx8(Text6, { children: theme.muted("Select a sub-agent to view its live activity, or press Enter on ") }),
|
|
14026
|
+
jsx8(Text6, { bold: true, children: theme.color("text", "main") }),
|
|
14027
|
+
jsx8(Text6, { children: theme.muted(" to return.") })
|
|
14028
|
+
]
|
|
14029
|
+
}),
|
|
14030
|
+
jsxs5(Box6, {
|
|
14031
|
+
flexDirection: "column",
|
|
14032
|
+
marginTop: 1,
|
|
14033
|
+
borderStyle: "single",
|
|
14034
|
+
borderColor: theme.colors["borderMuted"],
|
|
14035
|
+
borderBottom: false,
|
|
14036
|
+
borderLeft: false,
|
|
14037
|
+
borderRight: false,
|
|
14038
|
+
paddingTop: 0,
|
|
14039
|
+
children: [
|
|
14040
|
+
jsxs5(Box6, {
|
|
14041
|
+
children: [
|
|
14042
|
+
jsx8(Text6, { children: index === 0 ? theme.color("accent", "\u203A ") : " " }),
|
|
14043
|
+
jsx8(Text6, { children: index === 0 ? theme.color("text", "\u25CF ") : theme.dim("\u25CB ") }),
|
|
14044
|
+
jsx8(Text6, { bold: index === 0, children: theme.color("text", "main") })
|
|
14045
|
+
]
|
|
14046
|
+
}),
|
|
14047
|
+
runs.map((run, i) => {
|
|
14048
|
+
const selected = index === i + 1;
|
|
14049
|
+
const dot = run.status === "running" ? theme.color("accent", "\u25D0") : run.status === "error" ? theme.color("error", "\u25CF") : theme.color("success", "\u25CF");
|
|
14050
|
+
return jsxs5(
|
|
14051
|
+
Box6,
|
|
14052
|
+
{
|
|
14053
|
+
children: [
|
|
14054
|
+
jsx8(Text6, { children: selected ? theme.color("accent", "\u203A ") : " " }),
|
|
14055
|
+
jsx8(Box6, { width: 2, flexShrink: 0, children: jsx8(Text6, { children: dot }) }),
|
|
14056
|
+
jsx8(Box6, {
|
|
14057
|
+
width: NAME_WIDTH2,
|
|
14058
|
+
flexShrink: 0,
|
|
14059
|
+
children: jsx8(Text6, { bold: selected, children: theme.color("accent", clampLine(run.name, NAME_WIDTH2 - 1)) })
|
|
14060
|
+
}),
|
|
14061
|
+
jsx8(Box6, {
|
|
14062
|
+
flexGrow: 1,
|
|
14063
|
+
flexShrink: 1,
|
|
14064
|
+
children: jsx8(Text6, { wrap: "truncate", children: theme.muted(clampLine(run.objective, 56)) })
|
|
14065
|
+
}),
|
|
14066
|
+
jsx8(Text6, { children: theme.dim(` ${runStatusLine(run, clock, tokens[run.id])}`) })
|
|
14067
|
+
]
|
|
14068
|
+
},
|
|
14069
|
+
run.id
|
|
14070
|
+
);
|
|
14071
|
+
})
|
|
14072
|
+
]
|
|
14073
|
+
}),
|
|
14074
|
+
jsx8(Box6, { marginTop: 1, children: jsx8(Text6, { children: theme.dim("\u2191/\u2193 select \xB7 Enter to view \xB7 Enter on main / Esc to return") }) })
|
|
14075
|
+
]
|
|
14076
|
+
});
|
|
14077
|
+
}
|
|
14078
|
+
|
|
13574
14079
|
// src/console/components/Banner.ts
|
|
13575
|
-
import { Fragment as Fragment3, jsx as
|
|
13576
|
-
import { Box as
|
|
14080
|
+
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs6 } from "indusagi/react-host/jsx-runtime";
|
|
14081
|
+
import { Box as Box8, Text as Text7 } from "indusagi/react-host/ink";
|
|
13577
14082
|
import { ChangelogBlock } from "indusagi/react-ink";
|
|
13578
|
-
import { homedir as
|
|
13579
|
-
import { basename as
|
|
14083
|
+
import { homedir as homedir5 } from "node:os";
|
|
14084
|
+
import { basename as basename7 } from "node:path";
|
|
13580
14085
|
|
|
13581
14086
|
// src/console/components/banner-sweep.ts
|
|
13582
14087
|
var WELCOME_FALLBACK = "Welcome back!";
|
|
@@ -13587,6 +14092,70 @@ function welcomeLine(name) {
|
|
|
13587
14092
|
if (trimmed.length === 0 || trimmed.length > MAX_NAME) return WELCOME_FALLBACK;
|
|
13588
14093
|
return `Welcome back, ${trimmed}!`;
|
|
13589
14094
|
}
|
|
14095
|
+
function rowGradient(rowIndex, rowCount, primaryHex, secondaryHex) {
|
|
14096
|
+
if (rowCount <= 1) return primaryHex;
|
|
14097
|
+
const t = Math.max(0, Math.min(1, rowIndex / (rowCount - 1)));
|
|
14098
|
+
const a = Number.parseInt(primaryHex.replace("#", ""), 16);
|
|
14099
|
+
const b = Number.parseInt(secondaryHex.replace("#", ""), 16);
|
|
14100
|
+
const channel = (shift) => Math.round((a >> shift & 255) * (1 - t) + (b >> shift & 255) * t).toString(16).padStart(2, "0");
|
|
14101
|
+
return `#${channel(16)}${channel(8)}${channel(0)}`;
|
|
14102
|
+
}
|
|
14103
|
+
|
|
14104
|
+
// src/console/components/Banner.ts
|
|
14105
|
+
import chalk3 from "chalk";
|
|
14106
|
+
|
|
14107
|
+
// src/console/components/ScrollViewport.ts
|
|
14108
|
+
import React2, { useEffect as useEffect7, useState as useState8 } from "indusagi/react-host";
|
|
14109
|
+
import { Box as Box7, useInput as useInput5 } from "indusagi/react-host/ink";
|
|
14110
|
+
import { measureElement, useStdout } from "ink";
|
|
14111
|
+
import { jsx as jsx9 } from "indusagi/react-host/jsx-runtime";
|
|
14112
|
+
function useTerminalSize() {
|
|
14113
|
+
const { stdout } = useStdout();
|
|
14114
|
+
const read = () => ({ columns: Math.max(1, stdout.columns || 80), rows: Math.max(1, stdout.rows || 24) });
|
|
14115
|
+
const [size, setSize] = useState8(read);
|
|
14116
|
+
useEffect7(() => {
|
|
14117
|
+
const resize = () => setSize(read());
|
|
14118
|
+
stdout.on("resize", resize);
|
|
14119
|
+
return () => {
|
|
14120
|
+
stdout.off("resize", resize);
|
|
14121
|
+
};
|
|
14122
|
+
}, [stdout]);
|
|
14123
|
+
return size;
|
|
14124
|
+
}
|
|
14125
|
+
function ScrollViewport({ children, active = true, follow = true }) {
|
|
14126
|
+
const outer = React2.useRef(null);
|
|
14127
|
+
const inner = React2.useRef(null);
|
|
14128
|
+
const [metrics, setMetrics] = useState8({ height: 1, content: 1 });
|
|
14129
|
+
const [offset, setOffset] = useState8(0);
|
|
14130
|
+
useEffect7(() => {
|
|
14131
|
+
if (!outer.current || !inner.current) return;
|
|
14132
|
+
const height = measureElement(outer.current).height;
|
|
14133
|
+
const content = measureElement(inner.current).height;
|
|
14134
|
+
if (metrics.height !== height || metrics.content !== content) {
|
|
14135
|
+
const oldMax = Math.max(0, metrics.content - metrics.height);
|
|
14136
|
+
const newMax = Math.max(0, content - height);
|
|
14137
|
+
if (follow) setOffset((n) => n === 0 ? 0 : Math.max(0, Math.min(newMax, n + newMax - oldMax)));
|
|
14138
|
+
setMetrics({ height, content });
|
|
14139
|
+
}
|
|
14140
|
+
});
|
|
14141
|
+
const max = Math.max(0, metrics.content - metrics.height);
|
|
14142
|
+
const scroll = Math.min(max, offset);
|
|
14143
|
+
useInput5((_input, key) => {
|
|
14144
|
+
const step = Math.max(1, metrics.height - 2);
|
|
14145
|
+
if (key.pageUp) setOffset((n) => Math.min(max, n + (follow ? step : -step)));
|
|
14146
|
+
if (key.pageDown) setOffset((n) => Math.max(0, Math.min(max, n + (follow ? -step : step))));
|
|
14147
|
+
}, { isActive: active });
|
|
14148
|
+
const top = follow ? Math.max(0, max - scroll) : Math.max(0, scroll);
|
|
14149
|
+
return jsx9(Box7, {
|
|
14150
|
+
ref: outer,
|
|
14151
|
+
flexDirection: "column",
|
|
14152
|
+
flexGrow: 1,
|
|
14153
|
+
flexBasis: 0,
|
|
14154
|
+
minHeight: 1,
|
|
14155
|
+
overflow: "hidden",
|
|
14156
|
+
children: jsx9(Box7, { ref: inner, flexDirection: "column", flexShrink: 0, marginTop: -top, children })
|
|
14157
|
+
});
|
|
14158
|
+
}
|
|
13590
14159
|
|
|
13591
14160
|
// src/console/components/Banner.ts
|
|
13592
14161
|
var BRAND2 = "IndusCode";
|
|
@@ -13599,12 +14168,16 @@ var WORDMARK_ROWS = [
|
|
|
13599
14168
|
"\u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551",
|
|
13600
14169
|
"\u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"
|
|
13601
14170
|
];
|
|
14171
|
+
function StartupSummary({ theme, startup }) {
|
|
14172
|
+
if (!startup?.sections.length) return null;
|
|
14173
|
+
return jsx10(Text7, { wrap: "truncate-end", children: theme.muted(startup.sections.map((section2) => `${section2.title}: ${section2.count}`).join(" \xB7 ")) });
|
|
14174
|
+
}
|
|
13602
14175
|
function StartupNotices({ theme, notices }) {
|
|
13603
14176
|
if (notices.length === 0) return null;
|
|
13604
|
-
return
|
|
14177
|
+
return jsx10(Box8, {
|
|
13605
14178
|
flexDirection: "column",
|
|
13606
14179
|
marginBottom: 1,
|
|
13607
|
-
children: notices.map((notice, index) =>
|
|
14180
|
+
children: notices.map((notice, index) => jsx10(Text7, { children: paintNotice(theme, notice) }, index))
|
|
13608
14181
|
});
|
|
13609
14182
|
}
|
|
13610
14183
|
function paintNotice(theme, notice) {
|
|
@@ -13620,15 +14193,15 @@ function paintNotice(theme, notice) {
|
|
|
13620
14193
|
}
|
|
13621
14194
|
function StartupChangelogBlock({ theme, changelog }) {
|
|
13622
14195
|
if (changelog.mode === "full" && changelog.markdown !== void 0) {
|
|
13623
|
-
return
|
|
14196
|
+
return jsx10(ChangelogBlock, { markdown: changelog.markdown, theme, title: "What is new" });
|
|
13624
14197
|
}
|
|
13625
14198
|
if (changelog.mode === "condensed") {
|
|
13626
|
-
return jsxs6(
|
|
14199
|
+
return jsxs6(Box8, {
|
|
13627
14200
|
marginTop: 1,
|
|
13628
14201
|
children: [
|
|
13629
|
-
|
|
13630
|
-
|
|
13631
|
-
|
|
14202
|
+
jsx10(Text7, { children: theme.muted(`Updated to v${changelog.version}. Use `) }),
|
|
14203
|
+
jsx10(Text7, { children: theme.color("accent", "/changelog") }),
|
|
14204
|
+
jsx10(Text7, { children: theme.muted(" to view the full changelog.") })
|
|
13632
14205
|
]
|
|
13633
14206
|
});
|
|
13634
14207
|
}
|
|
@@ -13638,46 +14211,46 @@ function WelcomeLine({ theme, name, tone = "accent" }) {
|
|
|
13638
14211
|
const paint = (text) => tone === "muted" ? theme.muted(text) : theme.color("accent", text);
|
|
13639
14212
|
const line = welcomeLine(name);
|
|
13640
14213
|
if (name !== void 0 && line !== "Welcome back!") {
|
|
13641
|
-
return jsxs6(
|
|
14214
|
+
return jsxs6(Box8, {
|
|
13642
14215
|
children: [
|
|
13643
|
-
|
|
13644
|
-
|
|
13645
|
-
|
|
14216
|
+
jsx10(Text7, { children: paint("Welcome back, ") }),
|
|
14217
|
+
jsx10(Text7, { bold: true, children: name.trim() }),
|
|
14218
|
+
jsx10(Text7, { children: paint("!") })
|
|
13646
14219
|
]
|
|
13647
14220
|
});
|
|
13648
14221
|
}
|
|
13649
|
-
return
|
|
14222
|
+
return jsx10(Box8, { children: jsx10(Text7, { children: paint(line) }) });
|
|
13650
14223
|
}
|
|
13651
14224
|
function ShellLine({ theme, workspace, branch }) {
|
|
13652
|
-
const dir =
|
|
13653
|
-
return jsxs6(
|
|
14225
|
+
const dir = basename7(workspace);
|
|
14226
|
+
return jsxs6(Box8, {
|
|
13654
14227
|
children: [
|
|
13655
|
-
|
|
13656
|
-
|
|
13657
|
-
|
|
14228
|
+
jsx10(Text7, { children: theme.color("customMessage", "\u279C") }),
|
|
14229
|
+
jsx10(Text7, { children: " " }),
|
|
14230
|
+
jsx10(Text7, { bold: true, children: theme.color("text", dir) }),
|
|
13658
14231
|
branch !== void 0 && branch !== null && branch.length > 0 ? jsxs6(Fragment3, {
|
|
13659
14232
|
children: [
|
|
13660
|
-
|
|
13661
|
-
|
|
13662
|
-
|
|
13663
|
-
|
|
14233
|
+
jsx10(Text7, { children: " " }),
|
|
14234
|
+
jsx10(Text7, { children: theme.color("accent", "git:(") }),
|
|
14235
|
+
jsx10(Text7, { children: theme.color("customMessage", branch) }),
|
|
14236
|
+
jsx10(Text7, { children: theme.color("accent", ")") })
|
|
13664
14237
|
]
|
|
13665
14238
|
}) : null,
|
|
13666
|
-
|
|
14239
|
+
jsx10(Text7, { children: theme.dim(" indus") })
|
|
13667
14240
|
]
|
|
13668
14241
|
});
|
|
13669
14242
|
}
|
|
13670
|
-
function Wordmark({ theme }) {
|
|
13671
|
-
return
|
|
14243
|
+
function Wordmark({ theme, sweep }) {
|
|
14244
|
+
return jsx10(Box8, {
|
|
13672
14245
|
flexDirection: "column",
|
|
13673
|
-
children: WORDMARK_ROWS.map((line, index) =>
|
|
14246
|
+
children: WORDMARK_ROWS.map((line, index) => jsx10(Text7, { children: sweep ? chalk3.hex(rowGradient(index, WORDMARK_ROWS.length, theme.colors.accent, theme.colors.customMessage))(line) : theme.color("accent", line) }, index))
|
|
13674
14247
|
});
|
|
13675
14248
|
}
|
|
13676
14249
|
function SessionFact({ theme, label, value }) {
|
|
13677
|
-
return jsxs6(
|
|
14250
|
+
return jsxs6(Box8, {
|
|
13678
14251
|
children: [
|
|
13679
|
-
|
|
13680
|
-
|
|
14252
|
+
jsx10(Text7, { children: theme.dim(`${label.padEnd(7)} `) }),
|
|
14253
|
+
jsx10(Text7, { children: theme.muted(value) })
|
|
13681
14254
|
]
|
|
13682
14255
|
});
|
|
13683
14256
|
}
|
|
@@ -13693,17 +14266,17 @@ function paintMascot(theme, tone, text) {
|
|
|
13693
14266
|
return theme.dim(text);
|
|
13694
14267
|
}
|
|
13695
14268
|
}
|
|
13696
|
-
function Mascot({ theme, face }) {
|
|
13697
|
-
return
|
|
14269
|
+
function Mascot({ theme, face, sweep }) {
|
|
14270
|
+
return jsx10(Box8, {
|
|
13698
14271
|
flexDirection: "column",
|
|
13699
14272
|
alignItems: "center",
|
|
13700
14273
|
marginY: 1,
|
|
13701
14274
|
children: mascotRows(face).map(
|
|
13702
|
-
(row, rowIndex) =>
|
|
13703
|
-
|
|
14275
|
+
(row, rowIndex) => jsx10(
|
|
14276
|
+
Box8,
|
|
13704
14277
|
{
|
|
13705
14278
|
children: row.map(
|
|
13706
|
-
(seg, segIndex) =>
|
|
14279
|
+
(seg, segIndex) => jsx10(Text7, { children: sweep && seg.tone === "head" ? chalk3.hex(rowGradient(rowIndex, 5, theme.colors.accent, theme.colors.customMessage))(seg.text) : paintMascot(theme, seg.tone, seg.text) }, segIndex)
|
|
13707
14280
|
)
|
|
13708
14281
|
},
|
|
13709
14282
|
rowIndex
|
|
@@ -13712,13 +14285,14 @@ function Mascot({ theme, face }) {
|
|
|
13712
14285
|
});
|
|
13713
14286
|
}
|
|
13714
14287
|
function shortenWorkspace(workspace) {
|
|
13715
|
-
const home =
|
|
14288
|
+
const home = homedir5();
|
|
13716
14289
|
if (home.length > 0 && workspace.startsWith(home)) {
|
|
13717
14290
|
return `~${workspace.slice(home.length)}`;
|
|
13718
14291
|
}
|
|
13719
14292
|
return workspace;
|
|
13720
14293
|
}
|
|
13721
14294
|
function Banner(props) {
|
|
14295
|
+
const { columns } = useTerminalSize();
|
|
13722
14296
|
const {
|
|
13723
14297
|
theme,
|
|
13724
14298
|
modelId,
|
|
@@ -13732,71 +14306,75 @@ function Banner(props) {
|
|
|
13732
14306
|
variantSeed,
|
|
13733
14307
|
whatsNew,
|
|
13734
14308
|
notices,
|
|
13735
|
-
changelog
|
|
14309
|
+
changelog,
|
|
14310
|
+
sweep,
|
|
14311
|
+
startup
|
|
13736
14312
|
} = props;
|
|
13737
14313
|
const noticeList = notices ?? [];
|
|
13738
|
-
if (quiet || compact) {
|
|
13739
|
-
return jsxs6(
|
|
14314
|
+
if (quiet || compact || columns < 76) {
|
|
14315
|
+
return jsxs6(Box8, {
|
|
13740
14316
|
flexDirection: "column",
|
|
13741
14317
|
marginBottom: 1,
|
|
13742
14318
|
children: [
|
|
13743
|
-
|
|
13744
|
-
|
|
14319
|
+
jsx10(StartupNotices, { theme, notices: noticeList }),
|
|
14320
|
+
jsx10(StartupSummary, { theme, startup }),
|
|
14321
|
+
jsxs6(Box8, {
|
|
13745
14322
|
children: [
|
|
13746
14323
|
compact ? jsxs6(Fragment3, {
|
|
13747
14324
|
children: [
|
|
13748
|
-
|
|
13749
|
-
|
|
13750
|
-
|
|
14325
|
+
jsx10(Text7, { children: theme.color("accent", COMPACT_EMBLEM.slice(0, 2)) }),
|
|
14326
|
+
jsx10(Text7, { children: theme.color("customMessage", COMPACT_EMBLEM.slice(2)) }),
|
|
14327
|
+
jsx10(Text7, { children: " " })
|
|
13751
14328
|
]
|
|
13752
14329
|
}) : null,
|
|
13753
|
-
|
|
13754
|
-
|
|
13755
|
-
|
|
13756
|
-
|
|
13757
|
-
|
|
14330
|
+
jsx10(Text7, { bold: true, children: theme.color("accent", BRAND2) }),
|
|
14331
|
+
jsx10(Text7, { children: " " }),
|
|
14332
|
+
jsx10(Text7, { children: theme.muted(`v${version}`) }),
|
|
14333
|
+
jsx10(Text7, { children: " " }),
|
|
14334
|
+
jsx10(Text7, { children: theme.dim(modelId) })
|
|
13758
14335
|
]
|
|
13759
14336
|
}),
|
|
13760
|
-
|
|
13761
|
-
changelog ?
|
|
14337
|
+
jsx10(WelcomeLine, { theme, name, tone: "muted" }),
|
|
14338
|
+
changelog ? jsx10(StartupChangelogBlock, { theme, changelog }) : null
|
|
13762
14339
|
]
|
|
13763
14340
|
});
|
|
13764
14341
|
}
|
|
13765
14342
|
if (started) {
|
|
13766
|
-
return jsxs6(
|
|
14343
|
+
return jsxs6(Box8, {
|
|
13767
14344
|
flexDirection: "column",
|
|
13768
14345
|
marginBottom: 1,
|
|
13769
14346
|
children: [
|
|
13770
|
-
|
|
13771
|
-
|
|
13772
|
-
|
|
13773
|
-
|
|
14347
|
+
jsx10(StartupNotices, { theme, notices: noticeList }),
|
|
14348
|
+
jsx10(StartupSummary, { theme, startup }),
|
|
14349
|
+
jsx10(ShellLine, { theme, workspace, branch }),
|
|
14350
|
+
jsx10(Box8, { marginTop: 1, children: jsx10(Wordmark, { theme, sweep }) }),
|
|
14351
|
+
jsxs6(Box8, {
|
|
13774
14352
|
marginTop: 1,
|
|
13775
14353
|
flexDirection: "column",
|
|
13776
14354
|
children: [
|
|
13777
|
-
jsxs6(
|
|
14355
|
+
jsxs6(Box8, {
|
|
13778
14356
|
children: [
|
|
13779
|
-
|
|
13780
|
-
|
|
13781
|
-
|
|
14357
|
+
jsx10(Text7, { bold: true, children: theme.color("accent", "indus console") }),
|
|
14358
|
+
jsx10(Text7, { children: " " }),
|
|
14359
|
+
jsx10(Text7, { children: theme.dim(`v${version}`) })
|
|
13782
14360
|
]
|
|
13783
14361
|
}),
|
|
13784
|
-
|
|
14362
|
+
jsx10(WelcomeLine, { theme, name, tone: "accent" })
|
|
13785
14363
|
]
|
|
13786
14364
|
}),
|
|
13787
|
-
jsxs6(
|
|
14365
|
+
jsxs6(Box8, {
|
|
13788
14366
|
flexDirection: "column",
|
|
13789
14367
|
borderStyle: "round",
|
|
13790
14368
|
borderColor: theme.colors["accent"],
|
|
13791
14369
|
paddingX: 1,
|
|
13792
14370
|
marginTop: 1,
|
|
13793
14371
|
children: [
|
|
13794
|
-
|
|
13795
|
-
|
|
13796
|
-
|
|
14372
|
+
jsx10(Text7, { bold: true, children: theme.color("accent", "Session") }),
|
|
14373
|
+
jsx10(SessionFact, { theme, label: "model", value: modelId }),
|
|
14374
|
+
jsx10(SessionFact, { theme, label: "cwd", value: shortenWorkspace(workspace) })
|
|
13797
14375
|
]
|
|
13798
14376
|
}),
|
|
13799
|
-
changelog ?
|
|
14377
|
+
changelog ? jsx10(StartupChangelogBlock, { theme, changelog }) : null
|
|
13800
14378
|
]
|
|
13801
14379
|
});
|
|
13802
14380
|
}
|
|
@@ -13804,43 +14382,44 @@ function Banner(props) {
|
|
|
13804
14382
|
const greeting = welcomeLine(name);
|
|
13805
14383
|
const news = whatsNew && whatsNew.length > 0 ? whatsNew : WHATS_NEW;
|
|
13806
14384
|
const metaLine = modelId;
|
|
13807
|
-
return jsxs6(
|
|
14385
|
+
return jsxs6(Box8, {
|
|
13808
14386
|
flexDirection: "column",
|
|
13809
14387
|
marginBottom: 1,
|
|
13810
14388
|
children: [
|
|
13811
|
-
|
|
13812
|
-
|
|
14389
|
+
jsx10(StartupNotices, { theme, notices: noticeList }),
|
|
14390
|
+
jsx10(StartupSummary, { theme, startup }),
|
|
14391
|
+
jsxs6(Box8, {
|
|
13813
14392
|
flexDirection: "column",
|
|
13814
14393
|
borderStyle: "round",
|
|
13815
14394
|
borderColor: theme.colors["accent"],
|
|
13816
14395
|
paddingX: 2,
|
|
13817
14396
|
paddingY: 1,
|
|
13818
14397
|
children: [
|
|
13819
|
-
jsxs6(
|
|
14398
|
+
jsxs6(Box8, {
|
|
13820
14399
|
children: [
|
|
13821
|
-
|
|
13822
|
-
|
|
13823
|
-
|
|
14400
|
+
jsx10(Text7, { children: theme.color("customMessage", "\u25CF ") }),
|
|
14401
|
+
jsx10(Text7, { bold: true, children: theme.color("accent", `${BRAND2} `) }),
|
|
14402
|
+
jsx10(Text7, { children: theme.dim(`v${version}`) })
|
|
13824
14403
|
]
|
|
13825
14404
|
}),
|
|
13826
|
-
jsxs6(
|
|
14405
|
+
jsxs6(Box8, {
|
|
13827
14406
|
marginTop: 1,
|
|
13828
14407
|
flexDirection: "row",
|
|
13829
14408
|
children: [
|
|
13830
|
-
jsxs6(
|
|
14409
|
+
jsxs6(Box8, {
|
|
13831
14410
|
flexDirection: "column",
|
|
13832
14411
|
alignItems: "center",
|
|
13833
14412
|
width: 32,
|
|
13834
14413
|
flexShrink: 0,
|
|
13835
14414
|
marginRight: 2,
|
|
13836
14415
|
children: [
|
|
13837
|
-
|
|
13838
|
-
|
|
13839
|
-
|
|
13840
|
-
|
|
14416
|
+
jsx10(Text7, { bold: true, children: theme.color("text", greeting) }),
|
|
14417
|
+
jsx10(Mascot, { theme, face: variant.mascot, sweep }),
|
|
14418
|
+
jsx10(Text7, { children: theme.dim(metaLine) }),
|
|
14419
|
+
jsx10(Text7, { children: theme.dim(shortenWorkspace(workspace)) })
|
|
13841
14420
|
]
|
|
13842
14421
|
}),
|
|
13843
|
-
jsxs6(
|
|
14422
|
+
jsxs6(Box8, {
|
|
13844
14423
|
flexDirection: "column",
|
|
13845
14424
|
flexGrow: 1,
|
|
13846
14425
|
borderStyle: "single",
|
|
@@ -13850,108 +14429,96 @@ function Banner(props) {
|
|
|
13850
14429
|
borderBottom: false,
|
|
13851
14430
|
paddingLeft: 2,
|
|
13852
14431
|
children: [
|
|
13853
|
-
|
|
13854
|
-
|
|
13855
|
-
|
|
14432
|
+
jsx10(Text7, { bold: true, children: theme.color("accent", "Tips for getting started") }),
|
|
14433
|
+
jsx10(Text7, { children: theme.color("text", variant.tip) }),
|
|
14434
|
+
jsx10(Box8, { marginTop: 1, children: jsx10(Text7, { bold: true, children: theme.color("accent", "What's new") }) }),
|
|
13856
14435
|
news.map(
|
|
13857
|
-
(line, index) => jsxs6(
|
|
14436
|
+
(line, index) => jsxs6(Box8, {
|
|
13858
14437
|
flexDirection: "row",
|
|
13859
14438
|
children: [
|
|
13860
|
-
|
|
13861
|
-
|
|
14439
|
+
jsx10(Box8, { width: 2, flexShrink: 0, children: jsx10(Text7, { children: theme.color("customMessage", "\u25B8") }) }),
|
|
14440
|
+
jsx10(Box8, { flexGrow: 1, children: jsx10(Text7, { children: theme.color("text", line) }) })
|
|
13862
14441
|
]
|
|
13863
14442
|
}, index)
|
|
13864
14443
|
),
|
|
13865
|
-
|
|
14444
|
+
jsx10(Box8, { marginTop: 1, children: jsx10(Text7, { italic: true, children: theme.muted("/release-notes for more") }) })
|
|
13866
14445
|
]
|
|
13867
14446
|
})
|
|
13868
14447
|
]
|
|
13869
14448
|
})
|
|
13870
14449
|
]
|
|
13871
14450
|
}),
|
|
13872
|
-
changelog ?
|
|
14451
|
+
changelog ? jsx10(StartupChangelogBlock, { theme, changelog }) : null
|
|
13873
14452
|
]
|
|
13874
14453
|
});
|
|
13875
14454
|
}
|
|
13876
14455
|
|
|
13877
14456
|
// src/console/components/Composer.ts
|
|
13878
|
-
import { Box as
|
|
13879
|
-
import { jsx as
|
|
13880
|
-
|
|
13881
|
-
var
|
|
13882
|
-
|
|
13883
|
-
|
|
13884
|
-
|
|
13885
|
-
|
|
13886
|
-
|
|
13887
|
-
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
14457
|
+
import { Box as Box9, Text as Text8 } from "indusagi/react-host/ink";
|
|
14458
|
+
import { jsx as jsx11, jsxs as jsxs7 } from "indusagi/react-host/jsx-runtime";
|
|
14459
|
+
import stringWidth from "string-width";
|
|
14460
|
+
var segmenter2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
14461
|
+
function editorLines(buffer, caret, width) {
|
|
14462
|
+
const lines = [[]];
|
|
14463
|
+
let column = 0;
|
|
14464
|
+
caret = snapGrapheme(buffer, caret);
|
|
14465
|
+
for (const { segment, index } of segmenter2.segment(buffer + " ")) {
|
|
14466
|
+
const cursor = index === caret;
|
|
14467
|
+
if (segment === "\n") {
|
|
14468
|
+
if (cursor) lines.at(-1).push({ text: " ", caret: true });
|
|
14469
|
+
lines.push([]);
|
|
14470
|
+
column = 0;
|
|
14471
|
+
continue;
|
|
14472
|
+
}
|
|
14473
|
+
const text = segment === " " ? " " : segment.replace(/[\x00-\x1f\x7f]/g, "");
|
|
14474
|
+
const cells2 = stringWidth(text);
|
|
14475
|
+
if (column + cells2 > width && column > 0) {
|
|
14476
|
+
lines.push([]);
|
|
14477
|
+
column = 0;
|
|
14478
|
+
}
|
|
14479
|
+
lines.at(-1).push({ text: cells2 > width ? "?" : text, caret: cursor });
|
|
14480
|
+
column += Math.min(width, cells2);
|
|
14481
|
+
}
|
|
14482
|
+
return lines;
|
|
13896
14483
|
}
|
|
13897
|
-
function Composer({ theme, buffer, caret,
|
|
13898
|
-
const
|
|
13899
|
-
const
|
|
13900
|
-
const
|
|
13901
|
-
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
|
|
13905
|
-
|
|
13906
|
-
|
|
13907
|
-
|
|
13908
|
-
|
|
13909
|
-
|
|
13910
|
-
|
|
13911
|
-
|
|
13912
|
-
|
|
13913
|
-
|
|
13914
|
-
|
|
13915
|
-
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
jsx10(Box7, {
|
|
13930
|
-
width: 2,
|
|
13931
|
-
flexShrink: 0,
|
|
13932
|
-
children: jsx10(Text7, { children: active ? theme.color("accent", "\u25B8") : " " })
|
|
13933
|
-
}),
|
|
13934
|
-
jsx10(Box7, {
|
|
13935
|
-
width: nameWidth,
|
|
13936
|
-
flexShrink: 0,
|
|
13937
|
-
children: jsx10(Text7, { bold: active, children: theme.color("customMessage", name) })
|
|
13938
|
-
}),
|
|
13939
|
-
jsx10(Text7, { children: " " }),
|
|
13940
|
-
jsx10(Text7, { children: theme.muted(suggestion.detail) })
|
|
13941
|
-
]
|
|
13942
|
-
},
|
|
13943
|
-
suggestion.value
|
|
13944
|
-
);
|
|
13945
|
-
})
|
|
13946
|
-
}) : null
|
|
13947
|
-
]
|
|
13948
|
-
});
|
|
14484
|
+
function Composer({ theme, buffer, caret, suggestions, highlight, paddingX = 1 }) {
|
|
14485
|
+
const { columns, rows } = useTerminalSize();
|
|
14486
|
+
const padding = Math.max(0, Math.min(3, Math.floor(paddingX), Math.floor((columns - 8) / 2)));
|
|
14487
|
+
const sendWidth = columns >= 32 ? 7 : 0;
|
|
14488
|
+
const width = Math.max(1, columns - 2 - padding * 2 - 2 - sendWidth);
|
|
14489
|
+
const allLines = editorLines(buffer, caret, width);
|
|
14490
|
+
const caretRow = Math.max(0, allLines.findIndex((line) => line.some((cell) => cell.caret)));
|
|
14491
|
+
const editorBudget = Math.max(1, Math.min(6, Math.floor(rows / 4)));
|
|
14492
|
+
const top = Math.max(0, Math.min(caretRow - editorBudget + 1, allLines.length - editorBudget));
|
|
14493
|
+
const lines = allLines.slice(top, top + editorBudget);
|
|
14494
|
+
const budget = Math.max(1, Math.min(8, rows - lines.length - 12));
|
|
14495
|
+
const start = Math.max(0, Math.min(highlight - budget + 1, suggestions.length - budget));
|
|
14496
|
+
const shown = suggestions.slice(start, start + budget);
|
|
14497
|
+
const nameWidth = Math.max(1, Math.min(24, Math.floor(columns / 3)));
|
|
14498
|
+
return jsxs7(Box9, { flexDirection: "column", flexShrink: 0, children: [
|
|
14499
|
+
jsx11(Box9, {
|
|
14500
|
+
borderStyle: "round",
|
|
14501
|
+
borderColor: theme.colors.borderMuted ?? "gray",
|
|
14502
|
+
paddingX: padding,
|
|
14503
|
+
flexDirection: "column",
|
|
14504
|
+
children: lines.map((line, index) => jsxs7(Box9, { height: 1, flexShrink: 0, children: [
|
|
14505
|
+
jsx11(Box9, { width: 2, flexShrink: 0, children: jsx11(Text8, { children: theme.color("customMessage", index + top === 0 ? "\u203A " : "\xB7 ") }) }),
|
|
14506
|
+
jsx11(Box9, { width, flexShrink: 0, children: jsx11(Text8, { wrap: "truncate-end", children: line.map((cell, i) => jsx11(Text8, { inverse: cell.caret, children: cell.text }, i)) }) }),
|
|
14507
|
+
sendWidth ? jsx11(Box9, { width: sendWidth, flexShrink: 0, children: jsx11(Text8, { children: index === 0 ? theme.dim(" \u21B5 send") : "" }) }) : null
|
|
14508
|
+
] }, index))
|
|
14509
|
+
}),
|
|
14510
|
+
shown.length ? jsx11(Box9, { flexDirection: "column", marginTop: 1, children: shown.map((suggestion, index) => jsxs7(Box9, { height: 1, children: [
|
|
14511
|
+
jsx11(Box9, { width: 2, flexShrink: 0, children: jsx11(Text8, { children: start + index === highlight ? theme.color("accent", "\u25B8") : " " }) }),
|
|
14512
|
+
jsx11(Box9, { width: nameWidth, flexShrink: 0, children: jsx11(Text8, { wrap: "truncate-end", bold: start + index === highlight, children: theme.color("customMessage", suggestion.label) }) }),
|
|
14513
|
+
jsx11(Box9, { width: Math.max(1, columns - nameWidth - 2), children: jsx11(Text8, { wrap: "truncate-end", children: theme.muted(" " + suggestion.detail) }) })
|
|
14514
|
+
] }, suggestion.value)) }) : null
|
|
14515
|
+
] });
|
|
13949
14516
|
}
|
|
13950
14517
|
|
|
13951
14518
|
// src/console/components/StatusBar.ts
|
|
13952
|
-
import { Box as
|
|
14519
|
+
import { Box as Box10, Text as Text9 } from "indusagi/react-host/ink";
|
|
13953
14520
|
import { Footer, StatusLine } from "indusagi/react-ink";
|
|
13954
|
-
import { jsx as
|
|
14521
|
+
import { jsx as jsx12, jsxs as jsxs8 } from "indusagi/react-host/jsx-runtime";
|
|
13955
14522
|
function permissionBadge(mode) {
|
|
13956
14523
|
switch (mode) {
|
|
13957
14524
|
case "acceptEdits":
|
|
@@ -13968,26 +14535,26 @@ function permissionBadge(mode) {
|
|
|
13968
14535
|
}
|
|
13969
14536
|
function StatusBar({ theme, snapshot, branch, providerCount, status, permissionMode }) {
|
|
13970
14537
|
const badge = permissionMode !== void 0 ? permissionBadge(permissionMode) : null;
|
|
13971
|
-
return jsxs8(
|
|
14538
|
+
return jsxs8(Box10, {
|
|
13972
14539
|
flexDirection: "column",
|
|
13973
14540
|
children: [
|
|
13974
|
-
|
|
13975
|
-
badge !== null ?
|
|
13976
|
-
children: jsxs8(
|
|
14541
|
+
jsx12(StatusLine, { theme, snapshot, status, showBusyText: false }),
|
|
14542
|
+
badge !== null ? jsx12(Box10, {
|
|
14543
|
+
children: jsxs8(Text9, {
|
|
13977
14544
|
color: badge.color,
|
|
13978
14545
|
children: ["\u25CF permission: ", badge.label]
|
|
13979
14546
|
})
|
|
13980
14547
|
}) : null,
|
|
13981
|
-
|
|
14548
|
+
jsx12(Footer, { theme, branch, snapshot, availableProviderCount: providerCount })
|
|
13982
14549
|
]
|
|
13983
14550
|
});
|
|
13984
14551
|
}
|
|
13985
14552
|
|
|
13986
14553
|
// src/console/components/WorkingIndicator.ts
|
|
13987
|
-
import
|
|
13988
|
-
import { Box as
|
|
13989
|
-
import { jsx as
|
|
13990
|
-
var { useRef: useRef2 } =
|
|
14554
|
+
import React3, { useEffect as useEffect8, useState as useState9 } from "indusagi/react-host";
|
|
14555
|
+
import { Box as Box11, Text as Text10 } from "indusagi/react-host/ink";
|
|
14556
|
+
import { jsx as jsx13, jsxs as jsxs9 } from "indusagi/react-host/jsx-runtime";
|
|
14557
|
+
var { useRef: useRef2 } = React3;
|
|
13991
14558
|
var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
13992
14559
|
var FRAME_MS = 120;
|
|
13993
14560
|
var WORD_MS = 4e3;
|
|
@@ -14037,11 +14604,11 @@ function phaseLabel(phase) {
|
|
|
14037
14604
|
return null;
|
|
14038
14605
|
}
|
|
14039
14606
|
}
|
|
14040
|
-
function WorkingIndicator({ theme, busy, phase }) {
|
|
14041
|
-
const [frame, setFrame] =
|
|
14607
|
+
function WorkingIndicator({ theme, busy, phase, reducedMotion = false }) {
|
|
14608
|
+
const [frame, setFrame] = useState9(0);
|
|
14042
14609
|
const startRef = useRef2(null);
|
|
14043
14610
|
const wordOffsetRef = useRef2(0);
|
|
14044
|
-
|
|
14611
|
+
useEffect8(() => {
|
|
14045
14612
|
if (!busy) {
|
|
14046
14613
|
startRef.current = null;
|
|
14047
14614
|
return;
|
|
@@ -14050,28 +14617,27 @@ function WorkingIndicator({ theme, busy, phase }) {
|
|
|
14050
14617
|
startRef.current = Date.now();
|
|
14051
14618
|
wordOffsetRef.current = Math.floor(Math.random() * WORKING_WORDS.length);
|
|
14052
14619
|
}
|
|
14053
|
-
const id = setInterval(() => setFrame((f) => (f + 1) % SPINNER_FRAMES.length), FRAME_MS);
|
|
14620
|
+
const id = setInterval(() => setFrame((f) => (f + 1) % SPINNER_FRAMES.length), reducedMotion ? 1e3 : FRAME_MS);
|
|
14054
14621
|
return () => clearInterval(id);
|
|
14055
|
-
}, [busy]);
|
|
14622
|
+
}, [busy, reducedMotion]);
|
|
14056
14623
|
if (!busy) return null;
|
|
14057
14624
|
const elapsedMs = startRef.current !== null ? Date.now() - startRef.current : 0;
|
|
14058
14625
|
const elapsedSec = Math.floor(elapsedMs / 1e3);
|
|
14059
|
-
const spinner = SPINNER_FRAMES[frame % SPINNER_FRAMES.length];
|
|
14060
|
-
const label = phaseLabel(phase) ?? pickWord(wordOffsetRef.current + Math.floor(elapsedMs / WORD_MS));
|
|
14061
|
-
return jsxs9(
|
|
14626
|
+
const spinner = reducedMotion ? "\u2022" : SPINNER_FRAMES[frame % SPINNER_FRAMES.length];
|
|
14627
|
+
const label = phaseLabel(phase) ?? (reducedMotion ? "Working" : pickWord(wordOffsetRef.current + Math.floor(elapsedMs / WORD_MS)));
|
|
14628
|
+
return jsxs9(Box11, {
|
|
14062
14629
|
marginTop: 1,
|
|
14063
14630
|
children: [
|
|
14064
|
-
|
|
14065
|
-
|
|
14631
|
+
jsx13(Text10, { children: theme.color("accent", `${spinner} ${label}\u2026 `) }),
|
|
14632
|
+
jsx13(Text10, { children: theme.muted(`(${elapsedSec}s \xB7 esc to interrupt)`) })
|
|
14066
14633
|
]
|
|
14067
14634
|
});
|
|
14068
14635
|
}
|
|
14069
14636
|
|
|
14070
14637
|
// src/console/components/TerminalConsole.ts
|
|
14071
|
-
var { useReducer, useRef: useRef3, useCallback } =
|
|
14638
|
+
var { useReducer, useRef: useRef3, useCallback } = React4;
|
|
14072
14639
|
var CHORD_WINDOW_MS = 600;
|
|
14073
14640
|
var CTRL_C_EXIT_WINDOW_MS = 500;
|
|
14074
|
-
var FALLBACK_TERMINAL_ROWS = 40;
|
|
14075
14641
|
var CHROME_ROWS = 14;
|
|
14076
14642
|
var MODAL_CHROME_ROWS = 24;
|
|
14077
14643
|
var MIN_VISIBLE_ROWS = 8;
|
|
@@ -14212,8 +14778,39 @@ function permissionModeStatusText(mode) {
|
|
|
14212
14778
|
}
|
|
14213
14779
|
function TerminalConsole(props) {
|
|
14214
14780
|
const { conductor, theme, slash, verbose, onExit, initialInput, services } = props;
|
|
14215
|
-
const
|
|
14216
|
-
const
|
|
14781
|
+
const { stdin, internal_eventEmitter } = useStdin();
|
|
14782
|
+
const { stdout } = useStdout2();
|
|
14783
|
+
const rawKey = useRef3("");
|
|
14784
|
+
useEffect9(() => {
|
|
14785
|
+
const capture = (data) => {
|
|
14786
|
+
rawKey.current = String(data);
|
|
14787
|
+
};
|
|
14788
|
+
internal_eventEmitter.prependListener("input", capture);
|
|
14789
|
+
return () => {
|
|
14790
|
+
internal_eventEmitter.removeListener("input", capture);
|
|
14791
|
+
};
|
|
14792
|
+
}, [internal_eventEmitter]);
|
|
14793
|
+
const [state, dispatch2] = useReducer(consoleReducer, theme.scheme, (scheme) => {
|
|
14794
|
+
let stored;
|
|
14795
|
+
try {
|
|
14796
|
+
stored = services?.settings.get("colourScheme");
|
|
14797
|
+
} catch {
|
|
14798
|
+
}
|
|
14799
|
+
const flag = (key, fallback) => {
|
|
14800
|
+
try {
|
|
14801
|
+
const value = services?.settings.get(key);
|
|
14802
|
+
return typeof value === "boolean" ? value : fallback;
|
|
14803
|
+
} catch {
|
|
14804
|
+
return fallback;
|
|
14805
|
+
}
|
|
14806
|
+
};
|
|
14807
|
+
return initConsoleState({
|
|
14808
|
+
scheme: typeof stored === "string" && isThemeScheme(stored) ? stored : scheme,
|
|
14809
|
+
showReasoning: flag("showReasoning", false),
|
|
14810
|
+
showImages: flag("showImages", true)
|
|
14811
|
+
});
|
|
14812
|
+
});
|
|
14813
|
+
const adapter = resolveTheme(state.scheme).adapter;
|
|
14217
14814
|
const chord = useRef3(NO_CHORD);
|
|
14218
14815
|
const chordTimer = useRef3(null);
|
|
14219
14816
|
const paste = useRef3(EMPTY_PASTE_VAULT);
|
|
@@ -14224,34 +14821,39 @@ function TerminalConsole(props) {
|
|
|
14224
14821
|
const liveReason = useRef3(null);
|
|
14225
14822
|
const rowSeed = useRef3(0);
|
|
14226
14823
|
const ctrlCAt = useRef3(0);
|
|
14227
|
-
const
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
|
|
14231
|
-
const [
|
|
14232
|
-
const [
|
|
14233
|
-
const [
|
|
14234
|
-
const [,
|
|
14824
|
+
const resumeHandler = useRef3(null);
|
|
14825
|
+
useEffect9(() => () => {
|
|
14826
|
+
if (resumeHandler.current) process.off("SIGCONT", resumeHandler.current);
|
|
14827
|
+
}, []);
|
|
14828
|
+
const [highlight, setHighlight] = useState10(0);
|
|
14829
|
+
const [toolExecutions, setToolExecutions] = useState10({});
|
|
14830
|
+
const [taskTokens, setTaskTokens] = useState10({});
|
|
14831
|
+
const [subagentActivity, setSubagentActivity] = useState10({});
|
|
14832
|
+
const [expandTools, setExpandTools] = useState10(false);
|
|
14833
|
+
const [agentsOpen, setAgentsOpen] = useState10(false);
|
|
14834
|
+
const { rows: terminalRows, columns: terminalColumns } = useTerminalSize();
|
|
14835
|
+
const renderRows = Math.max(1, terminalRows - 1);
|
|
14836
|
+
const [, forceTick] = useState10(0);
|
|
14235
14837
|
const pulse = useCallback(() => forceTick((n) => n + 1), []);
|
|
14236
14838
|
const dirReader = useMemo2(() => createDirReader(process.cwd()), []);
|
|
14237
14839
|
const [approvalQueue, dispatchApproval] = useReducer(approvalQueueReducer, EMPTY_APPROVAL_QUEUE);
|
|
14238
14840
|
const approvalSeed = useRef3(0);
|
|
14239
14841
|
const approvalResolvers = useRef3(/* @__PURE__ */ new Map());
|
|
14240
14842
|
const settleApproval = useCallback((id, choice) => {
|
|
14241
|
-
const
|
|
14242
|
-
if (
|
|
14843
|
+
const resolve11 = approvalResolvers.current.get(id);
|
|
14844
|
+
if (resolve11 === void 0) return;
|
|
14243
14845
|
approvalResolvers.current.delete(id);
|
|
14244
14846
|
dispatchApproval({ type: "settle", id });
|
|
14245
|
-
|
|
14847
|
+
resolve11(choice);
|
|
14246
14848
|
}, []);
|
|
14247
14849
|
const denyAllApprovals = useCallback(() => {
|
|
14248
14850
|
const pending = [...approvalResolvers.current.entries()];
|
|
14249
14851
|
approvalResolvers.current.clear();
|
|
14250
14852
|
dispatchApproval({ type: "clear" });
|
|
14251
|
-
for (const [,
|
|
14853
|
+
for (const [, resolve11] of pending) resolve11("deny");
|
|
14252
14854
|
}, []);
|
|
14253
14855
|
const requestApproval = useCallback(
|
|
14254
|
-
(toolName, input, opts) => new Promise((
|
|
14856
|
+
(toolName, input, opts) => new Promise((resolve11) => {
|
|
14255
14857
|
approvalSeed.current += 1;
|
|
14256
14858
|
const id = `ap_${approvalSeed.current}`;
|
|
14257
14859
|
const request = {
|
|
@@ -14259,21 +14861,26 @@ function TerminalConsole(props) {
|
|
|
14259
14861
|
input,
|
|
14260
14862
|
suggestions: allowAlwaysRuleStrings(toolName, input)
|
|
14261
14863
|
};
|
|
14262
|
-
approvalResolvers.current.set(id, resolve9);
|
|
14263
14864
|
const signal = opts.signal;
|
|
14865
|
+
const onAbort = () => settleApproval(id, "deny");
|
|
14866
|
+
const finish = (choice) => {
|
|
14867
|
+
signal?.removeEventListener("abort", onAbort);
|
|
14868
|
+
resolve11(choice);
|
|
14869
|
+
};
|
|
14870
|
+
approvalResolvers.current.set(id, finish);
|
|
14264
14871
|
if (signal !== void 0) {
|
|
14265
14872
|
if (signal.aborted) {
|
|
14266
14873
|
approvalResolvers.current.delete(id);
|
|
14267
|
-
|
|
14874
|
+
resolve11("deny");
|
|
14268
14875
|
return;
|
|
14269
14876
|
}
|
|
14270
|
-
signal.addEventListener("abort",
|
|
14877
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
14271
14878
|
}
|
|
14272
|
-
dispatchApproval({ type: "enqueue", entry: { id, request, resolve:
|
|
14879
|
+
dispatchApproval({ type: "enqueue", entry: { id, request, resolve: finish } });
|
|
14273
14880
|
}),
|
|
14274
14881
|
[settleApproval]
|
|
14275
14882
|
);
|
|
14276
|
-
|
|
14883
|
+
useEffect9(() => {
|
|
14277
14884
|
conductor.setApprovalResolver(requestApproval);
|
|
14278
14885
|
return () => {
|
|
14279
14886
|
conductor.setApprovalResolver(void 0);
|
|
@@ -14283,7 +14890,7 @@ function TerminalConsole(props) {
|
|
|
14283
14890
|
const head = activeApproval(approvalQueue);
|
|
14284
14891
|
const headId = head?.id;
|
|
14285
14892
|
const approvalModalOpen = useRef3(false);
|
|
14286
|
-
|
|
14893
|
+
useEffect9(() => {
|
|
14287
14894
|
if (head === void 0) {
|
|
14288
14895
|
if (approvalModalOpen.current) {
|
|
14289
14896
|
approvalModalOpen.current = false;
|
|
@@ -14314,11 +14921,53 @@ function TerminalConsole(props) {
|
|
|
14314
14921
|
const answerText = useRef3("");
|
|
14315
14922
|
const reasonText = useRef3("");
|
|
14316
14923
|
const visibleFrom = useRef3(0);
|
|
14317
|
-
const [compactNote, setCompactNote] =
|
|
14318
|
-
|
|
14924
|
+
const [compactNote, setCompactNote] = useState10(null);
|
|
14925
|
+
const sessionId = conductor.snapshot().head.sessionId;
|
|
14926
|
+
const priorSession = useRef3(sessionId);
|
|
14927
|
+
const resetView = useCallback(() => {
|
|
14928
|
+
liveAnswer.current = null;
|
|
14929
|
+
liveReason.current = null;
|
|
14930
|
+
answerText.current = "";
|
|
14931
|
+
reasonText.current = "";
|
|
14932
|
+
visibleFrom.current = 0;
|
|
14933
|
+
activePaste.current = null;
|
|
14934
|
+
paste.current = EMPTY_PASTE_VAULT;
|
|
14935
|
+
burst.current = "";
|
|
14936
|
+
if (burstTimer.current !== null) {
|
|
14937
|
+
clearTimeout(burstTimer.current);
|
|
14938
|
+
burstTimer.current = null;
|
|
14939
|
+
}
|
|
14940
|
+
setToolExecutions({});
|
|
14941
|
+
setTaskTokens({});
|
|
14942
|
+
setSubagentActivity({});
|
|
14943
|
+
setCompactNote(null);
|
|
14944
|
+
setAgentsOpen(false);
|
|
14945
|
+
denyAllApprovals();
|
|
14946
|
+
dispatch2({ type: "view:reset" });
|
|
14947
|
+
}, [denyAllApprovals]);
|
|
14948
|
+
useEffect9(() => {
|
|
14949
|
+
if (priorSession.current !== sessionId) {
|
|
14950
|
+
priorSession.current = sessionId;
|
|
14951
|
+
resetView();
|
|
14952
|
+
}
|
|
14953
|
+
}, [sessionId, resetView]);
|
|
14954
|
+
useEffect9(() => {
|
|
14319
14955
|
const off = conductor.subscribe((signal) => {
|
|
14320
14956
|
switch (signal.kind) {
|
|
14957
|
+
case "reset": {
|
|
14958
|
+
resetView();
|
|
14959
|
+
break;
|
|
14960
|
+
}
|
|
14961
|
+
case "phase": {
|
|
14962
|
+
dispatch2({ type: "busy:set", busy: signal.phase === "streaming" || signal.phase === "tooling" || signal.phase === "condensing" });
|
|
14963
|
+
break;
|
|
14964
|
+
}
|
|
14321
14965
|
case "prompt": {
|
|
14966
|
+
liveAnswer.current = null;
|
|
14967
|
+
liveReason.current = null;
|
|
14968
|
+
answerText.current = "";
|
|
14969
|
+
reasonText.current = "";
|
|
14970
|
+
dispatch2({ type: "busy:set", busy: true });
|
|
14322
14971
|
break;
|
|
14323
14972
|
}
|
|
14324
14973
|
case "text": {
|
|
@@ -14326,10 +14975,8 @@ function TerminalConsole(props) {
|
|
|
14326
14975
|
const id = freshRowId(rowSeed.current++);
|
|
14327
14976
|
liveAnswer.current = id;
|
|
14328
14977
|
answerText.current = signal.delta;
|
|
14329
|
-
dispatch2({ type: "rows:append", row: { id, kind: "answer", text: answerText.current } });
|
|
14330
14978
|
} else {
|
|
14331
14979
|
answerText.current += signal.delta;
|
|
14332
|
-
dispatch2({ type: "rows:patch", id: liveAnswer.current, text: answerText.current });
|
|
14333
14980
|
}
|
|
14334
14981
|
break;
|
|
14335
14982
|
}
|
|
@@ -14338,19 +14985,14 @@ function TerminalConsole(props) {
|
|
|
14338
14985
|
const id = freshRowId(rowSeed.current++);
|
|
14339
14986
|
liveReason.current = id;
|
|
14340
14987
|
reasonText.current = signal.delta;
|
|
14341
|
-
dispatch2({ type: "rows:append", row: { id, kind: "reason", text: reasonText.current } });
|
|
14342
14988
|
} else {
|
|
14343
14989
|
reasonText.current += signal.delta;
|
|
14344
|
-
dispatch2({ type: "rows:patch", id: liveReason.current, text: reasonText.current });
|
|
14345
14990
|
}
|
|
14346
14991
|
break;
|
|
14347
14992
|
}
|
|
14348
14993
|
case "tool_start": {
|
|
14349
14994
|
liveAnswer.current = null;
|
|
14350
14995
|
liveReason.current = null;
|
|
14351
|
-
const id = `tool-${signal.id}`;
|
|
14352
|
-
const row = { id, kind: "toolRun", text: signal.name, runId: signal.id };
|
|
14353
|
-
dispatch2({ type: "rows:append", row });
|
|
14354
14996
|
setToolExecutions((current) => ({
|
|
14355
14997
|
...current,
|
|
14356
14998
|
[signal.id]: {
|
|
@@ -14395,11 +15037,6 @@ function TerminalConsole(props) {
|
|
|
14395
15037
|
break;
|
|
14396
15038
|
}
|
|
14397
15039
|
case "tool_end": {
|
|
14398
|
-
dispatch2({
|
|
14399
|
-
type: "rows:patch",
|
|
14400
|
-
id: `tool-${signal.id}`,
|
|
14401
|
-
text: signal.ok ? "done" : "failed"
|
|
14402
|
-
});
|
|
14403
15040
|
setToolExecutions((current) => {
|
|
14404
15041
|
const prior = current[signal.id];
|
|
14405
15042
|
if (prior === void 0) return current;
|
|
@@ -14424,7 +15061,7 @@ function TerminalConsole(props) {
|
|
|
14424
15061
|
if (signal.manual) {
|
|
14425
15062
|
const carried = [];
|
|
14426
15063
|
for (const message of conductor.messages()) {
|
|
14427
|
-
const content = message.content;
|
|
15064
|
+
const content = "content" in message ? message.content : void 0;
|
|
14428
15065
|
if (typeof content === "string" && content.startsWith(RESTORED_FILE_PREFIX)) {
|
|
14429
15066
|
const firstLine = content.slice(RESTORED_FILE_PREFIX.length).split("\n", 1)[0];
|
|
14430
15067
|
if (firstLine) carried.push(firstLine.trim());
|
|
@@ -14436,7 +15073,7 @@ function TerminalConsole(props) {
|
|
|
14436
15073
|
liveReason.current = null;
|
|
14437
15074
|
answerText.current = "";
|
|
14438
15075
|
reasonText.current = "";
|
|
14439
|
-
dispatch2({ type: "
|
|
15076
|
+
dispatch2({ type: "blocks:clear" });
|
|
14440
15077
|
}
|
|
14441
15078
|
dispatch2({
|
|
14442
15079
|
type: "status:set",
|
|
@@ -14463,6 +15100,8 @@ function TerminalConsole(props) {
|
|
|
14463
15100
|
break;
|
|
14464
15101
|
}
|
|
14465
15102
|
case "idle": {
|
|
15103
|
+
liveAnswer.current = null;
|
|
15104
|
+
liveReason.current = null;
|
|
14466
15105
|
dispatch2({ type: "busy:set", busy: false });
|
|
14467
15106
|
break;
|
|
14468
15107
|
}
|
|
@@ -14472,19 +15111,17 @@ function TerminalConsole(props) {
|
|
|
14472
15111
|
pulse();
|
|
14473
15112
|
});
|
|
14474
15113
|
return off;
|
|
14475
|
-
}, [conductor, pulse]);
|
|
15114
|
+
}, [conductor, pulse, resetView]);
|
|
14476
15115
|
const completion = useMemo2(
|
|
14477
15116
|
() => completeAt(state.buffer, state.caret, slash, dirReader),
|
|
14478
15117
|
[state.buffer, state.caret, slash, dirReader]
|
|
14479
15118
|
);
|
|
14480
15119
|
const suggestions = completion.suggestions;
|
|
14481
|
-
|
|
15120
|
+
useEffect9(() => {
|
|
14482
15121
|
if (highlight >= suggestions.length) setHighlight(0);
|
|
14483
15122
|
}, [suggestions.length, highlight]);
|
|
14484
15123
|
const runTurn = useCallback(
|
|
14485
15124
|
async (text) => {
|
|
14486
|
-
const id = freshRowId(rowSeed.current++);
|
|
14487
|
-
dispatch2({ type: "rows:append", row: { id, kind: "prompt", text } });
|
|
14488
15125
|
dispatch2({ type: "busy:set", busy: true });
|
|
14489
15126
|
if (conductor.snapshot().phase === "condensing") {
|
|
14490
15127
|
dispatch2({
|
|
@@ -14494,8 +15131,6 @@ function TerminalConsole(props) {
|
|
|
14494
15131
|
}
|
|
14495
15132
|
setCompactNote(null);
|
|
14496
15133
|
activePaste.current = null;
|
|
14497
|
-
answerText.current = "";
|
|
14498
|
-
reasonText.current = "";
|
|
14499
15134
|
try {
|
|
14500
15135
|
await conductor.submit(text);
|
|
14501
15136
|
} catch (err2) {
|
|
@@ -14514,15 +15149,29 @@ function TerminalConsole(props) {
|
|
|
14514
15149
|
const text = hasMarkers(raw, paste.current) ? expandMarkers(raw, paste.current) : raw;
|
|
14515
15150
|
const trimmed = text.trim();
|
|
14516
15151
|
dispatch2({ type: "buffer:set", text: "" });
|
|
14517
|
-
paste.current =
|
|
15152
|
+
paste.current = { bodies: /* @__PURE__ */ new Map(), minted: paste.current.minted };
|
|
15153
|
+
activePaste.current = null;
|
|
14518
15154
|
if (trimmed.length === 0) return;
|
|
14519
|
-
dispatch2({ type: "history:push", text
|
|
15155
|
+
dispatch2({ type: "history:push", text });
|
|
14520
15156
|
if (trimmed.startsWith("!")) {
|
|
14521
15157
|
const excludeFromContext = trimmed.startsWith("!!");
|
|
14522
15158
|
const command = trimmed.slice(excludeFromContext ? 2 : 1).trim();
|
|
14523
15159
|
if (command.length === 0) return;
|
|
14524
15160
|
dispatch2({ type: "status:set", status: { kind: "busy", text: `Running: ${command}` } });
|
|
14525
15161
|
void conductor.executeBash(command, { excludeFromContext }).then((outcome) => {
|
|
15162
|
+
const output = String(outcome.output ?? "");
|
|
15163
|
+
const fence = "`".repeat(Math.max(3, ...Array.from(output.matchAll(/`+/g), (m) => m[0].length + 1)));
|
|
15164
|
+
const recorded = conductor.messages().some((message) => message.role === "user" && message.content === `$ ${command}
|
|
15165
|
+
${output}`.trimEnd());
|
|
15166
|
+
if (!recorded || excludeFromContext) dispatch2({ type: "block:append", block: {
|
|
15167
|
+
id: freshRowId(rowSeed.current++),
|
|
15168
|
+
kind: "changelog",
|
|
15169
|
+
title: `$ ${command}`,
|
|
15170
|
+
markdown: `${fence}text
|
|
15171
|
+
${output || "(no output)"}
|
|
15172
|
+
${fence}`,
|
|
15173
|
+
timestamp: Date.now()
|
|
15174
|
+
} });
|
|
14526
15175
|
dispatch2({
|
|
14527
15176
|
type: "status:set",
|
|
14528
15177
|
status: {
|
|
@@ -14540,9 +15189,10 @@ function TerminalConsole(props) {
|
|
|
14540
15189
|
}
|
|
14541
15190
|
const resolution = resolveSlash(trimmed, slash);
|
|
14542
15191
|
if (resolution.kind === "match") {
|
|
14543
|
-
|
|
15192
|
+
void Promise.resolve().then(() => resolution.command.run({
|
|
14544
15193
|
args: resolution.args,
|
|
14545
15194
|
conductor,
|
|
15195
|
+
services,
|
|
14546
15196
|
dispatch: dispatch2,
|
|
14547
15197
|
openModal: (kind, payload) => dispatch2({ type: "modal:open", kind, payload }),
|
|
14548
15198
|
closeModal: () => dispatch2({ type: "modal:close" }),
|
|
@@ -14550,10 +15200,9 @@ function TerminalConsole(props) {
|
|
|
14550
15200
|
setStatus: (status) => dispatch2({ type: "status:set", status }),
|
|
14551
15201
|
setBuffer: (value) => dispatch2({ type: "buffer:set", text: value }),
|
|
14552
15202
|
appendBlock: (block2) => dispatch2({ type: "block:append", block: block2 })
|
|
14553
|
-
})
|
|
14554
|
-
void Promise.resolve(outcome).then((settled) => {
|
|
15203
|
+
})).then((settled) => {
|
|
14555
15204
|
if (settled.kind === "prompt") void runTurn(settled.text);
|
|
14556
|
-
});
|
|
15205
|
+
}).catch((error) => dispatch2({ type: "status:set", status: { kind: "error", text: error instanceof Error ? error.message : String(error) } }));
|
|
14557
15206
|
return;
|
|
14558
15207
|
}
|
|
14559
15208
|
if (resolution.kind === "miss") {
|
|
@@ -14565,7 +15214,7 @@ function TerminalConsole(props) {
|
|
|
14565
15214
|
}
|
|
14566
15215
|
void runTurn(text);
|
|
14567
15216
|
},
|
|
14568
|
-
[slash, conductor, onExit, runTurn]
|
|
15217
|
+
[slash, conductor, onExit, runTurn, services]
|
|
14569
15218
|
);
|
|
14570
15219
|
const flushBurst = useCallback(() => {
|
|
14571
15220
|
if (burstTimer.current !== null) {
|
|
@@ -14613,22 +15262,15 @@ function TerminalConsole(props) {
|
|
|
14613
15262
|
chordTimer.current = null;
|
|
14614
15263
|
}
|
|
14615
15264
|
}, []);
|
|
14616
|
-
|
|
15265
|
+
useEffect9(
|
|
14617
15266
|
() => () => {
|
|
14618
15267
|
if (chordTimer.current !== null) clearTimeout(chordTimer.current);
|
|
14619
15268
|
if (burstTimer.current !== null) clearTimeout(burstTimer.current);
|
|
14620
15269
|
},
|
|
14621
15270
|
[]
|
|
14622
15271
|
);
|
|
14623
|
-
useEffect7(() => {
|
|
14624
|
-
const onResize = () => setTerminalRows(process.stdout.rows ?? FALLBACK_TERMINAL_ROWS);
|
|
14625
|
-
process.stdout.on("resize", onResize);
|
|
14626
|
-
return () => {
|
|
14627
|
-
process.stdout.off("resize", onResize);
|
|
14628
|
-
};
|
|
14629
|
-
}, []);
|
|
14630
15272
|
const titleName = conductor.sessionName();
|
|
14631
|
-
|
|
15273
|
+
useEffect9(() => {
|
|
14632
15274
|
writeTerminalTitle(titleName && titleName.length > 0 ? titleName : "indus console");
|
|
14633
15275
|
}, [titleName]);
|
|
14634
15276
|
const requestExit = useCallback(() => {
|
|
@@ -14643,11 +15285,12 @@ function TerminalConsole(props) {
|
|
|
14643
15285
|
setHighlight(0);
|
|
14644
15286
|
return true;
|
|
14645
15287
|
}, [suggestions, highlight, state.buffer, completion.span]);
|
|
14646
|
-
|
|
15288
|
+
useInput6(
|
|
14647
15289
|
(rawInput, key) => {
|
|
14648
15290
|
const input = rawInput.replace(BRACKETED_PASTE, "");
|
|
14649
15291
|
if (input.length === 0 && input !== rawInput) return;
|
|
14650
|
-
const
|
|
15292
|
+
const isBackspaceByte = rawKey.current === "\x7F" || rawKey.current === "\b";
|
|
15293
|
+
const intent = readKey(input, { ...key, backspace: key.backspace || isBackspaceByte, delete: key.delete && !isBackspaceByte });
|
|
14651
15294
|
if (intent.verb === "text:type") {
|
|
14652
15295
|
burst.current += intent.text ?? "";
|
|
14653
15296
|
armChord(NO_CHORD);
|
|
@@ -14784,7 +15427,8 @@ function TerminalConsole(props) {
|
|
|
14784
15427
|
return;
|
|
14785
15428
|
}
|
|
14786
15429
|
case "flow:cycleModel":
|
|
14787
|
-
conductor.cycleModel?.("");
|
|
15430
|
+
conductor.cycleModel?.("", intent.direction ?? 1);
|
|
15431
|
+
pulse();
|
|
14788
15432
|
return;
|
|
14789
15433
|
case "model:cycleThinking": {
|
|
14790
15434
|
const level = conductor.cycleThinkingLevel();
|
|
@@ -14827,10 +15471,10 @@ function TerminalConsole(props) {
|
|
|
14827
15471
|
return;
|
|
14828
15472
|
}
|
|
14829
15473
|
case "input:pasteImage": {
|
|
14830
|
-
const
|
|
14831
|
-
if (
|
|
14832
|
-
const
|
|
14833
|
-
dispatch2({ type: "buffer:insert", text: `${
|
|
15474
|
+
const path5 = readClipboardImage();
|
|
15475
|
+
if (path5 !== null) {
|
|
15476
|
+
const sep2 = state.buffer.length > 0 && !/\s$/.test(state.buffer) ? " " : "";
|
|
15477
|
+
dispatch2({ type: "buffer:insert", text: `${sep2}${path5}` });
|
|
14834
15478
|
} else {
|
|
14835
15479
|
dispatch2({
|
|
14836
15480
|
type: "status:set",
|
|
@@ -14840,7 +15484,7 @@ function TerminalConsole(props) {
|
|
|
14840
15484
|
return;
|
|
14841
15485
|
}
|
|
14842
15486
|
case "input:externalEditor": {
|
|
14843
|
-
const edited = openInExternalEditor(state.buffer);
|
|
15487
|
+
const edited = openInExternalEditor(expandMarkers(state.buffer, paste.current), { terminal: { stdin, stdout } });
|
|
14844
15488
|
if (edited !== null) {
|
|
14845
15489
|
dispatch2({ type: "buffer:set", text: edited });
|
|
14846
15490
|
}
|
|
@@ -14854,9 +15498,30 @@ function TerminalConsole(props) {
|
|
|
14854
15498
|
case "view:expandTools":
|
|
14855
15499
|
setExpandTools((current) => !current);
|
|
14856
15500
|
return;
|
|
14857
|
-
case "flow:suspend":
|
|
14858
|
-
|
|
15501
|
+
case "flow:suspend": {
|
|
15502
|
+
if (process.platform === "win32") {
|
|
15503
|
+
dispatch2({ type: "status:set", status: { kind: "warning", text: "Process suspension is not supported on Windows." } });
|
|
15504
|
+
return;
|
|
15505
|
+
}
|
|
15506
|
+
const wasRaw = stdin.isRaw === true;
|
|
15507
|
+
const resume = () => {
|
|
15508
|
+
process.off("SIGCONT", resume);
|
|
15509
|
+
resumeHandler.current = null;
|
|
15510
|
+
stdin.setRawMode?.(wasRaw);
|
|
15511
|
+
if (stdout.isTTY) stdout.write("\x1B[?25l");
|
|
15512
|
+
dispatch2({ type: "status:set", status: { kind: "info", text: "Resumed console." } });
|
|
15513
|
+
};
|
|
15514
|
+
resumeHandler.current = resume;
|
|
15515
|
+
process.once("SIGCONT", resume);
|
|
15516
|
+
stdin.setRawMode?.(false);
|
|
15517
|
+
if (stdout.isTTY) stdout.write("\x1B[?25h");
|
|
15518
|
+
try {
|
|
15519
|
+
process.kill(process.pid, "SIGTSTP");
|
|
15520
|
+
} catch {
|
|
15521
|
+
resume();
|
|
15522
|
+
}
|
|
14859
15523
|
return;
|
|
15524
|
+
}
|
|
14860
15525
|
case "none":
|
|
14861
15526
|
default:
|
|
14862
15527
|
return;
|
|
@@ -14864,14 +15529,23 @@ function TerminalConsole(props) {
|
|
|
14864
15529
|
},
|
|
14865
15530
|
{ isActive: state.modal.kind === "none" && !agentsOpen }
|
|
14866
15531
|
);
|
|
14867
|
-
|
|
15532
|
+
useInput6((input, key) => {
|
|
15533
|
+
if (!key.ctrl || input !== "c") return;
|
|
15534
|
+
if (state.busy || conductor.isBusy?.() || conductor.snapshot().phase === "condensing") {
|
|
15535
|
+
denyAllApprovals();
|
|
15536
|
+
conductor.abort();
|
|
15537
|
+
}
|
|
15538
|
+
dispatch2({ type: "modal:close" });
|
|
15539
|
+
setAgentsOpen(false);
|
|
15540
|
+
}, { isActive: state.modal.kind !== "none" || agentsOpen });
|
|
15541
|
+
useInput6(
|
|
14868
15542
|
(_rawInput, key) => {
|
|
14869
15543
|
if (key.tab && key.shift) cyclePermission();
|
|
14870
15544
|
},
|
|
14871
15545
|
{ isActive: state.modal.kind === "approval" }
|
|
14872
15546
|
);
|
|
14873
15547
|
const seeded = useRef3(false);
|
|
14874
|
-
|
|
15548
|
+
useEffect9(() => {
|
|
14875
15549
|
if (seeded.current) return;
|
|
14876
15550
|
seeded.current = true;
|
|
14877
15551
|
const opening = conductor.permissionMode();
|
|
@@ -14905,7 +15579,7 @@ function TerminalConsole(props) {
|
|
|
14905
15579
|
const taskPanelRows = showTaskPanel ? 2 + Math.min(pendingMessages.length, 8) : 0;
|
|
14906
15580
|
const workingIndicatorRows = state.busy ? 2 : 0;
|
|
14907
15581
|
const maxItems = transcriptHeight(
|
|
14908
|
-
|
|
15582
|
+
renderRows,
|
|
14909
15583
|
modalOpen,
|
|
14910
15584
|
agentPanelRows(agentRuns) + streamingAnswerRows + taskPanelRows + workingIndicatorRows
|
|
14911
15585
|
);
|
|
@@ -14914,7 +15588,7 @@ function TerminalConsole(props) {
|
|
|
14914
15588
|
const startupMap = useMemo2(
|
|
14915
15589
|
() => gatherStartup({
|
|
14916
15590
|
cwd: process.cwd(),
|
|
14917
|
-
home:
|
|
15591
|
+
home: homedir6(),
|
|
14918
15592
|
version: VERSION,
|
|
14919
15593
|
lastSeenVersion
|
|
14920
15594
|
}),
|
|
@@ -14923,8 +15597,8 @@ function TerminalConsole(props) {
|
|
|
14923
15597
|
const quietStartup = (services?.settings.get("quietStartup") ?? false) && !verbose;
|
|
14924
15598
|
const sweep = (services?.settings.get("logoSweep") ?? false) && !(services?.settings.get("reducedMotion") ?? false) && Boolean(process.stdout.isTTY);
|
|
14925
15599
|
const welcomeSeed = PINNED_WELCOME_SEED;
|
|
14926
|
-
const [welcomeName, setWelcomeName] =
|
|
14927
|
-
|
|
15600
|
+
const [welcomeName, setWelcomeName] = useState10(void 0);
|
|
15601
|
+
useEffect9(() => {
|
|
14928
15602
|
if (!services) return;
|
|
14929
15603
|
let live3 = true;
|
|
14930
15604
|
const provider = services.settings.get("defaultProvider");
|
|
@@ -14936,119 +15610,127 @@ function TerminalConsole(props) {
|
|
|
14936
15610
|
live3 = false;
|
|
14937
15611
|
};
|
|
14938
15612
|
}, [services]);
|
|
14939
|
-
const
|
|
15613
|
+
const authRefreshKey = useMemo2(() => ({ status: state.status, modal: state.modal.kind }), [state.status, state.modal.kind]);
|
|
15614
|
+
const authedProviders = useAuthenticatedProviders(services, authRefreshKey);
|
|
14940
15615
|
const boundModelId = conductor.snapshot().modelId;
|
|
14941
15616
|
const boundProvider = boundModelId.includes("/") ? boundModelId.split("/")[0] : boundModelId;
|
|
14942
15617
|
const modelAuthed = authedProviders === null || authedProviders.has(boundProvider);
|
|
14943
15618
|
const bannerModelId = modelAuthed ? boundModelId : "no authenticated model \u2014 run /login";
|
|
14944
15619
|
const statusBarSnapshot = modelAuthed || !snapshot.model ? snapshot : { ...snapshot, model: { ...snapshot.model, provider: "no model", id: "run /login" } };
|
|
14945
|
-
return
|
|
15620
|
+
return jsx14(Box12, {
|
|
14946
15621
|
flexDirection: "column",
|
|
14947
|
-
|
|
14948
|
-
|
|
14949
|
-
|
|
14950
|
-
|
|
14951
|
-
|
|
14952
|
-
|
|
14953
|
-
|
|
14954
|
-
|
|
14955
|
-
|
|
14956
|
-
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
14961
|
-
|
|
14962
|
-
|
|
14963
|
-
|
|
14964
|
-
started: liveMessages.length > 0,
|
|
14965
|
-
branch,
|
|
14966
|
-
name: welcomeName,
|
|
14967
|
-
sweep,
|
|
14968
|
-
startup: startupMap,
|
|
14969
|
-
variantSeed: welcomeSeed
|
|
14970
|
-
}),
|
|
14971
|
-
compactNote !== null ? jsxs10(Box10, {
|
|
14972
|
-
flexDirection: "column",
|
|
14973
|
-
borderStyle: "round",
|
|
14974
|
-
borderColor: adapter.colors["borderMuted"],
|
|
14975
|
-
paddingX: 1,
|
|
14976
|
-
marginBottom: 1,
|
|
14977
|
-
children: [
|
|
14978
|
-
jsx13(Text10, {
|
|
14979
|
-
children: adapter.color("accent", "\u25C6 Context condensed \u2014 fresh session, history summarized")
|
|
14980
|
-
}),
|
|
14981
|
-
compactNote.length > 0 ? jsxs10(Fragment4, {
|
|
14982
|
-
children: [
|
|
14983
|
-
jsx13(Text10, { children: adapter.muted("Files carried into the new context:") }),
|
|
14984
|
-
compactNote.map(
|
|
14985
|
-
(file, index) => jsx13(Text10, { children: adapter.muted(` \xB7 ${file}`) }, index)
|
|
14986
|
-
)
|
|
14987
|
-
]
|
|
14988
|
-
}) : jsx13(Text10, {
|
|
14989
|
-
children: adapter.muted("No files re-attached; the summary digest carries the history.")
|
|
14990
|
-
})
|
|
14991
|
-
]
|
|
14992
|
-
}) : null,
|
|
14993
|
-
jsx13(MessageList, {
|
|
14994
|
-
messages: liveMessages,
|
|
14995
|
-
theme: adapter,
|
|
14996
|
-
showThinking: state.showReasoning,
|
|
14997
|
-
showImages: state.showImages,
|
|
14998
|
-
expandToolOutputs: expandTools,
|
|
14999
|
-
maxItems,
|
|
15000
|
-
displayBlocks: [...state.blocks]
|
|
15001
|
-
}),
|
|
15002
|
-
liveAnswer.current !== null && answerText.current ? jsx13(Box10, {
|
|
15003
|
-
flexDirection: "column",
|
|
15004
|
-
marginBottom: 1,
|
|
15005
|
-
children: jsx13(StreamingMarkdown, { theme: adapter, children: answerText.current })
|
|
15006
|
-
}) : null,
|
|
15007
|
-
showTaskPanel ? jsx13(TaskPanel, {
|
|
15008
|
-
theme: adapter,
|
|
15009
|
-
snapshot,
|
|
15010
|
-
toolExecutions: SHOW_TOOL_ACTIVITY ? toolExecutions : {},
|
|
15011
|
-
expandToolOutputs: expandTools,
|
|
15012
|
-
pendingMessages
|
|
15013
|
-
}) : null,
|
|
15014
|
-
jsx13(WorkingIndicator, {
|
|
15015
|
-
theme: adapter,
|
|
15016
|
-
busy: state.busy || conductor.snapshot().phase === "condensing",
|
|
15017
|
-
phase: conductor.snapshot().phase
|
|
15018
|
-
}),
|
|
15019
|
-
jsx13(Composer, {
|
|
15020
|
-
theme: adapter,
|
|
15021
|
-
buffer: state.buffer,
|
|
15022
|
-
caret: state.caret,
|
|
15023
|
-
busy: state.busy,
|
|
15024
|
-
suggestions,
|
|
15025
|
-
highlight
|
|
15026
|
-
}),
|
|
15027
|
-
jsx13(StatusBar, {
|
|
15028
|
-
theme: adapter,
|
|
15029
|
-
snapshot: statusBarSnapshot,
|
|
15030
|
-
branch,
|
|
15031
|
-
providerCount,
|
|
15032
|
-
status: state.status,
|
|
15033
|
-
permissionMode: conductor.permissionMode()
|
|
15034
|
-
}),
|
|
15035
|
-
jsx13(BackgroundAgents, { theme: adapter, runs: agentRuns, tokens: taskTokens })
|
|
15036
|
-
]
|
|
15037
|
-
}),
|
|
15038
|
-
jsx13(OverlayHost, {
|
|
15039
|
-
modal: state.modal,
|
|
15040
|
-
services,
|
|
15622
|
+
width: terminalColumns,
|
|
15623
|
+
height: renderRows,
|
|
15624
|
+
overflow: "hidden",
|
|
15625
|
+
children: modalOpen ? jsx14(ScrollViewport, { follow: false, children: jsx14(OverlayHost, {
|
|
15626
|
+
modal: state.modal,
|
|
15627
|
+
services,
|
|
15628
|
+
theme: adapter,
|
|
15629
|
+
dispatch: dispatch2,
|
|
15630
|
+
closeModal: () => dispatch2({ type: "modal:close" })
|
|
15631
|
+
}) }, state.modal.kind) : agentsOpen ? jsx14(ScrollViewport, { follow: false, children: jsx14(AgentsView, {
|
|
15632
|
+
theme: adapter,
|
|
15633
|
+
runs: agentRuns,
|
|
15634
|
+
activity: subagentActivity,
|
|
15635
|
+
tokens: taskTokens,
|
|
15636
|
+
onExit: () => setAgentsOpen(false)
|
|
15637
|
+
}) }, "agents") : jsxs10(Fragment4, { children: [
|
|
15638
|
+
terminalRows >= 18 ? jsx14(Box12, { flexShrink: 0, flexDirection: "column", children: jsx14(Banner, {
|
|
15041
15639
|
theme: adapter,
|
|
15042
|
-
|
|
15043
|
-
|
|
15044
|
-
|
|
15045
|
-
|
|
15640
|
+
modelId: bannerModelId,
|
|
15641
|
+
workspace: process.cwd(),
|
|
15642
|
+
version: VERSION,
|
|
15643
|
+
verbose,
|
|
15644
|
+
quiet: quietStartup,
|
|
15645
|
+
compact: liveMessages.length > 0 || terminalRows < 32,
|
|
15646
|
+
started: liveMessages.length > 0,
|
|
15647
|
+
branch,
|
|
15648
|
+
name: welcomeName,
|
|
15649
|
+
sweep,
|
|
15650
|
+
startup: startupMap,
|
|
15651
|
+
variantSeed: welcomeSeed
|
|
15652
|
+
}) }) : null,
|
|
15653
|
+
jsx14(ScrollViewport, { children: jsxs10(Fragment4, { children: [
|
|
15654
|
+
compactNote !== null ? jsx14(Text11, { children: adapter.muted(
|
|
15655
|
+
`Context condensed.${compactNote.length ? " Files carried: " + compactNote.join(", ") : ""}`
|
|
15656
|
+
) }) : null,
|
|
15657
|
+
jsx14(MessageList, {
|
|
15658
|
+
messages: liveMessages,
|
|
15659
|
+
theme: adapter,
|
|
15660
|
+
showThinking: state.showReasoning,
|
|
15661
|
+
showImages: state.showImages,
|
|
15662
|
+
expandToolOutputs: expandTools,
|
|
15663
|
+
maxItems: liveMessages.length + state.blocks.length,
|
|
15664
|
+
displayBlocks: [...state.blocks]
|
|
15665
|
+
}),
|
|
15666
|
+
state.showReasoning && liveReason.current !== null && reasonText.current ? jsx14(Box12, {
|
|
15667
|
+
flexDirection: "column",
|
|
15668
|
+
marginBottom: 1,
|
|
15669
|
+
children: jsx14(StreamingMarkdown, { theme: adapter, dim: true, children: reasonText.current })
|
|
15670
|
+
}) : null,
|
|
15671
|
+
liveAnswer.current !== null && answerText.current ? jsx14(Box12, {
|
|
15672
|
+
flexDirection: "column",
|
|
15673
|
+
marginBottom: 1,
|
|
15674
|
+
children: jsx14(StreamingMarkdown, { theme: adapter, children: answerText.current })
|
|
15675
|
+
}) : null,
|
|
15676
|
+
showTaskPanel ? jsx14(TaskPanel, {
|
|
15677
|
+
theme: adapter,
|
|
15678
|
+
snapshot,
|
|
15679
|
+
toolExecutions: SHOW_TOOL_ACTIVITY ? toolExecutions : {},
|
|
15680
|
+
expandToolOutputs: expandTools,
|
|
15681
|
+
pendingMessages
|
|
15682
|
+
}) : null,
|
|
15683
|
+
jsx14(BackgroundAgents, { theme: adapter, runs: agentRuns, tokens: taskTokens })
|
|
15684
|
+
] }) }, snapshot.sessionId),
|
|
15685
|
+
jsx14(Box12, { flexDirection: "column", flexShrink: 0, children: jsxs10(Fragment4, { children: [
|
|
15686
|
+
jsx14(WorkingIndicator, { theme: adapter, busy: state.busy || conductor.snapshot().phase === "condensing", phase: conductor.snapshot().phase, reducedMotion: services?.settings.get("reducedMotion") ?? false }),
|
|
15687
|
+
jsx14(Composer, {
|
|
15688
|
+
theme: adapter,
|
|
15689
|
+
buffer: state.buffer,
|
|
15690
|
+
caret: state.caret,
|
|
15691
|
+
busy: state.busy,
|
|
15692
|
+
suggestions,
|
|
15693
|
+
highlight,
|
|
15694
|
+
paddingX: services?.settings.get("editorPaddingX") ?? 1
|
|
15695
|
+
}),
|
|
15696
|
+
terminalRows >= 12 ? jsx14(StatusBar, {
|
|
15697
|
+
theme: adapter,
|
|
15698
|
+
snapshot: statusBarSnapshot,
|
|
15699
|
+
branch,
|
|
15700
|
+
providerCount,
|
|
15701
|
+
status: state.status,
|
|
15702
|
+
permissionMode: conductor.permissionMode()
|
|
15703
|
+
}) : null
|
|
15704
|
+
] }) })
|
|
15705
|
+
] })
|
|
15046
15706
|
});
|
|
15047
15707
|
}
|
|
15048
15708
|
|
|
15049
15709
|
// src/console/mount.ts
|
|
15050
15710
|
import { createElement as createElement2 } from "indusagi/react-host";
|
|
15051
15711
|
import { render as render2 } from "indusagi/react-host/ink";
|
|
15712
|
+
var SYNC_OUTPUT_BEGIN = "\x1B[?2026h";
|
|
15713
|
+
var SYNC_OUTPUT_END = "\x1B[?2026l";
|
|
15714
|
+
function supportsSynchronizedOutput(stream) {
|
|
15715
|
+
if (!stream.isTTY || process.env["INDUS_TUI_SYNC_OUTPUT"] === "0") return false;
|
|
15716
|
+
const term = process.env["TERM"] ?? "";
|
|
15717
|
+
return process.env["TMUX"] === void 0 && process.env["STY"] === void 0 && !term.startsWith("screen") && !term.startsWith("tmux");
|
|
15718
|
+
}
|
|
15719
|
+
function synchronizedOutputStream(stream, enabled = supportsSynchronizedOutput(stream)) {
|
|
15720
|
+
if (!enabled) return stream;
|
|
15721
|
+
const write = (chunk, encodingOrCallback, callback) => {
|
|
15722
|
+
const framed = typeof chunk === "string" ? `${SYNC_OUTPUT_BEGIN}${chunk}${SYNC_OUTPUT_END}` : Buffer.concat([Buffer.from(SYNC_OUTPUT_BEGIN), Buffer.from(chunk), Buffer.from(SYNC_OUTPUT_END)]);
|
|
15723
|
+
if (typeof encodingOrCallback === "function") return stream.write(framed, encodingOrCallback);
|
|
15724
|
+
return stream.write(framed, encodingOrCallback, callback);
|
|
15725
|
+
};
|
|
15726
|
+
return new Proxy(stream, {
|
|
15727
|
+
get(target, property) {
|
|
15728
|
+
if (property === "write") return write;
|
|
15729
|
+
const value = Reflect.get(target, property, target);
|
|
15730
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
15731
|
+
}
|
|
15732
|
+
});
|
|
15733
|
+
}
|
|
15052
15734
|
async function mountConsole(conductor, opts = {}) {
|
|
15053
15735
|
const theme = resolveTheme(opts.scheme ?? null);
|
|
15054
15736
|
const slash = opts.slash ?? DEFAULT_SLASH_REGISTRY;
|
|
@@ -15066,15 +15748,23 @@ async function mountConsole(conductor, opts = {}) {
|
|
|
15066
15748
|
instance.unmount();
|
|
15067
15749
|
}
|
|
15068
15750
|
};
|
|
15069
|
-
const
|
|
15070
|
-
|
|
15071
|
-
|
|
15751
|
+
const wasRaw = process.stdin.isRaw === true;
|
|
15752
|
+
const stdout = synchronizedOutputStream(process.stdout);
|
|
15753
|
+
const instance = render2(createElement2(TerminalConsole, props), { exitOnCtrlC: false, stdout });
|
|
15754
|
+
try {
|
|
15755
|
+
await instance.waitUntilExit();
|
|
15756
|
+
return { clean: exited };
|
|
15757
|
+
} finally {
|
|
15758
|
+
instance.unmount();
|
|
15759
|
+
if (process.stdin.isTTY) process.stdin.setRawMode(wasRaw);
|
|
15760
|
+
if (process.stdout.isTTY) process.stdout.write("\x1B[?25h");
|
|
15761
|
+
}
|
|
15072
15762
|
}
|
|
15073
15763
|
|
|
15074
15764
|
// src/boot/runners/session.ts
|
|
15075
|
-
import { existsSync as
|
|
15076
|
-
import { join as join22 } from "node:path";
|
|
15077
|
-
import { homedir as
|
|
15765
|
+
import { existsSync as existsSync8, readFileSync as readFileSync17 } from "node:fs";
|
|
15766
|
+
import { isAbsolute as isAbsolute6, join as join22, resolve as resolve10 } from "node:path";
|
|
15767
|
+
import { homedir as homedir10 } from "node:os";
|
|
15078
15768
|
import { createMCPAgentToolFactory as createMCPAgentToolFactory4, loadMCPConfig as loadMCPConfig2, MCPClientPool as MCPClientPool2 } from "indusagi/mcp";
|
|
15079
15769
|
|
|
15080
15770
|
// src/boot/runners/delegate-runner.ts
|
|
@@ -15131,7 +15821,7 @@ async function acquireTaskSlot() {
|
|
|
15131
15821
|
if (activeTasks < MAX_PARALLEL_TASKS) {
|
|
15132
15822
|
activeTasks++;
|
|
15133
15823
|
} else {
|
|
15134
|
-
await new Promise((
|
|
15824
|
+
await new Promise((resolve11) => taskQueue.push(resolve11));
|
|
15135
15825
|
}
|
|
15136
15826
|
let released = false;
|
|
15137
15827
|
return () => {
|
|
@@ -15236,7 +15926,7 @@ ${request.context}` : request.objective;
|
|
|
15236
15926
|
}
|
|
15237
15927
|
|
|
15238
15928
|
// src/boot/runners/checkpoint.ts
|
|
15239
|
-
import { mkdirSync as mkdirSync3, rmSync, writeFileSync as
|
|
15929
|
+
import { mkdirSync as mkdirSync3, rmSync as rmSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
15240
15930
|
import { dirname as dirname22, normalize as normalize2 } from "node:path";
|
|
15241
15931
|
var CHECKPOINT_HANDLE_KEY = "checkpoint";
|
|
15242
15932
|
var ROOT_NODE_ID = "__root__";
|
|
@@ -15304,7 +15994,7 @@ var CheckpointStore = class {
|
|
|
15304
15994
|
snapshotFor(nodeId) {
|
|
15305
15995
|
const paths = this.byNode.get(nodeId);
|
|
15306
15996
|
if (paths === void 0) return [];
|
|
15307
|
-
return [...paths].map(([
|
|
15997
|
+
return [...paths].map(([path5, previous]) => ({ path: path5, previous }));
|
|
15308
15998
|
}
|
|
15309
15999
|
/** Whether a node has ANY recorded file snapshot (the picker's restore gate). */
|
|
15310
16000
|
hasSnapshot(nodeId) {
|
|
@@ -15330,15 +16020,15 @@ var CheckpointStore = class {
|
|
|
15330
16020
|
restore(nodeId) {
|
|
15331
16021
|
const snapshots = this.snapshotFor(nodeId);
|
|
15332
16022
|
const restored = [];
|
|
15333
|
-
for (const { path:
|
|
16023
|
+
for (const { path: path5, previous } of snapshots) {
|
|
15334
16024
|
try {
|
|
15335
16025
|
if (previous === null) {
|
|
15336
|
-
|
|
16026
|
+
rmSync2(path5, { force: true });
|
|
15337
16027
|
} else {
|
|
15338
|
-
mkdirSync3(dirname22(
|
|
15339
|
-
|
|
16028
|
+
mkdirSync3(dirname22(path5), { recursive: true });
|
|
16029
|
+
writeFileSync7(path5, previous, "utf8");
|
|
15340
16030
|
}
|
|
15341
|
-
restored.push(
|
|
16031
|
+
restored.push(path5);
|
|
15342
16032
|
} catch {
|
|
15343
16033
|
}
|
|
15344
16034
|
}
|
|
@@ -15385,15 +16075,15 @@ function createReadStateStore() {
|
|
|
15385
16075
|
}
|
|
15386
16076
|
|
|
15387
16077
|
// src/integrations/zoho/config.ts
|
|
15388
|
-
import { existsSync as
|
|
15389
|
-
import { homedir as
|
|
15390
|
-
import { dirname as
|
|
16078
|
+
import { existsSync as existsSync4, readFileSync as readFileSync12, writeFileSync as writeFileSync8, mkdirSync as mkdirSync4 } from "node:fs";
|
|
16079
|
+
import { homedir as homedir7 } from "node:os";
|
|
16080
|
+
import { dirname as dirname6, join as join17 } from "node:path";
|
|
15391
16081
|
var ENV_URL = "ZOHO_MCP_URL";
|
|
15392
16082
|
var ENV_DISABLE = "ZOHO_DISABLED";
|
|
15393
|
-
function readJsonFile(
|
|
16083
|
+
function readJsonFile(path5) {
|
|
15394
16084
|
try {
|
|
15395
|
-
if (!
|
|
15396
|
-
const raw = readFileSync12(
|
|
16085
|
+
if (!existsSync4(path5)) return void 0;
|
|
16086
|
+
const raw = readFileSync12(path5, "utf8");
|
|
15397
16087
|
const parsed = JSON.parse(raw);
|
|
15398
16088
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
15399
16089
|
return void 0;
|
|
@@ -15412,11 +16102,11 @@ function configFromRecord(rec) {
|
|
|
15412
16102
|
const auth = rec.auth === "none" || rec.auth === "oauth" || rec.auth === "auto" ? rec.auth : "auto";
|
|
15413
16103
|
return { url, id, enabled, auth };
|
|
15414
16104
|
}
|
|
15415
|
-
function profileZohoPath(home =
|
|
15416
|
-
return
|
|
16105
|
+
function profileZohoPath(home = homedir7()) {
|
|
16106
|
+
return join17(home, ".indusagi", "agent", "zoho.json");
|
|
15417
16107
|
}
|
|
15418
16108
|
function projectZohoPath(cwd) {
|
|
15419
|
-
return
|
|
16109
|
+
return join17(cwd, ".indusagi", "zoho.json");
|
|
15420
16110
|
}
|
|
15421
16111
|
function resolveZohoConfig(opts = {}) {
|
|
15422
16112
|
const env2 = opts.env ?? process.env;
|
|
@@ -15428,7 +16118,7 @@ function resolveZohoConfig(opts = {}) {
|
|
|
15428
16118
|
const fromEnv = env2[ENV_URL]?.trim();
|
|
15429
16119
|
const fromProject = configFromRecord(readJsonFile(projectZohoPath(cwd)));
|
|
15430
16120
|
const fromProfile = configFromRecord(
|
|
15431
|
-
readJsonFile(profileZohoPath(opts.home ??
|
|
16121
|
+
readJsonFile(profileZohoPath(opts.home ?? homedir7()))
|
|
15432
16122
|
);
|
|
15433
16123
|
const base = (fromArg ? { url: fromArg, id: "zoho", enabled: true, auth: "auto" } : void 0) ?? (fromEnv ? { url: fromEnv, id: "zoho", enabled: true, auth: "auto" } : void 0) ?? fromProject ?? fromProfile;
|
|
15434
16124
|
if (!base) return void 0;
|
|
@@ -15440,9 +16130,9 @@ function resolveZohoConfig(opts = {}) {
|
|
|
15440
16130
|
}
|
|
15441
16131
|
|
|
15442
16132
|
// src/integrations/zoho/attach.ts
|
|
15443
|
-
import { existsSync as
|
|
15444
|
-
import { homedir as
|
|
15445
|
-
import { join as
|
|
16133
|
+
import { existsSync as existsSync5, readFileSync as readFileSync13 } from "node:fs";
|
|
16134
|
+
import { homedir as homedir8 } from "node:os";
|
|
16135
|
+
import { join as join18 } from "node:path";
|
|
15446
16136
|
import { connectZohoMcp } from "indusagi/zoho";
|
|
15447
16137
|
import { createMCPAgentToolFactory as createMCPAgentToolFactory2 } from "indusagi/mcp";
|
|
15448
16138
|
var live = null;
|
|
@@ -15451,15 +16141,15 @@ var cancelConnect = false;
|
|
|
15451
16141
|
var lastAuthUrl;
|
|
15452
16142
|
function zohoTokenPath(id = "zoho") {
|
|
15453
16143
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
15454
|
-
const home = process.env.HOME ?? process.env.USERPROFILE ??
|
|
15455
|
-
const dir = xdg && xdg.length > 0 ?
|
|
15456
|
-
return
|
|
16144
|
+
const home = process.env.HOME ?? process.env.USERPROFILE ?? homedir8();
|
|
16145
|
+
const dir = xdg && xdg.length > 0 ? join18(xdg, "indusagi", "credentials", "mcp") : join18(home, ".config", "indusagi", "credentials", "mcp");
|
|
16146
|
+
return join18(dir, `${id.replace(/[^a-zA-Z0-9._-]/g, "-")}.json`);
|
|
15457
16147
|
}
|
|
15458
16148
|
function hasUsableZohoTokens(id = "zoho") {
|
|
15459
|
-
const
|
|
16149
|
+
const path5 = zohoTokenPath(id);
|
|
15460
16150
|
try {
|
|
15461
|
-
if (!
|
|
15462
|
-
const raw = readFileSync13(
|
|
16151
|
+
if (!existsSync5(path5)) return false;
|
|
16152
|
+
const raw = readFileSync13(path5, "utf8");
|
|
15463
16153
|
const parsed = JSON.parse(raw);
|
|
15464
16154
|
return typeof parsed?.tokens?.access_token === "string" && parsed.tokens.access_token.length > 0;
|
|
15465
16155
|
} catch {
|
|
@@ -15598,17 +16288,18 @@ async function loadZohoAgentTools(opts) {
|
|
|
15598
16288
|
}
|
|
15599
16289
|
|
|
15600
16290
|
// src/integrations/sarvam/config.ts
|
|
15601
|
-
import { existsSync as
|
|
15602
|
-
import { homedir as
|
|
15603
|
-
import {
|
|
16291
|
+
import { existsSync as existsSync6, readFileSync as readFileSync14 } from "node:fs";
|
|
16292
|
+
import { homedir as homedir9 } from "node:os";
|
|
16293
|
+
import { join as join19 } from "node:path";
|
|
15604
16294
|
var ENV_KEY = "SARVAM_API_KEY";
|
|
15605
16295
|
var ENV_DISABLE2 = "SARVAM_DISABLED";
|
|
15606
16296
|
var ENV_BASE_URL = "SARVAM_API_BASE_URL";
|
|
15607
16297
|
var ENV_BASE_PATH = "SARVAM_MCP_BASE_PATH";
|
|
15608
|
-
function readJsonFile2(
|
|
16298
|
+
function readJsonFile2(path5, sensitive = false) {
|
|
15609
16299
|
try {
|
|
15610
|
-
if (!
|
|
15611
|
-
const raw = readFileSync14(
|
|
16300
|
+
if (!sensitive && !existsSync6(path5)) return void 0;
|
|
16301
|
+
const raw = sensitive ? readPrivateFileSync(path5) : readFileSync14(path5, "utf8");
|
|
16302
|
+
if (raw === null) return void 0;
|
|
15612
16303
|
const parsed = JSON.parse(raw);
|
|
15613
16304
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
15614
16305
|
return void 0;
|
|
@@ -15618,11 +16309,11 @@ function readJsonFile2(path4) {
|
|
|
15618
16309
|
return void 0;
|
|
15619
16310
|
}
|
|
15620
16311
|
}
|
|
15621
|
-
function configFromRecord2(rec) {
|
|
16312
|
+
function configFromRecord2(rec, includeApiKey = true) {
|
|
15622
16313
|
if (!rec) return void 0;
|
|
15623
16314
|
const enabled = rec.enabled === false ? false : true;
|
|
15624
16315
|
const id = typeof rec.id === "string" && rec.id.trim() ? rec.id.trim() : "sarvam";
|
|
15625
|
-
const apiKey = typeof rec.apiKey === "string" ? rec.apiKey.trim() : void 0;
|
|
16316
|
+
const apiKey = includeApiKey && typeof rec.apiKey === "string" ? rec.apiKey.trim() : void 0;
|
|
15626
16317
|
const baseUrl = typeof rec.baseUrl === "string" ? rec.baseUrl.trim() : void 0;
|
|
15627
16318
|
const basePath = typeof rec.basePath === "string" ? rec.basePath.trim() : void 0;
|
|
15628
16319
|
const command = typeof rec.command === "string" ? rec.command.trim() : void 0;
|
|
@@ -15635,11 +16326,11 @@ function configFromRecord2(rec) {
|
|
|
15635
16326
|
...command ? { command } : {}
|
|
15636
16327
|
};
|
|
15637
16328
|
}
|
|
15638
|
-
function profileSarvamPath(home =
|
|
15639
|
-
return
|
|
16329
|
+
function profileSarvamPath(home = homedir9()) {
|
|
16330
|
+
return join19(home, ".indusagi", "agent", "sarvam.json");
|
|
15640
16331
|
}
|
|
15641
16332
|
function projectSarvamPath(cwd) {
|
|
15642
|
-
return
|
|
16333
|
+
return join19(cwd, ".indusagi", "sarvam.json");
|
|
15643
16334
|
}
|
|
15644
16335
|
function resolveSarvamConfig(opts = {}) {
|
|
15645
16336
|
const env2 = opts.env ?? process.env;
|
|
@@ -15649,9 +16340,9 @@ function resolveSarvamConfig(opts = {}) {
|
|
|
15649
16340
|
}
|
|
15650
16341
|
const fromArgKey = opts.apiKey?.trim();
|
|
15651
16342
|
const fromEnvKey = env2[ENV_KEY]?.trim();
|
|
15652
|
-
const fromProject = configFromRecord2(readJsonFile2(projectSarvamPath(cwd)));
|
|
16343
|
+
const fromProject = configFromRecord2(readJsonFile2(projectSarvamPath(cwd)), false);
|
|
15653
16344
|
const fromProfile = configFromRecord2(
|
|
15654
|
-
readJsonFile2(profileSarvamPath(opts.home ??
|
|
16345
|
+
readJsonFile2(profileSarvamPath(opts.home ?? homedir9()), true)
|
|
15655
16346
|
);
|
|
15656
16347
|
const fileBase = fromProject ?? fromProfile;
|
|
15657
16348
|
const apiKey = fromArgKey || fromEnvKey || fileBase?.apiKey;
|
|
@@ -15776,8 +16467,6 @@ async function loadSarvamAgentTools(opts) {
|
|
|
15776
16467
|
}
|
|
15777
16468
|
|
|
15778
16469
|
// src/boot/auth-vault.ts
|
|
15779
|
-
import { mkdirSync as mkdirSync6, readFileSync as readFileSync15, writeFileSync as writeFileSync9 } from "node:fs";
|
|
15780
|
-
import { dirname as dirname7 } from "node:path";
|
|
15781
16470
|
import {
|
|
15782
16471
|
ensureFreshOAuthCredentials,
|
|
15783
16472
|
getOAuthProvider as getOAuthProvider3
|
|
@@ -15801,8 +16490,9 @@ function normaliseRecord(value) {
|
|
|
15801
16490
|
return void 0;
|
|
15802
16491
|
}
|
|
15803
16492
|
function readAuthFile(filePath) {
|
|
16493
|
+
const text = readPrivateFileSync(filePath);
|
|
16494
|
+
if (text === null) return {};
|
|
15804
16495
|
try {
|
|
15805
|
-
const text = readFileSync15(filePath, "utf8");
|
|
15806
16496
|
const parsed = JSON.parse(text);
|
|
15807
16497
|
if (parsed === null || typeof parsed !== "object") return {};
|
|
15808
16498
|
const file = {};
|
|
@@ -15821,9 +16511,8 @@ function readAuthFile(filePath) {
|
|
|
15821
16511
|
}
|
|
15822
16512
|
}
|
|
15823
16513
|
function writeAuthFile(filePath, data) {
|
|
15824
|
-
|
|
15825
|
-
|
|
15826
|
-
`, { mode: 384 });
|
|
16514
|
+
atomicWritePrivateFileSync(filePath, `${JSON.stringify(data, null, 2)}
|
|
16515
|
+
`);
|
|
15827
16516
|
}
|
|
15828
16517
|
function toCredentials(record) {
|
|
15829
16518
|
const { kind: _kind, isDefault: _isDefault, ...credentials } = record;
|
|
@@ -15917,8 +16606,8 @@ function createAuthVault(authPath) {
|
|
|
15917
16606
|
}
|
|
15918
16607
|
|
|
15919
16608
|
// src/boot/runners/memdir.ts
|
|
15920
|
-
import { existsSync as
|
|
15921
|
-
import { join as
|
|
16609
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync15, writeFileSync as writeFileSync9 } from "node:fs";
|
|
16610
|
+
import { join as join20 } from "node:path";
|
|
15922
16611
|
var MEMORY_ENTRYPOINT = "MEMORY.md";
|
|
15923
16612
|
var MAX_ENTRYPOINT_LINES = 200;
|
|
15924
16613
|
var MAX_ENTRYPOINT_BYTES = 25e3;
|
|
@@ -15944,27 +16633,27 @@ function truncateEntrypointContent(raw) {
|
|
|
15944
16633
|
}
|
|
15945
16634
|
function memoryDirFor(workspace, cwd) {
|
|
15946
16635
|
const slug = cwd.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
15947
|
-
return
|
|
16636
|
+
return join20(workspace.profileDir, "memory", `--${slug}--`);
|
|
15948
16637
|
}
|
|
15949
16638
|
var DiskMemoryStore = class {
|
|
15950
16639
|
memDir;
|
|
15951
16640
|
file;
|
|
15952
16641
|
constructor(memDir) {
|
|
15953
16642
|
this.memDir = memDir;
|
|
15954
|
-
this.file =
|
|
16643
|
+
this.file = join20(memDir, MEMORY_ENTRYPOINT);
|
|
15955
16644
|
}
|
|
15956
16645
|
/** The current note, or `""` when no file has been written yet. */
|
|
15957
16646
|
read() {
|
|
15958
16647
|
try {
|
|
15959
|
-
return
|
|
16648
|
+
return existsSync7(this.file) ? readFileSync15(this.file, "utf8") : "";
|
|
15960
16649
|
} catch {
|
|
15961
16650
|
return "";
|
|
15962
16651
|
}
|
|
15963
16652
|
}
|
|
15964
16653
|
/** Overwrite the note, creating the memory directory as needed (mode 0o600). */
|
|
15965
16654
|
replace(content) {
|
|
15966
|
-
|
|
15967
|
-
|
|
16655
|
+
mkdirSync5(this.memDir, { recursive: true });
|
|
16656
|
+
writeFileSync9(this.file, content, { mode: 384 });
|
|
15968
16657
|
}
|
|
15969
16658
|
/** Add a single line to the end of the note (composed of read + replace). */
|
|
15970
16659
|
append(line) {
|
|
@@ -15977,9 +16666,9 @@ ${line}`;
|
|
|
15977
16666
|
function loadMemoryDoc(memDir) {
|
|
15978
16667
|
let raw;
|
|
15979
16668
|
try {
|
|
15980
|
-
const file =
|
|
15981
|
-
if (!
|
|
15982
|
-
raw =
|
|
16669
|
+
const file = join20(memDir, MEMORY_ENTRYPOINT);
|
|
16670
|
+
if (!existsSync7(file)) return void 0;
|
|
16671
|
+
raw = readFileSync15(file, "utf8");
|
|
15983
16672
|
} catch {
|
|
15984
16673
|
return void 0;
|
|
15985
16674
|
}
|
|
@@ -15990,11 +16679,104 @@ function loadMemoryDoc(memDir) {
|
|
|
15990
16679
|
}
|
|
15991
16680
|
|
|
15992
16681
|
// src/boot/runners/addon-wiring.ts
|
|
16682
|
+
import { createHash } from "node:crypto";
|
|
16683
|
+
import { lstatSync as lstatSync3, readFileSync as readFileSync16, readdirSync as readdirSync5, realpathSync as realpathSync3 } from "node:fs";
|
|
16684
|
+
import { join as join21, relative, resolve as resolve9 } from "node:path";
|
|
16685
|
+
var TRUST_FILE = "addon-trust.json";
|
|
16686
|
+
function hashAddonTree(addonsDir) {
|
|
16687
|
+
let root;
|
|
16688
|
+
try {
|
|
16689
|
+
const rootStat = lstatSync3(addonsDir);
|
|
16690
|
+
if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) return null;
|
|
16691
|
+
root = realpathSync3(addonsDir);
|
|
16692
|
+
} catch (error) {
|
|
16693
|
+
if (error.code === "ENOENT") return null;
|
|
16694
|
+
throw error;
|
|
16695
|
+
}
|
|
16696
|
+
const files = [];
|
|
16697
|
+
const visit = (dir) => {
|
|
16698
|
+
for (const entry of readdirSync5(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
16699
|
+
const path5 = join21(dir, entry.name);
|
|
16700
|
+
const info2 = lstatSync3(path5);
|
|
16701
|
+
if (info2.isSymbolicLink()) throw new Error(`Refusing symlink in project addon tree: ${path5}`);
|
|
16702
|
+
if (info2.isDirectory()) visit(path5);
|
|
16703
|
+
else if (info2.isFile()) files.push(path5);
|
|
16704
|
+
else throw new Error(`Refusing special file in project addon tree: ${path5}`);
|
|
16705
|
+
}
|
|
16706
|
+
};
|
|
16707
|
+
visit(root);
|
|
16708
|
+
const hash = createHash("sha256");
|
|
16709
|
+
for (const file of files) {
|
|
16710
|
+
hash.update(relative(root, file));
|
|
16711
|
+
hash.update("\0");
|
|
16712
|
+
hash.update(readFileSync16(file));
|
|
16713
|
+
hash.update("\0");
|
|
16714
|
+
}
|
|
16715
|
+
return hash.digest("hex");
|
|
16716
|
+
}
|
|
16717
|
+
function readTrustStore(path5) {
|
|
16718
|
+
const raw = readPrivateFileSync(path5);
|
|
16719
|
+
if (raw === null) return { version: 1, projects: [] };
|
|
16720
|
+
try {
|
|
16721
|
+
const parsed = JSON.parse(raw);
|
|
16722
|
+
if (parsed.version !== 1 || !Array.isArray(parsed.projects)) return { version: 1, projects: [] };
|
|
16723
|
+
return {
|
|
16724
|
+
version: 1,
|
|
16725
|
+
projects: parsed.projects.filter((record) => typeof record?.root === "string" && typeof record?.digest === "string" && typeof record?.approvedAt === "string")
|
|
16726
|
+
};
|
|
16727
|
+
} catch {
|
|
16728
|
+
return { version: 1, projects: [] };
|
|
16729
|
+
}
|
|
16730
|
+
}
|
|
16731
|
+
function persistTrust(path5, root, digest) {
|
|
16732
|
+
const store = readTrustStore(path5);
|
|
16733
|
+
const projects = store.projects.filter((record) => record.root !== root);
|
|
16734
|
+
projects.push({ root, digest, approvedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
16735
|
+
atomicWritePrivateFileSync(path5, `${JSON.stringify({ version: 1, projects }, null, 2)}
|
|
16736
|
+
`);
|
|
16737
|
+
}
|
|
15993
16738
|
async function buildAddonHost(ctx) {
|
|
15994
16739
|
const host = createAddonHost({ handles: {} });
|
|
15995
|
-
host.onFault(() => {
|
|
16740
|
+
host.onFault((fault) => {
|
|
16741
|
+
process.stderr.write(`Addon ${fault.kind} fault: ${fault.message}
|
|
16742
|
+
`);
|
|
15996
16743
|
});
|
|
15997
|
-
|
|
16744
|
+
const workspace = resolve9(ctx.invocation.cwd ?? process.cwd());
|
|
16745
|
+
const addonsDir = join21(workspace, ".indus", "addons");
|
|
16746
|
+
let canonicalRoot;
|
|
16747
|
+
let digest;
|
|
16748
|
+
try {
|
|
16749
|
+
canonicalRoot = realpathSync3(workspace);
|
|
16750
|
+
digest = hashAddonTree(addonsDir);
|
|
16751
|
+
} catch (error) {
|
|
16752
|
+
process.stderr.write(`Project addons blocked: ${error instanceof Error ? error.message : String(error)}
|
|
16753
|
+
`);
|
|
16754
|
+
return host.loadAll({ explicitPaths: [] });
|
|
16755
|
+
}
|
|
16756
|
+
if (digest === null) return host.loadAll({ explicitPaths: [] });
|
|
16757
|
+
const trustPath = join21(ctx.workspace.profileDir, TRUST_FILE);
|
|
16758
|
+
const approvedNow = ctx.invocation.flags["trust-project-addons"] === true;
|
|
16759
|
+
let trusted = false;
|
|
16760
|
+
try {
|
|
16761
|
+
const store = readTrustStore(trustPath);
|
|
16762
|
+
trusted = store.projects.some((record) => record.root === canonicalRoot && record.digest === digest);
|
|
16763
|
+
if (!trusted && approvedNow) {
|
|
16764
|
+
persistTrust(trustPath, canonicalRoot, digest);
|
|
16765
|
+
trusted = true;
|
|
16766
|
+
}
|
|
16767
|
+
} catch (error) {
|
|
16768
|
+
process.stderr.write(`Project addons blocked: ${error instanceof Error ? error.message : String(error)}
|
|
16769
|
+
`);
|
|
16770
|
+
return host.loadAll({ explicitPaths: [] });
|
|
16771
|
+
}
|
|
16772
|
+
if (!trusted) {
|
|
16773
|
+
process.stderr.write(
|
|
16774
|
+
`Project addons are disabled until explicitly trusted for this exact content. Re-run with --trust-project-addons to approve ${canonicalRoot}.
|
|
16775
|
+
`
|
|
16776
|
+
);
|
|
16777
|
+
return host.loadAll({ explicitPaths: [] });
|
|
16778
|
+
}
|
|
16779
|
+
return host.loadAll({ workspace: canonicalRoot });
|
|
15998
16780
|
}
|
|
15999
16781
|
function wrapToolsWithAddons(tools, bundle) {
|
|
16000
16782
|
const chain = bundle.interceptors;
|
|
@@ -16035,12 +16817,107 @@ function concatAddonTools(deck, bundle) {
|
|
|
16035
16817
|
return fresh.length === 0 ? deck : [...deck, ...fresh];
|
|
16036
16818
|
}
|
|
16037
16819
|
|
|
16820
|
+
// src/boot/runners/benchmark-integrity.ts
|
|
16821
|
+
import { appendFileSync } from "node:fs";
|
|
16822
|
+
import path4 from "node:path";
|
|
16823
|
+
var GUARDED_TOOLS = /* @__PURE__ */ new Set(["read", "write", "edit", "grep", "find", "ls", "bash"]);
|
|
16824
|
+
var PATH_KEYS = /* @__PURE__ */ new Set(["path", "file", "file_path", "directory", "dir", "cwd", "search_path"]);
|
|
16825
|
+
var FORBIDDEN_ABSOLUTE = [
|
|
16826
|
+
"/tests",
|
|
16827
|
+
"/solution",
|
|
16828
|
+
"/solutions",
|
|
16829
|
+
"/reference",
|
|
16830
|
+
"/reference_solution",
|
|
16831
|
+
"/reference-solutions",
|
|
16832
|
+
"/reward.txt",
|
|
16833
|
+
"/rewards",
|
|
16834
|
+
"/grader",
|
|
16835
|
+
"/verifier"
|
|
16836
|
+
];
|
|
16837
|
+
var FORBIDDEN_BASENAMES = /* @__PURE__ */ new Set([
|
|
16838
|
+
"solution.sh",
|
|
16839
|
+
"solve.sh",
|
|
16840
|
+
"reward.txt",
|
|
16841
|
+
"expected_answer.txt",
|
|
16842
|
+
"expected_output.txt"
|
|
16843
|
+
]);
|
|
16844
|
+
function normalizeCandidate(value, cwd) {
|
|
16845
|
+
return path4.resolve(cwd, value);
|
|
16846
|
+
}
|
|
16847
|
+
function forbiddenPath(value, cwd) {
|
|
16848
|
+
const resolved = normalizeCandidate(value, cwd);
|
|
16849
|
+
const base = path4.basename(resolved).toLowerCase();
|
|
16850
|
+
if (FORBIDDEN_BASENAMES.has(base)) return true;
|
|
16851
|
+
return FORBIDDEN_ABSOLUTE.some((prefix) => resolved === prefix || resolved.startsWith(`${prefix}/`));
|
|
16852
|
+
}
|
|
16853
|
+
function pathValues(args) {
|
|
16854
|
+
if (args === null || typeof args !== "object" || Array.isArray(args)) return [];
|
|
16855
|
+
const values = [];
|
|
16856
|
+
for (const [key, value] of Object.entries(args)) {
|
|
16857
|
+
if (PATH_KEYS.has(key) && typeof value === "string") values.push(value);
|
|
16858
|
+
}
|
|
16859
|
+
return values;
|
|
16860
|
+
}
|
|
16861
|
+
function forbiddenShell(command, cwd) {
|
|
16862
|
+
const lower = command.toLowerCase();
|
|
16863
|
+
if ([...FORBIDDEN_BASENAMES].some((name) => lower.includes(name))) return true;
|
|
16864
|
+
if (FORBIDDEN_ABSOLUTE.some((prefix) => new RegExp(`(^|[\\s'"=])${prefix.replaceAll("/", "\\/")}(?:[/\\s'";|&]|$)`, "i").test(command))) return true;
|
|
16865
|
+
if (/(^|[\s'"=])\.\.\/(?:tests|solutions?|reference(?:[-_]solutions?)?|grader|verifier)(?:[/\s'";|&]|$)/i.test(command)) return true;
|
|
16866
|
+
if (/\b(?:find|ls|grep|rg)\s+(?:-[^\s]+\s+)*\/(?:\s|$)/i.test(command)) return true;
|
|
16867
|
+
const retrievesOnline = /\b(?:curl|wget|git\s+clone|gh\s+repo\s+clone)\b/i.test(command);
|
|
16868
|
+
const benchmarkMaterial = /terminal[-_ ]bench|reference[-_ ]solution|solution\.sh|solve\.sh|benchmark[-_ ]solution/i.test(command);
|
|
16869
|
+
if (retrievesOnline && benchmarkMaterial) return true;
|
|
16870
|
+
return false;
|
|
16871
|
+
}
|
|
16872
|
+
function denialReason(tool, args, cwd) {
|
|
16873
|
+
if (tool === "bash") {
|
|
16874
|
+
const command = typeof args?.command === "string" ? args.command : "";
|
|
16875
|
+
if (forbiddenShell(command, cwd)) return "Terminal-Bench integrity guard blocked benchmark-owned or solution material.";
|
|
16876
|
+
return void 0;
|
|
16877
|
+
}
|
|
16878
|
+
if (pathValues(args).some((candidate) => forbiddenPath(candidate, cwd))) {
|
|
16879
|
+
return "Terminal-Bench integrity guard blocked benchmark-owned or solution material.";
|
|
16880
|
+
}
|
|
16881
|
+
return void 0;
|
|
16882
|
+
}
|
|
16883
|
+
function recordDenial(tool, callId, reason, env2) {
|
|
16884
|
+
const auditPath = env2.INDUSAGI_BENCHMARK_AUDIT_LOG ?? "/logs/agent/integrity-denials.jsonl";
|
|
16885
|
+
try {
|
|
16886
|
+
appendFileSync(auditPath, `${JSON.stringify({ type: "integrity_denial", tool, call_id: callId, reason })}
|
|
16887
|
+
`, { encoding: "utf8" });
|
|
16888
|
+
} catch {
|
|
16889
|
+
}
|
|
16890
|
+
}
|
|
16891
|
+
function wrapOne2(tool, cwd, env2) {
|
|
16892
|
+
const execute = tool.execute.bind(tool);
|
|
16893
|
+
return {
|
|
16894
|
+
...tool,
|
|
16895
|
+
async execute(callId, args, signal, onUpdate) {
|
|
16896
|
+
const reason = denialReason(tool.name, args, cwd);
|
|
16897
|
+
if (reason !== void 0) {
|
|
16898
|
+
recordDenial(tool.name, callId, reason, env2);
|
|
16899
|
+
return {
|
|
16900
|
+
content: [{ type: "text", text: reason }],
|
|
16901
|
+
details: void 0,
|
|
16902
|
+
isError: true
|
|
16903
|
+
};
|
|
16904
|
+
}
|
|
16905
|
+
return execute(callId, args, signal, onUpdate);
|
|
16906
|
+
}
|
|
16907
|
+
};
|
|
16908
|
+
}
|
|
16909
|
+
function wrapToolsForTerminalBench(tools, cwd, env2 = process.env) {
|
|
16910
|
+
if (env2.INDUSAGI_BENCHMARK_PROFILE !== "terminal-bench") return tools;
|
|
16911
|
+
return tools.map((tool) => GUARDED_TOOLS.has(tool.name) ? wrapOne2(tool, cwd, env2) : tool);
|
|
16912
|
+
}
|
|
16913
|
+
|
|
16038
16914
|
// src/boot/runners/session.ts
|
|
16039
16915
|
function authenticatedProviders(ctx) {
|
|
16040
16916
|
try {
|
|
16041
|
-
const
|
|
16042
|
-
|
|
16043
|
-
|
|
16917
|
+
const path5 = ctx.workspace.authPath;
|
|
16918
|
+
const raw = readPrivateFileSync(path5);
|
|
16919
|
+
if (raw === null) return [];
|
|
16920
|
+
const data = JSON.parse(raw);
|
|
16044
16921
|
return Object.keys(data).filter((id) => {
|
|
16045
16922
|
const accounts = data[id];
|
|
16046
16923
|
return id.length > 0 && accounts !== null && typeof accounts === "object" && Object.keys(accounts).length > 0;
|
|
@@ -16118,9 +16995,9 @@ var PROVIDER_ENV = {
|
|
|
16118
16995
|
};
|
|
16119
16996
|
function primeProviderEnv(ctx) {
|
|
16120
16997
|
try {
|
|
16121
|
-
const
|
|
16122
|
-
if (!
|
|
16123
|
-
const data = JSON.parse(readFileSync17(
|
|
16998
|
+
const path5 = ctx.workspace.authPath;
|
|
16999
|
+
if (!existsSync8(path5)) return;
|
|
17000
|
+
const data = JSON.parse(readFileSync17(path5, "utf8"));
|
|
16124
17001
|
for (const [provider, accounts] of Object.entries(data)) {
|
|
16125
17002
|
if (provider.startsWith("_") || accounts === null || typeof accounts !== "object") continue;
|
|
16126
17003
|
const envVar = PROVIDER_ENV[provider];
|
|
@@ -16158,13 +17035,13 @@ function buildKeyResolver(ctx, vault, requestedAccount) {
|
|
|
16158
17035
|
}
|
|
16159
17036
|
};
|
|
16160
17037
|
}
|
|
16161
|
-
var THINKING_LEVELS = /* @__PURE__ */ new Set(["off", "minimal", "low", "medium", "high", "xhigh"]);
|
|
16162
|
-
function resolveThinkingLevel(raw) {
|
|
16163
|
-
return raw !== void 0 && THINKING_LEVELS.has(raw) ? raw : void 0;
|
|
17038
|
+
var THINKING_LEVELS = /* @__PURE__ */ new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
17039
|
+
function resolveThinkingLevel(raw, modelId) {
|
|
17040
|
+
return raw !== void 0 && THINKING_LEVELS.has(raw) && isReasoningEffortSupported(modelId, raw) ? raw : void 0;
|
|
16164
17041
|
}
|
|
16165
17042
|
function resolveText(value) {
|
|
16166
17043
|
try {
|
|
16167
|
-
if (
|
|
17044
|
+
if (existsSync8(value)) return readFileSync17(value, "utf8");
|
|
16168
17045
|
} catch {
|
|
16169
17046
|
}
|
|
16170
17047
|
return value;
|
|
@@ -16173,7 +17050,7 @@ var PROFILE_DIR2 = ".indusagi";
|
|
|
16173
17050
|
function skillRoots2(cwd) {
|
|
16174
17051
|
return [
|
|
16175
17052
|
{ dir: join22(cwd, PROFILE_DIR2, "skills"), origin: "project" },
|
|
16176
|
-
{ dir: join22(
|
|
17053
|
+
{ dir: join22(homedir10(), PROFILE_DIR2, "skills"), origin: "user" }
|
|
16177
17054
|
];
|
|
16178
17055
|
}
|
|
16179
17056
|
function gatherModelSkills(cwd) {
|
|
@@ -16204,8 +17081,9 @@ function selectTools(cwd, inv, runner, memoryStore, checkpoint, workflowRunner)
|
|
|
16204
17081
|
return visible.filter((tool) => allow.has(canon2(tool.name)));
|
|
16205
17082
|
}
|
|
16206
17083
|
function composeSystem(tools, inv, cwd, skills = [], memoryDoc) {
|
|
17084
|
+
const approvedExternalPaths = Array.isArray(inv.flags["allow-context-import"]) ? inv.flags["allow-context-import"].filter((path5) => typeof path5 === "string").map((path5) => isAbsolute6(path5) ? path5 : resolve10(cwd, path5)) : [];
|
|
16207
17085
|
const contextDocs = [
|
|
16208
|
-
...gatherContextDocs(cwd,
|
|
17086
|
+
...gatherContextDocs(cwd, homedir10(), { approvedExternalPaths }),
|
|
16209
17087
|
...memoryDoc ? [memoryDoc] : []
|
|
16210
17088
|
];
|
|
16211
17089
|
let base = inv.system !== void 0 ? resolveText(inv.system) : composeBriefing({ tools, contextDocs, skills });
|
|
@@ -16297,9 +17175,9 @@ async function loadMcpTools(inv, cwd) {
|
|
|
16297
17175
|
console.error = () => {
|
|
16298
17176
|
};
|
|
16299
17177
|
try {
|
|
16300
|
-
for (const
|
|
17178
|
+
for (const path5 of paths) {
|
|
16301
17179
|
try {
|
|
16302
|
-
const servers = loadMCPConfig2(
|
|
17180
|
+
const servers = loadMCPConfig2(path5);
|
|
16303
17181
|
if (servers.length === 0) continue;
|
|
16304
17182
|
const pool = new MCPClientPool2({ servers });
|
|
16305
17183
|
await pool.connectAll();
|
|
@@ -16331,7 +17209,8 @@ var condenseTranscript = async (messages, opts) => {
|
|
|
16331
17209
|
const deps = model ? {
|
|
16332
17210
|
model,
|
|
16333
17211
|
...opts?.apiKey !== void 0 ? { apiKey: opts.apiKey } : {},
|
|
16334
|
-
...opts?.signal !== void 0 ? { signal: opts.signal } : {}
|
|
17212
|
+
...opts?.signal !== void 0 ? { signal: opts.signal } : {},
|
|
17213
|
+
...opts?.instructions !== void 0 ? { instructions: opts.instructions } : {}
|
|
16335
17214
|
} : {};
|
|
16336
17215
|
const cleared = clearStaleToolResults(messages);
|
|
16337
17216
|
if (opts?.force) {
|
|
@@ -16371,7 +17250,7 @@ function resolveDefaultMode(store) {
|
|
|
16371
17250
|
const mode = tier.permissions?.defaultMode;
|
|
16372
17251
|
if (mode !== void 0 && isPermissionMode(mode)) return mode;
|
|
16373
17252
|
}
|
|
16374
|
-
return "
|
|
17253
|
+
return "acceptEdits";
|
|
16375
17254
|
}
|
|
16376
17255
|
function readOnlyNamesFromDeck(tools) {
|
|
16377
17256
|
const names = /* @__PURE__ */ new Set();
|
|
@@ -16458,10 +17337,13 @@ async function buildSessionConductor(ctx) {
|
|
|
16458
17337
|
basePath: typeof inv.sarvamBasePath === "string" ? inv.sarvamBasePath : typeof inv.flags?.["sarvam-base-path"] === "string" ? inv.flags["sarvam-base-path"] : void 0
|
|
16459
17338
|
})
|
|
16460
17339
|
];
|
|
16461
|
-
const tools =
|
|
17340
|
+
const tools = wrapToolsForTerminalBench(
|
|
17341
|
+
wrapToolsWithAddons(concatAddonTools(deck, addons), addons),
|
|
17342
|
+
cwd
|
|
17343
|
+
);
|
|
16462
17344
|
const skills = gatherModelSkills(cwd);
|
|
16463
17345
|
const system = composeSystem(tools, inv, cwd, skills, memoryDoc);
|
|
16464
|
-
const thinking = resolveThinkingLevel(inv.thinking);
|
|
17346
|
+
const thinking = resolveThinkingLevel(inv.thinking, modelId);
|
|
16465
17347
|
const fallbackModelId = inv.fallbackModelId;
|
|
16466
17348
|
const planReachable = inv.mode === "repl";
|
|
16467
17349
|
const canUseTool = buildPermissionGate(permissionRules, permissionMode, tools, planReachable);
|
|
@@ -16807,7 +17689,7 @@ function isProgramEntry() {
|
|
|
16807
17689
|
const entryArg = processArgv[1];
|
|
16808
17690
|
if (!entryArg) return false;
|
|
16809
17691
|
try {
|
|
16810
|
-
return
|
|
17692
|
+
return realpathSync4(fileURLToPath2(import.meta.url)) === realpathSync4(entryArg);
|
|
16811
17693
|
} catch {
|
|
16812
17694
|
return false;
|
|
16813
17695
|
}
|