@vascend/talos 0.1.4 → 0.1.6
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/LICENSE +22 -0
- package/README.md +37 -12
- package/dist/core/agent.d.ts +16 -3
- package/dist/core/agent.js +170 -70
- package/dist/core/background.d.ts +10 -3
- package/dist/core/background.js +55 -9
- package/dist/core/bootstrap.js +1 -0
- package/dist/core/compaction.js +1 -1
- package/dist/core/config-storage.d.ts +5 -0
- package/dist/core/config-storage.js +83 -0
- package/dist/core/config.d.ts +11 -2
- package/dist/core/config.js +24 -8
- package/dist/core/context-ledger.js +2 -1
- package/dist/core/context-policy.d.ts +1 -1
- package/dist/core/context-policy.js +10 -7
- package/dist/core/credentials.js +29 -30
- package/dist/core/effort.d.ts +1 -1
- package/dist/core/effort.js +5 -1
- package/dist/core/execution-guidance.d.ts +1 -1
- package/dist/core/execution-guidance.js +2 -0
- package/dist/core/file-coordination.d.ts +3 -0
- package/dist/core/file-coordination.js +28 -0
- package/dist/core/file-lease-store.d.ts +3 -0
- package/dist/core/file-lease-store.js +28 -12
- package/dist/core/fusion.d.ts +24 -0
- package/dist/core/fusion.js +80 -0
- package/dist/core/model-limits.d.ts +1 -0
- package/dist/core/model-limits.js +5 -1
- package/dist/core/permission-queue.js +15 -15
- package/dist/core/request-plan.js +4 -3
- package/dist/core/session-naming.d.ts +3 -0
- package/dist/core/session-naming.js +47 -0
- package/dist/core/session-usage.js +4 -1
- package/dist/core/session.d.ts +5 -2
- package/dist/core/session.js +22 -7
- package/dist/core/settings.d.ts +2 -0
- package/dist/core/settings.js +5 -16
- package/dist/core/step-policy.d.ts +18 -0
- package/dist/core/step-policy.js +6 -0
- package/dist/core/storage-health.d.ts +24 -0
- package/dist/core/storage-health.js +72 -0
- package/dist/core/tool-artifacts.d.ts +2 -0
- package/dist/core/tool-artifacts.js +21 -3
- package/dist/core/tool-result-index.js +29 -33
- package/dist/core/tool-result-store.js +6 -5
- package/dist/core/types.d.ts +26 -2
- package/dist/core/user-inbox.d.ts +9 -0
- package/dist/core/user-inbox.js +22 -3
- package/dist/core/user-input.js +1 -1
- package/dist/fusion/autopilot-fast.d.ts +59 -0
- package/dist/fusion/autopilot-fast.js +213 -0
- package/dist/fusion/autopilot.d.ts +75 -0
- package/dist/fusion/autopilot.js +308 -0
- package/dist/fusion/focus.d.ts +30 -0
- package/dist/fusion/focus.js +122 -0
- package/dist/fusion/gate.d.ts +30 -0
- package/dist/fusion/gate.js +95 -0
- package/dist/fusion/jev.d.ts +71 -0
- package/dist/fusion/jev.js +164 -0
- package/dist/fusion/receipts.d.ts +25 -0
- package/dist/fusion/receipts.js +34 -0
- package/dist/fusion/route.d.ts +25 -0
- package/dist/fusion/route.js +84 -0
- package/dist/fusion/run.d.ts +4 -0
- package/dist/fusion/run.js +186 -0
- package/dist/horizon/engine.d.ts +20 -1
- package/dist/horizon/engine.js +57 -0
- package/dist/horizon/index.d.ts +2 -2
- package/dist/horizon/index.js +1 -1
- package/dist/horizon/types.d.ts +29 -0
- package/dist/index.js +12 -0
- package/dist/providers/anthropic-oauth.d.ts +8 -3
- package/dist/providers/anthropic-oauth.js +13 -10
- package/dist/providers/anthropic.d.ts +9 -2
- package/dist/providers/anthropic.js +64 -21
- package/dist/providers/cli-models.d.ts +30 -0
- package/dist/providers/cli-models.js +194 -0
- package/dist/providers/model-effort.js +1 -1
- package/dist/providers/openai-oauth.d.ts +8 -3
- package/dist/providers/openai-oauth.js +9 -3
- package/dist/providers/openrouter-manual-fallback.d.ts +3 -1
- package/dist/providers/openrouter-manual-fallback.js +20 -20
- package/dist/providers/registry.js +3 -2
- package/dist/providers/retry.d.ts +3 -0
- package/dist/providers/retry.js +44 -1
- package/dist/remote/cifratura.d.ts +12 -0
- package/dist/remote/cifratura.js +66 -0
- package/dist/remote/index.d.ts +15 -0
- package/dist/remote/index.js +65 -0
- package/dist/remote/relay-client.d.ts +58 -0
- package/dist/remote/relay-client.js +315 -0
- package/dist/remote/sessione-remota.d.ts +60 -0
- package/dist/remote/sessione-remota.js +266 -0
- package/dist/sdk.d.ts +7 -2
- package/dist/sdk.js +3 -1
- package/dist/tools/builtin.js +41 -20
- package/dist/tools/capabilities.d.ts +3 -1
- package/dist/tools/capabilities.js +5 -2
- package/dist/tools/computer-use.js +2 -1
- package/dist/tools/pagination.js +1 -1
- package/dist/tools/program.js +34 -21
- package/dist/tools/team-tools.js +11 -6
- package/dist/tui/account-entry.js +14 -9
- package/dist/tui/agent-label.d.ts +2 -0
- package/dist/tui/agent-label.js +5 -0
- package/dist/tui/agent-sessions-screen.d.ts +35 -0
- package/dist/tui/agent-sessions-screen.js +178 -0
- package/dist/tui/agent-sessions.d.ts +53 -0
- package/dist/tui/agent-sessions.js +236 -0
- package/dist/tui/bottom-input.d.ts +57 -2
- package/dist/tui/bottom-input.js +449 -54
- package/dist/tui/branding.js +8 -4
- package/dist/tui/capability-lists.d.ts +10 -0
- package/dist/tui/capability-lists.js +41 -0
- package/dist/tui/command-output-registry.js +4 -0
- package/dist/tui/command-transcript.d.ts +1 -1
- package/dist/tui/command-transcript.js +17 -21
- package/dist/tui/commands.js +6 -2
- package/dist/tui/compaction-status.d.ts +7 -0
- package/dist/tui/compaction-status.js +39 -0
- package/dist/tui/config-recovery.d.ts +12 -0
- package/dist/tui/config-recovery.js +54 -0
- package/dist/tui/context-meter.d.ts +3 -0
- package/dist/tui/context-meter.js +35 -8
- package/dist/tui/diff.d.ts +9 -0
- package/dist/tui/diff.js +43 -19
- package/dist/tui/fusion-menu.d.ts +5 -0
- package/dist/tui/fusion-menu.js +89 -0
- package/dist/tui/i18n-catalog.js +351 -2
- package/dist/tui/live-command.d.ts +1 -0
- package/dist/tui/live-command.js +9 -0
- package/dist/tui/live-output.d.ts +1 -0
- package/dist/tui/live-output.js +11 -0
- package/dist/tui/logo.js +3 -0
- package/dist/tui/model-details.js +13 -12
- package/dist/tui/model-picker.d.ts +2 -0
- package/dist/tui/model-picker.js +59 -0
- package/dist/tui/model-selection.js +19 -10
- package/dist/tui/native-scrollback.d.ts +2 -1
- package/dist/tui/native-scrollback.js +31 -6
- package/dist/tui/prompt-queue-store.d.ts +1 -0
- package/dist/tui/prompt-queue-store.js +4 -0
- package/dist/tui/prompt-queue.d.ts +3 -0
- package/dist/tui/prompt-queue.js +19 -1
- package/dist/tui/provider-label.d.ts +2 -0
- package/dist/tui/provider-label.js +9 -0
- package/dist/tui/provider-menu.js +25 -24
- package/dist/tui/queue-screen.js +2 -1
- package/dist/tui/queued-questions.js +2 -4
- package/dist/tui/quick-help.d.ts +1 -1
- package/dist/tui/quick-help.js +3 -0
- package/dist/tui/remote-command.d.ts +7 -0
- package/dist/tui/remote-command.js +79 -0
- package/dist/tui/repl.d.ts +11 -2
- package/dist/tui/repl.js +457 -327
- package/dist/tui/review-store.d.ts +8 -1
- package/dist/tui/review-store.js +64 -11
- package/dist/tui/review-team.js +4 -3
- package/dist/tui/runtime-error.d.ts +2 -0
- package/dist/tui/runtime-error.js +26 -0
- package/dist/tui/scrollback-archive.d.ts +16 -0
- package/dist/tui/scrollback-archive.js +90 -0
- package/dist/tui/selector-mouse.d.ts +1 -0
- package/dist/tui/selector-mouse.js +1 -1
- package/dist/tui/selector.d.ts +11 -0
- package/dist/tui/selector.js +28 -4
- package/dist/tui/session-controls.d.ts +26 -0
- package/dist/tui/session-controls.js +65 -0
- package/dist/tui/session-naming-notice.d.ts +14 -0
- package/dist/tui/session-naming-notice.js +59 -0
- package/dist/tui/session-picker.d.ts +2 -0
- package/dist/tui/session-picker.js +32 -0
- package/dist/tui/session-replay.d.ts +1 -0
- package/dist/tui/session-replay.js +101 -32
- package/dist/tui/session-transcript-layout.d.ts +9 -0
- package/dist/tui/session-transcript-layout.js +41 -0
- package/dist/tui/startup.js +63 -33
- package/dist/tui/status-line.d.ts +1 -1
- package/dist/tui/status-line.js +20 -12
- package/dist/tui/storage-warning.d.ts +2 -0
- package/dist/tui/storage-warning.js +35 -0
- package/dist/tui/talos-art-data.d.ts +1 -0
- package/dist/tui/talos-art-data.js +2 -0
- package/dist/tui/talos-art.d.ts +1 -0
- package/dist/tui/talos-art.js +9 -0
- package/dist/tui/task-labels.d.ts +1 -0
- package/dist/tui/task-labels.js +8 -0
- package/dist/tui/terminal-text.d.ts +2 -1
- package/dist/tui/terminal-text.js +28 -2
- package/dist/tui/theme.js +2 -2
- package/dist/tui/tool-presentation.d.ts +3 -0
- package/dist/tui/tool-presentation.js +98 -0
- package/dist/tui/tool-style.js +4 -0
- package/dist/tui/transcript-store.d.ts +25 -0
- package/dist/tui/transcript-store.js +151 -0
- package/dist/tui/usage-footer.d.ts +1 -1
- package/dist/tui/usage-footer.js +3 -1
- package/dist/tui/vascend-id.d.ts +49 -0
- package/dist/tui/vascend-id.js +321 -0
- package/dist/tui/web-login-screen.js +4 -3
- package/dist/tui/web-login.d.ts +7 -15
- package/dist/tui/web-login.js +38 -78
- package/dist/tui/worker-transcripts.d.ts +31 -0
- package/dist/tui/worker-transcripts.js +91 -0
- package/dist/vascend/candidate-collector.d.ts +6 -5
- package/dist/vascend/candidate-collector.js +44 -43
- package/dist/vascend/context-feedback-loop.js +2 -0
- package/dist/vascend/context-lint.js +32 -2
- package/dist/vascend/context-market-selection.js +12 -5
- package/dist/vascend/context-pack-render.js +10 -4
- package/dist/vascend/context-packet-mirrors.d.ts +8 -0
- package/dist/vascend/context-packet-mirrors.js +24 -0
- package/dist/vascend/context-plan-events.d.ts +4 -0
- package/dist/vascend/context-plan-events.js +44 -0
- package/dist/vascend/context-snapshot.d.ts +1 -0
- package/dist/vascend/context-snapshot.js +8 -5
- package/dist/vascend/context-store-reader.d.ts +20 -0
- package/dist/vascend/context-store-reader.js +46 -0
- package/dist/vascend/context-window-compiler.d.ts +1 -0
- package/dist/vascend/context-window-compiler.js +1 -0
- package/dist/vascend/file-lock.d.ts +1 -0
- package/dist/vascend/file-lock.js +26 -0
- package/dist/vascend/granular-kingdom.d.ts +1 -0
- package/dist/vascend/granular-kingdom.js +52 -17
- package/dist/vascend/kingdom-bus.d.ts +1 -0
- package/dist/vascend/kingdom-bus.js +3 -0
- package/dist/vascend/kingdom-channel.d.ts +2 -0
- package/dist/vascend/kingdom-channel.js +3 -0
- package/dist/vascend/kingdom-live.d.ts +32 -4
- package/dist/vascend/kingdom-live.js +149 -13
- package/dist/vascend/kingdom-run.d.ts +5 -1
- package/dist/vascend/kingdom-run.js +6 -2
- package/dist/vascend/kingdom.d.ts +3 -0
- package/dist/vascend/kingdom.js +22 -11
- package/dist/vascend/memory-packet.d.ts +2 -1
- package/dist/vascend/memory-packet.js +31 -44
- package/dist/vascend/memory-store.d.ts +1 -0
- package/dist/vascend/memory-store.js +12 -4
- package/dist/vascend/plan-store.d.ts +3 -1
- package/dist/vascend/plan-store.js +6 -4
- package/dist/vascend/room-memory.d.ts +13 -2
- package/dist/vascend/room-memory.js +48 -6
- package/dist/vascend/runtime.d.ts +3 -11
- package/dist/vascend/runtime.js +11 -123
- package/dist/vascend/session-search.js +2 -0
- package/dist/vascend/team-session.js +3 -2
- package/dist/vascend/vision.d.ts +3 -1
- package/dist/vascend/vision.js +6 -4
- package/dist/vascend/worker-session.d.ts +20 -0
- package/dist/vascend/worker-session.js +83 -0
- package/package.json +2 -2
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { modelEfforts } from "../providers/model-effort.js";
|
|
2
|
+
import { getLanguage, tr } from "./i18n.js";
|
|
2
3
|
export function modelDetail(model) {
|
|
3
|
-
const yes = (v) => v === undefined ? "?" : v ? "sì" : "no";
|
|
4
|
-
const count = (n) => n === undefined ? "?" : n.toLocaleString(
|
|
4
|
+
const yes = (v) => v === undefined ? "?" : v ? tr("sì", "yes") : tr("no", "no");
|
|
5
|
+
const count = (n) => n === undefined ? "?" : n.toLocaleString(getLanguage());
|
|
5
6
|
const efforts = modelEfforts(`${model.provider}/${model.id}`, model).filter(Boolean);
|
|
6
7
|
const controls = model.reasoningOptions?.map(o => o.type === "effort" ? `effort ${o.values.join(" / ")}`
|
|
7
|
-
: o.type === "toggle" ? "on/off" :
|
|
8
|
+
: o.type === "toggle" ? "on/off" : tr("budget token {min}–{max}", "token budget {min}–{max}", { min: o.min ?? "?", max: o.max ?? "?" })).join("; ");
|
|
8
9
|
return [model.name, model.description,
|
|
9
|
-
|
|
10
|
+
tr("Contesto {context} · output {output}", "Context {context} · output {output}", { context: count(model.context), output: count(model.outputLimit) }) + (model.inputLimit ? ` · input ${count(model.inputLimit)}` : ""),
|
|
10
11
|
`Reasoning ${yes(model.reasoning)}${controls ? ` (${controls})` : ""}`,
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
tr("Effort in Talos: {levels}", "Effort in Talos: {levels}", { levels: efforts.length ? efforts.join(" / ") : tr("predefinito", "default") }),
|
|
13
|
+
tr("Tool {tools} · JSON strutturato {json} · temperatura {temperature}", "Tools {tools} · structured JSON {json} · temperature {temperature}", { tools: yes(model.toolCall), json: yes(model.structuredOutput), temperature: yes(model.temperature) }),
|
|
13
14
|
`Input: ${model.inputModalities.join(", ") || "?"} · output: ${model.outputModalities.join(", ") || "?"}`,
|
|
14
|
-
|
|
15
|
-
`USD/1M token: ${Object.entries(model.cost).map(([key, value]) => `${key} $${value}`).join(" · ") || "non disponibili"}`,
|
|
16
|
-
model.knowledge ?
|
|
17
|
-
model.releaseDate ?
|
|
18
|
-
model.updatedAt ?
|
|
19
|
-
"Fonte: models.dev · prezzi API di base; fasce, modalità e abbonamenti possono differire",
|
|
15
|
+
tr("Allegati {attachments} · pesi aperti {weights}", "Attachments {attachments} · open weights {weights}", { attachments: yes(model.attachment), weights: yes(model.openWeights) }),
|
|
16
|
+
`USD/1M token: ${Object.entries(model.cost).map(([key, value]) => `${key} $${value}`).join(" · ") || tr("non disponibili", "unavailable")}`,
|
|
17
|
+
model.knowledge ? tr("Conoscenze: {date}", "Knowledge cutoff: {date}", { date: model.knowledge }) : "",
|
|
18
|
+
model.releaseDate ? tr("Rilasciato: {date}", "Released: {date}", { date: model.releaseDate }) : "",
|
|
19
|
+
model.updatedAt ? tr("Dati aggiornati: {date}", "Data updated: {date}", { date: model.updatedAt }) : "", model.status,
|
|
20
|
+
tr("Fonte: models.dev · prezzi API di base; fasce, modalità e abbonamenti possono differire", "Source: models.dev · base API prices; tiers, modes and subscriptions may differ"),
|
|
20
21
|
].filter(Boolean).join("\n");
|
|
21
22
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { fitLine, oneLine, padLine, wrapText } from "./terminal-text.js";
|
|
2
|
+
import { tr } from "./i18n.js";
|
|
3
|
+
// Use provider metadata verbatim: prices and capabilities are never guessed.
|
|
4
|
+
export function renderModelPicker(opts) {
|
|
5
|
+
const width = Math.max(1, opts.columns - 2);
|
|
6
|
+
const height = Math.max(3, (opts.rows ?? opts.pageSize + 13) - 1);
|
|
7
|
+
const t = opts.theme;
|
|
8
|
+
const row = (text) => " " + fitLine(text, width);
|
|
9
|
+
const divider = row(t.muted("─".repeat(width)));
|
|
10
|
+
const page = Math.max(1, Math.min(opts.pageSize, height - 6));
|
|
11
|
+
const index = Math.max(0, Math.min(opts.index, opts.options.length - 1));
|
|
12
|
+
const start = Math.max(0, Math.min(index - Math.floor(page / 2), opts.options.length - page));
|
|
13
|
+
const selected = opts.options[index];
|
|
14
|
+
const current = (option) => option && (opts.currentKey !== undefined
|
|
15
|
+
? (option.key ?? String(option.value)) === opts.currentKey
|
|
16
|
+
: opts.current !== undefined && option.value === opts.current);
|
|
17
|
+
const lines = [row(t.chatText("› /model ")), divider,
|
|
18
|
+
row(t.muted("/ ") + (opts.query ? t.silver(oneLine(opts.query)) : t.muted(tr("Cerca", "Search")))), ""];
|
|
19
|
+
const providerWidth = width >= 50 ? Math.min(24, Math.floor(width * 0.27)) : 0;
|
|
20
|
+
const contextWidth = width >= 75 ? 12 : 0;
|
|
21
|
+
const reasoningWidth = width >= 100 ? 14 : 0;
|
|
22
|
+
const labelWidth = Math.max(1, width - providerWidth - contextWidth - reasoningWidth - 5);
|
|
23
|
+
for (const [offset, option] of opts.options.slice(start, start + page).entries()) {
|
|
24
|
+
const active = start + offset === index;
|
|
25
|
+
const name = `${active ? "›" : " "}${current(option) ? "●" : " "} `
|
|
26
|
+
+ padLine(oneLine(option.label), labelWidth);
|
|
27
|
+
const text = (active ? (t.markdownLink ?? t.accent)(name) : name)
|
|
28
|
+
+ (contextWidth ? padLine(option.modelInfo?.context !== undefined
|
|
29
|
+
? ` ${(option.modelInfo.context / 1000).toLocaleString("en-US", { maximumFractionDigits: 1 })}k ctx` : " —", contextWidth) : "")
|
|
30
|
+
+ (reasoningWidth ? padLine(option.modelInfo?.reasoning === true ? " Reasoning" : "", reasoningWidth) : "")
|
|
31
|
+
+ (providerWidth ? " " + fitLine(oneLine(option.group ?? ""), providerWidth) : "");
|
|
32
|
+
lines.push(row(active ? t.selected(padLine(text, width)) : t.silver(text)));
|
|
33
|
+
}
|
|
34
|
+
if (!opts.options.length)
|
|
35
|
+
lines.push(row(t.muted(tr(" Nessun risultato. Modifica la ricerca.", " No results. Change your search."))));
|
|
36
|
+
while (lines.length < page + 4)
|
|
37
|
+
lines.push("");
|
|
38
|
+
lines.push(row(t.muted(`${opts.options.length ? index + 1 : 0} / ${opts.options.length}`
|
|
39
|
+
+ (opts.totalCount !== undefined && opts.totalCount !== opts.options.length ? ` · ${opts.totalCount} ${tr("totali", "total")}` : ""))));
|
|
40
|
+
if (selected && height >= 12) {
|
|
41
|
+
lines.push(divider, row(t.accent(oneLine(selected.label))
|
|
42
|
+
+ (current(selected) ? t.muted(" · " + tr("Attuale", "Current")) : "")));
|
|
43
|
+
const info = selected.modelInfo;
|
|
44
|
+
if (info && width >= 45 && height - lines.length >= 5) {
|
|
45
|
+
const cell = Math.floor(width / 3);
|
|
46
|
+
const price = (value) => value === undefined ? "—" : `$${value.toLocaleString("en-US", { maximumFractionDigits: 4 })} / 1M`;
|
|
47
|
+
lines.push(row(t.muted(padLine("Input", cell) + padLine(tr("Input cache", "Cached input"), cell) + "Output")), row(t.bold(padLine(price(info.cost["input"]), cell) + padLine(price(info.cost["cache_read"]), cell) + price(info.cost["output"]))), row(t.dim(tr("Listino API · non il costo dell’abbonamento", "API list price · not subscription charges"))));
|
|
48
|
+
}
|
|
49
|
+
const detailSpace = Math.max(0, height - lines.length - 2);
|
|
50
|
+
lines.push(...wrapText(selected.detail, width, true).slice(0, detailSpace).map(text => row(t.muted(text))));
|
|
51
|
+
}
|
|
52
|
+
const footer = row(t.muted(width >= 55
|
|
53
|
+
? tr("↑↓ scegli · Invio conferma · Tab dettagli · Esc annulla", "↑↓ select · Enter confirm · Tab details · Esc cancel")
|
|
54
|
+
: tr("↑↓ · Invio · Tab · Esc", "↑↓ · Enter · Tab · Esc")));
|
|
55
|
+
const body = lines.slice(0, height - 1);
|
|
56
|
+
while (body.length < height - 1)
|
|
57
|
+
body.push("");
|
|
58
|
+
return [...body, footer];
|
|
59
|
+
}
|
|
@@ -1,22 +1,31 @@
|
|
|
1
|
+
import { tr } from "./i18n.js";
|
|
1
2
|
import { saveGlobalSettings } from "../core/settings.js";
|
|
2
3
|
import { cachedModelCatalog, loadModelsDev } from "../providers/models-dev.js";
|
|
3
4
|
import { modelEfforts } from "../providers/model-effort.js";
|
|
4
5
|
import { selectOption } from "./selector.js";
|
|
5
6
|
import { notifyStatus } from "./command-feedback.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
function effortDescriptions() {
|
|
8
|
+
return {
|
|
9
|
+
"": tr("Impostazione predefinita del provider", "Provider default"),
|
|
10
|
+
none: tr("Reasoning disattivato", "Reasoning disabled"),
|
|
11
|
+
minimal: tr("Ragionamento minimo", "Minimal reasoning"),
|
|
12
|
+
low: tr("Ragionamento leggero", "Light reasoning"),
|
|
13
|
+
medium: tr("Ragionamento intermedio", "Medium reasoning"),
|
|
14
|
+
high: tr("Ragionamento approfondito", "Deep reasoning"),
|
|
15
|
+
xhigh: tr("Ragionamento molto approfondito", "Very deep reasoning"),
|
|
16
|
+
max: tr("Massimo livello disponibile per questo modello", "Highest level available for this model"),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
11
19
|
export async function pickEffort(fullModel, harness, ctl, theme, terminalColumns, select = selectOption) {
|
|
12
20
|
const metadata = cachedModelCatalog(harness.env).get(fullModel);
|
|
13
21
|
const levels = modelEfforts(fullModel, metadata);
|
|
22
|
+
const descriptions = effortDescriptions();
|
|
14
23
|
const selected = await select({
|
|
15
24
|
title: `${metadata?.name ?? fullModel.split("/").pop()} · effort`,
|
|
16
|
-
hint: levels.length > 1 ? "Un livello maggiore può richiedere più tempo e token. Esc annulla la scelta del modello."
|
|
17
|
-
: metadata?.reasoning === false ? "Questo modello non supporta reasoning."
|
|
18
|
-
: "Nessun controllo effort verificato per questo modello e provider: usa il predefinito.",
|
|
19
|
-
options: levels.map(level => ({ key: level, label: level || "default", detail: descriptions[level], value: level })),
|
|
25
|
+
hint: levels.length > 1 ? tr("Un livello maggiore può richiedere più tempo e token. Esc annulla la scelta del modello.", "A higher level may take more time and tokens. Esc cancels model selection.")
|
|
26
|
+
: metadata?.reasoning === false ? tr("Questo modello non supporta reasoning.", "This model does not support reasoning.")
|
|
27
|
+
: tr("Nessun controllo effort verificato per questo modello e provider: usa il predefinito.", "No verified effort control for this model and provider: use the default."),
|
|
28
|
+
options: levels.map(level => ({ key: level, label: level || tr("predefinito", "default"), detail: descriptions[level], value: level })),
|
|
20
29
|
currentKey: levels.includes(harness.config.effort) ? harness.config.effort : "",
|
|
21
30
|
ctl, theme, terminalColumns,
|
|
22
31
|
});
|
|
@@ -25,7 +34,7 @@ export async function pickEffort(fullModel, harness, ctl, theme, terminalColumns
|
|
|
25
34
|
export async function applyModelChoice(model, harness, ctl, theme, terminalColumns, select = selectOption) {
|
|
26
35
|
const resolved = harness.providers.resolve(model);
|
|
27
36
|
if (!resolved) {
|
|
28
|
-
notifyStatus(ctl,
|
|
37
|
+
notifyStatus(ctl, tr("Provider non configurato per {p0}", "Provider not configured for {p0}", { p0: model }), true);
|
|
29
38
|
return false;
|
|
30
39
|
}
|
|
31
40
|
const fullModel = `${resolved.provider.id}/${resolved.modelId}`;
|
|
@@ -22,6 +22,7 @@ export declare class NativeScrollback {
|
|
|
22
22
|
isCommitted(id: number): boolean;
|
|
23
23
|
invalidate(): void;
|
|
24
24
|
reset(): string;
|
|
25
|
-
render(log: readonly ScrollbackLine[], input: ScrollbackInput, width: number, height: number, hideCursor?: boolean, preamble?: readonly string[]): string;
|
|
25
|
+
render(log: readonly ScrollbackLine[], input: ScrollbackInput, width: number, height: number, hideCursor?: boolean, preamble?: readonly string[], emit?: (chunk: string) => void): string;
|
|
26
26
|
release(): string;
|
|
27
|
+
dispose(): void;
|
|
27
28
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { fitLine } from "./terminal-text.js";
|
|
2
|
+
import { ScrollbackArchive } from "./scrollback-archive.js";
|
|
2
3
|
const RESET = "\x1b[0m\x1b]8;;\x1b\\";
|
|
3
4
|
const SYNC_ON = "\x1b[?2026h";
|
|
4
5
|
const SYNC_OFF = "\x1b[?2026l";
|
|
@@ -9,7 +10,7 @@ const move = (from, to) => from === to ? "\r"
|
|
|
9
10
|
// the composer are mutable; cursor movement never targets archived rows.
|
|
10
11
|
export class NativeScrollback {
|
|
11
12
|
committedThrough = 0;
|
|
12
|
-
history =
|
|
13
|
+
history = new ScrollbackArchive();
|
|
13
14
|
frame = [];
|
|
14
15
|
tail = [];
|
|
15
16
|
cursorRow = 0;
|
|
@@ -24,7 +25,7 @@ export class NativeScrollback {
|
|
|
24
25
|
// A session change replaces both the visible frame and native scrollback.
|
|
25
26
|
reset() {
|
|
26
27
|
this.committedThrough = 0;
|
|
27
|
-
this.history.
|
|
28
|
+
this.history.clear();
|
|
28
29
|
this.frame = [];
|
|
29
30
|
this.tail = [];
|
|
30
31
|
this.cursorRow = 0;
|
|
@@ -35,7 +36,7 @@ export class NativeScrollback {
|
|
|
35
36
|
this.preamble = [];
|
|
36
37
|
return SYNC_ON + RESET + "\x1b[2J\x1b[3J\x1b[H" + SYNC_OFF;
|
|
37
38
|
}
|
|
38
|
-
render(log, input, width, height, hideCursor = false, preamble = []) {
|
|
39
|
+
render(log, input, width, height, hideCursor = false, preamble = [], emit) {
|
|
39
40
|
if (width < 1 || height < 1)
|
|
40
41
|
return "";
|
|
41
42
|
const columns = Math.max(1, width);
|
|
@@ -77,24 +78,47 @@ export class NativeScrollback {
|
|
|
77
78
|
if (!committed.length && !resized) {
|
|
78
79
|
while (start < frame.length && start < this.frame.length && frame[start] === this.frame[start])
|
|
79
80
|
start++;
|
|
81
|
+
// Cursor-down cannot create a row below the terminal's bottom edge: it
|
|
82
|
+
// clamps to the last row. Repaint from an existing row so an appended
|
|
83
|
+
// input line (wrap, clipboard hint) advances with CRLF and scrolls.
|
|
84
|
+
if (frame.length > this.frame.length)
|
|
85
|
+
start = Math.min(start, Math.max(0, this.frame.length - 1));
|
|
80
86
|
}
|
|
81
87
|
const changed = committed.length > 0 || resized || start < Math.max(frame.length, this.frame.length);
|
|
82
88
|
if (!changed && row === this.cursorRow && col === this.cursorCol)
|
|
83
89
|
return "";
|
|
84
90
|
let out = SYNC_ON;
|
|
91
|
+
const append = (text) => {
|
|
92
|
+
out += text;
|
|
93
|
+
if (emit && out.length >= 64 * 1024) {
|
|
94
|
+
emit(out);
|
|
95
|
+
out = "";
|
|
96
|
+
}
|
|
97
|
+
};
|
|
85
98
|
if (resized)
|
|
86
99
|
out += RESET + "\x1b[2J\x1b[3J\x1b[H";
|
|
87
100
|
if (resized || this.width === 0) {
|
|
88
101
|
for (const line of preamble)
|
|
89
102
|
out += fitLine(line, textWidth) + RESET + "\r\n";
|
|
90
103
|
for (const line of this.history)
|
|
91
|
-
|
|
104
|
+
append(fitLine(line.text, textWidth) + RESET + "\r\n");
|
|
92
105
|
}
|
|
93
106
|
let current = this.cursorRow;
|
|
94
|
-
if (changed) {
|
|
107
|
+
if (changed && !resized && !committed.length && frame.length === this.frame.length) {
|
|
108
|
+
// Spinner/timer updates must not erase the composer and every row below
|
|
109
|
+
// them. Paint only changed rows, including on terminals without sync.
|
|
110
|
+
out += "\x1b[?25l";
|
|
111
|
+
for (let i = start; i < frame.length; i++) {
|
|
112
|
+
if (frame[i] === this.frame[i])
|
|
113
|
+
continue;
|
|
114
|
+
out += move(current, i) + "\x1b[2K" + frame[i] + RESET;
|
|
115
|
+
current = i;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else if (changed) {
|
|
95
119
|
out += move(current, start) + "\x1b[J";
|
|
96
120
|
for (const line of committed)
|
|
97
|
-
|
|
121
|
+
append(fitLine(line.text, textWidth) + RESET + "\r\n");
|
|
98
122
|
out += frame.slice(start).map(line => line + RESET).join("\r\n");
|
|
99
123
|
current = Math.max(start, frame.length - 1);
|
|
100
124
|
}
|
|
@@ -131,4 +155,5 @@ export class NativeScrollback {
|
|
|
131
155
|
this.cursorCol = 1;
|
|
132
156
|
return out;
|
|
133
157
|
}
|
|
158
|
+
dispose() { this.history.clear(); }
|
|
134
159
|
}
|
|
@@ -20,6 +20,7 @@ export declare class PromptQueueFile implements QueuePersistence {
|
|
|
20
20
|
private path;
|
|
21
21
|
load(): QueueFile | undefined;
|
|
22
22
|
save(snapshot: QueueSnapshot): void;
|
|
23
|
+
private write;
|
|
23
24
|
}
|
|
24
25
|
declare function processAlive(pid: number): boolean;
|
|
25
26
|
export declare function recoverableQueue(base: string, alive?: typeof processAlive): string | undefined;
|
|
@@ -2,6 +2,7 @@ import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, renameSync
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { validateSessionId } from "../core/session.js";
|
|
5
|
+
import { storageHealth } from "../core/storage-health.js";
|
|
5
6
|
export class PromptQueueFile {
|
|
6
7
|
base;
|
|
7
8
|
sessionId;
|
|
@@ -43,6 +44,9 @@ export class PromptQueueFile {
|
|
|
43
44
|
return data;
|
|
44
45
|
}
|
|
45
46
|
save(snapshot) {
|
|
47
|
+
storageHealth.write({ directory: this.base, sessionId: this.sessionId, kind: "queue" }, () => this.write(snapshot));
|
|
48
|
+
}
|
|
49
|
+
write(snapshot) {
|
|
46
50
|
const file = this.path(true);
|
|
47
51
|
const temporary = `${file}.${randomUUID()}.tmp`;
|
|
48
52
|
const data = { version: 1, sessionId: this.sessionId, updatedAt: Date.now(), ownerPid: process.pid, ...snapshot };
|
|
@@ -20,6 +20,8 @@ export declare class PromptQueue {
|
|
|
20
20
|
private holding;
|
|
21
21
|
readonly inbox: UserInbox;
|
|
22
22
|
constructor(prepare?: (text: string) => readonly ContentPart[], onChange?: () => void, persistence?: QueuePersistence | undefined, restoreInput?: (entry: QueuedPrompt) => QueuedPrompt);
|
|
23
|
+
/** Rilascia una coda worker dopo la chiusura definitiva della sua sessione. */
|
|
24
|
+
dispose(): void;
|
|
23
25
|
get length(): number;
|
|
24
26
|
get teamRequestCount(): number;
|
|
25
27
|
get blocked(): boolean;
|
|
@@ -37,6 +39,7 @@ export declare class PromptQueue {
|
|
|
37
39
|
add(text: string, delivery?: PromptDelivery, parts?: readonly ContentPart[], id?: string): QueuedPrompt;
|
|
38
40
|
update(id: string, text: string): boolean;
|
|
39
41
|
remove(id: string): boolean;
|
|
42
|
+
recallLast(): QueuedPrompt | undefined;
|
|
40
43
|
move(id: string, offset: number): boolean;
|
|
41
44
|
moveFirst(id: string): boolean;
|
|
42
45
|
setDelivery(id: string, delivery: PromptDelivery): boolean;
|
package/dist/tui/prompt-queue.js
CHANGED
|
@@ -40,8 +40,9 @@ export class PromptQueue {
|
|
|
40
40
|
const parts = typeof input === "string" ? queue.prepare(input) : input;
|
|
41
41
|
return queue.add(pendingText({ id: "", parts, queuedAt: 0 }), "during-turn", parts, id).id;
|
|
42
42
|
},
|
|
43
|
-
promote: id => queue.
|
|
43
|
+
promote: id => queue.sendNow(id),
|
|
44
44
|
get pending() { return queue.entries.filter(e => queue.ready(e)).length; },
|
|
45
|
+
get queued() { return queue.entries.length; },
|
|
45
46
|
onImmediate(listener) {
|
|
46
47
|
queue.immediateListeners.add(listener);
|
|
47
48
|
if (queue.immediatePending)
|
|
@@ -61,6 +62,12 @@ export class PromptQueue {
|
|
|
61
62
|
},
|
|
62
63
|
};
|
|
63
64
|
}
|
|
65
|
+
/** Rilascia una coda worker dopo la chiusura definitiva della sua sessione. */
|
|
66
|
+
dispose() {
|
|
67
|
+
this.entries = [];
|
|
68
|
+
this.delivered.clear();
|
|
69
|
+
this.immediateListeners.clear();
|
|
70
|
+
}
|
|
64
71
|
get length() { return this.entries.length; }
|
|
65
72
|
get teamRequestCount() { return this.entries.filter(e => !e.text.trimStart().startsWith("/")).length; }
|
|
66
73
|
get blocked() { return this.paused || this.held; }
|
|
@@ -128,6 +135,17 @@ export class PromptQueue {
|
|
|
128
135
|
this.changed();
|
|
129
136
|
return true;
|
|
130
137
|
}
|
|
138
|
+
// Estrae atomicamente l'ultimo messaggio ancora in attesa. Il composer lo
|
|
139
|
+
// usa per riportarlo nell'input con Freccia su: rimuoverlo prima evita che la
|
|
140
|
+
// versione originale e quella modificata possano essere consegnate entrambe.
|
|
141
|
+
recallLast() {
|
|
142
|
+
const entry = this.entries[this.entries.length - 1];
|
|
143
|
+
if (!entry)
|
|
144
|
+
return undefined;
|
|
145
|
+
this.entries = this.entries.slice(0, -1);
|
|
146
|
+
this.changed();
|
|
147
|
+
return entry;
|
|
148
|
+
}
|
|
131
149
|
move(id, offset) {
|
|
132
150
|
const from = this.entries.findIndex(e => e.id === id);
|
|
133
151
|
if (from < 0)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { tr } from "./i18n.js";
|
|
2
|
+
// Resolve display text when rendering so an existing provider follows language changes.
|
|
3
|
+
export function providerLabel(provider) {
|
|
4
|
+
if (provider.id === "claude-code")
|
|
5
|
+
return `Claude Code (${tr("abbonamento", "subscription")})`;
|
|
6
|
+
if (provider.id === "chatgpt")
|
|
7
|
+
return `ChatGPT (${tr("abbonamento", "subscription")})`;
|
|
8
|
+
return provider.label ?? provider.id;
|
|
9
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { tr } from "./i18n.js";
|
|
1
2
|
// Logica del menu provider navigabile (/provider). Parte PURA, senza
|
|
2
3
|
// dipendenze dalla TUI: calcola lo stato dei provider e incapsula le azioni di
|
|
3
4
|
// persistenza (salva chiave, salva endpoint, rimuovi). La UI in repl.ts si
|
|
@@ -88,34 +89,34 @@ export function providerRows(env, registry, currentModel) {
|
|
|
88
89
|
// Riepilogo di stato a una riga, da mostrare nel picker accanto al nome.
|
|
89
90
|
export function rowStatusLabel(row) {
|
|
90
91
|
if (row.active)
|
|
91
|
-
return "attivo";
|
|
92
|
+
return tr("attivo", "active");
|
|
92
93
|
if (row.source === "local")
|
|
93
|
-
return "locale";
|
|
94
|
+
return tr("locale", "local");
|
|
94
95
|
if (row.source === "env")
|
|
95
|
-
return "configurato (env)";
|
|
96
|
+
return tr("configurato (env)", "configured (env)");
|
|
96
97
|
if (row.source === "saved")
|
|
97
|
-
return "configurato";
|
|
98
|
-
return "da configurare";
|
|
98
|
+
return tr("configurato", "configured");
|
|
99
|
+
return tr("da configurare", "not configured");
|
|
99
100
|
}
|
|
100
101
|
// Suggerimento d'aiuto per ottenere la chiave del provider.
|
|
101
102
|
export function providerKeyHint(spec) {
|
|
102
103
|
switch (spec.id) {
|
|
103
104
|
case "openrouter":
|
|
104
|
-
return "ottieni la chiave su https://openrouter.ai/keys (sk-or-...) o usa il login OAuth";
|
|
105
|
+
return tr("ottieni la chiave su https://openrouter.ai/keys (sk-or-...) o usa il login OAuth", "Get a key at https://openrouter.ai/keys (sk-or-...) or sign in with OAuth");
|
|
105
106
|
case "anthropic":
|
|
106
|
-
return "ottieni la chiave su https://console.anthropic.com/settings/keys (sk-ant-...)";
|
|
107
|
+
return tr("ottieni la chiave su https://console.anthropic.com/settings/keys (sk-ant-...)", "Get a key at https://console.anthropic.com/settings/keys (sk-ant-...)");
|
|
107
108
|
case "openai":
|
|
108
|
-
return "ottieni la chiave su https://platform.openai.com/api-keys (sk-...)";
|
|
109
|
+
return tr("ottieni la chiave su https://platform.openai.com/api-keys (sk-...)", "Get a key at https://platform.openai.com/api-keys (sk-...)");
|
|
109
110
|
case "ollama":
|
|
110
|
-
return "provider locale: imposta solo l'endpoint (default http://localhost:11434/v1)";
|
|
111
|
+
return tr("provider locale: imposta solo l'endpoint (default http://localhost:11434/v1)", "Local provider: set the endpoint only (default http://localhost:11434/v1)");
|
|
111
112
|
case "lmstudio":
|
|
112
|
-
return "provider locale: avvia il server di LM Studio (default http://127.0.0.1:1234/v1)";
|
|
113
|
+
return tr("provider locale: avvia il server di LM Studio (default http://127.0.0.1:1234/v1)", "Local provider: start the LM Studio server (default http://127.0.0.1:1234/v1)");
|
|
113
114
|
case "opensource":
|
|
114
|
-
return "collega l'endpoint /v1 di Unsloth, vLLM, llama.cpp o qualsiasi server OpenAI-compatible";
|
|
115
|
+
return tr("collega l'endpoint /v1 di Unsloth, vLLM, llama.cpp o qualsiasi server OpenAI-compatible", "Connect the /v1 endpoint of Unsloth, vLLM, llama.cpp or any OpenAI-compatible server");
|
|
115
116
|
case "xai":
|
|
116
|
-
return "ottieni la chiave xAI per Grok su https://console.x.ai (XAI_API_KEY)";
|
|
117
|
+
return tr("ottieni la chiave xAI per Grok su https://console.x.ai (XAI_API_KEY)", "Get an xAI key for Grok at https://console.x.ai (XAI_API_KEY)");
|
|
117
118
|
default:
|
|
118
|
-
return spec.envKey ?
|
|
119
|
+
return spec.envKey ? tr("imposta la API key (variabile {p0})", "Set the API key ({p0} variable)", { p0: spec.envKey }) : tr("provider locale: nessuna chiave", "Local provider: no key required");
|
|
119
120
|
}
|
|
120
121
|
}
|
|
121
122
|
// Salva la API key di un provider sul file globale. Validazione di forma
|
|
@@ -123,21 +124,21 @@ export function providerKeyHint(spec) {
|
|
|
123
124
|
export function saveProviderKey(env, providerId, apiKey) {
|
|
124
125
|
const key = apiKey.trim();
|
|
125
126
|
if (!key)
|
|
126
|
-
return { ok: false, error: "API key vuota" };
|
|
127
|
+
return { ok: false, error: tr("API key vuota", "Empty API key") };
|
|
127
128
|
const ok = saveCredential(env, providerId, { apiKey: key });
|
|
128
|
-
return ok ? { ok: true } : { ok: false, error: "impossibile salvare (config globale disattivata?)" };
|
|
129
|
+
return ok ? { ok: true } : { ok: false, error: tr("impossibile salvare (config globale disattivata?)", "Unable to save (global configuration disabled?)") };
|
|
129
130
|
}
|
|
130
131
|
// Salva/aggiorna l'endpoint (baseUrl) di un provider. Una stringa vuota
|
|
131
132
|
// rimuove l'override e ripristina il default del catalogo.
|
|
132
133
|
export function saveProviderBaseUrl(env, providerId, baseUrl) {
|
|
133
134
|
const ok = saveCredential(env, providerId, { baseUrl: baseUrl.trim() });
|
|
134
|
-
return ok ? { ok: true } : { ok: false, error: "impossibile salvare l'endpoint" };
|
|
135
|
+
return ok ? { ok: true } : { ok: false, error: tr("impossibile salvare l'endpoint", "Unable to save the endpoint") };
|
|
135
136
|
}
|
|
136
137
|
// Rimuove la credenziale salvata di un provider. Non tocca le env esportate
|
|
137
138
|
// dall'utente (quelle hanno precedenza e restano).
|
|
138
139
|
export function removeProvider(env, providerId) {
|
|
139
140
|
const ok = deleteCredential(env, providerId);
|
|
140
|
-
return ok ? { ok: true } : { ok: false, error: "impossibile rimuovere la credenziale" };
|
|
141
|
+
return ok ? { ok: true } : { ok: false, error: tr("impossibile rimuovere la credenziale", "Unable to remove the credential") };
|
|
141
142
|
}
|
|
142
143
|
// Indica se la chiave di un provider e' stata salvata da noi (rimovibile dal
|
|
143
144
|
// menu) o proviene da una env esportata dall'utente (non rimovibile dal menu).
|
|
@@ -152,24 +153,24 @@ export function actionsFor(env, row) {
|
|
|
152
153
|
if (row.needsKey) {
|
|
153
154
|
out.push({
|
|
154
155
|
action: "set-key",
|
|
155
|
-
label: row.source === "saved" || row.source === "env" ? "aggiorna API key" : "imposta API key",
|
|
156
|
+
label: row.source === "saved" || row.source === "env" ? tr("aggiorna API key", "update API key") : tr("imposta API key", "set API key"),
|
|
156
157
|
detail: providerKeyHint(row.spec),
|
|
157
158
|
});
|
|
158
159
|
if (row.id === "openrouter") {
|
|
159
|
-
out.push({ action: "oauth", label: "accedi con OAuth (browser)", detail: "autorizza su openrouter.ai senza incollare la chiave" });
|
|
160
|
+
out.push({ action: "oauth", label: tr("accedi con OAuth (browser)", "sign in with OAuth (browser)"), detail: tr("autorizza su openrouter.ai senza incollare la chiave", "authorize on openrouter.ai without pasting a key") });
|
|
160
161
|
}
|
|
161
162
|
}
|
|
162
163
|
out.push({
|
|
163
164
|
action: "set-endpoint",
|
|
164
|
-
label: "imposta endpoint (baseUrl)",
|
|
165
|
-
detail: row.baseUrl ?
|
|
165
|
+
label: tr("imposta endpoint (baseUrl)", "set endpoint (baseUrl)"),
|
|
166
|
+
detail: row.baseUrl ? tr("attuale: {p0}", "current: {p0}", { p0: row.baseUrl }) : tr("endpoint API personalizzato", "custom API endpoint"),
|
|
166
167
|
});
|
|
167
168
|
if (row.configured) {
|
|
168
|
-
out.push({ action: "use-model", label: "scegli un modello di questo provider", detail: "apre il picker dei modelli" });
|
|
169
|
+
out.push({ action: "use-model", label: tr("scegli un modello di questo provider", "choose a model from this provider"), detail: tr("apre il picker dei modelli", "opens the model picker") });
|
|
169
170
|
}
|
|
170
171
|
if (isRemovable(env, row.id)) {
|
|
171
|
-
out.push({ action: "remove", label: "rimuovi credenziale salvata", detail: "elimina chiave/endpoint dal config" });
|
|
172
|
+
out.push({ action: "remove", label: tr("rimuovi credenziale salvata", "remove saved credential"), detail: tr("elimina chiave/endpoint dal config", "removes the key/endpoint from configuration") });
|
|
172
173
|
}
|
|
173
|
-
out.push({ action: "back", label: "← torna all'elenco", detail: "" });
|
|
174
|
+
out.push({ action: "back", label: tr("← torna all'elenco", "← back to the list"), detail: "" });
|
|
174
175
|
return out;
|
|
175
176
|
}
|
package/dist/tui/queue-screen.js
CHANGED
|
@@ -20,7 +20,8 @@ export function queuePreview(queue, width, style = PLAIN_QUEUE_STYLE, idle = fal
|
|
|
20
20
|
const shortMode = immediate ? next.teamBatchId ? tr("invio al team", "to team") : tr("invio", "sending") : paused ? tr("pausa", "paused")
|
|
21
21
|
: next.delivery === "during-turn" ? tr("dopo risposta/operazione", "after response/tool") : tr("dopo risposta", "after response");
|
|
22
22
|
const short = queue.length === 1 ? `${noun} · ${shortMode}` : `${queue.length} · ${shortMode}`;
|
|
23
|
-
const keys = [
|
|
23
|
+
const keys = [tr("↑ modifica ultimo", "↑ edit last"),
|
|
24
|
+
paused && idle ? tr("Invio riprende", "Enter resume") : !immediate && !next.text.trimStart().startsWith("/") ? tr("Alt+S subito", "Alt+S send now") : "",
|
|
24
25
|
"Alt+Q", queue.teamRequestCount >= 3 ? "Alt+T team" : ""].filter(Boolean);
|
|
25
26
|
const max = Math.max(0, width - 1);
|
|
26
27
|
let hint = ` (${keys.join(" · ")})`;
|
|
@@ -64,7 +64,7 @@ export class QueuedQuestions {
|
|
|
64
64
|
this.hide();
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
67
|
-
if (text === "\x1d" || key.ctrl && key.name === "]") {
|
|
67
|
+
if (key.name === "delete" || text === "\x1d" || key.ctrl && key.name === "]") {
|
|
68
68
|
q.finish(null);
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
@@ -100,8 +100,6 @@ export class QueuedQuestions {
|
|
|
100
100
|
q.text = q.text.slice(0, q.cursor - 1) + q.text.slice(q.cursor);
|
|
101
101
|
q.cursor--;
|
|
102
102
|
}
|
|
103
|
-
else if (key.name === "delete")
|
|
104
|
-
q.text = q.text.slice(0, q.cursor) + q.text.slice(q.cursor + 1);
|
|
105
103
|
else if (text && !key.ctrl && !key.meta && !/[\x00-\x1f\x7f]/.test(text)) {
|
|
106
104
|
this.paste(text);
|
|
107
105
|
return;
|
|
@@ -145,7 +143,7 @@ export class QueuedQuestions {
|
|
|
145
143
|
if (index === q.index)
|
|
146
144
|
selectedEnd = body.length;
|
|
147
145
|
});
|
|
148
|
-
const shortcuts = tr("Invio invia ·
|
|
146
|
+
const shortcuts = tr("Invio invia · Canc salta · Alt+↓ prompt", "Enter submit · Del skip · Alt+↓ main prompt");
|
|
149
147
|
const footer = wrapText(shortcuts, bodyWidth, true).map(row => style.muted(" " + row));
|
|
150
148
|
const page = Math.max(1, maxRows - footer.length - 2);
|
|
151
149
|
if (q.offset < 0)
|
package/dist/tui/quick-help.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const QUICK_HELP = "## Inizia qui\nScrivi una richiesta e premi **Invio**. Talos mostra la risposta nella chat; l'input resta in basso.\n\n### Token e contesto\n- **Contesto~** mostra una barra breve con token e percentuale **attivi** e **archiviati**, stimati rispetto alla finestra del modello. Il valore dopo **/** \u00E8 la capacit\u00E0 della finestra. Sotto l'input, **7g** \u00E8 la quota settimanale residua e **reset** il tempo rimasto; **~** davanti alla quota indica un dato non recente. Tutte le finestre e i consumi restano in **/usage**.\n- I blocchi **lime** rappresentano il contesto attivo; i **grigi** la quantit\u00E0 originale archiviata, dal pi\u00F9 vecchio (scuro) al pi\u00F9 recente (chiaro). **Archiviato** e **attivo** hanno percentuali separate rispetto alla finestra del modello. Il materiale grigio \u00E8 conservato fuori dalla finestra viva; riassunti e riferimenti fanno parte dell'attivo. **\u00D7N** indica la scala della barra quando il totale supera una finestra. Dettagli in **/context**.\n- Il totale in **/usage** somma i token delle chiamate della sessione, anche input ripetuti e cache: non indica il contesto di una singola richiesta. **\u2265** significa totale parziale.\n- Talos seleziona informazioni rilevanti e gestisce la cronologia con recupero e compattazione secondo la configurazione; i consumi del provider restano reali.\n- **ctx~** \u00E8 una stima locale del contesto, non la misura esatta del payload inviato. La quota ChatGPT \u00E8 separata. **/usage** mostra dettagli, cache e ultima chiamata.\n\n### Copiare e incollare\n- **/copy** copia l'ultima risposta testuale, senza colori del terminale (mantiene il Markdown).\n- **/copy una frase** copia soltanto il testo scritto dopo il comando.\n- Per selezionare una frase dalla chat: trascina il mouse senza tenere Shift, poi usa **Ctrl+Shift+C** (Windows/Linux) o **Cmd+C** (macOS). Dipende dalle impostazioni del terminale.\n- Incolla testo con **Ctrl+Shift+V** o **Cmd+V**. **Alt+V** legge un'immagine dagli appunti; puoi anche usare **/img percorso**.\n- I riferimenti **img #N** e **txt #N** sono evidenziati in ciano nel campo di input e nella chat; il contenuto completo viene allegato all'invio.\n- **Ctrl+C non \u00E8 il comando di copia di Talos.**\n\n### Fermare senza perdere il controllo\n- Primo **Ctrl+C**: avviso, nessuna azione. Secondo **Ctrl+C entro 2 secondi**: conferma l'azione indicata (fermare il lavoro, svuotare la bozza o uscire).\n- Un altro tasto annulla la conferma. **Esc** ferma subito il lavoro; in un menu o una domanda chiude solo quel pannello.\n- Fermare il lavoro conserva i messaggi in coda e li mette in pausa. **Alt+Q** apre la gestione per riprenderli o eliminarli. I processi in background si gestiscono con **/bg**.\n- **/quit** esce direttamente. Le chat gi\u00E0 inviate restano salvate; le bozze non sono salvate.\n\n### Messaggi in attesa\n- Sopra l'input, il punto **\u2022** indica i messaggi in attesa e quando verranno consegnati; la riga rientrata **\u21B3** mostra il prossimo messaggio. Normalmente partono in ordine dopo la risposta corrente; **Alt+Q** mostra tutti i messaggi.\n- **Alt+Q** o **/queue** (anche **/coda**) apre subito la coda: frecce per scegliere, **Invio** modifica, **Canc** elimina, **Shift+Su/Gi\u00F9** riordina, **p** mette in pausa o riprende.\n- **Alt+S** invia subito il testo che stai scrivendo, anche durante la risposta; se l'input \u00E8 vuoto, invia la prima richiesta in coda. Nella coda, **s \u00B7 Invia subito** invia il messaggio selezionato. Talos interrompe la generazione e riparte con il nuovo input; un'operazione gi\u00E0 avviata termina prima. **Alt+Invio** \u00E8 un alias nei terminali che lo inoltrano.\n- Con **almeno 3 richieste** in coda, **Alt+T** le invia subito insieme e chiede all'agente di ingaggiare il team per implementarle tutte. Nella gestione coda puoi usare anche **g \u00B7 Invia al team**. I comandi sono esclusi e la bozza che stai scrivendo resta intatta. Fino alla consegna puoi ancora modificare le singole richieste; il gruppo viene conservato anche al riavvio, in pausa.\n- **t** sceglie tra \u201Cdopo la risposta\u201D e \u201Cdurante il lavoro\u201D. Questa seconda modalit\u00E0 attende la risposta o l'operazione corrente senza interromperla.\n- Mentre gestisci o modifichi la coda nessun messaggio viene consegnato. **Invio** salva la modifica, **Esc** la annulla e conserva l'originale. La bozza precedente resta intatta.\n- Un messaggio compare nella conversazione solo alla consegna, con l'etichetta **Dalla coda \u00B7 consegnato**. Da quel momento non \u00E8 pi\u00F9 modificabile nella coda.\n- La coda \u00E8 salvata per chat, con ordine, modifiche confermate, testo incollato e immagini. Dopo la chiusura, il normale avvio riprende la chat con l'ultima coda pendente; una chat scelta esplicitamente ha precedenza. Aprire la chat lascia i messaggi **in pausa**. Quando Talos \u00E8 a riposo, **Invio** riprende la coda, anche con input vuoto; un nuovo prompt viene aggiunto in fondo e avvia la consegna. Puoi anche usare **Alt+Q**, poi **p** per riprenderli oppure **s** per inviarne uno subito.\n\n### Modalit\u00E0 fast\n- **/fast on** attiva la modalit\u00E0 veloce per ChatGPT/OpenAI, **/fast off** la disattiva, **/fast status** mostra lo stato. Quando \u00E8 attiva, **fast** compare accanto al modello. La preferenza \u00E8 salvata per i prossimi avvii.\n- Fast richiede il relativo supporto del modello e del provider e pu\u00F2 aumentare i consumi.\n\n### Ritrovare le chat\n- **/new** apre una chat vuota: la precedente resta salvata.\n- **/chats** (o **/resume**) apre la ricerca delle chat salvate; scrivi per filtrare, usa le frecce e Invio, Esc per annullare.\n- **/rename Titolo** assegna un nome riconoscibile alla chat corrente.\n- **/sessions** mostra gli ID; **/resume ID** riprende una chat specifica.\n\n### Leggere e navigare\n- **PageUp / PageDown**, rotella o **Shift+Su/Gi\u00F9** scorrono la conversazione senza spostare l'input.\n- **Su/Gi\u00F9** in fondo alla chat richiamano le richieste precedenti. **Tab** completa i comandi.\n- **Ctrl+R** apre la revisione delle attivit\u00E0; **Ctrl+O** apre l'elenco dei file modificati: frecce per scegliere, Invio per leggere il confronto, Esc per tornare. **Ctrl+G** o **/todo** apre la lista delle attivit\u00E0, con gruppi e stati: da fare, in corso, completata e fallita.\n- **/commands** apre tutti i comandi, con ricerca. **/help** riapre questa guida.\n\nLe scorciatoie descritte valgono nella TUI interattiva. In terminali remoti, copia e selezione dipendono anche dal client; /copy usa gli appunti della macchina dove gira Talos.\n";
|
|
1
|
+
export declare const QUICK_HELP = "## Inizia qui\nScrivi una richiesta e premi **Invio**. Talos mostra la risposta nella chat; l'input resta in basso.\n\n### Token e contesto\n- **Contesto~** mostra una barra breve con token e percentuale **attivi** e **archiviati**, stimati rispetto alla finestra del modello. Il valore dopo **/** \u00E8 la capacit\u00E0 della finestra. Sotto l'input, **7g** \u00E8 la quota settimanale residua e **reset** il tempo rimasto; **~** davanti alla quota indica un dato non recente. Tutte le finestre e i consumi restano in **/usage**.\n- I blocchi **lime** rappresentano il contesto attivo; i **grigi** la quantit\u00E0 originale archiviata, dal pi\u00F9 vecchio (scuro) al pi\u00F9 recente (chiaro). **Archiviato** e **attivo** hanno percentuali separate rispetto alla finestra del modello. Il materiale grigio \u00E8 conservato fuori dalla finestra viva; riassunti e riferimenti fanno parte dell'attivo. **\u00D7N** indica la scala della barra quando il totale supera una finestra. Dettagli in **/context**.\n- Il totale in **/usage** somma i token delle chiamate della sessione, anche input ripetuti e cache: non indica il contesto di una singola richiesta. **\u2265** significa totale parziale.\n- Talos seleziona informazioni rilevanti e gestisce la cronologia con recupero e compattazione secondo la configurazione; i consumi del provider restano reali.\n- **ctx~** \u00E8 una stima locale del contesto, non la misura esatta del payload inviato. La quota ChatGPT \u00E8 separata. **/usage** mostra dettagli, cache e ultima chiamata.\n\n### Copiare e incollare\n- **/copy** copia l'ultima risposta testuale, senza colori del terminale (mantiene il Markdown).\n- **/copy una frase** copia soltanto il testo scritto dopo il comando.\n- Per selezionare una frase dalla chat: trascina il mouse senza tenere Shift, poi usa **Ctrl+Shift+C** (Windows/Linux) o **Cmd+C** (macOS). Dipende dalle impostazioni del terminale.\n- Incolla testo con **Ctrl+Shift+V** o **Cmd+V**. **Alt+V** legge un'immagine dagli appunti; puoi anche usare **/img percorso**.\n- I riferimenti **img #N** e **txt #N** sono evidenziati in ciano nel campo di input e nella chat; il contenuto completo viene allegato all'invio.\n- **Ctrl+C non \u00E8 il comando di copia di Talos.**\n\n### Fermare senza perdere il controllo\n- Se il salvataggio di conversazione, coda o consumi fallisce, compare un avviso con la causa (per esempio disco pieno o permesso negato). Resta visibile finch\u00E9 le scritture falliscono; dopo una scrittura riuscita scompare in 5 secondi. La ripresa non garantisce il recupero dei dati precedenti non salvati.\n- Primo **Ctrl+C**: avviso, nessuna azione. Secondo **Ctrl+C entro 2 secondi**: conferma l'azione indicata (fermare il lavoro, svuotare la bozza o uscire).\n- Un altro tasto annulla la conferma. **Esc** ferma subito il lavoro; in un menu o una domanda chiude solo quel pannello.\n- Fermare il lavoro conserva i messaggi in coda e li mette in pausa. **Alt+Q** apre la gestione per riprenderli o eliminarli. I processi in background si gestiscono con **/bg**.\n- **/quit** esce direttamente. Le chat gi\u00E0 inviate restano salvate; le bozze non sono salvate.\n\n### Messaggi in attesa\n- **Shift+\u2190** apre le domande in coda. **Invio** invia la risposta; **Canc** salta la domanda aperta. **Alt+\u2193** torna al prompt conservando la domanda e la bozza della risposta.\n- Sopra l'input, il punto **\u2022** indica i messaggi in attesa e quando verranno consegnati; la riga rientrata **\u21B3** mostra il prossimo messaggio. Normalmente partono in ordine dopo la risposta corrente; **Alt+Q** mostra tutti i messaggi.\n- **Alt+Q** o **/queue** (anche **/coda**) apre subito la coda: frecce per scegliere, **Invio** modifica, **Canc** elimina, **Shift+Su/Gi\u00F9** riordina, **p** mette in pausa o riprende.\n- **Alt+S** invia subito il testo che stai scrivendo, anche durante la risposta; se l'input \u00E8 vuoto, invia la prima richiesta in coda. Nella coda, **s \u00B7 Invia subito** invia il messaggio selezionato. Talos interrompe la generazione e riparte con il nuovo input; un'operazione gi\u00E0 avviata termina prima. **Alt+Invio** \u00E8 un alias nei terminali che lo inoltrano.\n- Con **almeno 3 richieste** in coda, **Alt+T** le invia subito insieme e chiede all'agente di ingaggiare il team per implementarle tutte. Nella gestione coda puoi usare anche **g \u00B7 Invia al team**. I comandi sono esclusi e la bozza che stai scrivendo resta intatta. Fino alla consegna puoi ancora modificare le singole richieste; il gruppo viene conservato anche al riavvio, in pausa.\n- **t** sceglie tra \u201Cdopo la risposta\u201D e \u201Cdurante il lavoro\u201D. Questa seconda modalit\u00E0 attende la risposta o l'operazione corrente senza interromperla.\n- Mentre gestisci o modifichi la coda nessun messaggio viene consegnato. **Invio** salva la modifica, **Esc** la annulla e conserva l'originale. La bozza precedente resta intatta.\n- Un messaggio compare nella conversazione solo alla consegna, con l'etichetta **Dalla coda \u00B7 consegnato**. Da quel momento non \u00E8 pi\u00F9 modificabile nella coda.\n- La coda \u00E8 salvata per chat, con ordine, modifiche confermate, testo incollato e immagini. Dopo la chiusura, il normale avvio riprende la chat con l'ultima coda pendente; una chat scelta esplicitamente ha precedenza. Aprire la chat lascia i messaggi **in pausa**. Quando Talos \u00E8 a riposo, **Invio** riprende la coda, anche con input vuoto; un nuovo prompt viene aggiunto in fondo e avvia la consegna. Puoi anche usare **Alt+Q**, poi **p** per riprenderli oppure **s** per inviarne uno subito.\n\n### Modalit\u00E0 fast\n- **/fast on** attiva la modalit\u00E0 veloce per ChatGPT/OpenAI, **/fast off** la disattiva, **/fast status** mostra lo stato. Quando \u00E8 attiva, **fast** compare accanto al modello. La preferenza \u00E8 salvata per i prossimi avvii.\n- Fast richiede il relativo supporto del modello e del provider e pu\u00F2 aumentare i consumi.\n\n### Ritrovare le chat\n- **/new** apre una chat vuota: la precedente resta salvata.\n- **/chats** (o **/resume**) apre la ricerca delle chat salvate; scrivi per filtrare, usa le frecce e Invio, Esc per annullare.\n- **/rename Titolo** assegna un nome riconoscibile alla chat corrente.\n- **/sessions** mostra gli ID; **/resume ID** riprende una chat specifica.\n\n### Leggere e navigare\n- Con collaboratori attivi, **Gi\u00F9** dal prompt vuoto seleziona le sessioni; **Alt+A** o **/agents** attiva lo stesso elenco. **Su/Gi\u00F9** seleziona e **Invio** apre. Ogni riga mostra attivit\u00E0, durata e token. Per tornare scegli **main** e premi **Invio**; se il collaboratore visualizzato viene rimosso, il ritorno a **main** \u00E8 automatico. Nella sua vista **PageUp/PageDown** scorre l'output e **End** riprende il seguito automatico.\n- **PageUp / PageDown**, rotella o **Shift+Su/Gi\u00F9** scorrono la conversazione senza spostare l'input.\n- **Su/Gi\u00F9** in fondo alla chat richiamano le richieste precedenti. **Tab** completa i comandi.\n- **Ctrl+R** apre la revisione delle attivit\u00E0; **Ctrl+O** apre l'elenco dei file modificati: frecce per scegliere, Invio per leggere il confronto, Esc per tornare. **Ctrl+G** o **/todo** apre la lista delle attivit\u00E0, con gruppi e stati: da fare, in corso, completata e fallita.\n- **/commands** apre tutti i comandi, con ricerca. **/help** riapre questa guida.\n\nLe scorciatoie descritte valgono nella TUI interattiva. In terminali remoti, copia e selezione dipendono anche dal client; /copy usa gli appunti della macchina dove gira Talos.\n";
|
package/dist/tui/quick-help.js
CHANGED
|
@@ -18,12 +18,14 @@ Scrivi una richiesta e premi **Invio**. Talos mostra la risposta nella chat; l'i
|
|
|
18
18
|
- **Ctrl+C non è il comando di copia di Talos.**
|
|
19
19
|
|
|
20
20
|
### Fermare senza perdere il controllo
|
|
21
|
+
- Se il salvataggio di conversazione, coda o consumi fallisce, compare un avviso con la causa (per esempio disco pieno o permesso negato). Resta visibile finché le scritture falliscono; dopo una scrittura riuscita scompare in 5 secondi. La ripresa non garantisce il recupero dei dati precedenti non salvati.
|
|
21
22
|
- Primo **Ctrl+C**: avviso, nessuna azione. Secondo **Ctrl+C entro 2 secondi**: conferma l'azione indicata (fermare il lavoro, svuotare la bozza o uscire).
|
|
22
23
|
- Un altro tasto annulla la conferma. **Esc** ferma subito il lavoro; in un menu o una domanda chiude solo quel pannello.
|
|
23
24
|
- Fermare il lavoro conserva i messaggi in coda e li mette in pausa. **Alt+Q** apre la gestione per riprenderli o eliminarli. I processi in background si gestiscono con **/bg**.
|
|
24
25
|
- **/quit** esce direttamente. Le chat già inviate restano salvate; le bozze non sono salvate.
|
|
25
26
|
|
|
26
27
|
### Messaggi in attesa
|
|
28
|
+
- **Shift+←** apre le domande in coda. **Invio** invia la risposta; **Canc** salta la domanda aperta. **Alt+↓** torna al prompt conservando la domanda e la bozza della risposta.
|
|
27
29
|
- Sopra l'input, il punto **•** indica i messaggi in attesa e quando verranno consegnati; la riga rientrata **↳** mostra il prossimo messaggio. Normalmente partono in ordine dopo la risposta corrente; **Alt+Q** mostra tutti i messaggi.
|
|
28
30
|
- **Alt+Q** o **/queue** (anche **/coda**) apre subito la coda: frecce per scegliere, **Invio** modifica, **Canc** elimina, **Shift+Su/Giù** riordina, **p** mette in pausa o riprende.
|
|
29
31
|
- **Alt+S** invia subito il testo che stai scrivendo, anche durante la risposta; se l'input è vuoto, invia la prima richiesta in coda. Nella coda, **s · Invia subito** invia il messaggio selezionato. Talos interrompe la generazione e riparte con il nuovo input; un'operazione già avviata termina prima. **Alt+Invio** è un alias nei terminali che lo inoltrano.
|
|
@@ -44,6 +46,7 @@ Scrivi una richiesta e premi **Invio**. Talos mostra la risposta nella chat; l'i
|
|
|
44
46
|
- **/sessions** mostra gli ID; **/resume ID** riprende una chat specifica.
|
|
45
47
|
|
|
46
48
|
### Leggere e navigare
|
|
49
|
+
- Con collaboratori attivi, **Giù** dal prompt vuoto seleziona le sessioni; **Alt+A** o **/agents** attiva lo stesso elenco. **Su/Giù** seleziona e **Invio** apre. Ogni riga mostra attività, durata e token. Per tornare scegli **main** e premi **Invio**; se il collaboratore visualizzato viene rimosso, il ritorno a **main** è automatico. Nella sua vista **PageUp/PageDown** scorre l'output e **End** riprende il seguito automatico.
|
|
47
50
|
- **PageUp / PageDown**, rotella o **Shift+Su/Giù** scorrono la conversazione senza spostare l'input.
|
|
48
51
|
- **Su/Giù** in fondo alla chat richiamano le richieste precedenti. **Tab** completa i comandi.
|
|
49
52
|
- **Ctrl+R** apre la revisione delle attività; **Ctrl+O** apre l'elenco dei file modificati: frecce per scegliere, Invio per leggere il confronto, Esc per tornare. **Ctrl+G** o **/todo** apre la lista delle attività, con gruppi e stati: da fare, in corso, completata e fallita.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TuiTheme } from "./branding.js";
|
|
2
|
+
interface Uscita {
|
|
3
|
+
write(text: string): void;
|
|
4
|
+
writeConversation?(text: string): void;
|
|
5
|
+
}
|
|
6
|
+
export declare function comandoRemoto(args: string, out: Uscita, theme: TuiTheme, env: NodeJS.ProcessEnv, cwd: string, avvisa: (testo: string) => void): Promise<void>;
|
|
7
|
+
export {};
|