@botconnector/bccli 0.4.0-beta.13 → 0.4.0-beta.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/args-L555OESS.js +12 -0
- package/dist/{chunk-6BLZELE6.js → chunk-4KMOCORM.js} +2 -2
- package/dist/{chunk-TRMRDQ43.js → chunk-6AVRFRFU.js} +31 -24
- package/dist/{chunk-7S6JXQCH.js → chunk-D7CF42EW.js} +2 -1
- package/dist/chunk-DDA5TJ7T.js +440 -0
- package/dist/{chunk-BFZXRKW5.js → chunk-ERVDVPKJ.js} +4 -3
- package/dist/{chunk-KV27KTOX.js → chunk-K5J2GGXT.js} +11 -4
- package/dist/{chunk-DX7CZTBB.js → chunk-RQGMYLVH.js} +11 -10
- package/dist/{chunk-U7GK73CK.js → chunk-RY7NCJXH.js} +19 -18
- package/dist/{chunk-CLN4Z5E3.js → chunk-VEZFR7M7.js} +6 -3
- package/dist/cli.js +141 -119
- package/dist/{config-YUNKPCNB.js → config-CGYYFECG.js} +2 -2
- package/dist/{integrationCli-3CGHHTM2.js → integrationCli-RQO3HHQE.js} +31 -30
- package/dist/{login-N2CJC6RU.js → login-O2BQX6LZ.js} +1 -1
- package/dist/{mcpCli-DZWQPTOS.js → mcpCli-QJE7P76I.js} +11 -10
- package/dist/providerCli-3FJAUH7C.js +12 -0
- package/dist/{ui-JD5YWGPE.js → ui-HVH3TR3I.js} +218 -192
- package/package.json +1 -1
- package/dist/args-SKWUZOJD.js +0 -12
- package/dist/chunk-2MGINW4O.js +0 -114
- package/dist/providerCli-Q7LRM2NP.js +0 -12
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
instructionPaths,
|
|
6
6
|
parseFrontmatter,
|
|
7
7
|
toolLabel
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-K5J2GGXT.js";
|
|
9
9
|
import {
|
|
10
10
|
nextMode
|
|
11
11
|
} from "./chunk-ELML4KVQ.js";
|
|
@@ -13,30 +13,35 @@ import {
|
|
|
13
13
|
hasKey,
|
|
14
14
|
providerName,
|
|
15
15
|
writeGlobalConfig
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-D7CF42EW.js";
|
|
17
17
|
import {
|
|
18
18
|
REASONING_LEVELS,
|
|
19
19
|
assertReasoningSupported,
|
|
20
20
|
parseReasoningLevel,
|
|
21
21
|
supportedReasoningLevels
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-VEZFR7M7.js";
|
|
23
23
|
import {
|
|
24
24
|
Session
|
|
25
25
|
} from "./chunk-SJH3YLW4.js";
|
|
26
26
|
import {
|
|
27
27
|
CATALOG,
|
|
28
28
|
fillTemplate
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-RQGMYLVH.js";
|
|
30
30
|
import {
|
|
31
31
|
addGlobalServer,
|
|
32
32
|
globalMcpPath,
|
|
33
33
|
readMcpFile,
|
|
34
34
|
removeGlobalServer
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-ERVDVPKJ.js";
|
|
36
36
|
import {
|
|
37
37
|
PRESETS,
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
getLanguage,
|
|
39
|
+
locale,
|
|
40
|
+
parseLang,
|
|
41
|
+
removeCredential,
|
|
42
|
+
setLanguage,
|
|
43
|
+
t
|
|
44
|
+
} from "./chunk-DDA5TJ7T.js";
|
|
40
45
|
|
|
41
46
|
// src/ui/index.tsx
|
|
42
47
|
import { render } from "ink";
|
|
@@ -51,31 +56,32 @@ import { useCallback, useEffect as useEffect2, useRef, useState as useState8 } f
|
|
|
51
56
|
|
|
52
57
|
// src/commands.ts
|
|
53
58
|
var SLASH_COMMANDS = [
|
|
54
|
-
{ name: "help", description: "
|
|
55
|
-
{ name: "model", description: "
|
|
56
|
-
{ name: "reasoning", description: "
|
|
57
|
-
{ name: "provider", description: "
|
|
58
|
-
{ name: "mcp", description: "
|
|
59
|
-
{ name: "new", description: "
|
|
60
|
-
{ name: "resume", description: "
|
|
61
|
-
{ name: "session", description: "info
|
|
62
|
-
{ name: "status", description: "
|
|
63
|
-
{ name: "permissions", description: "
|
|
64
|
-
{ name: "undo", description: "
|
|
65
|
-
{ name: "diff", description: "git diff project" },
|
|
66
|
-
{ name: "copy", description: "
|
|
67
|
-
{ name: "export", description: "
|
|
68
|
-
{ name: "memory", description: "
|
|
69
|
-
{ name: "init", description: "
|
|
70
|
-
{ name: "agents", description: "
|
|
71
|
-
{ name: "skills", description: "
|
|
72
|
-
{ name: "doctor", description: "
|
|
73
|
-
{ name: "login", description: "
|
|
74
|
-
{ name: "logout", description: "
|
|
75
|
-
{ name: "
|
|
76
|
-
{ name: "
|
|
77
|
-
{ name: "
|
|
78
|
-
{ name: "
|
|
59
|
+
{ name: "help", description: "list of commands and shortcuts" },
|
|
60
|
+
{ name: "model", description: "change model" },
|
|
61
|
+
{ name: "reasoning", description: "set reasoning: auto/off/low/medium/high/max" },
|
|
62
|
+
{ name: "provider", description: "add/choose an AI provider" },
|
|
63
|
+
{ name: "mcp", description: "install/manage MCP servers" },
|
|
64
|
+
{ name: "new", description: "new session (the old one stays saved)" },
|
|
65
|
+
{ name: "resume", description: "continue another session in this folder" },
|
|
66
|
+
{ name: "session", description: "info about this session" },
|
|
67
|
+
{ name: "status", description: "version, model, permission mode, MCP, context" },
|
|
68
|
+
{ name: "permissions", description: "view/revoke permissions" },
|
|
69
|
+
{ name: "undo", description: "undo the file edits of the last turn" },
|
|
70
|
+
{ name: "diff", description: "git diff of the project" },
|
|
71
|
+
{ name: "copy", description: "copy the last answer" },
|
|
72
|
+
{ name: "export", description: "save the conversation as markdown" },
|
|
73
|
+
{ name: "memory", description: "project instructions (/memory <text>, /memory global <text>)" },
|
|
74
|
+
{ name: "init", description: "create/update AGENTS.md for this project" },
|
|
75
|
+
{ name: "agents", description: "list subagents" },
|
|
76
|
+
{ name: "skills", description: "list skills and custom commands" },
|
|
77
|
+
{ name: "doctor", description: "check installation health" },
|
|
78
|
+
{ name: "login", description: "save the API key of the current provider" },
|
|
79
|
+
{ name: "logout", description: "delete the API key of the current provider" },
|
|
80
|
+
{ name: "language", description: "set the interface language: en/id" },
|
|
81
|
+
{ name: "clear", description: "start a new conversation" },
|
|
82
|
+
{ name: "compact", description: "summarize the conversation" },
|
|
83
|
+
{ name: "cost", description: "token usage of this session" },
|
|
84
|
+
{ name: "exit", description: "quit" }
|
|
79
85
|
];
|
|
80
86
|
function parseSlash(text) {
|
|
81
87
|
if (!text.startsWith("/")) return void 0;
|
|
@@ -109,8 +115,8 @@ function git(cwd, args, bin = "git") {
|
|
|
109
115
|
}
|
|
110
116
|
async function gitDiff(cwd, maxLines = 400, bin = "git") {
|
|
111
117
|
const inside = await git(cwd, ["rev-parse", "--is-inside-work-tree"], bin);
|
|
112
|
-
if (inside.missing) return "git
|
|
113
|
-
if (!inside.ok || inside.out.trim() !== "true") return "
|
|
118
|
+
if (inside.missing) return t("git is not installed or not on PATH, so /diff cannot be used.");
|
|
119
|
+
if (!inside.ok || inside.out.trim() !== "true") return t("This folder is not a git repository, so there is no diff.");
|
|
114
120
|
const base = (await git(cwd, ["rev-parse", "--verify", "-q", "HEAD"])).ok ? "HEAD" : "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
|
115
121
|
const [stat, diff, untracked] = await Promise.all([
|
|
116
122
|
git(cwd, ["diff", "--stat", base]),
|
|
@@ -118,23 +124,23 @@ async function gitDiff(cwd, maxLines = 400, bin = "git") {
|
|
|
118
124
|
git(cwd, ["ls-files", "--others", "--exclude-standard"])
|
|
119
125
|
]);
|
|
120
126
|
const fresh = untracked.out.split("\n").filter(Boolean);
|
|
121
|
-
if (!diff.out.trim() && !fresh.length) return "
|
|
127
|
+
if (!diff.out.trim() && !fresh.length) return t("No uncommitted changes.");
|
|
122
128
|
const lines = diff.out.trimEnd().split("\n");
|
|
123
129
|
const more = lines.length > maxLines ? `
|
|
124
|
-
\u2026
|
|
125
|
-
return [stat.out.trim(), lines.slice(0, maxLines).join("\n") + more, fresh.length ?
|
|
130
|
+
${t("\u2026 {n} more lines", { n: lines.length - maxLines })}` : "";
|
|
131
|
+
return [stat.out.trim(), lines.slice(0, maxLines).join("\n") + more, fresh.length ? t("New files (untracked): {files}", { files: fresh.join(", ") }) : ""].filter(Boolean).join("\n\n");
|
|
126
132
|
}
|
|
127
133
|
|
|
128
134
|
// src/slash/doctor.ts
|
|
129
135
|
async function doctorText(input, deps) {
|
|
130
136
|
const major = Number(deps.nodeVersion.replace(/^v/, "").split(".")[0]);
|
|
131
|
-
const lines = [major >= 22 ? `\u2713 Node ${deps.nodeVersion}` :
|
|
132
|
-
for (const p of input.providers) lines.push(p.ready ? `\u2713 ${p.name}` :
|
|
137
|
+
const lines = [major >= 22 ? `\u2713 Node ${deps.nodeVersion}` : t("\u2717 Node {version} (needs \u2265 22)", { version: deps.nodeVersion })];
|
|
138
|
+
for (const p of input.providers) lines.push(p.ready ? `\u2713 ${p.name}` : t("\u25CB {name} (no key yet)", { name: p.name }));
|
|
133
139
|
const cmds = ["rg", "git", "npx", "uvx"];
|
|
134
140
|
const [connection, found] = await Promise.all([
|
|
135
141
|
deps.listModels().then(
|
|
136
|
-
(models) =>
|
|
137
|
-
(error) =>
|
|
142
|
+
(models) => t("\u2713 Connection {provider} ({n} models)", { provider: input.activeProvider, n: models.length }),
|
|
143
|
+
(error) => t("\u2717 Connection {provider}: {error}", { provider: input.activeProvider, error: error.message })
|
|
138
144
|
),
|
|
139
145
|
Promise.all(cmds.map(async (cmd) => deps.which(cmd)))
|
|
140
146
|
]);
|
|
@@ -165,31 +171,31 @@ function statusText(s) {
|
|
|
165
171
|
return [
|
|
166
172
|
`BCCLI ${s.version}`,
|
|
167
173
|
`Model: ${s.modelRef} (${s.providerLabel})`,
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
174
|
+
t("Permission mode: {mode}", { mode: s.mode }),
|
|
175
|
+
t("Folder: {cwd}", { cwd: s.cwd }),
|
|
176
|
+
t("MCP: {ready} active, {errors} errors", { ready, errors }),
|
|
177
|
+
t("Session tokens: {input} in \xB7 {output} out", { input: k(s.usage.inputTokens), output: k(s.usage.outputTokens) }),
|
|
178
|
+
t("Context: ~{pct}% of 128k", { pct: Math.round(s.lastInputTokens / 128e3 * 100) })
|
|
173
179
|
].join("\n");
|
|
174
180
|
}
|
|
175
181
|
function agentsText(defs) {
|
|
176
|
-
return defs.map((d) =>
|
|
182
|
+
return defs.map((d) => t("{name} \u2014 {description} \xB7 tools: {tools} \xB7 model: {model}", { name: d.name, description: d.description, tools: d.tools ? d.tools.join(", ") : t("all"), model: d.model ?? t("same as main") })).join("\n");
|
|
177
183
|
}
|
|
178
184
|
function skillsText(skills, commands) {
|
|
179
|
-
const s = skills.length ? skills.map((x) => `${x.name} \u2014 ${x.description.slice(0, 80)} (${x.dir})`).join("\n") : "(
|
|
180
|
-
const c = commands.length ? commands.map((x) => `/${x.name} \u2014 ${x.description ?? ""}`).join("\n") : "(
|
|
181
|
-
return
|
|
185
|
+
const s = skills.length ? skills.map((x) => `${x.name} \u2014 ${x.description.slice(0, 80)} (${x.dir})`).join("\n") : t("(no skills)");
|
|
186
|
+
const c = commands.length ? commands.map((x) => `/${x.name} \u2014 ${x.description ?? ""}`).join("\n") : t("(no custom commands)");
|
|
187
|
+
return `${t("Skills")}:
|
|
182
188
|
${s}
|
|
183
189
|
|
|
184
|
-
|
|
190
|
+
${t("Custom commands")}:
|
|
185
191
|
${c}`;
|
|
186
192
|
}
|
|
187
193
|
function sessionText(s) {
|
|
188
194
|
return [
|
|
189
|
-
|
|
190
|
-
|
|
195
|
+
t("Started: {when}", { when: s.started.toLocaleString(locale()) }),
|
|
196
|
+
t("{messages} messages \xB7 {input} tokens in \xB7 {output} out", { messages: s.messages, input: k(s.usage.inputTokens), output: k(s.usage.outputTokens) }),
|
|
191
197
|
`Model: ${s.modelRef}`,
|
|
192
|
-
|
|
198
|
+
t("File: {file}", { file: s.file })
|
|
193
199
|
].join("\n");
|
|
194
200
|
}
|
|
195
201
|
|
|
@@ -267,7 +273,7 @@ function LinePrompt({ label, mask, onSubmit, onCancel }) {
|
|
|
267
273
|
`${label}: `,
|
|
268
274
|
shown,
|
|
269
275
|
/* @__PURE__ */ jsx2(Text2, { inverse: true, children: " " }),
|
|
270
|
-
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " enter
|
|
276
|
+
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: t(" enter save \xB7 esc cancel") })
|
|
271
277
|
] }) });
|
|
272
278
|
}
|
|
273
279
|
|
|
@@ -296,12 +302,12 @@ function ListPicker({ title, items, onPick }) {
|
|
|
296
302
|
});
|
|
297
303
|
const start = Math.max(0, Math.min(cursor - 5, shown.length - VISIBLE));
|
|
298
304
|
return /* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
|
|
299
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, children:
|
|
305
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, children: t("{title} (\u2191\u2193 enter \xB7 type to filter{filter} \xB7 esc cancel)", { title, filter: filter ? `: ${filter}` : "" }) }),
|
|
300
306
|
shown.slice(start, start + VISIBLE).map((item, i) => /* @__PURE__ */ jsxs2(Text3, { color: start + i === cursor && !item.disabled ? color("green") : void 0, dimColor: item.disabled, children: [
|
|
301
307
|
`${start + i === cursor ? "\u203A" : " "} ${item.label}`,
|
|
302
308
|
item.hint ? /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: ` ${item.hint}` }) : null
|
|
303
309
|
] }, item.id)),
|
|
304
|
-
shown.length ? null : /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "
|
|
310
|
+
shown.length ? null : /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: t("No matches.") })
|
|
305
311
|
] });
|
|
306
312
|
}
|
|
307
313
|
|
|
@@ -341,11 +347,11 @@ function ModelPicker({ groups, current, onPick }) {
|
|
|
341
347
|
});
|
|
342
348
|
const start = Math.max(0, Math.min(cursor - 5, rows.length - VISIBLE2));
|
|
343
349
|
return /* @__PURE__ */ jsxs3(Box4, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
|
|
344
|
-
/* @__PURE__ */ jsx4(Text4, { bold: true, children:
|
|
350
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, children: t("Choose a model (type to filter{filter} \xB7 \u2191\u2193 enter \xB7 esc cancel)", { filter: filter ? `: ${filter}` : "" }) }),
|
|
345
351
|
rows.slice(start, start + VISIBLE2).map(
|
|
346
352
|
(row, i) => row.kind === "header" ? /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: `\u2500\u2500 ${row.text} ` }, `h${start + i}`) : /* @__PURE__ */ jsx4(Text4, { color: start + i === cursor ? color("green") : void 0, children: `${start + i === cursor ? "\u203A" : " "} ${row.label}${row.ref === current ? " (aktif)" : ""}` }, row.ref)
|
|
347
353
|
),
|
|
348
|
-
!selectable.length ? /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "
|
|
354
|
+
!selectable.length ? /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: t("No matching models.") }) : null,
|
|
349
355
|
groups.filter((g) => g.error).map((g) => /* @__PURE__ */ jsx4(Text4, { color: color("yellow"), children: `${g.providerName} \u2014 ${g.error}` }, `e-${g.providerId}`))
|
|
350
356
|
] });
|
|
351
357
|
}
|
|
@@ -364,7 +370,7 @@ function ProviderMenu({ entries, onPick }) {
|
|
|
364
370
|
else if (key.escape) onPick(void 0);
|
|
365
371
|
});
|
|
366
372
|
return /* @__PURE__ */ jsxs4(Box5, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
|
|
367
|
-
/* @__PURE__ */ jsx5(Text5, { bold: true, children: "Provider (\u2191\u2193 enter, esc
|
|
373
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, children: t("Provider (\u2191\u2193 enter, esc cancel) \xB7 \u2713 ready \xB7 \u25CB needs API key") }),
|
|
368
374
|
entries.map((e, i) => /* @__PURE__ */ jsxs4(Text5, { color: i === index ? color("green") : void 0, children: [
|
|
369
375
|
`${i === index ? "\u203A" : " "} ${e.ready ? "\u2713" : "\u25CB"} ${e.name}`,
|
|
370
376
|
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: ` ${e.baseURL}` })
|
|
@@ -389,7 +395,7 @@ function DiffView({ diff }) {
|
|
|
389
395
|
|
|
390
396
|
// src/ui/PermissionPrompt.tsx
|
|
391
397
|
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
392
|
-
var VERB = { edit: "edit", write: "
|
|
398
|
+
var VERB = { edit: "edit", write: "write", bash: "run", fetch: "fetch" };
|
|
393
399
|
function PermissionPrompt({
|
|
394
400
|
request,
|
|
395
401
|
onAnswer
|
|
@@ -402,16 +408,16 @@ function PermissionPrompt({
|
|
|
402
408
|
else if (k2 === "n" || key.escape) onAnswer("no");
|
|
403
409
|
});
|
|
404
410
|
const rules = request.sessionRules ?? [];
|
|
405
|
-
const sessionLabel = !rules.length ? null : request.kind === "edit" ? "
|
|
411
|
+
const sessionLabel = !rules.length ? null : request.kind === "edit" ? t("yes for all edits in this project, this session") : t("yes this session for {rules}", { rules: rules.join(", ") });
|
|
406
412
|
return /* @__PURE__ */ jsxs5(Box7, { flexDirection: "column", borderStyle: "round", borderColor: color("yellow"), paddingX: 1, children: [
|
|
407
|
-
/* @__PURE__ */ jsx7(Text7, { bold: true, children: `${request.agent ? `[${request.agent}] ` : ""}
|
|
413
|
+
/* @__PURE__ */ jsx7(Text7, { bold: true, children: `${request.agent ? `[${request.agent}] ` : ""}${t("Allow {verb} {target}?", { verb: t(VERB[request.tool] ?? request.tool), target: request.target })}` }),
|
|
408
414
|
request.preview ? /* @__PURE__ */ jsx7(DiffView, { diff: request.preview }) : null,
|
|
409
415
|
/* @__PURE__ */ jsxs5(Text7, { children: [
|
|
410
|
-
/* @__PURE__ */ jsx7(Text7, { color: color("green"), children: "[y]
|
|
416
|
+
/* @__PURE__ */ jsx7(Text7, { color: color("green"), children: t("[y] yes") }),
|
|
411
417
|
" ",
|
|
412
418
|
sessionLabel ? /* @__PURE__ */ jsx7(Text7, { color: color("cyan"), children: `[a] ${sessionLabel} ` }) : null,
|
|
413
|
-
/* @__PURE__ */ jsx7(Text7, { color: color("yellow"), children: "[s]
|
|
414
|
-
/* @__PURE__ */ jsx7(Text7, { color: color("red"), children: "[n]
|
|
419
|
+
/* @__PURE__ */ jsx7(Text7, { color: color("yellow"), children: t("[s] yes to all ") }),
|
|
420
|
+
/* @__PURE__ */ jsx7(Text7, { color: color("red"), children: t("[n] no") })
|
|
415
421
|
] })
|
|
416
422
|
] });
|
|
417
423
|
}
|
|
@@ -514,7 +520,7 @@ function PromptInput({ disabled, history, cwd, onSubmit, extraCommands }) {
|
|
|
514
520
|
value,
|
|
515
521
|
disabled ? "" : /* @__PURE__ */ jsx8(Text8, { inverse: true, children: " " })
|
|
516
522
|
] }) }),
|
|
517
|
-
suggestions.map((s, i) => /* @__PURE__ */ jsx8(Text8, { color: i === highlighted ? color("green") : void 0, dimColor: i !== highlighted, children: `${i === highlighted ? "\u203A" : " "} /${s.name} ${s.description}` }, s.name))
|
|
523
|
+
suggestions.map((s, i) => /* @__PURE__ */ jsx8(Text8, { color: i === highlighted ? color("green") : void 0, dimColor: i !== highlighted, children: `${i === highlighted ? "\u203A" : " "} /${s.name} ${t(s.description)}` }, s.name))
|
|
518
524
|
] });
|
|
519
525
|
}
|
|
520
526
|
|
|
@@ -526,11 +532,11 @@ var FRAMES = ["\xB7", "\u2722", "\u2733", "\u2736", "\u273B", "\u273D"];
|
|
|
526
532
|
function Spinner({ label, startedAt }) {
|
|
527
533
|
const [tick, setTick] = useState6(0);
|
|
528
534
|
useEffect(() => {
|
|
529
|
-
const id = setInterval(() => setTick((
|
|
535
|
+
const id = setInterval(() => setTick((t2) => t2 + 1), 120);
|
|
530
536
|
return () => clearInterval(id);
|
|
531
537
|
}, []);
|
|
532
538
|
const seconds = Math.floor((Date.now() - startedAt) / 1e3);
|
|
533
|
-
return /* @__PURE__ */ jsx9(Text9, { color: color(ACCENT), children: `${FRAMES[tick % FRAMES.length]} ${label}\u2026 (
|
|
539
|
+
return /* @__PURE__ */ jsx9(Text9, { color: color(ACCENT), children: `${FRAMES[tick % FRAMES.length]} ${t("{label}\u2026 ({seconds}s \xB7 esc to cancel)", { label, seconds })}` });
|
|
534
540
|
}
|
|
535
541
|
|
|
536
542
|
// src/ui/StatusBar.tsx
|
|
@@ -547,7 +553,7 @@ function formatTokens(n) {
|
|
|
547
553
|
}
|
|
548
554
|
function StatusBar({ mode, tokens, busy, model, reasoning = "auto" }) {
|
|
549
555
|
const danger = mode === "allowAll";
|
|
550
|
-
return /* @__PURE__ */ jsx10(Text10, { color: danger ? color("red") : void 0, dimColor: !danger, children: ` ${LABEL[mode]}${model ? ` \xB7 ${model}` : ""} \xB7 reasoning: ${reasoning} \xB7 shift+tab
|
|
556
|
+
return /* @__PURE__ */ jsx10(Text10, { color: danger ? color("red") : void 0, dimColor: !danger, children: ` ${LABEL[mode]}${model ? ` \xB7 ${model}` : ""} \xB7 reasoning: ${reasoning} \xB7 ${t("shift+tab switch mode")} \xB7 ${t("{n} tokens", { n: formatTokens(tokens) })} \xB7 ${busy ? t("esc to cancel") : t("/ for commands")}` });
|
|
551
557
|
}
|
|
552
558
|
|
|
553
559
|
// src/ui/McpMenu.tsx
|
|
@@ -564,7 +570,7 @@ function McpMenu({ items, onPick }) {
|
|
|
564
570
|
else if (key.escape) onPick(void 0);
|
|
565
571
|
});
|
|
566
572
|
return /* @__PURE__ */ jsxs7(Box9, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
|
|
567
|
-
/* @__PURE__ */ jsx11(Text11, { bold: true, children: "
|
|
573
|
+
/* @__PURE__ */ jsx11(Text11, { bold: true, children: t("MCP servers (enter: install / remove \xB7 esc close) \xB7 \u2713 active \u25CB not installed \u2717 error") }),
|
|
568
574
|
items.map((item, i) => /* @__PURE__ */ jsxs7(Text11, { color: i === index ? color("green") : void 0, children: [
|
|
569
575
|
`${i === index ? "\u203A" : " "} ${MARK[item.status]} ${item.name.padEnd(12)}`,
|
|
570
576
|
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: item.status === "error" ? ` ${item.error ?? ""}` : ` ${item.description}` })
|
|
@@ -583,14 +589,14 @@ function PlanApproval({ plan, onAnswer }) {
|
|
|
583
589
|
else if (k2 === "n" || key.escape) onAnswer("no");
|
|
584
590
|
});
|
|
585
591
|
return /* @__PURE__ */ jsxs8(Box10, { flexDirection: "column", borderStyle: "round", borderColor: color("cyan"), paddingX: 1, children: [
|
|
586
|
-
/* @__PURE__ */ jsx12(Text12, { bold: true, children: "
|
|
592
|
+
/* @__PURE__ */ jsx12(Text12, { bold: true, children: t("Plan from the agent") }),
|
|
587
593
|
/* @__PURE__ */ jsx12(Markdown, { text: plan }),
|
|
588
594
|
/* @__PURE__ */ jsxs8(Text12, { children: [
|
|
589
|
-
/* @__PURE__ */ jsx12(Text12, { color: color("green"), children: "[a]
|
|
595
|
+
/* @__PURE__ */ jsx12(Text12, { color: color("green"), children: t("[a] yes, auto-edit") }),
|
|
590
596
|
" ",
|
|
591
|
-
/* @__PURE__ */ jsx12(Text12, { color: color("cyan"), children: "[y]
|
|
597
|
+
/* @__PURE__ */ jsx12(Text12, { color: color("cyan"), children: t("[y] yes, ask at each step") }),
|
|
592
598
|
" ",
|
|
593
|
-
/* @__PURE__ */ jsx12(Text12, { color: color("red"), children: "[n]
|
|
599
|
+
/* @__PURE__ */ jsx12(Text12, { color: color("red"), children: t("[n] not yet, revise first") })
|
|
594
600
|
] })
|
|
595
601
|
] });
|
|
596
602
|
}
|
|
@@ -600,8 +606,8 @@ import { Box as Box11, Text as Text13 } from "ink";
|
|
|
600
606
|
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
601
607
|
var MARK2 = { completed: "\u2611", in_progress: "\u25FC", pending: "\u2610" };
|
|
602
608
|
function TodoList({ items }) {
|
|
603
|
-
if (!items.length || items.every((
|
|
604
|
-
return /* @__PURE__ */ jsx13(Box11, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: items.map((
|
|
609
|
+
if (!items.length || items.every((t2) => t2.status === "completed")) return null;
|
|
610
|
+
return /* @__PURE__ */ jsx13(Box11, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: items.map((t2, i) => /* @__PURE__ */ jsx13(Text13, { dimColor: t2.status === "completed", color: t2.status === "in_progress" ? color("yellow") : void 0, children: `${MARK2[t2.status]} ${t2.content}` }, i)) });
|
|
605
611
|
}
|
|
606
612
|
|
|
607
613
|
// src/ui/ToolBlock.tsx
|
|
@@ -622,12 +628,12 @@ function ToolBlock({ tool, target, output, display, isError, done, expanded, sub
|
|
|
622
628
|
] }),
|
|
623
629
|
sub?.length ? /* @__PURE__ */ jsxs9(Box12, { flexDirection: "column", marginLeft: 3, children: [
|
|
624
630
|
sub.slice(-6).map((s) => /* @__PURE__ */ jsx14(Text14, { dimColor: s.done && !s.isError, color: s.isError ? color("red") : void 0, children: `\u23BF ${toolLabel(s.tool)} ${s.target}` }, s.id)),
|
|
625
|
-
sub.length > 6 ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children:
|
|
631
|
+
sub.length > 6 ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: t("\u2026 {n} earlier steps", { n: sub.length - 6 }) }) : null
|
|
626
632
|
] }) : null,
|
|
627
|
-
isTask && done ? /* @__PURE__ */ jsx14(Box12, { marginLeft: 3, children: /* @__PURE__ */ jsx14(Text14, { color: isError ? color("red") : color("green"), children: `${isError ? "\u2717
|
|
633
|
+
isTask && done ? /* @__PURE__ */ jsx14(Box12, { marginLeft: 3, children: /* @__PURE__ */ jsx14(Text14, { color: isError ? color("red") : color("green"), children: `${isError ? t("\u2717 failed") : t("\u2713 done")}${display ? ` \xB7 ${display}` : ""}` }) }) : null,
|
|
628
634
|
isDiff ? /* @__PURE__ */ jsx14(Box12, { marginLeft: 3, children: /* @__PURE__ */ jsx14(DiffView, { diff: display }) }) : output && (isError || tool === "bash") && !(isTask && !isError) ? /* @__PURE__ */ jsxs9(Box12, { flexDirection: "column", marginLeft: 3, children: [
|
|
629
635
|
shown.map((line, i) => /* @__PURE__ */ jsx14(Text14, { dimColor: !isError, color: isError ? color("red") : void 0, children: line }, i)),
|
|
630
|
-
lines.length > shown.length ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children:
|
|
636
|
+
lines.length > shown.length ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: t("\u2026 {n} more lines (ctrl+o)", { n: lines.length - shown.length }) }) : null
|
|
631
637
|
] }) : null
|
|
632
638
|
] });
|
|
633
639
|
}
|
|
@@ -636,13 +642,13 @@ function ToolBlock({ tool, target, output, display, isError, done, expanded, sub
|
|
|
636
642
|
var nextId = 0;
|
|
637
643
|
var entry = (e) => ({ ...e, id: nextId++ });
|
|
638
644
|
var NOTICES = {
|
|
639
|
-
compacted: ["
|
|
640
|
-
stepLimit: ['
|
|
641
|
-
aborted: ["
|
|
645
|
+
compacted: ["Conversation summarized to fit the model context.", "info"],
|
|
646
|
+
stepLimit: ['Step limit of 50 reached. Type "continue" to keep going.', "warn"],
|
|
647
|
+
aborted: ["Cancelled.", "warn"]
|
|
642
648
|
};
|
|
643
649
|
var isEmptyCont = (e) => e.kind === "assistant" && e.cont && !e.text;
|
|
644
|
-
function endTurn(
|
|
645
|
-
return { done: [...
|
|
650
|
+
function endTurn(t2) {
|
|
651
|
+
return { done: [...t2.done, ...t2.live.filter((e) => !isEmptyCont(e))], live: [] };
|
|
646
652
|
}
|
|
647
653
|
var TOOL_MARKUP = /<\/?tool_call>|<\/?arg_(?:key|value)>|Tool call list|^\s*\d+\.\s*Tool:|`\s*=\s*`/;
|
|
648
654
|
function finishedCut(text) {
|
|
@@ -658,62 +664,62 @@ function finishedCut(text) {
|
|
|
658
664
|
}
|
|
659
665
|
return cut;
|
|
660
666
|
}
|
|
661
|
-
function flushLines(
|
|
662
|
-
const last =
|
|
663
|
-
if (last?.kind !== "assistant") return
|
|
667
|
+
function flushLines(t2) {
|
|
668
|
+
const last = t2.live.at(-1);
|
|
669
|
+
if (last?.kind !== "assistant") return t2;
|
|
664
670
|
const cut = finishedCut(last.text);
|
|
665
|
-
if (cut < 0) return
|
|
671
|
+
if (cut < 0) return t2;
|
|
666
672
|
const chunk = last.text.slice(0, cut);
|
|
667
|
-
if (!last.cont && !chunk.trim()) return
|
|
673
|
+
if (!last.cont && !chunk.trim()) return t2;
|
|
668
674
|
const rest = entry({ kind: "assistant", text: last.text.slice(cut + 1), cont: true, flushed: (last.flushed ?? 0) + cut + 1 });
|
|
669
|
-
return { done: [...
|
|
675
|
+
return { done: [...t2.done, ...t2.live.slice(0, -1).filter((e) => !isEmptyCont(e)), { ...last, text: chunk || " " }], live: [rest] };
|
|
670
676
|
}
|
|
671
|
-
function applyEvent(
|
|
677
|
+
function applyEvent(t2, event) {
|
|
672
678
|
switch (event.type) {
|
|
673
679
|
case "text": {
|
|
674
|
-
const last =
|
|
675
|
-
if (last?.kind === "assistant") return flushLines({ ...
|
|
676
|
-
return flushLines({ ...
|
|
680
|
+
const last = t2.live.at(-1);
|
|
681
|
+
if (last?.kind === "assistant") return flushLines({ ...t2, live: [...t2.live.slice(0, -1), { ...last, text: last.text + event.delta }] });
|
|
682
|
+
return flushLines({ ...t2, live: [...t2.live, entry({ kind: "assistant", text: event.delta })] });
|
|
677
683
|
}
|
|
678
684
|
case "thinking": {
|
|
679
|
-
const last =
|
|
680
|
-
if (last?.kind === "thinking") return { ...
|
|
681
|
-
return { ...
|
|
685
|
+
const last = t2.live.at(-1);
|
|
686
|
+
if (last?.kind === "thinking") return { ...t2, live: [...t2.live.slice(0, -1), { ...last, text: last.text + event.delta }] };
|
|
687
|
+
return { ...t2, live: [...t2.live, entry({ kind: "thinking", text: event.delta })] };
|
|
682
688
|
}
|
|
683
689
|
case "textReplace": {
|
|
684
|
-
const last =
|
|
685
|
-
if (last?.kind !== "assistant") return
|
|
686
|
-
return { ...
|
|
690
|
+
const last = t2.live.at(-1);
|
|
691
|
+
if (last?.kind !== "assistant") return t2;
|
|
692
|
+
return { ...t2, live: [...t2.live.slice(0, -1), { ...last, text: event.text.slice(last.flushed ?? 0) }] };
|
|
687
693
|
}
|
|
688
694
|
case "toolStart": {
|
|
689
|
-
const running =
|
|
695
|
+
const running = t2.live.some((e) => e.kind === "tool" && !e.done);
|
|
690
696
|
const tool = entry({ kind: "tool", callId: event.id, tool: event.tool, target: event.target, done: false });
|
|
691
|
-
return running ? { ...
|
|
697
|
+
return running ? { ...t2, live: [...t2.live, tool] } : { done: [...t2.done, ...t2.live.filter((e) => !isEmptyCont(e))], live: [tool] };
|
|
692
698
|
}
|
|
693
699
|
case "toolEnd": {
|
|
694
|
-
const live =
|
|
700
|
+
const live = t2.live.map(
|
|
695
701
|
(e) => e.kind === "tool" && e.callId === event.id ? { ...e, output: event.output, display: event.display, isError: event.isError, done: true } : e
|
|
696
702
|
);
|
|
697
703
|
const firstRunning = live.findIndex((e) => e.kind === "tool" && !e.done);
|
|
698
704
|
const cut = firstRunning === -1 ? live.length : firstRunning;
|
|
699
|
-
return { done: [...
|
|
705
|
+
return { done: [...t2.done, ...live.slice(0, cut)], live: live.slice(cut) };
|
|
700
706
|
}
|
|
701
707
|
case "subagent": {
|
|
702
708
|
const inner = event.event;
|
|
703
|
-
if (inner.type !== "toolStart" && inner.type !== "toolEnd") return
|
|
709
|
+
if (inner.type !== "toolStart" && inner.type !== "toolEnd") return t2;
|
|
704
710
|
const update = (e) => {
|
|
705
711
|
if (e.kind !== "tool" || e.callId !== event.parentId) return e;
|
|
706
712
|
const sub = e.sub ?? [];
|
|
707
713
|
if (inner.type === "toolStart") return { ...e, sub: [...sub, { id: inner.id, tool: inner.tool, target: inner.target, done: false }] };
|
|
708
714
|
return { ...e, sub: sub.map((s) => s.id === inner.id ? { ...s, done: true, isError: inner.isError } : s) };
|
|
709
715
|
};
|
|
710
|
-
return { ...
|
|
716
|
+
return { ...t2, live: t2.live.map(update) };
|
|
711
717
|
}
|
|
712
718
|
case "error":
|
|
713
|
-
return { ...
|
|
719
|
+
return { ...t2, live: [...t2.live, entry({ kind: "notice", text: `Error: ${event.message}`, tone: "error" })] };
|
|
714
720
|
default: {
|
|
715
721
|
const notice = NOTICES[event.type];
|
|
716
|
-
return notice ? { ...
|
|
722
|
+
return notice ? { ...t2, live: [...t2.live, entry({ kind: "notice", text: t(notice[0]), tone: notice[1] })] } : t2;
|
|
717
723
|
}
|
|
718
724
|
}
|
|
719
725
|
}
|
|
@@ -723,17 +729,17 @@ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
|
723
729
|
function helpText(runtime) {
|
|
724
730
|
const custom = runtime.commands.filter((c) => !SLASH_COMMANDS.some((b) => b.name === c.name));
|
|
725
731
|
return [
|
|
726
|
-
...SLASH_COMMANDS.map((c) => `/${c.name.padEnd(12)} ${c.description}`),
|
|
727
|
-
...custom.length ? ["", "
|
|
728
|
-
...runtime.skills.length ? ["", "
|
|
732
|
+
...SLASH_COMMANDS.map((c) => `/${c.name.padEnd(12)} ${t(c.description)}`),
|
|
733
|
+
...custom.length ? ["", t("Custom commands:"), ...custom.map((c) => `/${c.name.padEnd(8)} ${c.description ?? ""}`)] : [],
|
|
734
|
+
...runtime.skills.length ? ["", t("Skills:"), ...runtime.skills.map((s) => `/${s.name.padEnd(8)} ${s.description.slice(0, 60)}`)] : [],
|
|
729
735
|
"",
|
|
730
|
-
"shift+tab
|
|
731
|
-
"ctrl+o output
|
|
732
|
-
"ctrl+t
|
|
733
|
-
"@file + tab
|
|
736
|
+
t("shift+tab switch permission mode esc cancel the turn"),
|
|
737
|
+
t("ctrl+o full output of the last tool \\ + enter new line"),
|
|
738
|
+
t("ctrl+t show/hide the model\u2019s thinking"),
|
|
739
|
+
t("@file + tab complete file names \u2191\u2193 input history")
|
|
734
740
|
].join("\n");
|
|
735
741
|
}
|
|
736
|
-
var INIT_PROMPT = "
|
|
742
|
+
var INIT_PROMPT = "Study this project (folder structure, package/build files, test and lint commands, visible code conventions). Then create AGENTS.md in the project root, or update it if it already exists, covering: how to build, test, and lint; a short structure overview; important conventions. Keep it concise and factual, only what actually exists in the project.";
|
|
737
743
|
var labelFor = (runtime, ref) => `${ref.slice(ref.indexOf("/") + 1)} \xB7 ${runtime.providerLabel()}`;
|
|
738
744
|
function App({ runtime, initialPrompt, version }) {
|
|
739
745
|
const { exit } = useApp();
|
|
@@ -761,13 +767,13 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
761
767
|
const [showThinking, setShowThinking] = useState8(false);
|
|
762
768
|
useEffect2(() => runtime.todos.subscribe(setTodos), [runtime]);
|
|
763
769
|
const extraCommands = [
|
|
764
|
-
...runtime.commands.filter((c) => !SLASH_COMMANDS.some((b) => b.name === c.name.toLowerCase())).map((c) => ({ name: c.name.toLowerCase(), description: c.description ?? "
|
|
765
|
-
...runtime.skills.filter((s) => !runtime.commands.some((c) => c.name.toLowerCase() === s.name.toLowerCase())).filter((s) => !SLASH_COMMANDS.some((b) => b.name === s.name.toLowerCase())).map((s) => ({ name: s.name, description:
|
|
770
|
+
...runtime.commands.filter((c) => !SLASH_COMMANDS.some((b) => b.name === c.name.toLowerCase())).map((c) => ({ name: c.name.toLowerCase(), description: c.description ?? t("custom command") })),
|
|
771
|
+
...runtime.skills.filter((s) => !runtime.commands.some((c) => c.name.toLowerCase() === s.name.toLowerCase())).filter((s) => !SLASH_COMMANDS.some((b) => b.name === s.name.toLowerCase())).map((s) => ({ name: s.name, description: t("skill \xB7 {description}", { description: s.description.slice(0, 50) }) }))
|
|
766
772
|
];
|
|
767
773
|
const lastTool = useRef(null);
|
|
768
774
|
const toolTargets = useRef(/* @__PURE__ */ new Map());
|
|
769
775
|
const notice = useCallback((text, tone = "info") => {
|
|
770
|
-
setTranscript((
|
|
776
|
+
setTranscript((t2) => ({ ...t2, done: [...t2.done, entry({ kind: "notice", text, tone })] }));
|
|
771
777
|
}, []);
|
|
772
778
|
const onEvent = useCallback((event) => {
|
|
773
779
|
if (event.type === "toolStart") toolTargets.current.set(event.id, event.target);
|
|
@@ -775,7 +781,7 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
775
781
|
lastTool.current = { tool: event.tool, target: toolTargets.current.get(event.id) ?? "", output: event.output };
|
|
776
782
|
}
|
|
777
783
|
if (event.type === "usage") setTokens(event.inputTokens + event.outputTokens);
|
|
778
|
-
setTranscript((
|
|
784
|
+
setTranscript((t2) => applyEvent(t2, event));
|
|
779
785
|
}, []);
|
|
780
786
|
useEffect2(() => {
|
|
781
787
|
runtime.agent.onEvent = onEvent;
|
|
@@ -784,7 +790,7 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
784
790
|
}, [runtime, onEvent]);
|
|
785
791
|
const runTurn = useCallback(
|
|
786
792
|
async (text) => {
|
|
787
|
-
setTranscript((
|
|
793
|
+
setTranscript((t2) => ({ ...t2, done: [...t2.done, entry({ kind: "user", text })] }));
|
|
788
794
|
setBusy(true);
|
|
789
795
|
setStartedAt(Date.now());
|
|
790
796
|
controller.current = new AbortController();
|
|
@@ -807,11 +813,11 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
807
813
|
case "clear":
|
|
808
814
|
runtime.agent.clear();
|
|
809
815
|
setTokens(0);
|
|
810
|
-
notice("
|
|
816
|
+
notice(t("Conversation cleared."));
|
|
811
817
|
return;
|
|
812
818
|
case "cost": {
|
|
813
819
|
const u = runtime.agent.totalUsage;
|
|
814
|
-
notice(
|
|
820
|
+
notice(t("{input} tokens in \xB7 {output} tokens out", { input: u.inputTokens.toLocaleString(locale()), output: u.outputTokens.toLocaleString(locale()) }));
|
|
815
821
|
return;
|
|
816
822
|
}
|
|
817
823
|
case "compact": {
|
|
@@ -821,7 +827,7 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
821
827
|
try {
|
|
822
828
|
await runtime.agent.compact(controller.current.signal);
|
|
823
829
|
} catch (error) {
|
|
824
|
-
notice(
|
|
830
|
+
notice(t("Could not summarize: {error}", { error: error.message }), "error");
|
|
825
831
|
}
|
|
826
832
|
controller.current = null;
|
|
827
833
|
setBusy(false);
|
|
@@ -836,7 +842,7 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
836
842
|
runtime.setReasoning(level);
|
|
837
843
|
writeGlobalConfig({ reasoning: level }, runtime.env);
|
|
838
844
|
setReasoning(level);
|
|
839
|
-
notice(
|
|
845
|
+
notice(t("Reasoning: {level} (saved as default)", { level }));
|
|
840
846
|
} catch (error) {
|
|
841
847
|
notice(error.message, "error");
|
|
842
848
|
}
|
|
@@ -853,7 +859,7 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
853
859
|
id: level,
|
|
854
860
|
label: level === "auto" ? "Auto (model default)" : level.charAt(0).toUpperCase() + level.slice(1),
|
|
855
861
|
disabled: !supported.includes(level),
|
|
856
|
-
hint: supported.includes(level) ? void 0 : "
|
|
862
|
+
hint: supported.includes(level) ? void 0 : t("not supported by this provider")
|
|
857
863
|
})),
|
|
858
864
|
onPick: (id) => {
|
|
859
865
|
setListPicker(null);
|
|
@@ -868,7 +874,7 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
868
874
|
runtime.setModel(args);
|
|
869
875
|
writeGlobalConfig({ model: args }, runtime.env);
|
|
870
876
|
setModelLabel(labelFor(runtime, args));
|
|
871
|
-
notice(
|
|
877
|
+
notice(t("Model: {model} (saved as default)", { model: args }));
|
|
872
878
|
} catch (error) {
|
|
873
879
|
notice(error.message, "error");
|
|
874
880
|
}
|
|
@@ -877,7 +883,7 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
877
883
|
try {
|
|
878
884
|
setPicker(await runtime.listModels());
|
|
879
885
|
} catch (error) {
|
|
880
|
-
notice(
|
|
886
|
+
notice(t("Cannot fetch the model list: {error}", { error: error.message }), "error");
|
|
881
887
|
}
|
|
882
888
|
return;
|
|
883
889
|
}
|
|
@@ -885,7 +891,7 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
885
891
|
const installed = readMcpFile(globalMcpPath(runtime.home));
|
|
886
892
|
const states = runtime.mcp.states();
|
|
887
893
|
const items = [
|
|
888
|
-
...CATALOG.map((c) => ({ name: c.name, description: c.description, installed: !!installed[c.name] })),
|
|
894
|
+
...CATALOG.map((c) => ({ name: c.name, description: t(c.description), installed: !!installed[c.name] })),
|
|
889
895
|
...Object.keys(installed).filter((n) => !CATALOG.some((c) => c.name === n)).map((n) => ({ name: n, description: "(custom)", installed: true }))
|
|
890
896
|
].map((i) => {
|
|
891
897
|
const s = states.find((st) => st.name === i.name);
|
|
@@ -897,7 +903,7 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
897
903
|
case "new":
|
|
898
904
|
runtime.newSession();
|
|
899
905
|
setTokens(0);
|
|
900
|
-
notice("
|
|
906
|
+
notice(t("New session started. The previous session stays saved (/resume)."));
|
|
901
907
|
return;
|
|
902
908
|
case "session":
|
|
903
909
|
notice(
|
|
@@ -913,15 +919,15 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
913
919
|
case "resume": {
|
|
914
920
|
const others = Session.list(runtime.home, runtime.cwd).filter((s) => s.session.file !== runtime.session.file);
|
|
915
921
|
if (!others.length) {
|
|
916
|
-
notice("
|
|
922
|
+
notice(t("No other sessions in this folder yet."));
|
|
917
923
|
return;
|
|
918
924
|
}
|
|
919
925
|
setListPicker({
|
|
920
|
-
title: "
|
|
926
|
+
title: t("Continue a session"),
|
|
921
927
|
items: others.map((s) => ({
|
|
922
928
|
id: s.session.file,
|
|
923
|
-
label: `${s.mtime.toLocaleString(
|
|
924
|
-
hint:
|
|
929
|
+
label: `${s.mtime.toLocaleString(locale())} ${s.preview || t("(empty)")}`,
|
|
930
|
+
hint: t("{n} messages", { n: s.session.load().length })
|
|
925
931
|
})),
|
|
926
932
|
onPick: (id) => {
|
|
927
933
|
setListPicker(null);
|
|
@@ -937,7 +943,7 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
937
943
|
entry({ kind: "header" }),
|
|
938
944
|
entry({
|
|
939
945
|
kind: "notice",
|
|
940
|
-
text:
|
|
946
|
+
text: t("Resuming the session ({messages} messages saved \xB7 {chat} user/assistant chats shown).", { messages: runtime.agent.messages.length, chat: chat.length }),
|
|
941
947
|
tone: "info"
|
|
942
948
|
}),
|
|
943
949
|
...chat.map(
|
|
@@ -971,7 +977,7 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
971
977
|
notice(skillsText(runtime.skills, runtime.commands));
|
|
972
978
|
return;
|
|
973
979
|
case "doctor": {
|
|
974
|
-
notice("
|
|
980
|
+
notice(t("Checking\u2026"));
|
|
975
981
|
const c = runtime.config;
|
|
976
982
|
notice(
|
|
977
983
|
await doctorText(
|
|
@@ -992,20 +998,20 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
992
998
|
case "permissions": {
|
|
993
999
|
const rules = runtime.agent.permissions.list();
|
|
994
1000
|
if (!rules.length) {
|
|
995
|
-
notice("
|
|
1001
|
+
notice(t("No saved permissions yet. Permissions from [a] answers and from the config will appear here."));
|
|
996
1002
|
return;
|
|
997
1003
|
}
|
|
998
1004
|
setListPicker({
|
|
999
|
-
title: "
|
|
1000
|
-
items: rules.map((r) => ({ id: r.rule, label: r.rule, hint: r.source === "config" ? "config" : "
|
|
1005
|
+
title: t("Active permissions (enter: revoke a session permission)"),
|
|
1006
|
+
items: rules.map((r) => ({ id: r.rule, label: r.rule, hint: r.source === "config" ? "config" : t("this session") })),
|
|
1001
1007
|
onPick: (id) => {
|
|
1002
1008
|
setListPicker(null);
|
|
1003
1009
|
const rule = rules.find((r) => r.rule === id);
|
|
1004
1010
|
if (!rule) return;
|
|
1005
|
-
if (rule.source === "config") notice(
|
|
1011
|
+
if (rule.source === "config") notice(t("{rule} comes from the config/flag; remove it from ~/.bccli/config.json to revoke it.", { rule: rule.rule }), "warn");
|
|
1006
1012
|
else {
|
|
1007
1013
|
runtime.agent.permissions.revoke(rule.rule);
|
|
1008
|
-
notice(
|
|
1014
|
+
notice(t("Permission {rule} revoked.", { rule: rule.rule }));
|
|
1009
1015
|
}
|
|
1010
1016
|
}
|
|
1011
1017
|
});
|
|
@@ -1014,12 +1020,12 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
1014
1020
|
case "memory": {
|
|
1015
1021
|
if (!args) {
|
|
1016
1022
|
const files = instructionFiles(runtime.cwd, runtime.home);
|
|
1017
|
-
notice(files.length ? files.map((f) =>
|
|
1023
|
+
notice(files.length ? files.map((f) => t("{path} ({lines} lines)", { path: f.path, lines: f.lines })).join("\n") : t("No AGENTS.md / BCCLI.md yet. Add one with /memory <text>."));
|
|
1018
1024
|
return;
|
|
1019
1025
|
}
|
|
1020
1026
|
const { global, text } = parseMemoryArgs(args);
|
|
1021
1027
|
if (!text) {
|
|
1022
|
-
notice("
|
|
1028
|
+
notice(t("Write the text: /memory global <text>."), "warn");
|
|
1023
1029
|
return;
|
|
1024
1030
|
}
|
|
1025
1031
|
const file = global ? join(runtime.home, "BCCLI.md") : join(runtime.cwd, "AGENTS.md");
|
|
@@ -1027,19 +1033,38 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
1027
1033
|
mkdirSync(dirname(file), { recursive: true });
|
|
1028
1034
|
appendMemory(file, text);
|
|
1029
1035
|
} catch (error) {
|
|
1030
|
-
notice(
|
|
1036
|
+
notice(t("Could not write {file}: {error}", { file, error: error.message }), "error");
|
|
1031
1037
|
return;
|
|
1032
1038
|
}
|
|
1033
1039
|
runtime.rebuildSystemPrompt();
|
|
1034
|
-
notice(
|
|
1040
|
+
notice(t("Added to {file}.", { file }));
|
|
1035
1041
|
return;
|
|
1036
1042
|
}
|
|
1037
1043
|
case "init":
|
|
1038
1044
|
void runTurn(INIT_PROMPT);
|
|
1039
1045
|
return;
|
|
1046
|
+
case "language": {
|
|
1047
|
+
if (!args) {
|
|
1048
|
+
notice(t("Language: {lang}. Change it with /language en or /language id.", { lang: getLanguage() }));
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
const wanted = parseLang(args);
|
|
1052
|
+
if (!wanted) {
|
|
1053
|
+
notice(t('Unknown language "{lang}". Use en or id.', { lang: args }), "warn");
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
setLanguage(wanted);
|
|
1057
|
+
try {
|
|
1058
|
+
writeGlobalConfig({ language: wanted }, runtime.env);
|
|
1059
|
+
} catch (error) {
|
|
1060
|
+
notice(t("Could not save the language: {error}", { error: error.message }), "error");
|
|
1061
|
+
}
|
|
1062
|
+
notice(t("Language set to {lang} (saved as default).", { lang: wanted }));
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1040
1065
|
case "login": {
|
|
1041
1066
|
const id = runtime.modelRef.slice(0, runtime.modelRef.indexOf("/"));
|
|
1042
|
-
const key = await ask(
|
|
1067
|
+
const key = await ask(t("API key for {provider}", { provider: runtime.providerLabel() }), true);
|
|
1043
1068
|
if (!key) return;
|
|
1044
1069
|
const result = await runtime.addProviderKey(id, key);
|
|
1045
1070
|
if (!result.ok) {
|
|
@@ -1049,10 +1074,10 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
1049
1074
|
runtime.setModel(runtime.modelRef);
|
|
1050
1075
|
const envName = runtime.config.providers[id]?.apiKeyEnv;
|
|
1051
1076
|
if (envName && runtime.env[envName]) {
|
|
1052
|
-
notice(
|
|
1077
|
+
notice(t("Key for {provider} saved, but {env} in the environment takes precedence and is still used.", { provider: runtime.providerLabel(), env: envName }), "warn");
|
|
1053
1078
|
return;
|
|
1054
1079
|
}
|
|
1055
|
-
notice(
|
|
1080
|
+
notice(t("Key for {provider} saved \xB7 {n} models.", { provider: runtime.providerLabel(), n: result.models }));
|
|
1056
1081
|
return;
|
|
1057
1082
|
}
|
|
1058
1083
|
case "logout": {
|
|
@@ -1061,13 +1086,13 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
1061
1086
|
const envName = runtime.config.providers[id]?.apiKeyEnv;
|
|
1062
1087
|
if (envName && runtime.env[envName]) {
|
|
1063
1088
|
notice(
|
|
1064
|
-
|
|
1089
|
+
removed ? t("Stored key deleted, but {env} is still set in the environment and is still used.", { env: envName }) : t("No stored key; {env} is still set in the environment and is still used.", { env: envName }),
|
|
1065
1090
|
"warn"
|
|
1066
1091
|
);
|
|
1067
1092
|
return;
|
|
1068
1093
|
}
|
|
1069
1094
|
if (!removed) {
|
|
1070
|
-
notice(
|
|
1095
|
+
notice(t("No stored key for {provider}.", { provider: runtime.providerLabel() }));
|
|
1071
1096
|
return;
|
|
1072
1097
|
}
|
|
1073
1098
|
try {
|
|
@@ -1078,7 +1103,7 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
1078
1103
|
};
|
|
1079
1104
|
runtime.agent.provider = { chat: fail, listModels: fail };
|
|
1080
1105
|
}
|
|
1081
|
-
notice(
|
|
1106
|
+
notice(t("Key for {provider} deleted. Use /login or /provider to add one again.", { provider: runtime.providerLabel() }));
|
|
1082
1107
|
return;
|
|
1083
1108
|
}
|
|
1084
1109
|
case "diff":
|
|
@@ -1087,17 +1112,17 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
1087
1112
|
case "undo": {
|
|
1088
1113
|
const result = await runtime.checkpoints.undo();
|
|
1089
1114
|
if (!result) {
|
|
1090
|
-
notice("
|
|
1115
|
+
notice(t("No file edits to undo."));
|
|
1091
1116
|
return;
|
|
1092
1117
|
}
|
|
1093
1118
|
const rel = (p) => relative(runtime.cwd, p) || p;
|
|
1094
1119
|
notice(
|
|
1095
1120
|
[
|
|
1096
|
-
result.failed.length ?
|
|
1097
|
-
result.restored.length ?
|
|
1098
|
-
result.deleted.length ?
|
|
1099
|
-
result.skipped.length ?
|
|
1100
|
-
"
|
|
1121
|
+
result.failed.length ? t("Could not restore: {files}", { files: result.failed.map(rel).join(", ") }) : "",
|
|
1122
|
+
result.restored.length ? t("Restored: {files}", { files: result.restored.map(rel).join(", ") }) : "",
|
|
1123
|
+
result.deleted.length ? t("Deleted (new files): {files}", { files: result.deleted.map(rel).join(", ") }) : "",
|
|
1124
|
+
result.skipped.length ? t("Too large to back up, left unchanged: {files}", { files: result.skipped.map(rel).join(", ") }) : "",
|
|
1125
|
+
t("Note: changes made through bash commands cannot be undone.")
|
|
1101
1126
|
].filter(Boolean).join("\n")
|
|
1102
1127
|
);
|
|
1103
1128
|
return;
|
|
@@ -1105,33 +1130,33 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
1105
1130
|
case "copy": {
|
|
1106
1131
|
const last = runtime.agent.messages.findLast((m) => m.role === "assistant" && typeof m.content === "string" && m.content.trim());
|
|
1107
1132
|
if (!last || typeof last.content !== "string") {
|
|
1108
|
-
notice("
|
|
1133
|
+
notice(t("No answer to copy yet."));
|
|
1109
1134
|
return;
|
|
1110
1135
|
}
|
|
1111
1136
|
process.stdout.write(osc52(last.content, !!process.env.TMUX));
|
|
1112
1137
|
const file = join(runtime.home, "last-answer.md");
|
|
1113
1138
|
mkdirSync(runtime.home, { recursive: true });
|
|
1114
1139
|
writeFileSync(file, last.content);
|
|
1115
|
-
notice(
|
|
1140
|
+
notice(t("Copied to the clipboard (if the terminal supports OSC 52) and saved to {file}.", { file }));
|
|
1116
1141
|
return;
|
|
1117
1142
|
}
|
|
1118
1143
|
case "export": {
|
|
1119
1144
|
const name2 = args || `bccli-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 16).replace(/[:T]/g, "-")}.md`;
|
|
1120
1145
|
const file = resolve(runtime.cwd, name2);
|
|
1121
1146
|
if (existsSync2(file)) {
|
|
1122
|
-
const answer2 = await ask(
|
|
1147
|
+
const answer2 = await ask(t("{file} already exists. Overwrite? (y/N)", { file }));
|
|
1123
1148
|
if (!answer2 || !/^y(a|es)?$/i.test(answer2.trim())) {
|
|
1124
|
-
notice("
|
|
1149
|
+
notice(t("Export cancelled."));
|
|
1125
1150
|
return;
|
|
1126
1151
|
}
|
|
1127
1152
|
}
|
|
1128
1153
|
try {
|
|
1129
|
-
writeFileSync(file, exportMarkdown(runtime.agent.messages,
|
|
1154
|
+
writeFileSync(file, exportMarkdown(runtime.agent.messages, t("BCCLI session {when}", { when: runtime.startedAt.toLocaleString(locale()) })));
|
|
1130
1155
|
} catch (error) {
|
|
1131
|
-
notice(
|
|
1156
|
+
notice(t("Could not write {file}: {error}", { file, error: error.message }), "error");
|
|
1132
1157
|
return;
|
|
1133
1158
|
}
|
|
1134
|
-
notice(
|
|
1159
|
+
notice(t("Conversation saved to {file}.", { file }));
|
|
1135
1160
|
return;
|
|
1136
1161
|
}
|
|
1137
1162
|
case "provider": {
|
|
@@ -1142,7 +1167,7 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
1142
1167
|
return;
|
|
1143
1168
|
}
|
|
1144
1169
|
default:
|
|
1145
|
-
notice(
|
|
1170
|
+
notice(t("Unknown command: /{name}. Type /help.", { name }), "warn");
|
|
1146
1171
|
}
|
|
1147
1172
|
},
|
|
1148
1173
|
[runtime, notice, exit, version, runTurn, ask]
|
|
@@ -1168,7 +1193,7 @@ function App({ runtime, initialPrompt, version }) {
|
|
|
1168
1193
|
try {
|
|
1169
1194
|
body = parseFrontmatter(readFileSync2(skill.file, "utf8")).body;
|
|
1170
1195
|
} catch (error) {
|
|
1171
|
-
notice(
|
|
1196
|
+
notice(t("Skill {name} cannot be read: {error}", { name: skill.name, error: error.code ?? error.message }), "error");
|
|
1172
1197
|
return;
|
|
1173
1198
|
}
|
|
1174
1199
|
void runTurn(`${body}
|
|
@@ -1207,27 +1232,28 @@ ARGUMENTS: ${slash.args}`);
|
|
|
1207
1232
|
controller.current?.abort();
|
|
1208
1233
|
if (queued.length) {
|
|
1209
1234
|
setQueued([]);
|
|
1210
|
-
notice(
|
|
1235
|
+
notice(t("{n} queued messages cancelled.", { n: queued.length }), "warn");
|
|
1211
1236
|
}
|
|
1212
1237
|
} else if (key.ctrl && input === "t") {
|
|
1213
1238
|
const next = !showThinking;
|
|
1239
|
+
const toggled = next ? t("Thinking shown (ctrl+t to hide).") : t("Thinking hidden (ctrl+t to show).");
|
|
1214
1240
|
setShowThinking(next);
|
|
1215
|
-
setTranscript((
|
|
1216
|
-
const last = [...
|
|
1217
|
-
const reprint = next && last?.kind === "thinking" &&
|
|
1241
|
+
setTranscript((t2) => {
|
|
1242
|
+
const last = [...t2.done, ...t2.live].findLast((e) => e.kind === "thinking");
|
|
1243
|
+
const reprint = next && last?.kind === "thinking" && t2.done.includes(last);
|
|
1218
1244
|
return {
|
|
1219
|
-
...
|
|
1245
|
+
...t2,
|
|
1220
1246
|
done: [
|
|
1221
|
-
...
|
|
1247
|
+
...t2.done,
|
|
1222
1248
|
...reprint ? [entry({ kind: "thinking", text: last.text, open: true })] : [],
|
|
1223
|
-
entry({ kind: "notice", text:
|
|
1249
|
+
entry({ kind: "notice", text: toggled, tone: "info" })
|
|
1224
1250
|
]
|
|
1225
1251
|
};
|
|
1226
1252
|
});
|
|
1227
1253
|
} else if (key.ctrl && input === "o" && lastTool.current) {
|
|
1228
|
-
const
|
|
1229
|
-
notice(`\u23BF ${
|
|
1230
|
-
${
|
|
1254
|
+
const t2 = lastTool.current;
|
|
1255
|
+
notice(`\u23BF ${t2.tool} ${t2.target}
|
|
1256
|
+
${t2.output}`);
|
|
1231
1257
|
}
|
|
1232
1258
|
});
|
|
1233
1259
|
const pickMcp = async (name) => {
|
|
@@ -1237,24 +1263,24 @@ ${t.output}`);
|
|
|
1237
1263
|
if (item.installed) {
|
|
1238
1264
|
removeGlobalServer(runtime.home, item.name);
|
|
1239
1265
|
await runtime.mcp.remove(item.name);
|
|
1240
|
-
notice(
|
|
1266
|
+
notice(t("MCP {name} removed.", { name: item.name }));
|
|
1241
1267
|
return;
|
|
1242
1268
|
}
|
|
1243
1269
|
const entry2 = CATALOG.find((c) => c.name === item.name);
|
|
1244
1270
|
if (!entry2) return;
|
|
1245
1271
|
const values = {};
|
|
1246
1272
|
for (const input of entry2.inputs ?? []) {
|
|
1247
|
-
const v = await ask(input.label, !!input.secret);
|
|
1273
|
+
const v = await ask(t(input.label), !!input.secret);
|
|
1248
1274
|
if (!v) return;
|
|
1249
1275
|
values[input.key] = v;
|
|
1250
1276
|
}
|
|
1251
1277
|
const config = fillTemplate(entry2.config, values);
|
|
1252
1278
|
addGlobalServer(runtime.home, entry2.name, config);
|
|
1253
|
-
notice(
|
|
1279
|
+
notice(t("MCP {name} installed, connecting\u2026", { name: entry2.name }));
|
|
1254
1280
|
await runtime.mcp.add({ name: entry2.name, config, source: "global" });
|
|
1255
1281
|
const state = runtime.mcp.states().find((s) => s.name === entry2.name);
|
|
1256
|
-
if (state?.status === "ready") notice(
|
|
1257
|
-
else notice(
|
|
1282
|
+
if (state?.status === "ready") notice(t("MCP {name} active \xB7 {n} tools.", { name: entry2.name, n: state.tools }));
|
|
1283
|
+
else notice(t("MCP {name} failed: {error}", { name: entry2.name, error: state?.error ?? t("unknown") }), "error");
|
|
1258
1284
|
};
|
|
1259
1285
|
const pickProvider = async (id) => {
|
|
1260
1286
|
setProviderMenu(null);
|
|
@@ -1271,7 +1297,7 @@ ${t.output}`);
|
|
|
1271
1297
|
const c = runtime.config;
|
|
1272
1298
|
const keyless = !c.providers[target].apiKeyEnv && PRESETS.some((p) => p.id === target);
|
|
1273
1299
|
if (!hasKey(c, target, runtime.env) || id === "custom") {
|
|
1274
|
-
const key = keyless ? "" : await ask(
|
|
1300
|
+
const key = keyless ? "" : await ask(t("API key for {provider}", { provider: providerName(c, target) }), true);
|
|
1275
1301
|
if (key === void 0) return;
|
|
1276
1302
|
const result = await runtime.addProviderKey(target, key);
|
|
1277
1303
|
if (!result.ok) {
|
|
@@ -1312,10 +1338,10 @@ ${t.output}`);
|
|
|
1312
1338
|
if (!text) return null;
|
|
1313
1339
|
if (!(e.open ?? showThinking)) {
|
|
1314
1340
|
const lines = text.split("\n").length;
|
|
1315
|
-
return /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children:
|
|
1341
|
+
return /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: t("\u273B Thinking \xB7 {n} lines \xB7 ctrl+t to show", { n: lines }) }) }, e.id);
|
|
1316
1342
|
}
|
|
1317
1343
|
return /* @__PURE__ */ jsxs10(Box13, { marginTop: 1, flexDirection: "column", children: [
|
|
1318
|
-
/* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "\u273B
|
|
1344
|
+
/* @__PURE__ */ jsx15(Text15, { dimColor: true, children: t("\u273B Thinking (ctrl+t to hide)") }),
|
|
1319
1345
|
/* @__PURE__ */ jsx15(Box13, { paddingLeft: 2, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, italic: true, children: text }) })
|
|
1320
1346
|
] }, e.id);
|
|
1321
1347
|
}
|
|
@@ -1328,7 +1354,7 @@ ${t.output}`);
|
|
|
1328
1354
|
return /* @__PURE__ */ jsxs10(Box13, { flexDirection: "column", children: [
|
|
1329
1355
|
/* @__PURE__ */ jsx15(Static, { items: transcript.done, children: renderEntry }),
|
|
1330
1356
|
transcript.live.map(renderEntry),
|
|
1331
|
-
busy && !pending && !planAsk ? /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Spinner, { label: "
|
|
1357
|
+
busy && !pending && !planAsk ? /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Spinner, { label: t("Thinking"), startedAt }) }) : null,
|
|
1332
1358
|
pending ? /* @__PURE__ */ jsx15(PermissionPrompt, { request: pending.request, onAnswer: answer }, pending.id) : null,
|
|
1333
1359
|
picker ? /* @__PURE__ */ jsx15(
|
|
1334
1360
|
ModelPicker,
|
|
@@ -1371,7 +1397,7 @@ ${t.output}`);
|
|
|
1371
1397
|
}
|
|
1372
1398
|
) : null,
|
|
1373
1399
|
/* @__PURE__ */ jsx15(TodoList, { items: todos }),
|
|
1374
|
-
queued.map((q, i) => /* @__PURE__ */ jsx15(Text15, { dimColor: true, children:
|
|
1400
|
+
queued.map((q, i) => /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: t(" \u23F3 queued: {q}", { q }) }, `${i}-${q}`)),
|
|
1375
1401
|
/* @__PURE__ */ jsx15(PromptInput, { disabled: !!pending || !!picker || !!providerMenu || !!prompt || !!planAsk || !!mcpMenu || !!listPicker, history, cwd: runtime.cwd, onSubmit: onPrompt, extraCommands }),
|
|
1376
1402
|
/* @__PURE__ */ jsx15(StatusBar, { mode, tokens, busy, model: modelLabel, reasoning })
|
|
1377
1403
|
] });
|
|
@@ -1383,27 +1409,27 @@ async function startInteractive(rt, opts) {
|
|
|
1383
1409
|
if (opts.resume) {
|
|
1384
1410
|
const { Session: Session2 } = await import("./session-7UB77CEG.js");
|
|
1385
1411
|
const list = Session2.list(rt.home, rt.cwd).slice(0, 20);
|
|
1386
|
-
if (!list.length) console.log("
|
|
1412
|
+
if (!list.length) console.log(t("No sessions in this folder yet; starting a new one."));
|
|
1387
1413
|
else {
|
|
1388
1414
|
list.forEach((s, i) => {
|
|
1389
|
-
console.log(`${String(i + 1).padStart(2)}. ${s.mtime.toLocaleString(
|
|
1415
|
+
console.log(`${String(i + 1).padStart(2)}. ${s.mtime.toLocaleString(locale())} ${s.preview}`);
|
|
1390
1416
|
});
|
|
1391
1417
|
const { createInterface } = await import("readline/promises");
|
|
1392
1418
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1393
|
-
const answer = Number(await rl.question("
|
|
1419
|
+
const answer = Number(await rl.question(t("Session number (enter = new): ")));
|
|
1394
1420
|
rl.close();
|
|
1395
1421
|
const chosen = list[answer - 1];
|
|
1396
1422
|
if (chosen) rt.resume(chosen.session);
|
|
1397
1423
|
}
|
|
1398
1424
|
}
|
|
1399
|
-
const { serversToStart, setProjectTrust } = await import("./config-
|
|
1425
|
+
const { serversToStart, setProjectTrust } = await import("./config-CGYYFECG.js");
|
|
1400
1426
|
const plan = serversToStart(rt.home, rt.cwd);
|
|
1401
1427
|
if (plan.needTrust.length) {
|
|
1402
1428
|
const { createInterface } = await import("readline/promises");
|
|
1403
1429
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1404
1430
|
for (const s of plan.needTrust) {
|
|
1405
1431
|
const what = s.config.type === "http" ? s.config.url : [s.config.command, ...s.config.args ?? []].join(" ");
|
|
1406
|
-
const answer = (await rl.question(
|
|
1432
|
+
const answer = (await rl.question(t('This repo wants to run the MCP server "{name}" ({what}). Allow? [y/N] ', { name: s.name, what }))).trim().toLowerCase();
|
|
1407
1433
|
setProjectTrust(rt.home, rt.cwd, s.name, answer === "y", s.config);
|
|
1408
1434
|
if (answer === "y") plan.start.push(s);
|
|
1409
1435
|
}
|