@raegent/earshot 0.1.0 → 0.3.0
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/dist/main.js +1424 -199
- package/dist/main.js.map +16 -11
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -17094,6 +17094,7 @@ class Agent {
|
|
|
17094
17094
|
readFiles = new Set;
|
|
17095
17095
|
queued = [];
|
|
17096
17096
|
rules;
|
|
17097
|
+
resolved;
|
|
17097
17098
|
mode;
|
|
17098
17099
|
totalCostUsd = 0;
|
|
17099
17100
|
maxCostUsd;
|
|
@@ -17129,6 +17130,18 @@ class Agent {
|
|
|
17129
17130
|
this.askFn = options.ask;
|
|
17130
17131
|
this.systemPrompt = options.system;
|
|
17131
17132
|
this.maxCostUsd = options.maxCostUsd;
|
|
17133
|
+
this.resolved = options.model;
|
|
17134
|
+
}
|
|
17135
|
+
get model() {
|
|
17136
|
+
return this.resolved;
|
|
17137
|
+
}
|
|
17138
|
+
async changeModel(ref) {
|
|
17139
|
+
const resolved = await resolveModel(this.options.registry, ref);
|
|
17140
|
+
this.resolved = resolved;
|
|
17141
|
+
return resolved;
|
|
17142
|
+
}
|
|
17143
|
+
get permissionRules() {
|
|
17144
|
+
return [...this.rules];
|
|
17132
17145
|
}
|
|
17133
17146
|
get budgetUsd() {
|
|
17134
17147
|
return this.maxCostUsd;
|
|
@@ -17176,7 +17189,7 @@ ${renderPlan(this.plan)}`;
|
|
|
17176
17189
|
this.options.onCost?.(costUsd);
|
|
17177
17190
|
}
|
|
17178
17191
|
get contextUse() {
|
|
17179
|
-
return { tokens: this.lastRequestTokens, window: this.
|
|
17192
|
+
return { tokens: this.lastRequestTokens, window: this.resolved.model.contextWindow ?? 0 };
|
|
17180
17193
|
}
|
|
17181
17194
|
get touchedFiles() {
|
|
17182
17195
|
return [...this.readFiles];
|
|
@@ -17204,12 +17217,12 @@ ${renderPlan(this.plan)}`;
|
|
|
17204
17217
|
this.checksThisTurn = 0;
|
|
17205
17218
|
const promptText = userPromptText(prompt);
|
|
17206
17219
|
const promptParts = typeof prompt === "string" ? [{ type: "text", text: prompt }] : prompt.map((part) => ({ ...part }));
|
|
17207
|
-
if (promptParts.some((part) => part.type === "image") && !this.
|
|
17220
|
+
if (promptParts.some((part) => part.type === "image") && !this.resolved.model.capabilities.vision) {
|
|
17208
17221
|
yield {
|
|
17209
17222
|
type: "error",
|
|
17210
17223
|
error: {
|
|
17211
17224
|
kind: "invalid_request",
|
|
17212
|
-
message: `${this.
|
|
17225
|
+
message: `${this.resolved.model.name} does not support image input`,
|
|
17213
17226
|
retryable: false
|
|
17214
17227
|
}
|
|
17215
17228
|
};
|
|
@@ -17254,7 +17267,7 @@ ${context.join(`
|
|
|
17254
17267
|
content
|
|
17255
17268
|
});
|
|
17256
17269
|
const maxSteps = this.options.maxSteps ?? DEFAULT_MAX_STEPS;
|
|
17257
|
-
const modelName = `${this.
|
|
17270
|
+
const modelName = `${this.resolved.provider.id}/${this.resolved.model.id}`;
|
|
17258
17271
|
for (let step = 0;step < maxSteps; step++) {
|
|
17259
17272
|
if (signal.aborted) {
|
|
17260
17273
|
yield { type: "turn_end", reason: "aborted" };
|
|
@@ -17278,7 +17291,7 @@ ${context.join(`
|
|
|
17278
17291
|
yield { type: "model_start", model: modelName };
|
|
17279
17292
|
let assistant;
|
|
17280
17293
|
let failed;
|
|
17281
|
-
for await (const event of streamModel(this.options.registry, this.
|
|
17294
|
+
for await (const event of streamModel(this.options.registry, this.resolved, {
|
|
17282
17295
|
system: this.effectiveSystem,
|
|
17283
17296
|
messages,
|
|
17284
17297
|
tools: this.offeredTools(),
|
|
@@ -17293,7 +17306,7 @@ ${context.join(`
|
|
|
17293
17306
|
break;
|
|
17294
17307
|
case "finish": {
|
|
17295
17308
|
assistant = event.message;
|
|
17296
|
-
const costUsd = turnCost(this.
|
|
17309
|
+
const costUsd = turnCost(this.resolved.model, event.usage);
|
|
17297
17310
|
this.addCost(costUsd);
|
|
17298
17311
|
yield { type: "usage", usage: event.usage, costUsd };
|
|
17299
17312
|
break;
|
|
@@ -17598,11 +17611,20 @@ If something is failing, fix it or say what is ` + `failing and why - do not des
|
|
|
17598
17611
|
return shapeMessages(base, { ...DEFAULT_SHAPER_OPTIONS, ...this.options.shapers });
|
|
17599
17612
|
}
|
|
17600
17613
|
async* prepareRequest(signal) {
|
|
17601
|
-
const window = this.
|
|
17614
|
+
const window = this.resolved.model.contextWindow ?? 0;
|
|
17602
17615
|
const policy = { threshold: 0.8, keepRecentMessages: 8, ...this.options.compaction };
|
|
17603
17616
|
const shaped = this.requestMessages();
|
|
17604
17617
|
if (!shouldCompact(shaped, this.effectiveSystem, window, policy))
|
|
17605
17618
|
return;
|
|
17619
|
+
yield* this.runCompaction(signal);
|
|
17620
|
+
}
|
|
17621
|
+
async* compactNow(signal) {
|
|
17622
|
+
yield* this.runCompaction(signal);
|
|
17623
|
+
}
|
|
17624
|
+
async* runCompaction(signal) {
|
|
17625
|
+
const window = this.resolved.model.contextWindow ?? 0;
|
|
17626
|
+
const policy = { threshold: 0.8, keepRecentMessages: 8, ...this.options.compaction };
|
|
17627
|
+
const shaped = this.requestMessages();
|
|
17606
17628
|
const result = await compact({
|
|
17607
17629
|
messages: shaped,
|
|
17608
17630
|
system: this.effectiveSystem,
|
|
@@ -17625,7 +17647,7 @@ If something is failing, fix it or say what is ` + `failing and why - do not des
|
|
|
17625
17647
|
}
|
|
17626
17648
|
async summarise(messages, signal) {
|
|
17627
17649
|
let text2 = "";
|
|
17628
|
-
for await (const event of streamModel(this.options.registry, this.
|
|
17650
|
+
for await (const event of streamModel(this.options.registry, this.resolved, {
|
|
17629
17651
|
system: SUMMARY_PROMPT,
|
|
17630
17652
|
messages: [...messages, { role: "user", content: [{ type: "text", text: SUMMARY_PROMPT }] }],
|
|
17631
17653
|
abortSignal: signal
|
|
@@ -18359,7 +18381,7 @@ class ShadowGit {
|
|
|
18359
18381
|
}
|
|
18360
18382
|
|
|
18361
18383
|
// packages/core/src/version.ts
|
|
18362
|
-
var VERSION = "0.
|
|
18384
|
+
var VERSION = "0.3.0";
|
|
18363
18385
|
|
|
18364
18386
|
// packages/core/src/session/repair.ts
|
|
18365
18387
|
var REPAIR_TEXT = "No result was recorded for this call: earshot exited before the tool finished. " + "The call may or may not have run, so treat its effect as unknown and check " + "the current state rather than assuming either outcome.";
|
|
@@ -18620,7 +18642,16 @@ function parseArgs(argv) {
|
|
|
18620
18642
|
positionals.push(arg);
|
|
18621
18643
|
}
|
|
18622
18644
|
}
|
|
18623
|
-
const known = new Set([
|
|
18645
|
+
const known = new Set([
|
|
18646
|
+
"auth",
|
|
18647
|
+
"mcp",
|
|
18648
|
+
"extensions",
|
|
18649
|
+
"config",
|
|
18650
|
+
"models",
|
|
18651
|
+
"acp",
|
|
18652
|
+
"doctor",
|
|
18653
|
+
"update"
|
|
18654
|
+
]);
|
|
18624
18655
|
const command = positionals[0] !== undefined && known.has(positionals[0]) ? positionals[0] : undefined;
|
|
18625
18656
|
return { command, flags, positionals: command ? positionals.slice(1) : positionals };
|
|
18626
18657
|
}
|
|
@@ -20256,10 +20287,124 @@ run \`earshot models\` to see what is available
|
|
|
20256
20287
|
}
|
|
20257
20288
|
|
|
20258
20289
|
// packages/tui/src/app.tsx
|
|
20259
|
-
import { Box as
|
|
20290
|
+
import { Box as Box9, Static, Text as Text10, useApp, useInput as useInput4 } from "ink";
|
|
20260
20291
|
import { useCallback, useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
|
|
20261
20292
|
|
|
20262
|
-
// packages/tui/src/
|
|
20293
|
+
// packages/tui/src/commands.ts
|
|
20294
|
+
var SPECS = [
|
|
20295
|
+
{
|
|
20296
|
+
name: "help",
|
|
20297
|
+
summary: "List the commands you can type"
|
|
20298
|
+
},
|
|
20299
|
+
{
|
|
20300
|
+
name: "model",
|
|
20301
|
+
args: "[ref]",
|
|
20302
|
+
summary: "Show the model in use, or switch to another for the rest of the session"
|
|
20303
|
+
},
|
|
20304
|
+
{
|
|
20305
|
+
name: "mode",
|
|
20306
|
+
args: "<plan|ask|accept-edits|auto|yolo>",
|
|
20307
|
+
summary: "Change the permission mode"
|
|
20308
|
+
},
|
|
20309
|
+
{
|
|
20310
|
+
name: "plan",
|
|
20311
|
+
args: "<task>",
|
|
20312
|
+
summary: "Draft a plan in plan mode and write it to a file",
|
|
20313
|
+
idleOnly: true,
|
|
20314
|
+
verbs: [
|
|
20315
|
+
{ name: "edit", summary: "Open the plan in $VISUAL/$EDITOR, or print its path" },
|
|
20316
|
+
{ name: "approve", summary: "Pin the plan as the file now reads for the rest of the run" },
|
|
20317
|
+
{ name: "show", summary: "Read the plan back" },
|
|
20318
|
+
{ name: "clear", summary: "Unpin the plan" }
|
|
20319
|
+
]
|
|
20320
|
+
},
|
|
20321
|
+
{
|
|
20322
|
+
name: "compact",
|
|
20323
|
+
summary: "Summarise the session so far and free up the context window",
|
|
20324
|
+
idleOnly: true
|
|
20325
|
+
},
|
|
20326
|
+
{
|
|
20327
|
+
name: "context",
|
|
20328
|
+
summary: "Show what is in the context window and what compaction has dropped"
|
|
20329
|
+
},
|
|
20330
|
+
{
|
|
20331
|
+
name: "cost",
|
|
20332
|
+
args: "[usd]",
|
|
20333
|
+
summary: "Show what this session has spent, or set the budget ceiling; 0 removes it"
|
|
20334
|
+
},
|
|
20335
|
+
{
|
|
20336
|
+
name: "todo",
|
|
20337
|
+
summary: "Show the agent's current todo list"
|
|
20338
|
+
},
|
|
20339
|
+
{
|
|
20340
|
+
name: "permissions",
|
|
20341
|
+
summary: "Show the permission mode and the rules in force"
|
|
20342
|
+
},
|
|
20343
|
+
{
|
|
20344
|
+
name: "init",
|
|
20345
|
+
summary: "Write an AGENTS.md describing this project",
|
|
20346
|
+
idleOnly: true
|
|
20347
|
+
},
|
|
20348
|
+
{
|
|
20349
|
+
name: "skills",
|
|
20350
|
+
summary: "List discovered skills and user-defined commands"
|
|
20351
|
+
},
|
|
20352
|
+
{
|
|
20353
|
+
name: "memory",
|
|
20354
|
+
summary: "List remembered preferences, each with the sentence it came from",
|
|
20355
|
+
verbs: [{ name: "forget", args: "<id>", summary: "Delete one remembered preference" }]
|
|
20356
|
+
},
|
|
20357
|
+
{
|
|
20358
|
+
name: "tree",
|
|
20359
|
+
summary: "List this session's prompts, numbered",
|
|
20360
|
+
idleOnly: true
|
|
20361
|
+
},
|
|
20362
|
+
{
|
|
20363
|
+
name: "rewind",
|
|
20364
|
+
args: "<n>",
|
|
20365
|
+
summary: "Go back to the state before prompt n; nothing is deleted",
|
|
20366
|
+
idleOnly: true
|
|
20367
|
+
},
|
|
20368
|
+
{
|
|
20369
|
+
name: "fork",
|
|
20370
|
+
args: "<n>",
|
|
20371
|
+
summary: "Branch from prompt n into a new transcript",
|
|
20372
|
+
idleOnly: true
|
|
20373
|
+
},
|
|
20374
|
+
{
|
|
20375
|
+
name: "undo",
|
|
20376
|
+
summary: "Revert the last tool batch's file changes; again to step back further"
|
|
20377
|
+
},
|
|
20378
|
+
{
|
|
20379
|
+
name: "exit",
|
|
20380
|
+
aliases: ["quit"],
|
|
20381
|
+
summary: "Quit"
|
|
20382
|
+
}
|
|
20383
|
+
];
|
|
20384
|
+
var COMMANDS = SPECS;
|
|
20385
|
+
function findCommand(name) {
|
|
20386
|
+
return COMMANDS.find((command) => command.name === name || command.aliases?.includes(name));
|
|
20387
|
+
}
|
|
20388
|
+
function commandRows() {
|
|
20389
|
+
const rows = [];
|
|
20390
|
+
for (const spec of COMMANDS) {
|
|
20391
|
+
rows.push({
|
|
20392
|
+
command: spec.args ? `/${spec.name} ${spec.args}` : `/${spec.name}`,
|
|
20393
|
+
summary: spec.summary,
|
|
20394
|
+
spec
|
|
20395
|
+
});
|
|
20396
|
+
for (const verb of spec.verbs ?? []) {
|
|
20397
|
+
rows.push({
|
|
20398
|
+
command: `/${spec.name} ${verb.name}${verb.args ? ` ${verb.args}` : ""}`,
|
|
20399
|
+
summary: verb.summary,
|
|
20400
|
+
spec
|
|
20401
|
+
});
|
|
20402
|
+
}
|
|
20403
|
+
}
|
|
20404
|
+
return rows;
|
|
20405
|
+
}
|
|
20406
|
+
|
|
20407
|
+
// packages/tui/src/components/command-menu.tsx
|
|
20263
20408
|
import { Box, Text } from "ink";
|
|
20264
20409
|
|
|
20265
20410
|
// packages/tui/src/theme.ts
|
|
@@ -20292,13 +20437,123 @@ var MODE_COLOR = {
|
|
|
20292
20437
|
yolo: theme.danger
|
|
20293
20438
|
};
|
|
20294
20439
|
|
|
20440
|
+
// packages/tui/src/components/command-menu.tsx
|
|
20441
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
20442
|
+
var SUMMARY_WIDTH = 58;
|
|
20443
|
+
var VISIBLE = 10;
|
|
20444
|
+
function menuEntries(query, commands, busy) {
|
|
20445
|
+
const entries = [];
|
|
20446
|
+
for (const spec of ranked(COMMANDS, query)) {
|
|
20447
|
+
if (!matches2(spec.name, query))
|
|
20448
|
+
continue;
|
|
20449
|
+
const disabled = busy && spec.idleOnly === true;
|
|
20450
|
+
const expanded = query !== "" && spec.name.startsWith(query);
|
|
20451
|
+
for (const row of commandRows()) {
|
|
20452
|
+
if (row.spec.name !== spec.name)
|
|
20453
|
+
continue;
|
|
20454
|
+
const isBase = row.command === (spec.args ? `/${spec.name} ${spec.args}` : `/${spec.name}`);
|
|
20455
|
+
if (!isBase && !expanded)
|
|
20456
|
+
continue;
|
|
20457
|
+
entries.push({
|
|
20458
|
+
insert: insertFor(row.command, spec),
|
|
20459
|
+
label: row.command,
|
|
20460
|
+
summary: row.summary,
|
|
20461
|
+
...disabled ? { disabled: true } : {}
|
|
20462
|
+
});
|
|
20463
|
+
}
|
|
20464
|
+
}
|
|
20465
|
+
for (const command of ranked(commands, query)) {
|
|
20466
|
+
if (!matches2(command.name, query))
|
|
20467
|
+
continue;
|
|
20468
|
+
entries.push({
|
|
20469
|
+
insert: `/${command.name}`,
|
|
20470
|
+
label: `/${command.name}`,
|
|
20471
|
+
summary: command.description,
|
|
20472
|
+
scope: command.scope
|
|
20473
|
+
});
|
|
20474
|
+
}
|
|
20475
|
+
return entries;
|
|
20476
|
+
}
|
|
20477
|
+
function insertFor(command, spec) {
|
|
20478
|
+
const withoutArgs = spec.args ? command.replace(` ${spec.args}`, "") : command;
|
|
20479
|
+
return withoutArgs.replace(/\s<[^>]*>$/, "");
|
|
20480
|
+
}
|
|
20481
|
+
var clamp = (text2) => text2.length <= SUMMARY_WIDTH ? text2 : `${text2.slice(0, SUMMARY_WIDTH - 1)}…`;
|
|
20482
|
+
function rowColor(entry, active) {
|
|
20483
|
+
if (entry.disabled)
|
|
20484
|
+
return { color: theme.muted };
|
|
20485
|
+
if (active)
|
|
20486
|
+
return { color: theme.user };
|
|
20487
|
+
return {};
|
|
20488
|
+
}
|
|
20489
|
+
function matches2(name, query) {
|
|
20490
|
+
return query === "" || name.includes(query);
|
|
20491
|
+
}
|
|
20492
|
+
function ranked(items, query) {
|
|
20493
|
+
if (query === "")
|
|
20494
|
+
return [...items];
|
|
20495
|
+
return [
|
|
20496
|
+
...items.filter((item) => item.name.startsWith(query)),
|
|
20497
|
+
...items.filter((item) => !item.name.startsWith(query))
|
|
20498
|
+
];
|
|
20499
|
+
}
|
|
20500
|
+
function CommandMenu({ entries, selected }) {
|
|
20501
|
+
if (entries.length === 0) {
|
|
20502
|
+
return /* @__PURE__ */ jsxDEV(Box, {
|
|
20503
|
+
marginTop: 1,
|
|
20504
|
+
children: /* @__PURE__ */ jsxDEV(Text, {
|
|
20505
|
+
color: theme.muted,
|
|
20506
|
+
children: "no command matches"
|
|
20507
|
+
}, undefined, false, undefined, this)
|
|
20508
|
+
}, undefined, false, undefined, this);
|
|
20509
|
+
}
|
|
20510
|
+
const start = Math.min(Math.max(0, selected - VISIBLE + 1), Math.max(0, entries.length - VISIBLE));
|
|
20511
|
+
const shown = entries.slice(start, start + VISIBLE);
|
|
20512
|
+
const hidden = entries.length - shown.length;
|
|
20513
|
+
return /* @__PURE__ */ jsxDEV(Box, {
|
|
20514
|
+
flexDirection: "column",
|
|
20515
|
+
marginTop: 1,
|
|
20516
|
+
children: [
|
|
20517
|
+
shown.map((entry, index) => {
|
|
20518
|
+
const active = start + index === selected;
|
|
20519
|
+
return /* @__PURE__ */ jsxDEV(Box, {
|
|
20520
|
+
children: [
|
|
20521
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
20522
|
+
color: active ? theme.user : theme.muted,
|
|
20523
|
+
children: active ? "› " : " "
|
|
20524
|
+
}, undefined, false, undefined, this),
|
|
20525
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
20526
|
+
...rowColor(entry, active),
|
|
20527
|
+
children: entry.label.padEnd(34)
|
|
20528
|
+
}, undefined, false, undefined, this),
|
|
20529
|
+
/* @__PURE__ */ jsxDEV(Text, {
|
|
20530
|
+
color: theme.muted,
|
|
20531
|
+
children: clamp(`${entry.scope ? `[${entry.scope}] ` : ""}${entry.summary}${entry.disabled ? " (not while a turn is running)" : ""}`)
|
|
20532
|
+
}, undefined, false, undefined, this)
|
|
20533
|
+
]
|
|
20534
|
+
}, entry.label, true, undefined, this);
|
|
20535
|
+
}),
|
|
20536
|
+
/* @__PURE__ */ jsxDEV(Box, {
|
|
20537
|
+
children: /* @__PURE__ */ jsxDEV(Text, {
|
|
20538
|
+
color: theme.muted,
|
|
20539
|
+
children: [
|
|
20540
|
+
hidden > 0 ? ` ${hidden} more · ` : " ",
|
|
20541
|
+
"↑↓ choose · tab complete · enter run · esc close"
|
|
20542
|
+
]
|
|
20543
|
+
}, undefined, true, undefined, this)
|
|
20544
|
+
}, undefined, false, undefined, this)
|
|
20545
|
+
]
|
|
20546
|
+
}, undefined, true, undefined, this);
|
|
20547
|
+
}
|
|
20548
|
+
|
|
20295
20549
|
// packages/tui/src/components/markdown.tsx
|
|
20296
|
-
import {
|
|
20550
|
+
import { Box as Box2, Text as Text2 } from "ink";
|
|
20551
|
+
import { jsxDEV as jsxDEV2, Fragment } from "react/jsx-dev-runtime";
|
|
20297
20552
|
function Markdown({ text: text2 }) {
|
|
20298
20553
|
const blocks = splitBlocks(text2);
|
|
20299
|
-
return /* @__PURE__ */
|
|
20554
|
+
return /* @__PURE__ */ jsxDEV2(Box2, {
|
|
20300
20555
|
flexDirection: "column",
|
|
20301
|
-
children: blocks.map((block, index) => /* @__PURE__ */
|
|
20556
|
+
children: blocks.map((block, index) => /* @__PURE__ */ jsxDEV2(Block, {
|
|
20302
20557
|
block
|
|
20303
20558
|
}, index, false, undefined, this))
|
|
20304
20559
|
}, undefined, false, undefined, this);
|
|
@@ -20377,19 +20632,19 @@ function splitBlocks(text2) {
|
|
|
20377
20632
|
function Block({ block }) {
|
|
20378
20633
|
switch (block.kind) {
|
|
20379
20634
|
case "code":
|
|
20380
|
-
return /* @__PURE__ */
|
|
20635
|
+
return /* @__PURE__ */ jsxDEV2(Box2, {
|
|
20381
20636
|
flexDirection: "column",
|
|
20382
20637
|
marginY: 1,
|
|
20383
20638
|
paddingLeft: 2,
|
|
20384
|
-
children: block.lines.map((line, index) => /* @__PURE__ */
|
|
20639
|
+
children: block.lines.map((line, index) => /* @__PURE__ */ jsxDEV2(Text2, {
|
|
20385
20640
|
color: theme.tool,
|
|
20386
20641
|
children: line
|
|
20387
20642
|
}, index, false, undefined, this))
|
|
20388
20643
|
}, undefined, false, undefined, this);
|
|
20389
20644
|
case "heading":
|
|
20390
|
-
return /* @__PURE__ */
|
|
20645
|
+
return /* @__PURE__ */ jsxDEV2(Box2, {
|
|
20391
20646
|
marginTop: block.level <= 2 ? 1 : 0,
|
|
20392
|
-
children: /* @__PURE__ */
|
|
20647
|
+
children: /* @__PURE__ */ jsxDEV2(Text2, {
|
|
20393
20648
|
bold: true,
|
|
20394
20649
|
underline: block.level === 1,
|
|
20395
20650
|
color: theme.assistant,
|
|
@@ -20397,29 +20652,29 @@ function Block({ block }) {
|
|
|
20397
20652
|
}, undefined, false, undefined, this)
|
|
20398
20653
|
}, undefined, false, undefined, this);
|
|
20399
20654
|
case "rule":
|
|
20400
|
-
return /* @__PURE__ */
|
|
20655
|
+
return /* @__PURE__ */ jsxDEV2(Text2, {
|
|
20401
20656
|
color: theme.muted,
|
|
20402
20657
|
children: "─".repeat(40)
|
|
20403
20658
|
}, undefined, false, undefined, this);
|
|
20404
20659
|
case "list":
|
|
20405
|
-
return /* @__PURE__ */
|
|
20660
|
+
return /* @__PURE__ */ jsxDEV2(Box2, {
|
|
20406
20661
|
flexDirection: "column",
|
|
20407
|
-
children: block.items.map((item, index) => /* @__PURE__ */
|
|
20662
|
+
children: block.items.map((item, index) => /* @__PURE__ */ jsxDEV2(Text2, {
|
|
20408
20663
|
children: [
|
|
20409
20664
|
" ",
|
|
20410
20665
|
block.ordered ? `${index + 1}.` : "-",
|
|
20411
20666
|
" ",
|
|
20412
|
-
/* @__PURE__ */
|
|
20667
|
+
/* @__PURE__ */ jsxDEV2(Inline, {
|
|
20413
20668
|
text: item
|
|
20414
20669
|
}, undefined, false, undefined, this)
|
|
20415
20670
|
]
|
|
20416
20671
|
}, index, true, undefined, this))
|
|
20417
20672
|
}, undefined, false, undefined, this);
|
|
20418
20673
|
case "quote":
|
|
20419
|
-
return /* @__PURE__ */
|
|
20674
|
+
return /* @__PURE__ */ jsxDEV2(Box2, {
|
|
20420
20675
|
flexDirection: "column",
|
|
20421
20676
|
paddingLeft: 1,
|
|
20422
|
-
children: block.lines.map((line, index) => /* @__PURE__ */
|
|
20677
|
+
children: block.lines.map((line, index) => /* @__PURE__ */ jsxDEV2(Text2, {
|
|
20423
20678
|
color: theme.muted,
|
|
20424
20679
|
italic: true,
|
|
20425
20680
|
children: [
|
|
@@ -20429,8 +20684,8 @@ function Block({ block }) {
|
|
|
20429
20684
|
}, index, true, undefined, this))
|
|
20430
20685
|
}, undefined, false, undefined, this);
|
|
20431
20686
|
default:
|
|
20432
|
-
return /* @__PURE__ */
|
|
20433
|
-
children: /* @__PURE__ */
|
|
20687
|
+
return /* @__PURE__ */ jsxDEV2(Text2, {
|
|
20688
|
+
children: /* @__PURE__ */ jsxDEV2(Inline, {
|
|
20434
20689
|
text: block.text
|
|
20435
20690
|
}, undefined, false, undefined, this)
|
|
20436
20691
|
}, undefined, false, undefined, this);
|
|
@@ -20442,41 +20697,41 @@ function inlineToText(text2) {
|
|
|
20442
20697
|
function Inline({ text: text2 }) {
|
|
20443
20698
|
const pattern = /(\*\*.+?\*\*|__.+?__|`.+?`|\*.+?\*|_.+?_)/g;
|
|
20444
20699
|
const parts = text2.split(pattern);
|
|
20445
|
-
return /* @__PURE__ */
|
|
20700
|
+
return /* @__PURE__ */ jsxDEV2(Fragment, {
|
|
20446
20701
|
children: parts.map((part, index) => {
|
|
20447
20702
|
if (part === "")
|
|
20448
20703
|
return null;
|
|
20449
20704
|
if (part.startsWith("**") && part.endsWith("**")) {
|
|
20450
|
-
return /* @__PURE__ */
|
|
20705
|
+
return /* @__PURE__ */ jsxDEV2(Text2, {
|
|
20451
20706
|
bold: true,
|
|
20452
20707
|
children: part.slice(2, -2)
|
|
20453
20708
|
}, index, false, undefined, this);
|
|
20454
20709
|
}
|
|
20455
20710
|
if (part.startsWith("__") && part.endsWith("__")) {
|
|
20456
|
-
return /* @__PURE__ */
|
|
20711
|
+
return /* @__PURE__ */ jsxDEV2(Text2, {
|
|
20457
20712
|
bold: true,
|
|
20458
20713
|
children: part.slice(2, -2)
|
|
20459
20714
|
}, index, false, undefined, this);
|
|
20460
20715
|
}
|
|
20461
20716
|
if (part.startsWith("`") && part.endsWith("`")) {
|
|
20462
|
-
return /* @__PURE__ */
|
|
20717
|
+
return /* @__PURE__ */ jsxDEV2(Text2, {
|
|
20463
20718
|
color: theme.tool,
|
|
20464
20719
|
children: part.slice(1, -1)
|
|
20465
20720
|
}, index, false, undefined, this);
|
|
20466
20721
|
}
|
|
20467
20722
|
if (part.startsWith("*") && part.endsWith("*")) {
|
|
20468
|
-
return /* @__PURE__ */
|
|
20723
|
+
return /* @__PURE__ */ jsxDEV2(Text2, {
|
|
20469
20724
|
italic: true,
|
|
20470
20725
|
children: part.slice(1, -1)
|
|
20471
20726
|
}, index, false, undefined, this);
|
|
20472
20727
|
}
|
|
20473
20728
|
if (part.startsWith("_") && part.endsWith("_")) {
|
|
20474
|
-
return /* @__PURE__ */
|
|
20729
|
+
return /* @__PURE__ */ jsxDEV2(Text2, {
|
|
20475
20730
|
italic: true,
|
|
20476
20731
|
children: part.slice(1, -1)
|
|
20477
20732
|
}, index, false, undefined, this);
|
|
20478
20733
|
}
|
|
20479
|
-
return /* @__PURE__ */
|
|
20734
|
+
return /* @__PURE__ */ jsxDEV2(Text2, {
|
|
20480
20735
|
children: part
|
|
20481
20736
|
}, index, false, undefined, this);
|
|
20482
20737
|
})
|
|
@@ -20484,24 +20739,24 @@ function Inline({ text: text2 }) {
|
|
|
20484
20739
|
}
|
|
20485
20740
|
|
|
20486
20741
|
// packages/tui/src/components/memory-capture.tsx
|
|
20487
|
-
import { Box as
|
|
20488
|
-
import { jsxDEV as
|
|
20742
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
20743
|
+
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
20489
20744
|
function MemoryCapture({ candidate }) {
|
|
20490
|
-
return /* @__PURE__ */
|
|
20745
|
+
return /* @__PURE__ */ jsxDEV3(Box3, {
|
|
20491
20746
|
marginTop: 1,
|
|
20492
20747
|
children: [
|
|
20493
|
-
/* @__PURE__ */
|
|
20748
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
20494
20749
|
color: theme.accent,
|
|
20495
20750
|
children: "remember "
|
|
20496
20751
|
}, undefined, false, undefined, this),
|
|
20497
|
-
/* @__PURE__ */
|
|
20752
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
20498
20753
|
children: [
|
|
20499
20754
|
"“",
|
|
20500
20755
|
candidate.text,
|
|
20501
20756
|
"”"
|
|
20502
20757
|
]
|
|
20503
20758
|
}, undefined, true, undefined, this),
|
|
20504
|
-
/* @__PURE__ */
|
|
20759
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
20505
20760
|
color: theme.muted,
|
|
20506
20761
|
children: "? ctrl+r for this project · ctrl+g everywhere"
|
|
20507
20762
|
}, undefined, false, undefined, this)
|
|
@@ -20510,12 +20765,12 @@ function MemoryCapture({ candidate }) {
|
|
|
20510
20765
|
}
|
|
20511
20766
|
|
|
20512
20767
|
// packages/tui/src/components/permission.tsx
|
|
20513
|
-
import { Box as
|
|
20768
|
+
import { Box as Box5, Text as Text5, useInput } from "ink";
|
|
20514
20769
|
import { useState } from "react";
|
|
20515
20770
|
|
|
20516
20771
|
// packages/tui/src/components/diff.tsx
|
|
20517
|
-
import { Box as
|
|
20518
|
-
import { jsxDEV as
|
|
20772
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
20773
|
+
import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
|
|
20519
20774
|
var MAX_LINES = 60;
|
|
20520
20775
|
function DiffView({ diff: diff2, maxLines = MAX_LINES }) {
|
|
20521
20776
|
const lines = diff2.split(`
|
|
@@ -20523,15 +20778,15 @@ function DiffView({ diff: diff2, maxLines = MAX_LINES }) {
|
|
|
20523
20778
|
const body = lines.filter((line) => !line.startsWith("---") && !line.startsWith("+++"));
|
|
20524
20779
|
const shown = body.slice(0, maxLines);
|
|
20525
20780
|
const hidden = body.length - shown.length;
|
|
20526
|
-
return /* @__PURE__ */
|
|
20781
|
+
return /* @__PURE__ */ jsxDEV4(Box4, {
|
|
20527
20782
|
flexDirection: "column",
|
|
20528
20783
|
children: [
|
|
20529
|
-
shown.map((line, index) => /* @__PURE__ */
|
|
20784
|
+
shown.map((line, index) => /* @__PURE__ */ jsxDEV4(Text4, {
|
|
20530
20785
|
color: colorFor(line),
|
|
20531
20786
|
wrap: "truncate-end",
|
|
20532
20787
|
children: line === "" ? " " : line
|
|
20533
20788
|
}, index, false, undefined, this)),
|
|
20534
|
-
hidden > 0 && /* @__PURE__ */
|
|
20789
|
+
hidden > 0 && /* @__PURE__ */ jsxDEV4(Text4, {
|
|
20535
20790
|
color: theme.muted,
|
|
20536
20791
|
children: [
|
|
20537
20792
|
" ",
|
|
@@ -20566,7 +20821,7 @@ function diffStat(diff2) {
|
|
|
20566
20821
|
}
|
|
20567
20822
|
|
|
20568
20823
|
// packages/tui/src/components/permission.tsx
|
|
20569
|
-
import { jsxDEV as
|
|
20824
|
+
import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
|
|
20570
20825
|
function PermissionPrompt({ request, reason, onChoice }) {
|
|
20571
20826
|
const [selected, setSelected] = useState(0);
|
|
20572
20827
|
const options = [
|
|
@@ -20594,32 +20849,32 @@ function PermissionPrompt({ request, reason, onChoice }) {
|
|
|
20594
20849
|
});
|
|
20595
20850
|
const isDiff = request.detail.includes(`
|
|
20596
20851
|
@@`) || request.detail.startsWith("---");
|
|
20597
|
-
return /* @__PURE__ */
|
|
20852
|
+
return /* @__PURE__ */ jsxDEV5(Box5, {
|
|
20598
20853
|
flexDirection: "column",
|
|
20599
20854
|
borderStyle: "round",
|
|
20600
20855
|
borderColor: theme.warning,
|
|
20601
20856
|
paddingX: 1,
|
|
20602
20857
|
children: [
|
|
20603
|
-
/* @__PURE__ */
|
|
20858
|
+
/* @__PURE__ */ jsxDEV5(Text5, {
|
|
20604
20859
|
bold: true,
|
|
20605
20860
|
color: theme.warning,
|
|
20606
20861
|
children: request.title
|
|
20607
20862
|
}, undefined, false, undefined, this),
|
|
20608
|
-
/* @__PURE__ */
|
|
20863
|
+
/* @__PURE__ */ jsxDEV5(Text5, {
|
|
20609
20864
|
color: theme.muted,
|
|
20610
20865
|
children: reason
|
|
20611
20866
|
}, undefined, false, undefined, this),
|
|
20612
|
-
/* @__PURE__ */
|
|
20867
|
+
/* @__PURE__ */ jsxDEV5(Box5, {
|
|
20613
20868
|
marginY: 1,
|
|
20614
20869
|
flexDirection: "column",
|
|
20615
|
-
children: isDiff ? /* @__PURE__ */
|
|
20870
|
+
children: isDiff ? /* @__PURE__ */ jsxDEV5(DiffView, {
|
|
20616
20871
|
diff: request.detail
|
|
20617
|
-
}, undefined, false, undefined, this) : /* @__PURE__ */
|
|
20872
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV5(Text5, {
|
|
20618
20873
|
wrap: "wrap",
|
|
20619
20874
|
children: request.detail
|
|
20620
20875
|
}, undefined, false, undefined, this)
|
|
20621
20876
|
}, undefined, false, undefined, this),
|
|
20622
|
-
options.map((option, index) => /* @__PURE__ */
|
|
20877
|
+
options.map((option, index) => /* @__PURE__ */ jsxDEV5(Text5, {
|
|
20623
20878
|
color: index === selected ? theme.accent : option.color,
|
|
20624
20879
|
children: [
|
|
20625
20880
|
index === selected ? "❯ " : " ",
|
|
@@ -20634,13 +20889,13 @@ function truncate2(value, max) {
|
|
|
20634
20889
|
}
|
|
20635
20890
|
|
|
20636
20891
|
// packages/tui/src/components/question.tsx
|
|
20637
|
-
import { Box as
|
|
20892
|
+
import { Box as Box6, Text as Text7, useInput as useInput3 } from "ink";
|
|
20638
20893
|
import { useState as useState2 } from "react";
|
|
20639
20894
|
|
|
20640
20895
|
// packages/tui/src/components/text-input.tsx
|
|
20641
|
-
import { Text as
|
|
20896
|
+
import { Text as Text6, useInput as useInput2 } from "ink";
|
|
20642
20897
|
import { useEffect, useRef } from "react";
|
|
20643
|
-
import { jsxDEV as
|
|
20898
|
+
import { jsxDEV as jsxDEV6 } from "react/jsx-dev-runtime";
|
|
20644
20899
|
function TextInput({
|
|
20645
20900
|
value,
|
|
20646
20901
|
onChange,
|
|
@@ -20674,23 +20929,23 @@ function TextInput({
|
|
|
20674
20929
|
}
|
|
20675
20930
|
}, { isActive });
|
|
20676
20931
|
if (value === "") {
|
|
20677
|
-
return /* @__PURE__ */
|
|
20932
|
+
return /* @__PURE__ */ jsxDEV6(Text6, {
|
|
20678
20933
|
children: [
|
|
20679
|
-
/* @__PURE__ */
|
|
20934
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
20680
20935
|
inverse: true,
|
|
20681
20936
|
children: " "
|
|
20682
20937
|
}, undefined, false, undefined, this),
|
|
20683
|
-
/* @__PURE__ */
|
|
20938
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
20684
20939
|
color: theme.muted,
|
|
20685
20940
|
children: placeholder
|
|
20686
20941
|
}, undefined, false, undefined, this)
|
|
20687
20942
|
]
|
|
20688
20943
|
}, undefined, true, undefined, this);
|
|
20689
20944
|
}
|
|
20690
|
-
return /* @__PURE__ */
|
|
20945
|
+
return /* @__PURE__ */ jsxDEV6(Text6, {
|
|
20691
20946
|
children: [
|
|
20692
20947
|
value,
|
|
20693
|
-
/* @__PURE__ */
|
|
20948
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
20694
20949
|
inverse: true,
|
|
20695
20950
|
children: " "
|
|
20696
20951
|
}, undefined, false, undefined, this)
|
|
@@ -20699,7 +20954,7 @@ function TextInput({
|
|
|
20699
20954
|
}
|
|
20700
20955
|
|
|
20701
20956
|
// packages/tui/src/components/question.tsx
|
|
20702
|
-
import { jsxDEV as
|
|
20957
|
+
import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
|
|
20703
20958
|
function QuestionPrompt({ question, options = [], onAnswer }) {
|
|
20704
20959
|
const [selected, setSelected] = useState2(0);
|
|
20705
20960
|
const [typing, setTyping] = useState2(options.length === 0);
|
|
@@ -20716,29 +20971,29 @@ function QuestionPrompt({ question, options = [], onAnswer }) {
|
|
|
20716
20971
|
setValue(input);
|
|
20717
20972
|
}
|
|
20718
20973
|
}, { isActive: !typing });
|
|
20719
|
-
return /* @__PURE__ */
|
|
20974
|
+
return /* @__PURE__ */ jsxDEV7(Box6, {
|
|
20720
20975
|
flexDirection: "column",
|
|
20721
20976
|
borderStyle: "round",
|
|
20722
20977
|
borderColor: theme.accent,
|
|
20723
20978
|
paddingX: 1,
|
|
20724
20979
|
children: [
|
|
20725
|
-
/* @__PURE__ */
|
|
20980
|
+
/* @__PURE__ */ jsxDEV7(Text7, {
|
|
20726
20981
|
bold: true,
|
|
20727
20982
|
color: theme.accent,
|
|
20728
20983
|
children: question
|
|
20729
20984
|
}, undefined, false, undefined, this),
|
|
20730
|
-
!typing && options.map((option, index) => /* @__PURE__ */
|
|
20985
|
+
!typing && options.map((option, index) => /* @__PURE__ */ jsxDEV7(Text7, {
|
|
20731
20986
|
color: index === selected ? theme.accent : theme.muted,
|
|
20732
20987
|
children: [
|
|
20733
20988
|
index === selected ? "❯ " : " ",
|
|
20734
20989
|
option
|
|
20735
20990
|
]
|
|
20736
20991
|
}, option, true, undefined, this)),
|
|
20737
|
-
!typing && /* @__PURE__ */
|
|
20992
|
+
!typing && /* @__PURE__ */ jsxDEV7(Text7, {
|
|
20738
20993
|
color: theme.muted,
|
|
20739
20994
|
children: "or start typing to answer in your own words"
|
|
20740
20995
|
}, undefined, false, undefined, this),
|
|
20741
|
-
typing && /* @__PURE__ */
|
|
20996
|
+
typing && /* @__PURE__ */ jsxDEV7(TextInput, {
|
|
20742
20997
|
value,
|
|
20743
20998
|
onChange: setValue,
|
|
20744
20999
|
onSubmit: (answer) => onAnswer(answer.trim()),
|
|
@@ -20749,8 +21004,8 @@ function QuestionPrompt({ question, options = [], onAnswer }) {
|
|
|
20749
21004
|
}
|
|
20750
21005
|
|
|
20751
21006
|
// packages/tui/src/components/status.tsx
|
|
20752
|
-
import { Box as
|
|
20753
|
-
import { jsxDEV as
|
|
21007
|
+
import { Box as Box7, Text as Text8 } from "ink";
|
|
21008
|
+
import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
|
|
20754
21009
|
function StatusLine({
|
|
20755
21010
|
model: model2,
|
|
20756
21011
|
mode,
|
|
@@ -20764,27 +21019,27 @@ function StatusLine({
|
|
|
20764
21019
|
const done = todos.filter((todo2) => todo2.status === "done").length;
|
|
20765
21020
|
const current = todos.find((todo2) => todo2.status === "in_progress");
|
|
20766
21021
|
const used = context2.window > 0 ? Math.min(100, context2.tokens / context2.window * 100) : 0;
|
|
20767
|
-
return /* @__PURE__ */
|
|
21022
|
+
return /* @__PURE__ */ jsxDEV8(Box7, {
|
|
20768
21023
|
children: [
|
|
20769
|
-
/* @__PURE__ */
|
|
21024
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
20770
21025
|
color: MODE_COLOR[mode] ?? theme.muted,
|
|
20771
21026
|
children: MODE_LABEL[mode] ?? mode
|
|
20772
21027
|
}, undefined, false, undefined, this),
|
|
20773
|
-
/* @__PURE__ */
|
|
21028
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
20774
21029
|
color: theme.muted,
|
|
20775
21030
|
children: [
|
|
20776
21031
|
" · ",
|
|
20777
21032
|
model2
|
|
20778
21033
|
]
|
|
20779
21034
|
}, undefined, true, undefined, this),
|
|
20780
|
-
/* @__PURE__ */
|
|
21035
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
20781
21036
|
color: theme.muted,
|
|
20782
21037
|
children: [
|
|
20783
21038
|
" · $",
|
|
20784
21039
|
costUsd.toFixed(4)
|
|
20785
21040
|
]
|
|
20786
21041
|
}, undefined, true, undefined, this),
|
|
20787
|
-
context2.window > 0 && /* @__PURE__ */
|
|
21042
|
+
context2.window > 0 && /* @__PURE__ */ jsxDEV8(Text8, {
|
|
20788
21043
|
color: used >= 80 ? theme.warning : theme.muted,
|
|
20789
21044
|
children: [
|
|
20790
21045
|
" · ",
|
|
@@ -20792,7 +21047,7 @@ function StatusLine({
|
|
|
20792
21047
|
"% ctx"
|
|
20793
21048
|
]
|
|
20794
21049
|
}, undefined, true, undefined, this),
|
|
20795
|
-
compacted > 0 && /* @__PURE__ */
|
|
21050
|
+
compacted > 0 && /* @__PURE__ */ jsxDEV8(Text8, {
|
|
20796
21051
|
color: theme.muted,
|
|
20797
21052
|
children: [
|
|
20798
21053
|
" · ",
|
|
@@ -20800,7 +21055,7 @@ function StatusLine({
|
|
|
20800
21055
|
" summarised"
|
|
20801
21056
|
]
|
|
20802
21057
|
}, undefined, true, undefined, this),
|
|
20803
|
-
todos.length > 0 && /* @__PURE__ */
|
|
21058
|
+
todos.length > 0 && /* @__PURE__ */ jsxDEV8(Text8, {
|
|
20804
21059
|
color: theme.muted,
|
|
20805
21060
|
children: [
|
|
20806
21061
|
" ",
|
|
@@ -20811,11 +21066,11 @@ function StatusLine({
|
|
|
20811
21066
|
current ? ` ${truncate3(current.text, 40)}` : ""
|
|
20812
21067
|
]
|
|
20813
21068
|
}, undefined, true, undefined, this),
|
|
20814
|
-
busy && /* @__PURE__ */
|
|
21069
|
+
busy && /* @__PURE__ */ jsxDEV8(Text8, {
|
|
20815
21070
|
color: theme.warning,
|
|
20816
21071
|
children: " · working (esc to interrupt)"
|
|
20817
21072
|
}, undefined, false, undefined, this),
|
|
20818
|
-
queued > 0 && /* @__PURE__ */
|
|
21073
|
+
queued > 0 && /* @__PURE__ */ jsxDEV8(Text8, {
|
|
20819
21074
|
color: theme.accent,
|
|
20820
21075
|
children: [
|
|
20821
21076
|
" · ",
|
|
@@ -20831,8 +21086,8 @@ function truncate3(value, max) {
|
|
|
20831
21086
|
}
|
|
20832
21087
|
|
|
20833
21088
|
// packages/tui/src/components/tool-block.tsx
|
|
20834
|
-
import { Box as
|
|
20835
|
-
import { jsxDEV as
|
|
21089
|
+
import { Box as Box8, Text as Text9 } from "ink";
|
|
21090
|
+
import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
|
|
20836
21091
|
var PREVIEW_LINES = 8;
|
|
20837
21092
|
function ToolBlock({
|
|
20838
21093
|
name,
|
|
@@ -20851,27 +21106,27 @@ function ToolBlock({
|
|
|
20851
21106
|
const showAll = expanded || isError;
|
|
20852
21107
|
const shown = showAll ? lines : lines.slice(0, PREVIEW_LINES);
|
|
20853
21108
|
const hidden = lines.length - shown.length;
|
|
20854
|
-
return /* @__PURE__ */
|
|
21109
|
+
return /* @__PURE__ */ jsxDEV9(Box8, {
|
|
20855
21110
|
flexDirection: "column",
|
|
20856
21111
|
marginTop: 1,
|
|
20857
21112
|
children: [
|
|
20858
|
-
/* @__PURE__ */
|
|
21113
|
+
/* @__PURE__ */ jsxDEV9(Text9, {
|
|
20859
21114
|
color,
|
|
20860
21115
|
children: [
|
|
20861
21116
|
marker2,
|
|
20862
21117
|
" ",
|
|
20863
|
-
/* @__PURE__ */
|
|
21118
|
+
/* @__PURE__ */ jsxDEV9(Text9, {
|
|
20864
21119
|
bold: true,
|
|
20865
21120
|
children: name
|
|
20866
21121
|
}, undefined, false, undefined, this),
|
|
20867
|
-
title ? /* @__PURE__ */
|
|
21122
|
+
title ? /* @__PURE__ */ jsxDEV9(Text9, {
|
|
20868
21123
|
color: theme.muted,
|
|
20869
21124
|
children: [
|
|
20870
21125
|
" ",
|
|
20871
21126
|
title
|
|
20872
21127
|
]
|
|
20873
21128
|
}, undefined, true, undefined, this) : null,
|
|
20874
|
-
isDiff && !showAll ? /* @__PURE__ */
|
|
21129
|
+
isDiff && !showAll ? /* @__PURE__ */ jsxDEV9(Text9, {
|
|
20875
21130
|
color: theme.muted,
|
|
20876
21131
|
children: [
|
|
20877
21132
|
" ",
|
|
@@ -20880,12 +21135,12 @@ function ToolBlock({
|
|
|
20880
21135
|
}, undefined, true, undefined, this) : null
|
|
20881
21136
|
]
|
|
20882
21137
|
}, undefined, true, undefined, this),
|
|
20883
|
-
isDiff && showAll ? /* @__PURE__ */
|
|
21138
|
+
isDiff && showAll ? /* @__PURE__ */ jsxDEV9(Box8, {
|
|
20884
21139
|
marginLeft: 2,
|
|
20885
|
-
children: /* @__PURE__ */
|
|
21140
|
+
children: /* @__PURE__ */ jsxDEV9(DiffView, {
|
|
20886
21141
|
diff: output
|
|
20887
21142
|
}, undefined, false, undefined, this)
|
|
20888
|
-
}, undefined, false, undefined, this) : shown.map((line, index) => /* @__PURE__ */
|
|
21143
|
+
}, undefined, false, undefined, this) : shown.map((line, index) => /* @__PURE__ */ jsxDEV9(Text9, {
|
|
20889
21144
|
color: theme.muted,
|
|
20890
21145
|
wrap: "truncate-end",
|
|
20891
21146
|
children: [
|
|
@@ -20893,7 +21148,7 @@ function ToolBlock({
|
|
|
20893
21148
|
line
|
|
20894
21149
|
]
|
|
20895
21150
|
}, index, true, undefined, this)),
|
|
20896
|
-
hidden > 0 && !isDiff && /* @__PURE__ */
|
|
21151
|
+
hidden > 0 && !isDiff && /* @__PURE__ */ jsxDEV9(Text9, {
|
|
20897
21152
|
color: theme.muted,
|
|
20898
21153
|
children: [
|
|
20899
21154
|
" ",
|
|
@@ -20907,7 +21162,7 @@ function ToolBlock({
|
|
|
20907
21162
|
}
|
|
20908
21163
|
|
|
20909
21164
|
// packages/tui/src/app.tsx
|
|
20910
|
-
import { jsxDEV as
|
|
21165
|
+
import { jsxDEV as jsxDEV10 } from "react/jsx-dev-runtime";
|
|
20911
21166
|
var sequence = 0;
|
|
20912
21167
|
var nextId = () => `item_${sequence++}`;
|
|
20913
21168
|
function promptLabel(prompt) {
|
|
@@ -20916,9 +21171,10 @@ function promptLabel(prompt) {
|
|
|
20916
21171
|
return prompt.map((part) => part.type === "text" ? part.text : `[attached ${part.mediaType} image]`).join(`
|
|
20917
21172
|
`);
|
|
20918
21173
|
}
|
|
20919
|
-
function App({ session: session2, model:
|
|
21174
|
+
function App({ session: session2, model: initialModel, initialPrompt }) {
|
|
20920
21175
|
const { exit } = useApp();
|
|
20921
21176
|
const agent3 = session2.agent;
|
|
21177
|
+
const [model2, setModel] = useState3(initialModel);
|
|
20922
21178
|
const [items, setItems] = useState3(() => session2.problems.map((problem) => ({
|
|
20923
21179
|
kind: "notice",
|
|
20924
21180
|
id: nextId(),
|
|
@@ -20928,6 +21184,7 @@ function App({ session: session2, model: model2, initialPrompt }) {
|
|
|
20928
21184
|
const [live, setLive] = useState3("");
|
|
20929
21185
|
const [runningTool, setRunningTool] = useState3();
|
|
20930
21186
|
const [input, setInput] = useState3("");
|
|
21187
|
+
const [menuIndex, setMenuIndex] = useState3(0);
|
|
20931
21188
|
const [busy, setBusy] = useState3(false);
|
|
20932
21189
|
const [mode, setMode] = useState3(agent3.permissionMode);
|
|
20933
21190
|
const [cost, setCost] = useState3(0);
|
|
@@ -21154,8 +21411,8 @@ function App({ session: session2, model: model2, initialPrompt }) {
|
|
|
21154
21411
|
});
|
|
21155
21412
|
}, [agent3, candidate, model2, push, session2.skills]);
|
|
21156
21413
|
const sessionTree = useCallback(async (name, argument) => {
|
|
21157
|
-
const
|
|
21158
|
-
const prompts =
|
|
21414
|
+
const entries2 = await session2.branch();
|
|
21415
|
+
const prompts = entries2.filter((entry) => entry.type === "message" && entry.message.role === "user" && entry.message.content.some((part) => part.type === "text" && !part.text.startsWith("<self-check>")));
|
|
21159
21416
|
if (name === "tree" || !argument) {
|
|
21160
21417
|
if (prompts.length === 0) {
|
|
21161
21418
|
push({ kind: "notice", id: nextId(), text: "nothing in this session yet" });
|
|
@@ -21187,7 +21444,7 @@ function App({ session: session2, model: model2, initialPrompt }) {
|
|
|
21187
21444
|
});
|
|
21188
21445
|
return;
|
|
21189
21446
|
}
|
|
21190
|
-
const previous =
|
|
21447
|
+
const previous = entries2[entries2.indexOf(target) - 1] ?? target;
|
|
21191
21448
|
if (name === "rewind") {
|
|
21192
21449
|
const kept = await session2.rewindTo(previous.id);
|
|
21193
21450
|
push({
|
|
@@ -21304,16 +21561,149 @@ ${PLAN_PROMPT}`);
|
|
|
21304
21561
|
/plan edit to change it, /plan approve to pin it`
|
|
21305
21562
|
});
|
|
21306
21563
|
}, [agent3, push, runTurn, session2.store]);
|
|
21307
|
-
const
|
|
21308
|
-
|
|
21309
|
-
|
|
21310
|
-
|
|
21311
|
-
|
|
21312
|
-
|
|
21313
|
-
|
|
21564
|
+
const switchModel = useCallback(async (ref) => {
|
|
21565
|
+
if (!ref) {
|
|
21566
|
+
const current = agent3.model;
|
|
21567
|
+
const price = current.model.cost;
|
|
21568
|
+
push({
|
|
21569
|
+
kind: "notice",
|
|
21570
|
+
id: nextId(),
|
|
21571
|
+
text: [
|
|
21572
|
+
` ${current.provider.id}/${current.model.id}`,
|
|
21573
|
+
` context ${(current.model.contextWindow ?? 0).toLocaleString()} tokens`,
|
|
21574
|
+
` price $${price?.input ?? "?"} in / $${price?.output ?? "?"} out per million`,
|
|
21575
|
+
"",
|
|
21576
|
+
" /model <provider/model> switches; `earshot models` lists them"
|
|
21577
|
+
].join(`
|
|
21578
|
+
`)
|
|
21579
|
+
});
|
|
21314
21580
|
return;
|
|
21315
21581
|
}
|
|
21316
|
-
|
|
21582
|
+
try {
|
|
21583
|
+
const resolved = await agent3.changeModel(ref);
|
|
21584
|
+
const next = `${resolved.provider.id}/${resolved.model.id}`;
|
|
21585
|
+
setModel(next);
|
|
21586
|
+
await refreshSystemPrompt(agent3, next, session2.skills);
|
|
21587
|
+
push({ kind: "notice", id: nextId(), text: `model: ${next}` });
|
|
21588
|
+
} catch (error) {
|
|
21589
|
+
push({
|
|
21590
|
+
kind: "notice",
|
|
21591
|
+
id: nextId(),
|
|
21592
|
+
text: `${error.message}`,
|
|
21593
|
+
color: theme.warning
|
|
21594
|
+
});
|
|
21595
|
+
}
|
|
21596
|
+
}, [agent3, push, session2.skills]);
|
|
21597
|
+
const compactNow = useCallback(async () => {
|
|
21598
|
+
const abort = new AbortController;
|
|
21599
|
+
controller.current = abort;
|
|
21600
|
+
setBusy(true);
|
|
21601
|
+
try {
|
|
21602
|
+
let compactedAnything = false;
|
|
21603
|
+
for await (const event of agent3.compactNow(abort.signal)) {
|
|
21604
|
+
if (event.type === "compacted") {
|
|
21605
|
+
compactedAnything = true;
|
|
21606
|
+
setCompacted((count) => count + event.replaced);
|
|
21607
|
+
push({
|
|
21608
|
+
kind: "notice",
|
|
21609
|
+
id: nextId(),
|
|
21610
|
+
text: `compacted: ${event.replaced} earlier messages are now a summary`
|
|
21611
|
+
});
|
|
21612
|
+
}
|
|
21613
|
+
}
|
|
21614
|
+
if (!compactedAnything) {
|
|
21615
|
+
push({ kind: "notice", id: nextId(), text: "nothing to compact yet" });
|
|
21616
|
+
}
|
|
21617
|
+
} catch (error) {
|
|
21618
|
+
push({
|
|
21619
|
+
kind: "notice",
|
|
21620
|
+
id: nextId(),
|
|
21621
|
+
text: `could not compact: ${error.message}`,
|
|
21622
|
+
color: theme.warning
|
|
21623
|
+
});
|
|
21624
|
+
} finally {
|
|
21625
|
+
setBusy(false);
|
|
21626
|
+
setContext(agent3.contextUse);
|
|
21627
|
+
controller.current = undefined;
|
|
21628
|
+
}
|
|
21629
|
+
}, [agent3, push]);
|
|
21630
|
+
const handlers = {
|
|
21631
|
+
exit: () => exit(),
|
|
21632
|
+
help: () => push({ kind: "notice", id: nextId(), text: describeCommands(session2) }),
|
|
21633
|
+
model: (argument) => void switchModel(argument),
|
|
21634
|
+
compact: () => void compactNow(),
|
|
21635
|
+
context: () => {
|
|
21636
|
+
const { tokens, window } = agent3.contextUse;
|
|
21637
|
+
const percent = window > 0 ? Math.round(tokens / window * 100) : 0;
|
|
21638
|
+
const files = agent3.touchedFiles;
|
|
21639
|
+
push({
|
|
21640
|
+
kind: "notice",
|
|
21641
|
+
id: nextId(),
|
|
21642
|
+
text: [
|
|
21643
|
+
` model ${model2}`,
|
|
21644
|
+
` context ~${tokens.toLocaleString()} of ${window.toLocaleString()} tokens (${percent}%)`,
|
|
21645
|
+
` dropped ${compacted} earlier message${compacted === 1 ? "" : "s"} replaced by a summary`,
|
|
21646
|
+
` files ${files.length === 0 ? "none touched yet" : files.join(", ")}`,
|
|
21647
|
+
"",
|
|
21648
|
+
" /compact summarises now rather than waiting for 80%"
|
|
21649
|
+
].join(`
|
|
21650
|
+
`)
|
|
21651
|
+
});
|
|
21652
|
+
},
|
|
21653
|
+
cost: (argument) => {
|
|
21654
|
+
if (argument !== undefined && argument !== "") {
|
|
21655
|
+
const amount = Number.parseFloat(argument.replace(/^\$/, ""));
|
|
21656
|
+
if (Number.isNaN(amount)) {
|
|
21657
|
+
push({
|
|
21658
|
+
kind: "notice",
|
|
21659
|
+
id: nextId(),
|
|
21660
|
+
text: `usage: /cost [usd] - "${argument}" is not an amount`,
|
|
21661
|
+
color: theme.warning
|
|
21662
|
+
});
|
|
21663
|
+
return;
|
|
21664
|
+
}
|
|
21665
|
+
agent3.setBudget(amount > 0 ? amount : undefined);
|
|
21666
|
+
push({
|
|
21667
|
+
kind: "notice",
|
|
21668
|
+
id: nextId(),
|
|
21669
|
+
text: amount > 0 ? `budget: $${amount.toFixed(2)}` : "budget removed"
|
|
21670
|
+
});
|
|
21671
|
+
return;
|
|
21672
|
+
}
|
|
21673
|
+
const budget = agent3.budgetUsd;
|
|
21674
|
+
push({
|
|
21675
|
+
kind: "notice",
|
|
21676
|
+
id: nextId(),
|
|
21677
|
+
text: ` spent $${agent3.costUsd.toFixed(4)}
|
|
21678
|
+
` + ` budget ${budget === undefined ? "none - /cost <usd> sets one" : `$${budget.toFixed(2)}`}`
|
|
21679
|
+
});
|
|
21680
|
+
},
|
|
21681
|
+
todo: () => {
|
|
21682
|
+
const todos2 = agent3.todos.list();
|
|
21683
|
+
push({
|
|
21684
|
+
kind: "notice",
|
|
21685
|
+
id: nextId(),
|
|
21686
|
+
text: todos2.length === 0 ? "no todos in this session" : todos2.map((todo2) => ` ${todo2.status === "done" ? "x" : todo2.status === "in_progress" ? ">" : " "} ${todo2.text}`).join(`
|
|
21687
|
+
`)
|
|
21688
|
+
});
|
|
21689
|
+
},
|
|
21690
|
+
permissions: () => {
|
|
21691
|
+
const rules2 = agent3.permissionRules;
|
|
21692
|
+
push({
|
|
21693
|
+
kind: "notice",
|
|
21694
|
+
id: nextId(),
|
|
21695
|
+
text: [
|
|
21696
|
+
` mode ${agent3.permissionMode} (/mode changes it)`,
|
|
21697
|
+
...rules2.length === 0 ? [" rules none configured"] : [
|
|
21698
|
+
" rules (deny always wins, whatever the mode or scope)",
|
|
21699
|
+
...rules2.map((rule) => ` ${rule.effect.padEnd(5)} ${rule.source} [${rule.scope}]`)
|
|
21700
|
+
]
|
|
21701
|
+
].join(`
|
|
21702
|
+
`)
|
|
21703
|
+
});
|
|
21704
|
+
},
|
|
21705
|
+
init: () => void runTurn(INIT_PROMPT),
|
|
21706
|
+
mode: (argument) => {
|
|
21317
21707
|
if (argument && isPermissionMode(argument)) {
|
|
21318
21708
|
agent3.setPermissionMode(argument);
|
|
21319
21709
|
setMode(argument);
|
|
@@ -21326,31 +21716,25 @@ ${PLAN_PROMPT}`);
|
|
|
21326
21716
|
color: theme.warning
|
|
21327
21717
|
});
|
|
21328
21718
|
}
|
|
21329
|
-
|
|
21330
|
-
|
|
21331
|
-
|
|
21332
|
-
|
|
21333
|
-
|
|
21334
|
-
|
|
21335
|
-
|
|
21336
|
-
|
|
21337
|
-
|
|
21338
|
-
|
|
21339
|
-
|
|
21340
|
-
|
|
21341
|
-
|
|
21342
|
-
|
|
21343
|
-
|
|
21344
|
-
|
|
21345
|
-
|
|
21346
|
-
|
|
21347
|
-
|
|
21348
|
-
if (name === "undo") {
|
|
21349
|
-
undoLast();
|
|
21350
|
-
return;
|
|
21351
|
-
}
|
|
21352
|
-
if (name === "plan") {
|
|
21353
|
-
if (busy) {
|
|
21719
|
+
},
|
|
21720
|
+
memory: (argument) => void showMemories(argument),
|
|
21721
|
+
tree: (argument) => void sessionTree("tree", argument),
|
|
21722
|
+
rewind: (argument) => void sessionTree("rewind", argument),
|
|
21723
|
+
fork: (argument) => void sessionTree("fork", argument),
|
|
21724
|
+
undo: () => void undoLast(),
|
|
21725
|
+
plan: (argument) => void plan2(argument),
|
|
21726
|
+
skills: () => push({ kind: "notice", id: nextId(), text: describeExtensions(session2) })
|
|
21727
|
+
};
|
|
21728
|
+
const handlersRef = useRef2(handlers);
|
|
21729
|
+
handlersRef.current = handlers;
|
|
21730
|
+
const handleCommand = useCallback((command) => {
|
|
21731
|
+
const body = command.slice(1).trim();
|
|
21732
|
+
const space = body.search(/\s/);
|
|
21733
|
+
const name = space === -1 ? body : body.slice(0, space);
|
|
21734
|
+
const argument = space === -1 ? undefined : body.slice(space + 1).trim();
|
|
21735
|
+
const spec = findCommand(name);
|
|
21736
|
+
if (spec) {
|
|
21737
|
+
if (spec.idleOnly && busy) {
|
|
21354
21738
|
push({
|
|
21355
21739
|
kind: "notice",
|
|
21356
21740
|
id: nextId(),
|
|
@@ -21359,15 +21743,7 @@ ${PLAN_PROMPT}`);
|
|
|
21359
21743
|
});
|
|
21360
21744
|
return;
|
|
21361
21745
|
}
|
|
21362
|
-
|
|
21363
|
-
return;
|
|
21364
|
-
}
|
|
21365
|
-
if (name === "skills") {
|
|
21366
|
-
push({
|
|
21367
|
-
kind: "notice",
|
|
21368
|
-
id: nextId(),
|
|
21369
|
-
text: describeExtensions(session2)
|
|
21370
|
-
});
|
|
21746
|
+
handlersRef.current[spec.name](argument);
|
|
21371
21747
|
return;
|
|
21372
21748
|
}
|
|
21373
21749
|
const custom = session2.commands.find((entry) => entry.name === name);
|
|
@@ -21397,8 +21773,15 @@ ${PLAN_PROMPT}`);
|
|
|
21397
21773
|
text: `unknown command "${name}"`,
|
|
21398
21774
|
color: theme.warning
|
|
21399
21775
|
});
|
|
21400
|
-
}, [agent3, busy,
|
|
21776
|
+
}, [agent3, busy, push, runTurn, session2]);
|
|
21401
21777
|
const submit = useCallback((text2) => {
|
|
21778
|
+
const entry = menuOpenRef.current ? menuEntriesRef.current[selectedRef.current] : undefined;
|
|
21779
|
+
if (entry) {
|
|
21780
|
+
setInput("");
|
|
21781
|
+
setMenuIndex(0);
|
|
21782
|
+
handleCommand(entry.insert);
|
|
21783
|
+
return;
|
|
21784
|
+
}
|
|
21402
21785
|
const trimmed = text2.trim();
|
|
21403
21786
|
setInput("");
|
|
21404
21787
|
if (trimmed === "")
|
|
@@ -21417,7 +21800,38 @@ ${PLAN_PROMPT}`);
|
|
|
21417
21800
|
runTurn(trimmed);
|
|
21418
21801
|
}, [agent3, busy, push, runTurn, handleCommand]);
|
|
21419
21802
|
const inputActive = !pending && !question;
|
|
21803
|
+
const menuOpen = inputActive && input.startsWith("/") && !input.includes(" ");
|
|
21804
|
+
const entries = menuOpen ? menuEntries(input.slice(1), session2.commands, busy) : [];
|
|
21805
|
+
const selected = Math.min(menuIndex, Math.max(0, entries.length - 1));
|
|
21806
|
+
const menuOpenRef = useRef2(menuOpen);
|
|
21807
|
+
menuOpenRef.current = menuOpen;
|
|
21808
|
+
const menuEntriesRef = useRef2(entries);
|
|
21809
|
+
menuEntriesRef.current = entries;
|
|
21810
|
+
const selectedRef = useRef2(selected);
|
|
21811
|
+
selectedRef.current = selected;
|
|
21420
21812
|
useInput4((input_, key2) => {
|
|
21813
|
+
if (menuOpen && entries.length > 0) {
|
|
21814
|
+
if (key2.upArrow) {
|
|
21815
|
+
setMenuIndex((current) => current <= 0 ? entries.length - 1 : current - 1);
|
|
21816
|
+
return;
|
|
21817
|
+
}
|
|
21818
|
+
if (key2.downArrow) {
|
|
21819
|
+
setMenuIndex((current) => current >= entries.length - 1 ? 0 : current + 1);
|
|
21820
|
+
return;
|
|
21821
|
+
}
|
|
21822
|
+
if (key2.tab) {
|
|
21823
|
+
const entry = entries[selected];
|
|
21824
|
+
if (entry)
|
|
21825
|
+
setInput(`${entry.insert} `);
|
|
21826
|
+
setMenuIndex(0);
|
|
21827
|
+
return;
|
|
21828
|
+
}
|
|
21829
|
+
if (key2.escape) {
|
|
21830
|
+
setInput("");
|
|
21831
|
+
setMenuIndex(0);
|
|
21832
|
+
return;
|
|
21833
|
+
}
|
|
21834
|
+
}
|
|
21421
21835
|
if (key2.escape) {
|
|
21422
21836
|
setCandidate(undefined);
|
|
21423
21837
|
if (busy)
|
|
@@ -21428,26 +21842,26 @@ ${PLAN_PROMPT}`);
|
|
|
21428
21842
|
remember(input_ === "r" ? "project" : "user");
|
|
21429
21843
|
}
|
|
21430
21844
|
}, { isActive: inputActive });
|
|
21431
|
-
return /* @__PURE__ */
|
|
21845
|
+
return /* @__PURE__ */ jsxDEV10(Box9, {
|
|
21432
21846
|
flexDirection: "column",
|
|
21433
21847
|
children: [
|
|
21434
|
-
/* @__PURE__ */
|
|
21848
|
+
/* @__PURE__ */ jsxDEV10(Static, {
|
|
21435
21849
|
items,
|
|
21436
|
-
children: (item) => /* @__PURE__ */
|
|
21850
|
+
children: (item) => /* @__PURE__ */ jsxDEV10(ScrollRow, {
|
|
21437
21851
|
item
|
|
21438
21852
|
}, item.id, false, undefined, this)
|
|
21439
21853
|
}, undefined, false, undefined, this),
|
|
21440
|
-
live !== "" && /* @__PURE__ */
|
|
21854
|
+
live !== "" && /* @__PURE__ */ jsxDEV10(Box9, {
|
|
21441
21855
|
marginTop: 1,
|
|
21442
|
-
children: /* @__PURE__ */
|
|
21856
|
+
children: /* @__PURE__ */ jsxDEV10(Markdown, {
|
|
21443
21857
|
text: live
|
|
21444
21858
|
}, undefined, false, undefined, this)
|
|
21445
21859
|
}, undefined, false, undefined, this),
|
|
21446
|
-
runningTool && /* @__PURE__ */
|
|
21860
|
+
runningTool && /* @__PURE__ */ jsxDEV10(ToolBlock, {
|
|
21447
21861
|
name: runningTool,
|
|
21448
21862
|
running: true
|
|
21449
21863
|
}, undefined, false, undefined, this),
|
|
21450
|
-
pending && /* @__PURE__ */
|
|
21864
|
+
pending && /* @__PURE__ */ jsxDEV10(PermissionPrompt, {
|
|
21451
21865
|
request: pending.request,
|
|
21452
21866
|
reason: pending.reason,
|
|
21453
21867
|
onChoice: (choice) => {
|
|
@@ -21455,7 +21869,7 @@ ${PLAN_PROMPT}`);
|
|
|
21455
21869
|
pending.resolve(choice);
|
|
21456
21870
|
}
|
|
21457
21871
|
}, undefined, false, undefined, this),
|
|
21458
|
-
question && /* @__PURE__ */
|
|
21872
|
+
question && /* @__PURE__ */ jsxDEV10(QuestionPrompt, {
|
|
21459
21873
|
question: question.question,
|
|
21460
21874
|
...question.options ? { options: question.options } : {},
|
|
21461
21875
|
onAnswer: (answer) => {
|
|
@@ -21463,25 +21877,32 @@ ${PLAN_PROMPT}`);
|
|
|
21463
21877
|
question.resolve(answer);
|
|
21464
21878
|
}
|
|
21465
21879
|
}, undefined, false, undefined, this),
|
|
21466
|
-
candidate && inputActive && /* @__PURE__ */
|
|
21880
|
+
candidate && inputActive && /* @__PURE__ */ jsxDEV10(MemoryCapture, {
|
|
21467
21881
|
candidate
|
|
21468
21882
|
}, undefined, false, undefined, this),
|
|
21469
|
-
|
|
21883
|
+
menuOpen && /* @__PURE__ */ jsxDEV10(CommandMenu, {
|
|
21884
|
+
entries,
|
|
21885
|
+
selected
|
|
21886
|
+
}, undefined, false, undefined, this),
|
|
21887
|
+
inputActive && /* @__PURE__ */ jsxDEV10(Box9, {
|
|
21470
21888
|
marginTop: 1,
|
|
21471
21889
|
children: [
|
|
21472
|
-
/* @__PURE__ */
|
|
21890
|
+
/* @__PURE__ */ jsxDEV10(Text10, {
|
|
21473
21891
|
color: theme.user,
|
|
21474
21892
|
children: "> "
|
|
21475
21893
|
}, undefined, false, undefined, this),
|
|
21476
|
-
/* @__PURE__ */
|
|
21894
|
+
/* @__PURE__ */ jsxDEV10(TextInput, {
|
|
21477
21895
|
value: input,
|
|
21478
|
-
onChange:
|
|
21896
|
+
onChange: (value) => {
|
|
21897
|
+
setInput(value);
|
|
21898
|
+
setMenuIndex(0);
|
|
21899
|
+
},
|
|
21479
21900
|
onSubmit: submit,
|
|
21480
21901
|
placeholder: busy ? "steer the agent, or esc to interrupt" : "what should I do?"
|
|
21481
21902
|
}, undefined, false, undefined, this)
|
|
21482
21903
|
]
|
|
21483
21904
|
}, undefined, true, undefined, this),
|
|
21484
|
-
/* @__PURE__ */
|
|
21905
|
+
/* @__PURE__ */ jsxDEV10(StatusLine, {
|
|
21485
21906
|
model: model2,
|
|
21486
21907
|
mode,
|
|
21487
21908
|
costUsd: cost,
|
|
@@ -21496,45 +21917,60 @@ ${PLAN_PROMPT}`);
|
|
|
21496
21917
|
}
|
|
21497
21918
|
function ScrollRow({ item }) {
|
|
21498
21919
|
if (item.kind === "user") {
|
|
21499
|
-
return /* @__PURE__ */
|
|
21920
|
+
return /* @__PURE__ */ jsxDEV10(Box9, {
|
|
21500
21921
|
marginTop: 1,
|
|
21501
21922
|
children: [
|
|
21502
|
-
/* @__PURE__ */
|
|
21923
|
+
/* @__PURE__ */ jsxDEV10(Text10, {
|
|
21503
21924
|
color: theme.user,
|
|
21504
21925
|
children: "> "
|
|
21505
21926
|
}, undefined, false, undefined, this),
|
|
21506
|
-
/* @__PURE__ */
|
|
21927
|
+
/* @__PURE__ */ jsxDEV10(Text10, {
|
|
21507
21928
|
children: item.text
|
|
21508
21929
|
}, undefined, false, undefined, this)
|
|
21509
21930
|
]
|
|
21510
21931
|
}, undefined, true, undefined, this);
|
|
21511
21932
|
}
|
|
21512
21933
|
if (item.kind === "assistant") {
|
|
21513
|
-
return /* @__PURE__ */
|
|
21934
|
+
return /* @__PURE__ */ jsxDEV10(Box9, {
|
|
21514
21935
|
marginTop: 1,
|
|
21515
|
-
children: /* @__PURE__ */
|
|
21936
|
+
children: /* @__PURE__ */ jsxDEV10(Markdown, {
|
|
21516
21937
|
text: item.text
|
|
21517
21938
|
}, undefined, false, undefined, this)
|
|
21518
21939
|
}, undefined, false, undefined, this);
|
|
21519
21940
|
}
|
|
21520
21941
|
if (item.kind === "tool") {
|
|
21521
|
-
return /* @__PURE__ */
|
|
21942
|
+
return /* @__PURE__ */ jsxDEV10(ToolBlock, {
|
|
21522
21943
|
name: item.name,
|
|
21523
21944
|
...item.title ? { title: item.title } : {},
|
|
21524
21945
|
...item.output ? { output: item.output } : {},
|
|
21525
21946
|
...item.isError ? { isError: true } : {}
|
|
21526
21947
|
}, undefined, false, undefined, this);
|
|
21527
21948
|
}
|
|
21528
|
-
return /* @__PURE__ */
|
|
21949
|
+
return /* @__PURE__ */ jsxDEV10(Box9, {
|
|
21529
21950
|
marginTop: 1,
|
|
21530
|
-
children: /* @__PURE__ */
|
|
21951
|
+
children: /* @__PURE__ */ jsxDEV10(Text10, {
|
|
21531
21952
|
color: item.color ?? theme.muted,
|
|
21532
21953
|
children: item.text
|
|
21533
21954
|
}, undefined, false, undefined, this)
|
|
21534
21955
|
}, undefined, false, undefined, this);
|
|
21535
21956
|
}
|
|
21536
|
-
function
|
|
21537
|
-
const lines =
|
|
21957
|
+
function describeCommands(session2) {
|
|
21958
|
+
const lines = commandRows().map((row) => ` ${row.command.padEnd(34)} ${row.summary}`);
|
|
21959
|
+
if (session2.commands.length > 0) {
|
|
21960
|
+
lines.push("", " commands from this directory:");
|
|
21961
|
+
for (const command of session2.commands) {
|
|
21962
|
+
lines.push(` ${`/${command.name}`.padEnd(34)} ${command.description}`);
|
|
21963
|
+
}
|
|
21964
|
+
}
|
|
21965
|
+
lines.push("", " type / at the prompt to filter this list and pick one");
|
|
21966
|
+
return lines.join(`
|
|
21967
|
+
`);
|
|
21968
|
+
}
|
|
21969
|
+
var INIT_PROMPT = `Write an AGENTS.md at the root of this project for a coding agent that has never seen it.
|
|
21970
|
+
|
|
21971
|
+
Read enough of the repository first to be accurate. Cover: what the project is, how it is laid out, the commands to build, test and lint it, and the conventions and rules that are not obvious from the code. Prefer rules that prevent a specific failure, and say what the failure is. If an AGENTS.md or CLAUDE.md already exists, improve it in place rather than replacing it.`;
|
|
21972
|
+
function describeExtensions(session2) {
|
|
21973
|
+
const lines = [];
|
|
21538
21974
|
if (session2.skills.length > 0) {
|
|
21539
21975
|
lines.push("skills (the agent loads these itself when they fit):");
|
|
21540
21976
|
for (const skill of session2.skills) {
|
|
@@ -21552,14 +21988,347 @@ function describeExtensions(session2) {
|
|
|
21552
21988
|
return lines.length === 0 ? "no skills or commands found in .earshot/skills, .earshot/commands or your config directory" : lines.join(`
|
|
21553
21989
|
`);
|
|
21554
21990
|
}
|
|
21991
|
+
// packages/tui/src/onboarding.tsx
|
|
21992
|
+
import { Box as Box10, Text as Text11, useApp as useApp2, useInput as useInput5 } from "ink";
|
|
21993
|
+
import { useCallback as useCallback2, useRef as useRef3, useState as useState4 } from "react";
|
|
21994
|
+
import { jsxDEV as jsxDEV11 } from "react/jsx-dev-runtime";
|
|
21995
|
+
function Onboarding({ onDone, ...rest }) {
|
|
21996
|
+
const { exit } = useApp2();
|
|
21997
|
+
const options = useRef3(rest);
|
|
21998
|
+
options.current = rest;
|
|
21999
|
+
const [screen, setScreen] = useState4({ name: "choose" });
|
|
22000
|
+
const [cursor, setCursor] = useState4(0);
|
|
22001
|
+
const [input, setInput] = useState4("");
|
|
22002
|
+
const [error, setError] = useState4();
|
|
22003
|
+
const secret = useRef3("");
|
|
22004
|
+
const providers = order(rest.providers, rest.wanted);
|
|
22005
|
+
const finish = useCallback2((result) => {
|
|
22006
|
+
onDone(result);
|
|
22007
|
+
exit();
|
|
22008
|
+
}, [exit, onDone]);
|
|
22009
|
+
const verify2 = useCallback2(async (provider) => {
|
|
22010
|
+
setScreen({ name: "probing", provider });
|
|
22011
|
+
const result = await options.current.probe(provider.id);
|
|
22012
|
+
if (result.ok) {
|
|
22013
|
+
setScreen({ name: "ready", provider });
|
|
22014
|
+
return;
|
|
22015
|
+
}
|
|
22016
|
+
if (result.reason === "rejected")
|
|
22017
|
+
await options.current.forgetKey(provider.id).catch(() => {});
|
|
22018
|
+
setScreen({ name: "failed", provider, result });
|
|
22019
|
+
}, []);
|
|
22020
|
+
const submitKey = useCallback2(async () => {
|
|
22021
|
+
const provider = screen.name === "key" ? screen.provider : undefined;
|
|
22022
|
+
const key2 = secret.current;
|
|
22023
|
+
secret.current = "";
|
|
22024
|
+
setInput("");
|
|
22025
|
+
if (!provider)
|
|
22026
|
+
return;
|
|
22027
|
+
if (key2.trim() === "") {
|
|
22028
|
+
setError("a key is needed, or press esc to go back");
|
|
22029
|
+
return;
|
|
22030
|
+
}
|
|
22031
|
+
setError(undefined);
|
|
22032
|
+
await options.current.storeKey(provider.id, key2.trim());
|
|
22033
|
+
await verify2(provider);
|
|
22034
|
+
}, [screen, verify2]);
|
|
22035
|
+
const startSignIn = useCallback2(async (provider) => {
|
|
22036
|
+
setScreen({ name: "oauth", provider });
|
|
22037
|
+
try {
|
|
22038
|
+
await options.current.signIn(provider.id, (url) => setScreen({ name: "oauth", provider, url }));
|
|
22039
|
+
} catch (failure) {
|
|
22040
|
+
setScreen({
|
|
22041
|
+
name: "failed",
|
|
22042
|
+
provider,
|
|
22043
|
+
result: { ok: false, reason: "other", message: failure.message }
|
|
22044
|
+
});
|
|
22045
|
+
return;
|
|
22046
|
+
}
|
|
22047
|
+
await verify2(provider);
|
|
22048
|
+
}, [verify2]);
|
|
22049
|
+
const choose = useCallback2((provider) => {
|
|
22050
|
+
setError(undefined);
|
|
22051
|
+
if (provider.kind === "oauth")
|
|
22052
|
+
startSignIn(provider);
|
|
22053
|
+
else
|
|
22054
|
+
setScreen({ name: "key", provider });
|
|
22055
|
+
}, [startSignIn]);
|
|
22056
|
+
useInput5((key2, meta) => {
|
|
22057
|
+
if (meta.ctrl && key2 === "c") {
|
|
22058
|
+
finish({ outcome: "quit" });
|
|
22059
|
+
return;
|
|
22060
|
+
}
|
|
22061
|
+
if (screen.name === "choose") {
|
|
22062
|
+
if (key2 === "q") {
|
|
22063
|
+
finish({ outcome: "quit" });
|
|
22064
|
+
return;
|
|
22065
|
+
}
|
|
22066
|
+
if (meta.upArrow)
|
|
22067
|
+
setCursor((c) => c <= 0 ? providers.length - 1 : c - 1);
|
|
22068
|
+
if (meta.downArrow)
|
|
22069
|
+
setCursor((c) => c >= providers.length - 1 ? 0 : c + 1);
|
|
22070
|
+
if (meta.return) {
|
|
22071
|
+
const provider = providers[cursor];
|
|
22072
|
+
if (provider)
|
|
22073
|
+
choose(provider);
|
|
22074
|
+
}
|
|
22075
|
+
return;
|
|
22076
|
+
}
|
|
22077
|
+
if (screen.name === "key" && !meta.escape) {
|
|
22078
|
+
if (meta.return) {
|
|
22079
|
+
submitKey();
|
|
22080
|
+
return;
|
|
22081
|
+
}
|
|
22082
|
+
if (meta.backspace || meta.delete) {
|
|
22083
|
+
secret.current = secret.current.slice(0, -1);
|
|
22084
|
+
setInput(secret.current);
|
|
22085
|
+
return;
|
|
22086
|
+
}
|
|
22087
|
+
if (meta.ctrl || meta.meta || meta.tab)
|
|
22088
|
+
return;
|
|
22089
|
+
if (key2) {
|
|
22090
|
+
secret.current += key2;
|
|
22091
|
+
setInput(secret.current);
|
|
22092
|
+
}
|
|
22093
|
+
return;
|
|
22094
|
+
}
|
|
22095
|
+
if (meta.escape) {
|
|
22096
|
+
secret.current = "";
|
|
22097
|
+
setInput("");
|
|
22098
|
+
setError(undefined);
|
|
22099
|
+
setScreen({ name: "choose" });
|
|
22100
|
+
return;
|
|
22101
|
+
}
|
|
22102
|
+
if (screen.name === "failed" && key2 === "k" && screen.result.reason === "unreachable") {
|
|
22103
|
+
setScreen({ name: "ready", provider: screen.provider });
|
|
22104
|
+
}
|
|
22105
|
+
});
|
|
22106
|
+
if (screen.name === "choose") {
|
|
22107
|
+
return /* @__PURE__ */ jsxDEV11(Box10, {
|
|
22108
|
+
flexDirection: "column",
|
|
22109
|
+
children: [
|
|
22110
|
+
/* @__PURE__ */ jsxDEV11(Header, {}, undefined, false, undefined, this),
|
|
22111
|
+
providers.map((provider, index) => /* @__PURE__ */ jsxDEV11(Box10, {
|
|
22112
|
+
children: [
|
|
22113
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22114
|
+
color: index === cursor ? theme.user : theme.muted,
|
|
22115
|
+
children: index === cursor ? "› " : " "
|
|
22116
|
+
}, undefined, false, undefined, this),
|
|
22117
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22118
|
+
...index === cursor ? { color: theme.user } : {},
|
|
22119
|
+
children: provider.id.padEnd(14)
|
|
22120
|
+
}, undefined, false, undefined, this),
|
|
22121
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22122
|
+
color: theme.muted,
|
|
22123
|
+
children: hint(provider)
|
|
22124
|
+
}, undefined, false, undefined, this)
|
|
22125
|
+
]
|
|
22126
|
+
}, provider.id, true, undefined, this)),
|
|
22127
|
+
/* @__PURE__ */ jsxDEV11(Box10, {
|
|
22128
|
+
marginTop: 1,
|
|
22129
|
+
children: /* @__PURE__ */ jsxDEV11(Text11, {
|
|
22130
|
+
color: theme.muted,
|
|
22131
|
+
children: "↑↓ choose · enter select · q quit"
|
|
22132
|
+
}, undefined, false, undefined, this)
|
|
22133
|
+
}, undefined, false, undefined, this),
|
|
22134
|
+
error ? /* @__PURE__ */ jsxDEV11(Text11, {
|
|
22135
|
+
color: theme.warning,
|
|
22136
|
+
children: error
|
|
22137
|
+
}, undefined, false, undefined, this) : null
|
|
22138
|
+
]
|
|
22139
|
+
}, undefined, true, undefined, this);
|
|
22140
|
+
}
|
|
22141
|
+
if (screen.name === "key") {
|
|
22142
|
+
return /* @__PURE__ */ jsxDEV11(Box10, {
|
|
22143
|
+
flexDirection: "column",
|
|
22144
|
+
children: [
|
|
22145
|
+
/* @__PURE__ */ jsxDEV11(Header, {}, undefined, false, undefined, this),
|
|
22146
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22147
|
+
children: [
|
|
22148
|
+
"paste an api key for ",
|
|
22149
|
+
screen.provider.id
|
|
22150
|
+
]
|
|
22151
|
+
}, undefined, true, undefined, this),
|
|
22152
|
+
/* @__PURE__ */ jsxDEV11(Box10, {
|
|
22153
|
+
marginTop: 1,
|
|
22154
|
+
children: /* @__PURE__ */ jsxDEV11(Text11, {
|
|
22155
|
+
color: theme.muted,
|
|
22156
|
+
children: [
|
|
22157
|
+
screen.provider.envVars?.length ? `or set ${screen.provider.envVars.join(" or ")} instead and restart.
|
|
22158
|
+
` : "",
|
|
22159
|
+
"stored in your config directory, readable only by you, and never printed."
|
|
22160
|
+
]
|
|
22161
|
+
}, undefined, true, undefined, this)
|
|
22162
|
+
}, undefined, false, undefined, this),
|
|
22163
|
+
/* @__PURE__ */ jsxDEV11(Box10, {
|
|
22164
|
+
marginTop: 1,
|
|
22165
|
+
children: [
|
|
22166
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22167
|
+
color: theme.user,
|
|
22168
|
+
children: "> "
|
|
22169
|
+
}, undefined, false, undefined, this),
|
|
22170
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22171
|
+
children: "•".repeat(input.length)
|
|
22172
|
+
}, undefined, false, undefined, this),
|
|
22173
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22174
|
+
inverse: true,
|
|
22175
|
+
children: " "
|
|
22176
|
+
}, undefined, false, undefined, this)
|
|
22177
|
+
]
|
|
22178
|
+
}, undefined, true, undefined, this),
|
|
22179
|
+
error ? /* @__PURE__ */ jsxDEV11(Text11, {
|
|
22180
|
+
color: theme.warning,
|
|
22181
|
+
children: error
|
|
22182
|
+
}, undefined, false, undefined, this) : null,
|
|
22183
|
+
/* @__PURE__ */ jsxDEV11(Box10, {
|
|
22184
|
+
marginTop: 1,
|
|
22185
|
+
children: /* @__PURE__ */ jsxDEV11(Text11, {
|
|
22186
|
+
color: theme.muted,
|
|
22187
|
+
children: "enter continue · esc back"
|
|
22188
|
+
}, undefined, false, undefined, this)
|
|
22189
|
+
}, undefined, false, undefined, this)
|
|
22190
|
+
]
|
|
22191
|
+
}, undefined, true, undefined, this);
|
|
22192
|
+
}
|
|
22193
|
+
if (screen.name === "oauth") {
|
|
22194
|
+
return /* @__PURE__ */ jsxDEV11(Box10, {
|
|
22195
|
+
flexDirection: "column",
|
|
22196
|
+
children: [
|
|
22197
|
+
/* @__PURE__ */ jsxDEV11(Header, {}, undefined, false, undefined, this),
|
|
22198
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22199
|
+
children: [
|
|
22200
|
+
"signing in to ",
|
|
22201
|
+
screen.provider.id,
|
|
22202
|
+
" in your browser…"
|
|
22203
|
+
]
|
|
22204
|
+
}, undefined, true, undefined, this),
|
|
22205
|
+
screen.url ? /* @__PURE__ */ jsxDEV11(Box10, {
|
|
22206
|
+
marginTop: 1,
|
|
22207
|
+
flexDirection: "column",
|
|
22208
|
+
children: [
|
|
22209
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22210
|
+
color: theme.muted,
|
|
22211
|
+
children: "if it did not open, use this link:"
|
|
22212
|
+
}, undefined, false, undefined, this),
|
|
22213
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22214
|
+
children: screen.url
|
|
22215
|
+
}, undefined, false, undefined, this)
|
|
22216
|
+
]
|
|
22217
|
+
}, undefined, true, undefined, this) : null,
|
|
22218
|
+
/* @__PURE__ */ jsxDEV11(Box10, {
|
|
22219
|
+
marginTop: 1,
|
|
22220
|
+
children: /* @__PURE__ */ jsxDEV11(Text11, {
|
|
22221
|
+
color: theme.muted,
|
|
22222
|
+
children: "esc cancel"
|
|
22223
|
+
}, undefined, false, undefined, this)
|
|
22224
|
+
}, undefined, false, undefined, this)
|
|
22225
|
+
]
|
|
22226
|
+
}, undefined, true, undefined, this);
|
|
22227
|
+
}
|
|
22228
|
+
if (screen.name === "probing") {
|
|
22229
|
+
return /* @__PURE__ */ jsxDEV11(Box10, {
|
|
22230
|
+
flexDirection: "column",
|
|
22231
|
+
children: [
|
|
22232
|
+
/* @__PURE__ */ jsxDEV11(Header, {}, undefined, false, undefined, this),
|
|
22233
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22234
|
+
color: theme.muted,
|
|
22235
|
+
children: [
|
|
22236
|
+
"checking the credentials with ",
|
|
22237
|
+
screen.provider.id,
|
|
22238
|
+
"…"
|
|
22239
|
+
]
|
|
22240
|
+
}, undefined, true, undefined, this)
|
|
22241
|
+
]
|
|
22242
|
+
}, undefined, true, undefined, this);
|
|
22243
|
+
}
|
|
22244
|
+
if (screen.name === "failed") {
|
|
22245
|
+
return /* @__PURE__ */ jsxDEV11(Box10, {
|
|
22246
|
+
flexDirection: "column",
|
|
22247
|
+
children: [
|
|
22248
|
+
/* @__PURE__ */ jsxDEV11(Header, {}, undefined, false, undefined, this),
|
|
22249
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22250
|
+
color: theme.warning,
|
|
22251
|
+
children: screen.result.reason === "rejected" ? `${screen.provider.id} rejected that credential. It has not been kept.` : screen.result.reason === "unreachable" ? `could not reach ${screen.provider.id}.` : `${screen.provider.id} said:`
|
|
22252
|
+
}, undefined, false, undefined, this),
|
|
22253
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22254
|
+
color: theme.muted,
|
|
22255
|
+
children: screen.result.message
|
|
22256
|
+
}, undefined, false, undefined, this),
|
|
22257
|
+
/* @__PURE__ */ jsxDEV11(Box10, {
|
|
22258
|
+
marginTop: 1,
|
|
22259
|
+
children: /* @__PURE__ */ jsxDEV11(Text11, {
|
|
22260
|
+
color: theme.muted,
|
|
22261
|
+
children: screen.result.reason === "unreachable" ? "k keep it anyway and carry on · esc start over · ctrl-c quit" : "esc start over · ctrl-c quit"
|
|
22262
|
+
}, undefined, false, undefined, this)
|
|
22263
|
+
}, undefined, false, undefined, this)
|
|
22264
|
+
]
|
|
22265
|
+
}, undefined, true, undefined, this);
|
|
22266
|
+
}
|
|
22267
|
+
return /* @__PURE__ */ jsxDEV11(Box10, {
|
|
22268
|
+
flexDirection: "column",
|
|
22269
|
+
children: [
|
|
22270
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22271
|
+
color: theme.user,
|
|
22272
|
+
children: [
|
|
22273
|
+
"ready: ",
|
|
22274
|
+
screen.provider.id
|
|
22275
|
+
]
|
|
22276
|
+
}, undefined, true, undefined, this),
|
|
22277
|
+
/* @__PURE__ */ jsxDEV11(Box10, {
|
|
22278
|
+
marginTop: 1,
|
|
22279
|
+
children: /* @__PURE__ */ jsxDEV11(Text11, {
|
|
22280
|
+
color: theme.muted,
|
|
22281
|
+
children: "what should I do? (enter to start with nothing)"
|
|
22282
|
+
}, undefined, false, undefined, this)
|
|
22283
|
+
}, undefined, false, undefined, this),
|
|
22284
|
+
/* @__PURE__ */ jsxDEV11(Box10, {
|
|
22285
|
+
children: [
|
|
22286
|
+
/* @__PURE__ */ jsxDEV11(Text11, {
|
|
22287
|
+
color: theme.user,
|
|
22288
|
+
children: "> "
|
|
22289
|
+
}, undefined, false, undefined, this),
|
|
22290
|
+
/* @__PURE__ */ jsxDEV11(TextInput, {
|
|
22291
|
+
value: input,
|
|
22292
|
+
onChange: setInput,
|
|
22293
|
+
onSubmit: (text2) => finish({ outcome: "ready", providerId: screen.provider.id, firstPrompt: text2.trim() })
|
|
22294
|
+
}, undefined, false, undefined, this)
|
|
22295
|
+
]
|
|
22296
|
+
}, undefined, true, undefined, this)
|
|
22297
|
+
]
|
|
22298
|
+
}, undefined, true, undefined, this);
|
|
22299
|
+
}
|
|
22300
|
+
function Header() {
|
|
22301
|
+
return /* @__PURE__ */ jsxDEV11(Box10, {
|
|
22302
|
+
flexDirection: "column",
|
|
22303
|
+
marginBottom: 1,
|
|
22304
|
+
children: /* @__PURE__ */ jsxDEV11(Text11, {
|
|
22305
|
+
children: "earshot needs a model provider before it can do anything."
|
|
22306
|
+
}, undefined, false, undefined, this)
|
|
22307
|
+
}, undefined, false, undefined, this);
|
|
22308
|
+
}
|
|
22309
|
+
function hint(provider) {
|
|
22310
|
+
if (provider.configured)
|
|
22311
|
+
return provider.configured;
|
|
22312
|
+
if (provider.kind === "oauth")
|
|
22313
|
+
return "sign in with a browser - no key to paste";
|
|
22314
|
+
return provider.envVars?.length ? provider.envVars.join(" or ") : "api key";
|
|
22315
|
+
}
|
|
22316
|
+
function order(providers, wanted) {
|
|
22317
|
+
if (!wanted)
|
|
22318
|
+
return providers;
|
|
22319
|
+
return [
|
|
22320
|
+
...providers.filter((provider) => provider.id === wanted),
|
|
22321
|
+
...providers.filter((provider) => provider.id !== wanted)
|
|
22322
|
+
];
|
|
22323
|
+
}
|
|
21555
22324
|
// packages/tui/src/run.tsx
|
|
21556
22325
|
import { platform as platform6 } from "node:os";
|
|
21557
22326
|
import { render } from "ink";
|
|
21558
|
-
import { jsxDEV as
|
|
22327
|
+
import { jsxDEV as jsxDEV12 } from "react/jsx-dev-runtime";
|
|
21559
22328
|
var WINDOWS_MAX_FPS = 30;
|
|
21560
22329
|
async function runTui(options) {
|
|
21561
22330
|
const isWindows = platform6() === "win32";
|
|
21562
|
-
const instance = render(/* @__PURE__ */
|
|
22331
|
+
const instance = render(/* @__PURE__ */ jsxDEV12(App, {
|
|
21563
22332
|
session: options.session,
|
|
21564
22333
|
model: options.model,
|
|
21565
22334
|
...options.initialPrompt ? { initialPrompt: options.initialPrompt } : {}
|
|
@@ -21575,6 +22344,105 @@ async function runTui(options) {
|
|
|
21575
22344
|
}
|
|
21576
22345
|
return 0;
|
|
21577
22346
|
}
|
|
22347
|
+
async function runOnboarding(options) {
|
|
22348
|
+
const isWindows = platform6() === "win32";
|
|
22349
|
+
let result = { outcome: "quit" };
|
|
22350
|
+
const instance = render(/* @__PURE__ */ jsxDEV12(Onboarding, {
|
|
22351
|
+
...options,
|
|
22352
|
+
onDone: (decided) => {
|
|
22353
|
+
result = decided;
|
|
22354
|
+
}
|
|
22355
|
+
}, undefined, false, undefined, this), {
|
|
22356
|
+
exitOnCtrlC: false,
|
|
22357
|
+
patchConsole: true,
|
|
22358
|
+
...isWindows ? { maxFps: WINDOWS_MAX_FPS } : {}
|
|
22359
|
+
});
|
|
22360
|
+
await instance.waitUntilExit();
|
|
22361
|
+
return result;
|
|
22362
|
+
}
|
|
22363
|
+
// packages/cli/src/onboard.ts
|
|
22364
|
+
async function buildOnboardingOptions(wanted) {
|
|
22365
|
+
const registry2 = buildRegistry();
|
|
22366
|
+
const store3 = new AuthStore;
|
|
22367
|
+
const providers = [];
|
|
22368
|
+
for (const provider of registry2.list()) {
|
|
22369
|
+
if (provider.auth.kind === "none")
|
|
22370
|
+
continue;
|
|
22371
|
+
providers.push(await describe3(provider, store3));
|
|
22372
|
+
}
|
|
22373
|
+
providers.sort((a, b) => Number(b.kind === "oauth") - Number(a.kind === "oauth"));
|
|
22374
|
+
return {
|
|
22375
|
+
providers,
|
|
22376
|
+
...wanted ? { wanted } : {},
|
|
22377
|
+
storeKey: (providerId, key2) => store3.set(providerId, { type: "api-key", apiKey: key2 }),
|
|
22378
|
+
forgetKey: (providerId) => store3.remove(providerId),
|
|
22379
|
+
signIn: async (providerId, onUrl) => {
|
|
22380
|
+
const credentials = await loginToOpenRouter({ onUrl });
|
|
22381
|
+
await store3.set(providerId, credentials);
|
|
22382
|
+
},
|
|
22383
|
+
probe: (providerId) => probe(registry2, providerId)
|
|
22384
|
+
};
|
|
22385
|
+
}
|
|
22386
|
+
async function describe3(provider, store3) {
|
|
22387
|
+
const configured = await resolveCredentials(provider, { store: store3 }).catch(() => {
|
|
22388
|
+
return;
|
|
22389
|
+
});
|
|
22390
|
+
return {
|
|
22391
|
+
id: provider.id,
|
|
22392
|
+
kind: provider.auth.kind === "oauth" ? "oauth" : "api-key",
|
|
22393
|
+
...envVarsOf2(provider.auth).length ? { envVars: envVarsOf2(provider.auth) } : {},
|
|
22394
|
+
...configured ? { configured: describeConfigured(configured.type) } : {}
|
|
22395
|
+
};
|
|
22396
|
+
}
|
|
22397
|
+
function envVarsOf2(auth2) {
|
|
22398
|
+
return auth2.kind === "api-key" || auth2.kind === "oauth" ? auth2.envVars ?? [] : [];
|
|
22399
|
+
}
|
|
22400
|
+
function describeConfigured(kind) {
|
|
22401
|
+
return kind === "ambient" ? "ambient credentials" : kind === "oauth" ? "signed in" : "api key set";
|
|
22402
|
+
}
|
|
22403
|
+
async function probe(registry2, providerId) {
|
|
22404
|
+
const listed = registry2.list().find((provider) => provider.id === providerId);
|
|
22405
|
+
if (!listed)
|
|
22406
|
+
return { ok: false, reason: "other", message: `unknown provider "${providerId}"` };
|
|
22407
|
+
const model2 = listed.models()[0];
|
|
22408
|
+
if (!model2) {
|
|
22409
|
+
return {
|
|
22410
|
+
ok: false,
|
|
22411
|
+
reason: "other",
|
|
22412
|
+
message: `${providerId} publishes no models to check against`
|
|
22413
|
+
};
|
|
22414
|
+
}
|
|
22415
|
+
let resolved;
|
|
22416
|
+
try {
|
|
22417
|
+
resolved = await resolveModel(registry2, `${providerId}/${model2.id}`);
|
|
22418
|
+
} catch (error) {
|
|
22419
|
+
return { ok: false, reason: "other", message: error.message };
|
|
22420
|
+
}
|
|
22421
|
+
const controller = new AbortController;
|
|
22422
|
+
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
22423
|
+
try {
|
|
22424
|
+
for await (const event of streamModel(registry2, resolved, {
|
|
22425
|
+
system: "Reply with one word.",
|
|
22426
|
+
messages: [{ role: "user", content: [{ type: "text", text: "hi" }] }],
|
|
22427
|
+
maxOutputTokens: 1,
|
|
22428
|
+
abortSignal: controller.signal
|
|
22429
|
+
})) {
|
|
22430
|
+
controller.abort();
|
|
22431
|
+
if (event.type === "error") {
|
|
22432
|
+
return event.error.kind === "auth" ? { ok: false, reason: "rejected", message: event.error.message } : event.error.kind === "network" ? { ok: false, reason: "unreachable", message: event.error.message } : { ok: false, reason: "other", message: event.error.message };
|
|
22433
|
+
}
|
|
22434
|
+
return { ok: true };
|
|
22435
|
+
}
|
|
22436
|
+
return { ok: true };
|
|
22437
|
+
} catch (error) {
|
|
22438
|
+
const message = error.message;
|
|
22439
|
+
const timedOut = controller.signal.aborted && error.name === "AbortError";
|
|
22440
|
+
return timedOut ? { ok: false, reason: "unreachable", message: "timed out waiting for a response" } : { ok: false, reason: "other", message };
|
|
22441
|
+
} finally {
|
|
22442
|
+
clearTimeout(timeout);
|
|
22443
|
+
}
|
|
22444
|
+
}
|
|
22445
|
+
|
|
21578
22446
|
// packages/cli/src/commands/interactive.ts
|
|
21579
22447
|
var DEFAULT_MODEL3 = "anthropic/claude-opus-5";
|
|
21580
22448
|
async function interactiveCommand(args) {
|
|
@@ -21617,46 +22485,63 @@ async function interactiveCommand(args) {
|
|
|
21617
22485
|
return 2;
|
|
21618
22486
|
}
|
|
21619
22487
|
const extensions = await startExtensions(process.cwd());
|
|
21620
|
-
|
|
21621
|
-
|
|
21622
|
-
|
|
21623
|
-
|
|
21624
|
-
|
|
21625
|
-
|
|
21626
|
-
|
|
21627
|
-
|
|
21628
|
-
|
|
21629
|
-
|
|
21630
|
-
|
|
21631
|
-
|
|
21632
|
-
|
|
21633
|
-
|
|
21634
|
-
|
|
21635
|
-
|
|
21636
|
-
|
|
21637
|
-
|
|
21638
|
-
|
|
21639
|
-
|
|
21640
|
-
|
|
21641
|
-
|
|
21642
|
-
|
|
21643
|
-
|
|
22488
|
+
const model2 = typeof flags.model === "string" ? flags.model : DEFAULT_MODEL3;
|
|
22489
|
+
const onboardingAllowed = flags["no-onboarding"] !== true;
|
|
22490
|
+
let firstPrompt = initialPrompt;
|
|
22491
|
+
let attempted = false;
|
|
22492
|
+
for (;; ) {
|
|
22493
|
+
try {
|
|
22494
|
+
const session2 = await createSession({
|
|
22495
|
+
cwd: process.cwd(),
|
|
22496
|
+
extraTools: extensions.tools,
|
|
22497
|
+
problems: extensions.problems,
|
|
22498
|
+
onDispose: () => extensions.close(),
|
|
22499
|
+
model: model2,
|
|
22500
|
+
...mode ? { mode } : {},
|
|
22501
|
+
...typeof flags["api-key"] === "string" ? { apiKey: flags["api-key"] } : {},
|
|
22502
|
+
...curiosity ? { curiosity } : {},
|
|
22503
|
+
...maxCostUsd !== undefined ? { maxCostUsd } : {},
|
|
22504
|
+
...resumeFrom2(flags)
|
|
22505
|
+
});
|
|
22506
|
+
return await runTui({
|
|
22507
|
+
session: session2,
|
|
22508
|
+
model: model2,
|
|
22509
|
+
...firstPrompt !== "" || image ? {
|
|
22510
|
+
initialPrompt: image ? [...firstPrompt ? [{ type: "text", text: firstPrompt }] : [], image] : firstPrompt
|
|
22511
|
+
} : {}
|
|
22512
|
+
});
|
|
22513
|
+
} catch (error) {
|
|
22514
|
+
if (error instanceof MissingCredentialsError && onboardingAllowed && !attempted) {
|
|
22515
|
+
attempted = true;
|
|
22516
|
+
const result = await runOnboarding(await buildOnboardingOptions(error.provider.id));
|
|
22517
|
+
if (result.outcome === "quit") {
|
|
22518
|
+
process.stdout.write("nothing was stored. run `earshot auth login <provider>` when you are ready.\n");
|
|
22519
|
+
await extensions.close();
|
|
22520
|
+
return 0;
|
|
22521
|
+
}
|
|
22522
|
+
firstPrompt = result.firstPrompt ?? firstPrompt;
|
|
22523
|
+
continue;
|
|
22524
|
+
}
|
|
22525
|
+
await extensions.close();
|
|
22526
|
+
if (error instanceof UnknownModelError) {
|
|
22527
|
+
process.stderr.write(`${error.message}
|
|
21644
22528
|
|
|
21645
22529
|
run \`earshot models\` to see what is available
|
|
21646
22530
|
`);
|
|
21647
|
-
|
|
21648
|
-
|
|
21649
|
-
|
|
21650
|
-
|
|
22531
|
+
return 2;
|
|
22532
|
+
}
|
|
22533
|
+
if (error instanceof MissingCredentialsError) {
|
|
22534
|
+
process.stderr.write(`${error.message}
|
|
21651
22535
|
`);
|
|
21652
|
-
|
|
21653
|
-
|
|
21654
|
-
|
|
21655
|
-
|
|
22536
|
+
return 3;
|
|
22537
|
+
}
|
|
22538
|
+
if (error instanceof NoSessionToResumeError) {
|
|
22539
|
+
process.stderr.write(`${error.message}
|
|
21656
22540
|
`);
|
|
21657
|
-
|
|
22541
|
+
return 2;
|
|
22542
|
+
}
|
|
22543
|
+
throw error;
|
|
21658
22544
|
}
|
|
21659
|
-
throw error;
|
|
21660
22545
|
}
|
|
21661
22546
|
}
|
|
21662
22547
|
function resumeFrom2(flags) {
|
|
@@ -21778,6 +22663,343 @@ ${models.length} models across ${new Set(models.map((m) => m.providerId)).size}
|
|
|
21778
22663
|
return 0;
|
|
21779
22664
|
}
|
|
21780
22665
|
|
|
22666
|
+
// packages/cli/src/commands/update.ts
|
|
22667
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
22668
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
22669
|
+
import { existsSync as existsSync2, realpathSync } from "node:fs";
|
|
22670
|
+
import { chmod, readdir as readdir8, rename as rename2, rm as rm2, writeFile as writeFile10 } from "node:fs/promises";
|
|
22671
|
+
import { basename as basename2, dirname as dirname9, join as join19, sep as sep5 } from "node:path";
|
|
22672
|
+
import { createInterface } from "node:readline/promises";
|
|
22673
|
+
import { fileURLToPath } from "node:url";
|
|
22674
|
+
var PACKAGE = "@raegent/earshot";
|
|
22675
|
+
var REPO = "rishabhguptajs/earshot";
|
|
22676
|
+
var REGISTRY = `https://registry.npmjs.org/${PACKAGE.replace("/", "%2f")}/latest`;
|
|
22677
|
+
var RELEASE = `https://api.github.com/repos/${REPO}/releases/latest`;
|
|
22678
|
+
var BUNFS_MARKERS = ["/$bunfs/", "\\$bunfs\\", "/~BUN/", "\\~BUN\\"];
|
|
22679
|
+
var ASSETS = {
|
|
22680
|
+
"darwin-arm64": "earshot-darwin-arm64",
|
|
22681
|
+
"darwin-x64": "earshot-darwin-x64",
|
|
22682
|
+
"linux-x64": "earshot-linux-x64",
|
|
22683
|
+
"linux-arm64": "earshot-linux-arm64",
|
|
22684
|
+
"win32-x64": "earshot-windows-x64.exe"
|
|
22685
|
+
};
|
|
22686
|
+
function modulePath(moduleUrl) {
|
|
22687
|
+
try {
|
|
22688
|
+
return fileURLToPath(moduleUrl);
|
|
22689
|
+
} catch {
|
|
22690
|
+
return moduleUrl;
|
|
22691
|
+
}
|
|
22692
|
+
}
|
|
22693
|
+
function managerOf(dir) {
|
|
22694
|
+
const lower = dir.toLowerCase().replaceAll("\\", "/");
|
|
22695
|
+
if (lower.includes("/.bun/install/global"))
|
|
22696
|
+
return "bun";
|
|
22697
|
+
if (lower.includes("/.volta/"))
|
|
22698
|
+
return "volta";
|
|
22699
|
+
if (lower.includes("/pnpm/global") || lower.includes("/.pnpm/"))
|
|
22700
|
+
return "pnpm";
|
|
22701
|
+
if (lower.includes("/.yarn/") || lower.includes("/yarn/global"))
|
|
22702
|
+
return "yarn";
|
|
22703
|
+
return "npm";
|
|
22704
|
+
}
|
|
22705
|
+
function detectInstall(options) {
|
|
22706
|
+
const { execPath, moduleUrl, bunVersion, platform: platform7, arch } = options;
|
|
22707
|
+
const realpath = options.realpath ?? ((path) => path);
|
|
22708
|
+
const file = modulePath(moduleUrl);
|
|
22709
|
+
if (BUNFS_MARKERS.some((marker3) => file.includes(marker3)) && bunVersion !== undefined) {
|
|
22710
|
+
const asset = ASSETS[`${platform7}-${arch}`];
|
|
22711
|
+
const target = realpath(execPath);
|
|
22712
|
+
if (asset === undefined) {
|
|
22713
|
+
return {
|
|
22714
|
+
kind: "binary",
|
|
22715
|
+
path: target,
|
|
22716
|
+
reason: `no release asset is built for ${platform7}-${arch}`
|
|
22717
|
+
};
|
|
22718
|
+
}
|
|
22719
|
+
return { kind: "binary", path: target, asset };
|
|
22720
|
+
}
|
|
22721
|
+
const marker2 = `${sep5}node_modules${sep5}${PACKAGE.split("/").join(sep5)}${sep5}`;
|
|
22722
|
+
const index = `${file}${sep5}`.indexOf(marker2);
|
|
22723
|
+
if (index !== -1) {
|
|
22724
|
+
const packageDir = file.slice(0, index + marker2.length - 1);
|
|
22725
|
+
const tree = packageDir.slice(0, packageDir.indexOf(`${sep5}node_modules${sep5}`));
|
|
22726
|
+
const isProjectRoot = options.isProjectRoot ?? (() => false);
|
|
22727
|
+
return {
|
|
22728
|
+
kind: "npm",
|
|
22729
|
+
path: packageDir,
|
|
22730
|
+
manager: managerOf(packageDir),
|
|
22731
|
+
local: isProjectRoot(tree)
|
|
22732
|
+
};
|
|
22733
|
+
}
|
|
22734
|
+
if (file.includes(`${sep5}packages${sep5}cli${sep5}`) || file.endsWith(".ts")) {
|
|
22735
|
+
return { kind: "source", path: file, reason: "running from a source checkout" };
|
|
22736
|
+
}
|
|
22737
|
+
return { kind: "unknown", path: file, reason: `cannot tell how ${execPath} was installed` };
|
|
22738
|
+
}
|
|
22739
|
+
function compareVersions(a, b) {
|
|
22740
|
+
const split = (value) => {
|
|
22741
|
+
const [core = "", pre] = value.replace(/^v/, "").split("-");
|
|
22742
|
+
const parts = core.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
22743
|
+
return { parts, pre };
|
|
22744
|
+
};
|
|
22745
|
+
const left = split(a);
|
|
22746
|
+
const right = split(b);
|
|
22747
|
+
for (let i = 0;i < 3; i++) {
|
|
22748
|
+
const diff2 = (left.parts[i] ?? 0) - (right.parts[i] ?? 0);
|
|
22749
|
+
if (diff2 !== 0)
|
|
22750
|
+
return diff2 < 0 ? -1 : 1;
|
|
22751
|
+
}
|
|
22752
|
+
if (left.pre === right.pre)
|
|
22753
|
+
return 0;
|
|
22754
|
+
if (left.pre === undefined)
|
|
22755
|
+
return 1;
|
|
22756
|
+
if (right.pre === undefined)
|
|
22757
|
+
return -1;
|
|
22758
|
+
return left.pre < right.pre ? -1 : 1;
|
|
22759
|
+
}
|
|
22760
|
+
async function resolveLatest(kind, fetchImpl) {
|
|
22761
|
+
if (kind === "npm") {
|
|
22762
|
+
const response2 = await fetchImpl(REGISTRY);
|
|
22763
|
+
if (!response2.ok)
|
|
22764
|
+
throw new Error(`npm registry returned ${response2.status}`);
|
|
22765
|
+
const body2 = await response2.json();
|
|
22766
|
+
if (!body2.version)
|
|
22767
|
+
throw new Error("npm registry returned no version");
|
|
22768
|
+
return body2.version;
|
|
22769
|
+
}
|
|
22770
|
+
const response = await fetchImpl(RELEASE);
|
|
22771
|
+
if (!response.ok)
|
|
22772
|
+
throw new Error(`GitHub releases returned ${response.status}`);
|
|
22773
|
+
const body = await response.json();
|
|
22774
|
+
if (!body.tag_name)
|
|
22775
|
+
throw new Error("GitHub returned a release with no tag");
|
|
22776
|
+
return body.tag_name.replace(/^v/, "");
|
|
22777
|
+
}
|
|
22778
|
+
function findChecksum(sums, asset) {
|
|
22779
|
+
for (const line of sums.split(`
|
|
22780
|
+
`)) {
|
|
22781
|
+
const [hash, ...rest] = line.trim().split(/\s+/);
|
|
22782
|
+
const name = rest.join(" ").replace(/^\*/, "");
|
|
22783
|
+
if (hash && name && basename2(name) === asset)
|
|
22784
|
+
return hash.toLowerCase();
|
|
22785
|
+
}
|
|
22786
|
+
return;
|
|
22787
|
+
}
|
|
22788
|
+
var installCommand = {
|
|
22789
|
+
npm: `npm install -g ${PACKAGE}@latest`,
|
|
22790
|
+
bun: `bun add -g ${PACKAGE}@latest`,
|
|
22791
|
+
pnpm: `pnpm add -g ${PACKAGE}@latest`,
|
|
22792
|
+
yarn: `yarn global add ${PACKAGE}@latest`,
|
|
22793
|
+
volta: `volta install ${PACKAGE}@latest`
|
|
22794
|
+
};
|
|
22795
|
+
async function runUpdate(options = {}) {
|
|
22796
|
+
const out = options.out ?? ((text2) => process.stdout.write(text2));
|
|
22797
|
+
const err = options.err ?? ((text2) => process.stderr.write(text2));
|
|
22798
|
+
const current = options.current ?? VERSION;
|
|
22799
|
+
const install = options.install ?? detectInstall({
|
|
22800
|
+
execPath: process.execPath,
|
|
22801
|
+
moduleUrl: import.meta.url,
|
|
22802
|
+
bunVersion: process.versions.bun,
|
|
22803
|
+
platform: process.platform,
|
|
22804
|
+
arch: process.arch,
|
|
22805
|
+
realpath: (path) => {
|
|
22806
|
+
try {
|
|
22807
|
+
return realpathSync(path);
|
|
22808
|
+
} catch {
|
|
22809
|
+
return path;
|
|
22810
|
+
}
|
|
22811
|
+
},
|
|
22812
|
+
isProjectRoot: (dir) => existsSync2(join19(dir, "package.json"))
|
|
22813
|
+
});
|
|
22814
|
+
const fetchImpl = options.fetch ?? ((url) => fetch(url));
|
|
22815
|
+
if (install.kind === "source" || install.kind === "unknown") {
|
|
22816
|
+
err(`earshot update: ${install.reason}
|
|
22817
|
+
`);
|
|
22818
|
+
err(install.kind === "source" ? `update the checkout with git instead
|
|
22819
|
+
` : `reinstall from ${`https://github.com/${REPO}/releases`}
|
|
22820
|
+
`);
|
|
22821
|
+
return 2;
|
|
22822
|
+
}
|
|
22823
|
+
if (install.kind === "binary" && install.asset === undefined) {
|
|
22824
|
+
err(`earshot update: ${install.reason}
|
|
22825
|
+
`);
|
|
22826
|
+
return 2;
|
|
22827
|
+
}
|
|
22828
|
+
let latest;
|
|
22829
|
+
try {
|
|
22830
|
+
latest = await resolveLatest(install.kind, fetchImpl);
|
|
22831
|
+
} catch (error) {
|
|
22832
|
+
err(`earshot update: ${error.message}
|
|
22833
|
+
`);
|
|
22834
|
+
return 1;
|
|
22835
|
+
}
|
|
22836
|
+
if (compareVersions(current, latest) >= 0) {
|
|
22837
|
+
out(`earshot ${current} is the latest version
|
|
22838
|
+
`);
|
|
22839
|
+
return 0;
|
|
22840
|
+
}
|
|
22841
|
+
const where = install.kind === "npm" ? `installed with ${install.manager}, ${install.local ? "in this project" : "globally"}` : "standalone binary";
|
|
22842
|
+
out(`earshot ${current} -> ${latest} (${where})
|
|
22843
|
+
`);
|
|
22844
|
+
if (install.kind === "npm") {
|
|
22845
|
+
const manager2 = install.manager ?? "npm";
|
|
22846
|
+
const command = install.local ? `${manager2 === "npm" ? "npm install" : `${manager2} add`} ${PACKAGE}@latest` : installCommand[manager2];
|
|
22847
|
+
out(`
|
|
22848
|
+
${command}
|
|
22849
|
+
|
|
22850
|
+
`);
|
|
22851
|
+
if (install.local || manager2 !== "npm") {
|
|
22852
|
+
out(`run that to update
|
|
22853
|
+
`);
|
|
22854
|
+
return options.check ? 4 : 0;
|
|
22855
|
+
}
|
|
22856
|
+
if (options.check)
|
|
22857
|
+
return 4;
|
|
22858
|
+
if (!await confirmed(options, "run it now?")) {
|
|
22859
|
+
out(`run that to update
|
|
22860
|
+
`);
|
|
22861
|
+
return 0;
|
|
22862
|
+
}
|
|
22863
|
+
const run4 = options.run ?? runCommand2;
|
|
22864
|
+
const result = run4("npm", ["install", "-g", `${PACKAGE}@latest`]);
|
|
22865
|
+
if (result.status !== 0) {
|
|
22866
|
+
err(`earshot update: npm exited ${result.status}
|
|
22867
|
+
`);
|
|
22868
|
+
return 1;
|
|
22869
|
+
}
|
|
22870
|
+
out(`updated to ${latest}
|
|
22871
|
+
`);
|
|
22872
|
+
return 0;
|
|
22873
|
+
}
|
|
22874
|
+
return await updateBinary(install, latest, options, out, err);
|
|
22875
|
+
}
|
|
22876
|
+
function runCommand2(command, args) {
|
|
22877
|
+
const result = spawnSync2(command, args, { stdio: "inherit", windowsHide: true, shell: false });
|
|
22878
|
+
return { status: result.status };
|
|
22879
|
+
}
|
|
22880
|
+
async function confirmed(options, question) {
|
|
22881
|
+
if (options.yes)
|
|
22882
|
+
return true;
|
|
22883
|
+
const confirm = options.confirm ?? defaultConfirm;
|
|
22884
|
+
return await confirm(question);
|
|
22885
|
+
}
|
|
22886
|
+
async function defaultConfirm(question) {
|
|
22887
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
22888
|
+
return false;
|
|
22889
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
22890
|
+
try {
|
|
22891
|
+
const answer = await rl.question(`${question} [y/N] `);
|
|
22892
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
22893
|
+
} finally {
|
|
22894
|
+
rl.close();
|
|
22895
|
+
}
|
|
22896
|
+
}
|
|
22897
|
+
async function updateBinary(install, latest, options, out, err) {
|
|
22898
|
+
const target = install.path;
|
|
22899
|
+
const asset = install.asset;
|
|
22900
|
+
const dir = dirname9(target);
|
|
22901
|
+
const fetchImpl = options.fetch ?? ((url) => fetch(url));
|
|
22902
|
+
await sweepStale(dir, target);
|
|
22903
|
+
out(` ${target} ${asset}
|
|
22904
|
+
`);
|
|
22905
|
+
if (options.check)
|
|
22906
|
+
return 4;
|
|
22907
|
+
try {
|
|
22908
|
+
await writeFile10(join19(dir, `.earshot-update-probe-${process.pid}`), "");
|
|
22909
|
+
await rm2(join19(dir, `.earshot-update-probe-${process.pid}`), { force: true });
|
|
22910
|
+
} catch {
|
|
22911
|
+
err(`earshot update: cannot write to ${dir}
|
|
22912
|
+
`);
|
|
22913
|
+
err(`re-run with the permissions that own that directory
|
|
22914
|
+
`);
|
|
22915
|
+
return 1;
|
|
22916
|
+
}
|
|
22917
|
+
if (!await confirmed(options, `download ${asset} and replace it?`)) {
|
|
22918
|
+
out(`nothing was changed
|
|
22919
|
+
`);
|
|
22920
|
+
return 0;
|
|
22921
|
+
}
|
|
22922
|
+
const base = `https://github.com/${REPO}/releases/download/v${latest}`;
|
|
22923
|
+
const temp = join19(dir, `.earshot-update-${process.pid}.tmp`);
|
|
22924
|
+
try {
|
|
22925
|
+
out(" downloading… ");
|
|
22926
|
+
const download = await fetchImpl(`${base}/${asset}`);
|
|
22927
|
+
if (!download.ok)
|
|
22928
|
+
throw new Error(`downloading ${asset} returned ${download.status}`);
|
|
22929
|
+
const bytes = new Uint8Array(await download.arrayBuffer());
|
|
22930
|
+
out("verifying SHA256… ");
|
|
22931
|
+
const sumsResponse = await fetchImpl(`${base}/SHA256SUMS`);
|
|
22932
|
+
if (!sumsResponse.ok)
|
|
22933
|
+
throw new Error(`SHA256SUMS returned ${sumsResponse.status}`);
|
|
22934
|
+
const expected = findChecksum(await sumsResponse.text(), asset);
|
|
22935
|
+
if (expected === undefined)
|
|
22936
|
+
throw new Error(`SHA256SUMS does not list ${asset}`);
|
|
22937
|
+
const actual = createHash4("sha256").update(bytes).digest("hex");
|
|
22938
|
+
if (actual !== expected) {
|
|
22939
|
+
throw new Error(`checksum mismatch for ${asset}: expected ${expected}, got ${actual}`);
|
|
22940
|
+
}
|
|
22941
|
+
out("replacing… ");
|
|
22942
|
+
await writeFile10(temp, bytes);
|
|
22943
|
+
const platform7 = options.platform ?? process.platform;
|
|
22944
|
+
if (platform7 !== "win32")
|
|
22945
|
+
await chmod(temp, 493);
|
|
22946
|
+
await replace(temp, target, platform7);
|
|
22947
|
+
out(`
|
|
22948
|
+
updated to ${latest}
|
|
22949
|
+
`);
|
|
22950
|
+
return 0;
|
|
22951
|
+
} catch (error) {
|
|
22952
|
+
await rm2(temp, { force: true });
|
|
22953
|
+
out(`
|
|
22954
|
+
`);
|
|
22955
|
+
err(`earshot update: ${error.message}
|
|
22956
|
+
`);
|
|
22957
|
+
err(`nothing was replaced
|
|
22958
|
+
`);
|
|
22959
|
+
return 1;
|
|
22960
|
+
}
|
|
22961
|
+
}
|
|
22962
|
+
var realIo = {
|
|
22963
|
+
rename: (from, to) => rename2(from, to),
|
|
22964
|
+
remove: (path) => rm2(path, { force: true })
|
|
22965
|
+
};
|
|
22966
|
+
async function replace(temp, target, platform7, io = realIo) {
|
|
22967
|
+
if (platform7 !== "win32") {
|
|
22968
|
+
await io.rename(temp, target);
|
|
22969
|
+
return;
|
|
22970
|
+
}
|
|
22971
|
+
const aside = `${target}.old-${process.pid}`;
|
|
22972
|
+
await io.rename(target, aside);
|
|
22973
|
+
try {
|
|
22974
|
+
await io.rename(temp, target);
|
|
22975
|
+
} catch (error) {
|
|
22976
|
+
await io.rename(aside, target).catch(() => {});
|
|
22977
|
+
throw error;
|
|
22978
|
+
}
|
|
22979
|
+
await io.remove(aside).catch(() => {});
|
|
22980
|
+
}
|
|
22981
|
+
async function sweepStale(dir, target) {
|
|
22982
|
+
const prefix = `${basename2(target)}.old-`;
|
|
22983
|
+
const entries = await readdir8(dir).catch(() => []);
|
|
22984
|
+
for (const entry of entries) {
|
|
22985
|
+
if (entry.startsWith(prefix))
|
|
22986
|
+
await rm2(join19(dir, entry), { force: true }).catch(() => {});
|
|
22987
|
+
}
|
|
22988
|
+
}
|
|
22989
|
+
async function updateCommand(args) {
|
|
22990
|
+
if (args.positionals.length > 0) {
|
|
22991
|
+
process.stderr.write(`earshot update: unexpected argument "${args.positionals[0]}"
|
|
22992
|
+
`);
|
|
22993
|
+
process.stderr.write(`usage: earshot update [--check] [--yes]
|
|
22994
|
+
`);
|
|
22995
|
+
return 2;
|
|
22996
|
+
}
|
|
22997
|
+
return runUpdate({
|
|
22998
|
+
check: args.flags.check === true,
|
|
22999
|
+
yes: args.flags.yes === true || args.flags.y === true
|
|
23000
|
+
});
|
|
23001
|
+
}
|
|
23002
|
+
|
|
21781
23003
|
// packages/cli/src/index.ts
|
|
21782
23004
|
var HELP = `earshot ${VERSION} - a terminal coding agent that actually listens
|
|
21783
23005
|
|
|
@@ -21790,6 +23012,7 @@ Usage
|
|
|
21790
23012
|
earshot extensions <cmd> list, trust or untrust in-process extensions
|
|
21791
23013
|
earshot acp serve editor clients over ACP v1 on stdio
|
|
21792
23014
|
earshot doctor diagnose the local setup
|
|
23015
|
+
earshot update [--check] update earshot to the latest release
|
|
21793
23016
|
|
|
21794
23017
|
Flags
|
|
21795
23018
|
--model <provider/model> model for this session
|
|
@@ -21829,6 +23052,8 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
21829
23052
|
return authCommand(args);
|
|
21830
23053
|
if (command === "doctor")
|
|
21831
23054
|
return doctorCommand(args);
|
|
23055
|
+
if (command === "update")
|
|
23056
|
+
return updateCommand(args);
|
|
21832
23057
|
if (command === "acp")
|
|
21833
23058
|
return acpCommand(args);
|
|
21834
23059
|
if (command) {
|
|
@@ -21843,5 +23068,5 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
21843
23068
|
var code = await main();
|
|
21844
23069
|
process.exitCode = code;
|
|
21845
23070
|
|
|
21846
|
-
//# debugId=
|
|
23071
|
+
//# debugId=8F9F015F9221906F64756E2164756E21
|
|
21847
23072
|
//# sourceMappingURL=main.js.map
|