@vascend/talos 0.1.5 → 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/dist/core/agent.d.ts +16 -3
- package/dist/core/agent.js +114 -34
- 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.js +4 -0
- package/dist/core/session.d.ts +4 -2
- package/dist/core/session.js +13 -4
- 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/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 +10 -3
- 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 +12 -2
- package/dist/tui/agent-sessions-screen.js +62 -16
- package/dist/tui/agent-sessions.d.ts +14 -0
- package/dist/tui/agent-sessions.js +67 -6
- package/dist/tui/bottom-input.d.ts +46 -2
- package/dist/tui/bottom-input.js +358 -59
- 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 +4 -1
- 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 +312 -1
- 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/model-details.js +13 -12
- package/dist/tui/model-picker.js +17 -7
- package/dist/tui/model-selection.js +19 -10
- package/dist/tui/native-scrollback.js +5 -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/remote-command.d.ts +7 -0
- package/dist/tui/remote-command.js +79 -0
- package/dist/tui/repl.d.ts +8 -2
- package/dist/tui/repl.js +355 -311
- package/dist/tui/review-store.d.ts +1 -0
- package/dist/tui/review-store.js +28 -7
- 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/selector-mouse.d.ts +1 -0
- package/dist/tui/selector-mouse.js +1 -1
- package/dist/tui/selector.d.ts +7 -0
- package/dist/tui/selector.js +19 -2
- package/dist/tui/session-controls.d.ts +26 -0
- package/dist/tui/session-controls.js +65 -0
- package/dist/tui/session-naming-notice.js +5 -3
- 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/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-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.js +4 -2
- package/dist/vascend/context-store-reader.d.ts +20 -0
- package/dist/vascend/context-store-reader.js +46 -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 +22 -15
- 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 +20 -13
- package/dist/vascend/memory-packet.d.ts +2 -1
- package/dist/vascend/memory-packet.js +31 -44
- package/dist/vascend/plan-store.d.ts +3 -1
- package/dist/vascend/plan-store.js +6 -4
- package/dist/vascend/room-memory.d.ts +10 -1
- package/dist/vascend/room-memory.js +42 -2
- 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 +1 -1
package/dist/tui/startup.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { TALOS_VERSION } from "../core/version.js";
|
|
2
|
+
import { talosArtwork } from "./talos-art.js";
|
|
2
3
|
import { tr } from "./i18n.js";
|
|
3
4
|
import { fitLine, oneLine, padLine, terminalWidth, wrapText } from "./terminal-text.js";
|
|
4
5
|
function modelLabel(d, t, width) {
|
|
@@ -11,51 +12,80 @@ export function permissionLabel(mode = "normal") {
|
|
|
11
12
|
const labels = { normal: tr("Conferma azioni", "Ask before actions"), acceptEdits: tr("Modifiche automatiche", "Automatic edits"), auto: tr("Senza conferme", "No confirmations") };
|
|
12
13
|
return labels[mode] ?? labels["normal"];
|
|
13
14
|
}
|
|
14
|
-
//
|
|
15
|
+
// Keep the project name visible instead of wrapping a Windows path mid-word.
|
|
16
|
+
// Both path separators are supported, independently of the host platform.
|
|
17
|
+
function workspaceLabel(value, width) {
|
|
18
|
+
const path = oneLine(value);
|
|
19
|
+
if (terminalWidth(path) <= width)
|
|
20
|
+
return path;
|
|
21
|
+
const end = path.replace(/[\\/]+$/, "");
|
|
22
|
+
const split = Math.max(end.lastIndexOf("/"), end.lastIndexOf("\\"));
|
|
23
|
+
if (split < 0)
|
|
24
|
+
return fitLine(path, width);
|
|
25
|
+
const suffix = "…" + end.slice(split);
|
|
26
|
+
if (terminalWidth(suffix) >= width)
|
|
27
|
+
return fitLine(suffix, width);
|
|
28
|
+
const budget = width - terminalWidth(suffix);
|
|
29
|
+
const prefix = oneLine(fitLine(end.slice(0, split), budget, false));
|
|
30
|
+
const boundary = Math.max(prefix.lastIndexOf("/"), prefix.lastIndexOf("\\"));
|
|
31
|
+
return (boundary >= 0 ? prefix.slice(0, boundary + 1) : prefix) + suffix;
|
|
32
|
+
}
|
|
33
|
+
// The native renderer refreshes this header when the settings or viewport change.
|
|
15
34
|
export function buildTerminalStartup(d, t) {
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
35
|
+
const available = Math.max(0, Math.floor(d.width) - 1);
|
|
36
|
+
const framed = available >= 24;
|
|
37
|
+
const inset = framed ? " " : "";
|
|
38
|
+
const inner = framed ? Math.min(88, available - 7) : available;
|
|
39
|
+
const fullContent = Math.max(1, inner - terminalWidth(inset) * 2);
|
|
40
|
+
const art = talosArtwork(Math.min(30, fullContent));
|
|
41
|
+
const artWidth = Math.max(0, ...art.map(terminalWidth));
|
|
42
|
+
const artBeside = art.length > 0 && fullContent >= artWidth + 3 + 35;
|
|
43
|
+
const content = artBeside ? fullContent - artWidth - 3 : fullContent;
|
|
44
|
+
const brand = t.accent(">_ ") + t.bold(t.silver("Vascend Talos"));
|
|
45
|
+
const version = t.muted(`v${TALOS_VERSION}`);
|
|
46
|
+
const gap = content - terminalWidth(brand) - terminalWidth(version);
|
|
47
|
+
const body = gap >= 2
|
|
48
|
+
? [brand + " ".repeat(gap) + version]
|
|
49
|
+
: [fitLine(brand, content), fitLine(version, content)];
|
|
50
|
+
if (content >= 30)
|
|
51
|
+
body.push(t.muted(fitLine(tr("Sviluppato da Vascend Technologies", "Developed by Vascend Technologies"), content)));
|
|
52
|
+
body.push("");
|
|
53
|
+
const labels = {
|
|
54
|
+
model: tr("Modello", "Model"), workspace: "Workspace",
|
|
55
|
+
permissions: tr("Permessi", "Permissions"), chat: "Chat",
|
|
56
|
+
};
|
|
57
|
+
const labelWidth = Math.max(...Object.values(labels).map(terminalWidth)) + 2;
|
|
58
|
+
const stacked = content < labelWidth + 22;
|
|
59
|
+
const valueWidth = Math.max(1, content - (stacked ? 2 : labelWidth));
|
|
60
|
+
const field = (label, rows) => {
|
|
26
61
|
if (stacked) {
|
|
27
62
|
body.push(t.muted(label));
|
|
28
|
-
body.push(...
|
|
63
|
+
body.push(...rows.map(line => " " + line));
|
|
29
64
|
}
|
|
30
65
|
else {
|
|
31
|
-
|
|
32
|
-
body.push(...rows.map((line, i) => (i === 0 ? t.muted(label.padEnd(labelWidth)) : " ".repeat(labelWidth)) + paint(line)));
|
|
66
|
+
body.push(...rows.map((line, index) => (index === 0 ? t.muted(padLine(label, labelWidth)) : " ".repeat(labelWidth)) + line));
|
|
33
67
|
}
|
|
34
68
|
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const shortcut = tr(" /model cambia", " /model change");
|
|
41
|
-
if (terminalWidth(model) + shortcut.length <= inner - labelWidth)
|
|
42
|
-
model += t.accent(shortcut);
|
|
43
|
-
body.push(t.muted(tr("modello:", "model:").padEnd(labelWidth)) + model);
|
|
44
|
-
}
|
|
45
|
-
field(tr("cartella:", "directory:"), d.cwd, t.silver);
|
|
46
|
-
field(tr("permessi:", "permissions:"), permission, permissionPaint);
|
|
69
|
+
field(labels.model, [modelLabel(d, t, valueWidth)]);
|
|
70
|
+
field(labels.workspace, [t.silver(workspaceLabel(d.cwd, valueWidth))]);
|
|
71
|
+
const permission = (d.permissions === "auto" ? "! " : "") + permissionLabel(d.permissions);
|
|
72
|
+
const permissionPaint = d.permissions === "auto" ? t.yellow : t.silver;
|
|
73
|
+
field(labels.permissions, wrapText(permission, valueWidth, true).map(line => permissionPaint(line)));
|
|
47
74
|
if (d.sessionLabel)
|
|
48
|
-
field(
|
|
49
|
-
if (
|
|
50
|
-
return body.map(line => fitLine(line,
|
|
51
|
-
const
|
|
52
|
-
|
|
75
|
+
field(labels.chat, [t.silver(fitLine(oneLine(d.sessionLabel), valueWidth))]);
|
|
76
|
+
if (!framed)
|
|
77
|
+
return body.map(line => fitLine(line, available));
|
|
78
|
+
const decorated = artBeside
|
|
79
|
+
? Array.from({ length: Math.max(body.length, art.length) }, (_, i) => padLine(body[i] ?? "", content) + " " + (art[i] ?? ""))
|
|
80
|
+
: art.length ? [...body, "", ...art.map(line => " ".repeat(Math.floor((fullContent - artWidth) / 2)) + line)] : body;
|
|
81
|
+
const edge = (left, right) => " " + t.chatBorder(left + "─".repeat(inner + 2) + right);
|
|
82
|
+
return [edge("╭", "╮"), ...decorated.map(line => " " + t.chatBorder("│ ") + padLine(inset + fitLine(line, fullContent), inner) + t.chatBorder(" │")), edge("╰", "╯")];
|
|
53
83
|
}
|
|
54
84
|
export function buildStartupRuntime(d, t) {
|
|
55
85
|
const width = Math.max(1, d.width - 3);
|
|
56
86
|
let line = modelLabel(d, t, width);
|
|
57
87
|
const remaining = width - terminalWidth(line) - 3;
|
|
58
88
|
if (remaining >= 8)
|
|
59
|
-
line += t.dim(" · ") + t.muted(
|
|
60
|
-
return fitLine(" " + line, Math.max(
|
|
89
|
+
line += t.dim(" · ") + t.muted(workspaceLabel(d.cwd, remaining));
|
|
90
|
+
return fitLine(" " + line, Math.max(0, d.width - 1));
|
|
61
91
|
}
|
|
@@ -35,4 +35,4 @@ export declare const DEFAULT_ORDER: readonly string[];
|
|
|
35
35
|
export declare const BUILTIN_SEGMENTS: Readonly<Record<string, SegmentRender>>;
|
|
36
36
|
export declare function buildStatusLine(d: StatusData, theme: TuiTheme, opts?: StatusOptions): string;
|
|
37
37
|
export declare function buildTerminalHeader(d: StatusData, theme: TuiTheme): readonly string[];
|
|
38
|
-
export declare function buildTerminalWelcome(width: number, theme: TuiTheme): string;
|
|
38
|
+
export declare function buildTerminalWelcome(width: number, theme: TuiTheme, accountNote?: string): string;
|
package/dist/tui/status-line.js
CHANGED
|
@@ -104,17 +104,13 @@ export const BUILTIN_SEGMENTS = {
|
|
|
104
104
|
const head = r.castles > 1 ? `◆ ${r.castles} gruppi · ${r.done}/${r.total}` : `◆ ${r.done}/${r.total}`;
|
|
105
105
|
return t.silver(head) + t.dark(" Ctrl+G");
|
|
106
106
|
},
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
// perche' StatusData.bg viene ricalcolato dal backgroundManager.
|
|
107
|
+
// Count only live commands. Completed output remains available in /bg,
|
|
108
|
+
// but its history must not look like terminals left open.
|
|
110
109
|
bg: (d, t) => {
|
|
111
110
|
const b = d.bg;
|
|
112
|
-
if (!b ||
|
|
111
|
+
if (!b || b.running <= 0)
|
|
113
112
|
return null;
|
|
114
|
-
|
|
115
|
-
? t.accent("⚙ ") + t.silver(`${b.running}/${b.total} bg`)
|
|
116
|
-
: t.dark("⚙ ") + t.muted(`${b.total} bg`);
|
|
117
|
-
return head + t.dark(" /bg");
|
|
113
|
+
return t.silver(tr("{count} bg attivi", "{count} bg running", { count: b.running })) + t.dark(" /bg");
|
|
118
114
|
},
|
|
119
115
|
time: (_d, t) => {
|
|
120
116
|
const dt = new Date();
|
|
@@ -205,9 +201,21 @@ export function buildTerminalHeader(d, theme) {
|
|
|
205
201
|
const context = theme.muted(tr("Progetto ", "Project ")) + theme.silver(project) + theme.muted(chat);
|
|
206
202
|
return [...identity, context].map((line) => " " + fitLine(line, width));
|
|
207
203
|
}
|
|
208
|
-
export function buildTerminalWelcome(width, theme) {
|
|
209
|
-
const
|
|
210
|
-
|
|
204
|
+
export function buildTerminalWelcome(width, theme, accountNote = "") {
|
|
205
|
+
const available = Math.max(0, width - 3);
|
|
206
|
+
const shortcuts = [
|
|
207
|
+
{ command: "/model", label: tr("Modello", "Model") },
|
|
208
|
+
{ command: "/chats", label: tr("Chat recenti", "Recent chats") },
|
|
209
|
+
{ command: "/help", label: tr("Guida", "Help") },
|
|
211
210
|
];
|
|
212
|
-
|
|
211
|
+
const items = shortcuts.map(({ command, label }) => theme.accent(command) + " " + theme.muted(label));
|
|
212
|
+
const inline = items.join(theme.dim(" · "));
|
|
213
|
+
const lines = terminalWidth(inline) <= available ? [inline] : shortcuts.flatMap(({ command, label }) => {
|
|
214
|
+
if (terminalWidth(command + " " + label) <= available)
|
|
215
|
+
return [theme.accent(command) + " " + theme.muted(label)];
|
|
216
|
+
return [theme.accent(fitLine(command, available)), ...wrapText(label, Math.max(1, available), true).map(line => theme.muted(line))];
|
|
217
|
+
});
|
|
218
|
+
if (accountNote)
|
|
219
|
+
lines.push(...wrapText(oneLine(accountNote), Math.max(1, available), true).map(line => theme.muted(line)));
|
|
220
|
+
return "\n" + lines.map(line => fitLine(" " + line, Math.max(0, width - 1))).join("\n") + "\n\n";
|
|
213
221
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const TALOS_LOGO_SVG = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1536 1536\" width=\"1536\" height=\"1536\">\n<g transform=\"translate(40, 283) scale(0.9479)\">\n<g transform=\"translate(0.000000,1024.000000) scale(0.100000,-0.100000)\"\nfill=\"#ffffff\" stroke=\"none\">\n<path d=\"M4090 8420 l0 -1529 143 -3 142 -3 0 -507 c0 -278 -4 -510 -8 -515\n-5 -4 -121 -8 -258 -7 l-249 1 0 -294 0 -293 -57 -63 c-31 -34 -169 -180 -306\n-325 -138 -144 -256 -271 -264 -282 -14 -20 -12 -20 619 -20 l633 0 -135 -133\nc-74 -73 -242 -237 -372 -364 l-238 -231 0 -331 0 -331 315 0 315 0 0 154 0\n154 78 4 c42 2 193 2 335 0 l257 -3 0 -289 0 -288 340 -228 340 -228 0 -258 0\n-258 190 0 190 0 0 -370 0 -370 170 0 169 0 3 -128 3 -127 213 -3 212 -2 0\n-165 0 -165 79 0 c43 0 105 -3 139 -6 l60 -7 -1 -141 -2 -141 535 0 535 0 3\n140 c2 96 6 142 15 147 7 4 67 8 135 8 l122 0 0 165 0 165 209 0 209 0 7 130\n8 130 168 0 169 0 0 370 0 370 190 0 190 0 0 243 c0 173 4 249 13 265 6 12\n158 121 337 241 l325 218 3 292 2 291 335 0 335 0 0 -155 0 -155 320 0 320 0\n0 325 0 325 -262 258 c-145 141 -311 304 -370 361 -60 58 -108 108 -108 113 0\n4 282 9 627 10 l627 3 -125 132 c-68 72 -211 224 -316 337 l-193 205 0 295 0\n296 -222 0 c-123 0 -240 3 -260 6 l-38 7 0 513 0 514 140 0 140 0 0 1530 0\n1530 -360 0 -360 0 0 -175 0 -175 -170 0 -170 0 0 -180 0 -180 -185 0 -185 0\n0 -180 0 -180 -187 -2 -188 -3 -3 -192 -2 -193 -190 0 -190 0 0 -295 0 -295\n-117 0 c-65 -1 -246 -2 -403 -3 l-285 -2 -3 -397 -2 -398 -595 0 -595 0 0 394\n0 394 -27 6 c-16 4 -143 6 -283 5 -140 -1 -308 -1 -372 -1 l-118 2 0 295 0\n295 -190 0 -190 0 -1 183 c-1 100 -1 185 0 190 0 4 -41 8 -91 8 -51 1 -111 2\n-133 3 -22 1 -66 3 -97 4 l-58 2 0 180 0 180 -185 0 -185 0 0 180 0 180 -170\n0 -170 0 0 175 0 175 -360 0 -360 0 0 -1530z m688 273 l2 -183 159 0 158 0 5\n-117 c3 -65 5 -197 4 -293 l-1 -175 155 -5 155 -5 3 -237 2 -237 148 -3 147\n-3 0 -103 0 -103 -415 -403 -415 -404 -3 364 -2 364 -160 0 -160 0 0 865 0\n866 108 -3 107 -3 3 -182z m6022 -678 l0 -865 -160 0 -160 0 0 -361 c0 -198\n-4 -359 -8 -357 -5 2 -194 183 -421 403 l-412 400 3 100 3 100 147 3 148 3 2\n237 3 237 158 3 157 3 0 294 0 295 165 0 165 0 0 185 0 185 105 0 105 0 0\n-865z m-850 -2857 l0 -178 -104 0 -104 0 -217 -225 -217 -225 -434 0 -434 0 0\n249 0 249 31 6 c17 3 156 6 308 6 l276 1 150 144 150 144 85 3 c47 2 181 3\n297 3 l213 0 0 -177z m-3790 27 l145 -145 307 0 308 0 0 -255 0 -255 -433 0\n-433 0 -218 225 -218 225 -104 0 -104 0 0 175 0 175 303 0 302 0 145 -145z\nm2260 -1305 l0 -320 215 0 215 0 0 -1045 0 -1045 -150 0 -150 0 0 -135 0 -135\n-870 0 -870 0 0 135 0 135 -150 0 -150 0 2 1042 3 1043 213 3 212 2 0 320 0\n320 740 0 740 0 0 -320z\"/>\n<path d=\"M7030 2095 l0 -315 135 0 135 0 0 -135 0 -135 380 0 380 0 0 135 0\n135 134 0 134 0 7 123 c3 67 5 208 3 312 l-3 190 -652 3 -653 2 0 -315z\"/>\n</g>\n</g>\n</svg>\n";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// Bundled from vascend-horizon/assets/logo.svg, used by scripts/dev.js.
|
|
2
|
+
export const TALOS_LOGO_SVG = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1536 1536\" width=\"1536\" height=\"1536\">\n<g transform=\"translate(40, 283) scale(0.9479)\">\n<g transform=\"translate(0.000000,1024.000000) scale(0.100000,-0.100000)\"\nfill=\"#ffffff\" stroke=\"none\">\n<path d=\"M4090 8420 l0 -1529 143 -3 142 -3 0 -507 c0 -278 -4 -510 -8 -515\n-5 -4 -121 -8 -258 -7 l-249 1 0 -294 0 -293 -57 -63 c-31 -34 -169 -180 -306\n-325 -138 -144 -256 -271 -264 -282 -14 -20 -12 -20 619 -20 l633 0 -135 -133\nc-74 -73 -242 -237 -372 -364 l-238 -231 0 -331 0 -331 315 0 315 0 0 154 0\n154 78 4 c42 2 193 2 335 0 l257 -3 0 -289 0 -288 340 -228 340 -228 0 -258 0\n-258 190 0 190 0 0 -370 0 -370 170 0 169 0 3 -128 3 -127 213 -3 212 -2 0\n-165 0 -165 79 0 c43 0 105 -3 139 -6 l60 -7 -1 -141 -2 -141 535 0 535 0 3\n140 c2 96 6 142 15 147 7 4 67 8 135 8 l122 0 0 165 0 165 209 0 209 0 7 130\n8 130 168 0 169 0 0 370 0 370 190 0 190 0 0 243 c0 173 4 249 13 265 6 12\n158 121 337 241 l325 218 3 292 2 291 335 0 335 0 0 -155 0 -155 320 0 320 0\n0 325 0 325 -262 258 c-145 141 -311 304 -370 361 -60 58 -108 108 -108 113 0\n4 282 9 627 10 l627 3 -125 132 c-68 72 -211 224 -316 337 l-193 205 0 295 0\n296 -222 0 c-123 0 -240 3 -260 6 l-38 7 0 513 0 514 140 0 140 0 0 1530 0\n1530 -360 0 -360 0 0 -175 0 -175 -170 0 -170 0 0 -180 0 -180 -185 0 -185 0\n0 -180 0 -180 -187 -2 -188 -3 -3 -192 -2 -193 -190 0 -190 0 0 -295 0 -295\n-117 0 c-65 -1 -246 -2 -403 -3 l-285 -2 -3 -397 -2 -398 -595 0 -595 0 0 394\n0 394 -27 6 c-16 4 -143 6 -283 5 -140 -1 -308 -1 -372 -1 l-118 2 0 295 0\n295 -190 0 -190 0 -1 183 c-1 100 -1 185 0 190 0 4 -41 8 -91 8 -51 1 -111 2\n-133 3 -22 1 -66 3 -97 4 l-58 2 0 180 0 180 -185 0 -185 0 0 180 0 180 -170\n0 -170 0 0 175 0 175 -360 0 -360 0 0 -1530z m688 273 l2 -183 159 0 158 0 5\n-117 c3 -65 5 -197 4 -293 l-1 -175 155 -5 155 -5 3 -237 2 -237 148 -3 147\n-3 0 -103 0 -103 -415 -403 -415 -404 -3 364 -2 364 -160 0 -160 0 0 865 0\n866 108 -3 107 -3 3 -182z m6022 -678 l0 -865 -160 0 -160 0 0 -361 c0 -198\n-4 -359 -8 -357 -5 2 -194 183 -421 403 l-412 400 3 100 3 100 147 3 148 3 2\n237 3 237 158 3 157 3 0 294 0 295 165 0 165 0 0 185 0 185 105 0 105 0 0\n-865z m-850 -2857 l0 -178 -104 0 -104 0 -217 -225 -217 -225 -434 0 -434 0 0\n249 0 249 31 6 c17 3 156 6 308 6 l276 1 150 144 150 144 85 3 c47 2 181 3\n297 3 l213 0 0 -177z m-3790 27 l145 -145 307 0 308 0 0 -255 0 -255 -433 0\n-433 0 -218 225 -218 225 -104 0 -104 0 0 175 0 175 303 0 302 0 145 -145z\nm2260 -1305 l0 -320 215 0 215 0 0 -1045 0 -1045 -150 0 -150 0 0 -135 0 -135\n-870 0 -870 0 0 135 0 135 -150 0 -150 0 2 1042 3 1043 213 3 212 2 0 320 0\n320 740 0 740 0 0 -320z\"/>\n<path d=\"M7030 2095 l0 -315 135 0 135 0 0 -135 0 -135 380 0 380 0 0 135 0\n135 134 0 134 0 7 123 c3 67 5 208 3 312 l-3 190 -652 3 -653 2 0 -315z\"/>\n</g>\n</g>\n</svg>\n";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function talosArtwork(columns: number): readonly string[];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { renderBlockLogo } from "./logo.js";
|
|
2
|
+
import { TALOS_LOGO_SVG } from "./talos-art-data.js";
|
|
3
|
+
// Match Horizon scripts/dev.js: same SVG, renderer and 30 x 14 dimensions.
|
|
4
|
+
// Bundle the SVG so installed Talos does not depend on the Horizon checkout.
|
|
5
|
+
const logo = Object.freeze(renderBlockLogo(TALOS_LOGO_SVG, { columns: 30, rows: 14, samples: 4, ansi: true }));
|
|
6
|
+
const empty = Object.freeze([]);
|
|
7
|
+
export function talosArtwork(columns) {
|
|
8
|
+
return columns >= 30 ? logo : empty;
|
|
9
|
+
}
|
package/dist/tui/task-labels.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { tr } from "./i18n.js";
|
|
2
|
+
// Translate the status at render time, leaving task/group identifiers intact.
|
|
3
|
+
export function taskActivityLabel(task, status) {
|
|
4
|
+
if (status === "running")
|
|
5
|
+
return tr("attività {task} avviata", "task {task} started", { task });
|
|
6
|
+
if (status === "failed")
|
|
7
|
+
return tr("attività {task} non riuscita", "task {task} failed", { task });
|
|
8
|
+
return tr("attività {task} completata", "task {task} completed", { task });
|
|
9
|
+
}
|
|
2
10
|
export const TASK_STATUS_LABELS = {
|
|
3
11
|
get pending() { return tr("da fare", "pending"); },
|
|
4
12
|
get running() { return tr("in corso", "running"); },
|
|
@@ -3,5 +3,6 @@ export declare function terminalWidth(value: string): number;
|
|
|
3
3
|
export declare function exceedsTerminalWidth(value: string, width: number): boolean;
|
|
4
4
|
export declare function fitLine(value: string, width: number, ellipsis?: boolean): string;
|
|
5
5
|
export declare function padLine(value: string, width: number): string;
|
|
6
|
-
export declare function
|
|
6
|
+
export declare function wrappedLineCount(value: string, width: number): number;
|
|
7
|
+
export declare function wrapText(value: string, width: number, wordWrap?: boolean, maxLines?: number): string[];
|
|
7
8
|
export declare function oneLine(value: string): string;
|
|
@@ -80,15 +80,39 @@ export function padLine(value, width) {
|
|
|
80
80
|
const fitted = fitLine(value, width);
|
|
81
81
|
return fitted + " ".repeat(Math.max(0, width - terminalWidth(fitted)));
|
|
82
82
|
}
|
|
83
|
-
|
|
83
|
+
// Count hard-wrapped rows without allocating or painting the hidden text.
|
|
84
|
+
export function wrappedLineCount(value, width) {
|
|
85
|
+
const max = Math.max(2, width);
|
|
86
|
+
let count = 0;
|
|
87
|
+
for (const line of plainText(value).split("\n")) {
|
|
88
|
+
if (printableAscii.test(line)) {
|
|
89
|
+
count += Math.max(1, Math.ceil(line.length / Math.floor(max)));
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
count++;
|
|
93
|
+
let used = 0;
|
|
94
|
+
for (const { segment } of graphemes.segment(line)) {
|
|
95
|
+
const size = cellWidth(segment);
|
|
96
|
+
if (used + size > max) {
|
|
97
|
+
count++;
|
|
98
|
+
used = 0;
|
|
99
|
+
}
|
|
100
|
+
used += size;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return count;
|
|
104
|
+
}
|
|
105
|
+
export function wrapText(value, width, wordWrap = false, maxLines = Infinity) {
|
|
84
106
|
const max = Math.max(2, width);
|
|
85
107
|
const lines = [];
|
|
86
108
|
for (const line of plainText(value).split("\n")) {
|
|
109
|
+
if (lines.length >= maxLines)
|
|
110
|
+
break;
|
|
87
111
|
if (!wordWrap && printableAscii.test(line)) {
|
|
88
112
|
const chunk = Math.max(1, Math.floor(max));
|
|
89
113
|
if (!line.length)
|
|
90
114
|
lines.push("");
|
|
91
|
-
for (let i = 0; i < line.length; i += chunk)
|
|
115
|
+
for (let i = 0; i < line.length && lines.length < maxLines; i += chunk)
|
|
92
116
|
lines.push(line.slice(i, i + chunk));
|
|
93
117
|
continue;
|
|
94
118
|
}
|
|
@@ -108,6 +132,8 @@ export function wrapText(value, width, wordWrap = false) {
|
|
|
108
132
|
row = "";
|
|
109
133
|
used = 0;
|
|
110
134
|
}
|
|
135
|
+
if (lines.length >= maxLines)
|
|
136
|
+
return lines;
|
|
111
137
|
if (wordWrap && !row && segment === " ")
|
|
112
138
|
continue;
|
|
113
139
|
}
|
package/dist/tui/theme.js
CHANGED
|
@@ -86,8 +86,8 @@ const VASCEND_DARK_COLORS = {
|
|
|
86
86
|
dim: "dimSilver",
|
|
87
87
|
text: CHAT_TEXT,
|
|
88
88
|
thinkingText: "darkSilver",
|
|
89
|
-
selectedBg: "#
|
|
90
|
-
userMessageBg: "#
|
|
89
|
+
selectedBg: "#292929",
|
|
90
|
+
userMessageBg: "#2b2b2b",
|
|
91
91
|
userMessageText: CHAT_TEXT,
|
|
92
92
|
attachmentRef: "#28aacc",
|
|
93
93
|
customMessageBg: "#12151b",
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { tr } from "./i18n.js";
|
|
2
|
+
import { oneLine } from "./terminal-text.js";
|
|
3
|
+
function truncate(value, max) {
|
|
4
|
+
if (value.length <= max)
|
|
5
|
+
return value;
|
|
6
|
+
if (max <= 1)
|
|
7
|
+
return value.slice(0, max);
|
|
8
|
+
return `${value.slice(0, max - 1)}…`;
|
|
9
|
+
}
|
|
10
|
+
function compactArgs(input) {
|
|
11
|
+
const value = JSON.stringify(input);
|
|
12
|
+
return value.length > 80 ? value.slice(0, 77) + "..." : value;
|
|
13
|
+
}
|
|
14
|
+
function vascendArg(call) {
|
|
15
|
+
const input = call.input;
|
|
16
|
+
const castle = typeof input["castle"] === "string" && input["castle"] && input["castle"] !== "master"
|
|
17
|
+
? ` @${input["castle"]}` : "";
|
|
18
|
+
switch (call.name) {
|
|
19
|
+
case "vascend_mark": {
|
|
20
|
+
const task = String(input["task"] ?? "");
|
|
21
|
+
const status = String(input["status"] ?? "completed");
|
|
22
|
+
return truncate(`${task} → ${status}${castle}`, 56);
|
|
23
|
+
}
|
|
24
|
+
case "vascend_plan": {
|
|
25
|
+
const tasks = Array.isArray(input["tasks"]) ? input["tasks"].length : 0;
|
|
26
|
+
const title = typeof input["title"] === "string" ? input["title"] : "";
|
|
27
|
+
const count = tr("{count} attività", "{count} tasks", { count: tasks });
|
|
28
|
+
return truncate(title ? `${title} · ${count}${castle}` : `${count}${castle}`, 60);
|
|
29
|
+
}
|
|
30
|
+
case "vascend_addtasks": {
|
|
31
|
+
const tasks = Array.isArray(input["tasks"]) ? input["tasks"].length : 0;
|
|
32
|
+
return truncate("+" + tr("{count} attività", "{count} tasks", { count: tasks }) + castle, 56);
|
|
33
|
+
}
|
|
34
|
+
case "vascend_note": {
|
|
35
|
+
const task = typeof input["task"] === "string" && input["task"] ? `${input["task"]}: ` : "";
|
|
36
|
+
return truncate(`${task}${String(input["text"] ?? input["note"] ?? "")}`, 56);
|
|
37
|
+
}
|
|
38
|
+
case "vascend_skill": {
|
|
39
|
+
const task = typeof input["task"] === "string" && input["task"] ? `${input["task"]}: ` : "";
|
|
40
|
+
const skills = Array.isArray(input["skills"])
|
|
41
|
+
? input["skills"].join(", ") : String(input["skills"] ?? input["skill"] ?? "");
|
|
42
|
+
return truncate(`${task}${skills}`, 56);
|
|
43
|
+
}
|
|
44
|
+
default:
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export function toolLabel(name) {
|
|
49
|
+
if (/(?:^|_)(?:widget_)?read_me$/.test(name))
|
|
50
|
+
return tr('Istruzioni visuali', 'Visual instructions');
|
|
51
|
+
if (/(?:^|_)(?:visualize|show_widget)$/.test(name))
|
|
52
|
+
return tr('Artifact', 'Artifact');
|
|
53
|
+
const labels = {
|
|
54
|
+
read_file: "Read", write_file: "Write", edit_file: "Update", list_dir: "List",
|
|
55
|
+
bash: "Bash", bash_output: tr("Processo in background", "Background process"), web_fetch: "Fetch", ask_user: "Ask",
|
|
56
|
+
wait: "Wait", tool_search: "ToolSearch", tool_invoke: "Invoke", skill_search: "SkillSearch",
|
|
57
|
+
skill_load: "SkillLoad", output_page: "Page", kingdoms_warm: tr("Collaboratori", "Collaborators"),
|
|
58
|
+
kingdom_send: "Send", kingdom_inbox: "Inbox", kingdom_wait: "WaitMsg", glob: "Glob",
|
|
59
|
+
grep: "Grep", recall: "Recall", image_generate: "Image",
|
|
60
|
+
vascend_plan: tr("Lista attività", "Task list"), vascend_mark: tr("Stato attività", "Task status"),
|
|
61
|
+
vascend_note: "Note", vascend_skill: "Skill",
|
|
62
|
+
vascend_addtasks: tr("Aggiungi attività", "Add tasks"),
|
|
63
|
+
vascend_addrooms: tr("Aggiungi attività", "Add tasks"),
|
|
64
|
+
vascend_status: tr("Lista attività", "Task list"),
|
|
65
|
+
};
|
|
66
|
+
return labels[name] ?? name;
|
|
67
|
+
}
|
|
68
|
+
export function toolArg(call) {
|
|
69
|
+
const path = call.input["path"];
|
|
70
|
+
if (call.name === "run_program") {
|
|
71
|
+
const code = String(call.input["code"] ?? "");
|
|
72
|
+
return tr("JavaScript · {count} righe · Ctrl+R dettagli", "JavaScript · {count} lines · Ctrl+R details", { count: code.split("\n").length });
|
|
73
|
+
}
|
|
74
|
+
if (call.name === "tool_invoke") {
|
|
75
|
+
const inner = String(call.input["name"] ?? "");
|
|
76
|
+
const args = call.input["args"] && typeof call.input["args"] === "object"
|
|
77
|
+
? compactArgs(call.input["args"]) : "";
|
|
78
|
+
return truncate(`${inner}${args && args !== "{}" ? ` ${args}` : ""}`, 56);
|
|
79
|
+
}
|
|
80
|
+
if (call.name === "tool_search" || call.name === "skill_search")
|
|
81
|
+
return truncate(String(call.input["query"] ?? ""), 50);
|
|
82
|
+
if (call.name === "skill_load")
|
|
83
|
+
return String(call.input["name"] ?? "");
|
|
84
|
+
if (call.name === "grep" || call.name === "glob")
|
|
85
|
+
return truncate(String(call.input["pattern"] ?? ""), 50);
|
|
86
|
+
if (call.name === "wait") {
|
|
87
|
+
const until = call.input["until"];
|
|
88
|
+
return typeof until === "string" && until ? `until ${truncate(until, 44)}` : `${call.input["seconds"] ?? 5}s`;
|
|
89
|
+
}
|
|
90
|
+
const danilov = vascendArg(call);
|
|
91
|
+
if (danilov !== null)
|
|
92
|
+
return danilov;
|
|
93
|
+
if (typeof path === "string" && path)
|
|
94
|
+
return path;
|
|
95
|
+
if (call.name === "bash")
|
|
96
|
+
return truncate(oneLine(String(call.input["command"] ?? "")), 60);
|
|
97
|
+
return compactArgs(call.input);
|
|
98
|
+
}
|
package/dist/tui/tool-style.js
CHANGED
|
@@ -39,6 +39,10 @@ const CATEGORY = {
|
|
|
39
39
|
image_generate: "image",
|
|
40
40
|
};
|
|
41
41
|
export function toolCategory(name) {
|
|
42
|
+
if (/(?:^|_)(?:widget_)?read_me$/.test(name))
|
|
43
|
+
return 'search';
|
|
44
|
+
if (/(?:^|_)(?:visualize|show_widget)$/.test(name))
|
|
45
|
+
return 'image';
|
|
42
46
|
return CATEGORY[name] ?? "misc";
|
|
43
47
|
}
|
|
44
48
|
// Colore PIENO di ogni categoria (tinta a cui punta il pulse), come tripla RGB.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare class TranscriptStore<T> {
|
|
2
|
+
private readonly maxChars;
|
|
3
|
+
private readonly maxItems;
|
|
4
|
+
private tail;
|
|
5
|
+
private tailChars;
|
|
6
|
+
private stored;
|
|
7
|
+
private chunks;
|
|
8
|
+
private cache;
|
|
9
|
+
private directory?;
|
|
10
|
+
private fd?;
|
|
11
|
+
private bytes;
|
|
12
|
+
constructor(maxChars?: number, maxItems?: number);
|
|
13
|
+
get length(): number;
|
|
14
|
+
get retainedChars(): number;
|
|
15
|
+
push(value: T): void;
|
|
16
|
+
get(index: number): T | undefined;
|
|
17
|
+
set(index: number, value: T): void;
|
|
18
|
+
slice(start?: number, end?: number): T[];
|
|
19
|
+
from(start?: number, end?: number): IterableIterator<T>;
|
|
20
|
+
clear(): void;
|
|
21
|
+
private chunkAt;
|
|
22
|
+
private spill;
|
|
23
|
+
private write;
|
|
24
|
+
private load;
|
|
25
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { closeSync, mkdtempSync, openSync, readSync, rmSync, writeSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
// Disposable UI history, not model memory. Keep a small mutable tail and spill
|
|
5
|
+
// complete chunks to disk. Indexed slices read only the visible chunks; resize
|
|
6
|
+
// can replay original events without retaining their entire payload in the heap.
|
|
7
|
+
export class TranscriptStore {
|
|
8
|
+
maxChars;
|
|
9
|
+
maxItems;
|
|
10
|
+
tail = [];
|
|
11
|
+
tailChars = 0;
|
|
12
|
+
stored = 0;
|
|
13
|
+
chunks = [];
|
|
14
|
+
cache = new Map();
|
|
15
|
+
directory;
|
|
16
|
+
fd;
|
|
17
|
+
bytes = 0;
|
|
18
|
+
constructor(maxChars = 256_000, maxItems = 512) {
|
|
19
|
+
this.maxChars = maxChars;
|
|
20
|
+
this.maxItems = maxItems;
|
|
21
|
+
}
|
|
22
|
+
get length() { return this.stored + this.tail.length; }
|
|
23
|
+
get retainedChars() { return this.tailChars; }
|
|
24
|
+
push(value) {
|
|
25
|
+
const size = JSON.stringify(value).length;
|
|
26
|
+
if (this.tail.length && (this.tail.length >= this.maxItems || this.tailChars + size > this.maxChars))
|
|
27
|
+
this.spill();
|
|
28
|
+
this.tail.push(value);
|
|
29
|
+
this.tailChars += size;
|
|
30
|
+
if (this.tailChars >= this.maxChars)
|
|
31
|
+
this.spill();
|
|
32
|
+
}
|
|
33
|
+
get(index) {
|
|
34
|
+
if (index < 0 || index >= this.length)
|
|
35
|
+
return undefined;
|
|
36
|
+
if (index >= this.stored)
|
|
37
|
+
return this.tail[index - this.stored];
|
|
38
|
+
const chunk = this.chunkAt(index);
|
|
39
|
+
return this.load(chunk)[index - this.chunks[chunk].start];
|
|
40
|
+
}
|
|
41
|
+
set(index, value) {
|
|
42
|
+
if (index < 0 || index >= this.length)
|
|
43
|
+
return;
|
|
44
|
+
if (index >= this.stored) {
|
|
45
|
+
const at = index - this.stored;
|
|
46
|
+
this.tailChars += JSON.stringify(value).length - JSON.stringify(this.tail[at]).length;
|
|
47
|
+
this.tail[at] = value;
|
|
48
|
+
if (this.tailChars >= this.maxChars)
|
|
49
|
+
this.spill();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const chunk = this.chunkAt(index), previous = this.chunks[chunk];
|
|
53
|
+
const values = [...this.load(chunk)];
|
|
54
|
+
values[index - previous.start] = value;
|
|
55
|
+
this.chunks[chunk] = this.write(values, previous.start);
|
|
56
|
+
this.cache.delete(chunk);
|
|
57
|
+
}
|
|
58
|
+
slice(start = 0, end = this.length) {
|
|
59
|
+
const rows = [];
|
|
60
|
+
for (const value of this.from(start, end))
|
|
61
|
+
rows.push(value);
|
|
62
|
+
return rows;
|
|
63
|
+
}
|
|
64
|
+
*from(start = 0, end = this.length) {
|
|
65
|
+
let index = Math.max(0, start);
|
|
66
|
+
const limit = Math.min(end, this.length);
|
|
67
|
+
while (index < Math.min(limit, this.stored)) {
|
|
68
|
+
const chunk = this.chunkAt(index), info = this.chunks[chunk];
|
|
69
|
+
const values = this.load(chunk), stop = Math.min(limit, info.start + info.count);
|
|
70
|
+
while (index < stop)
|
|
71
|
+
yield values[index++ - info.start];
|
|
72
|
+
}
|
|
73
|
+
while (index < limit)
|
|
74
|
+
yield this.tail[index++ - this.stored];
|
|
75
|
+
}
|
|
76
|
+
clear() {
|
|
77
|
+
this.tail = [];
|
|
78
|
+
this.tailChars = 0;
|
|
79
|
+
this.stored = 0;
|
|
80
|
+
this.chunks = [];
|
|
81
|
+
this.cache.clear();
|
|
82
|
+
this.bytes = 0;
|
|
83
|
+
if (this.fd !== undefined) {
|
|
84
|
+
closeSync(this.fd);
|
|
85
|
+
this.fd = undefined;
|
|
86
|
+
}
|
|
87
|
+
if (this.directory) {
|
|
88
|
+
const directory = this.directory;
|
|
89
|
+
this.directory = undefined;
|
|
90
|
+
try {
|
|
91
|
+
rmSync(directory, { recursive: true, force: true });
|
|
92
|
+
}
|
|
93
|
+
catch { /* Disposable cache may be held by a scanner. */ }
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
chunkAt(index) {
|
|
97
|
+
let low = 0, high = this.chunks.length - 1;
|
|
98
|
+
while (low < high) {
|
|
99
|
+
const mid = Math.ceil((low + high) / 2);
|
|
100
|
+
if (this.chunks[mid].start <= index)
|
|
101
|
+
low = mid;
|
|
102
|
+
else
|
|
103
|
+
high = mid - 1;
|
|
104
|
+
}
|
|
105
|
+
return low;
|
|
106
|
+
}
|
|
107
|
+
spill() {
|
|
108
|
+
this.chunks.push(this.write(this.tail, this.stored));
|
|
109
|
+
this.stored += this.tail.length;
|
|
110
|
+
this.tail = [];
|
|
111
|
+
this.tailChars = 0;
|
|
112
|
+
}
|
|
113
|
+
write(values, start) {
|
|
114
|
+
if (this.fd === undefined) {
|
|
115
|
+
this.directory = mkdtempSync(join(tmpdir(), "talos-transcript-"));
|
|
116
|
+
this.fd = openSync(join(this.directory, "chunks.json"), "w+", 0o600);
|
|
117
|
+
}
|
|
118
|
+
const buffer = Buffer.from(JSON.stringify(values));
|
|
119
|
+
const offset = this.bytes;
|
|
120
|
+
let written = 0;
|
|
121
|
+
while (written < buffer.length) {
|
|
122
|
+
const size = writeSync(this.fd, buffer, written, buffer.length - written, offset + written);
|
|
123
|
+
if (!size)
|
|
124
|
+
throw new Error("Unable to write transcript cache");
|
|
125
|
+
written += size;
|
|
126
|
+
}
|
|
127
|
+
this.bytes += written;
|
|
128
|
+
return { start, count: values.length, offset, bytes: written };
|
|
129
|
+
}
|
|
130
|
+
load(index) {
|
|
131
|
+
const cached = this.cache.get(index);
|
|
132
|
+
if (cached)
|
|
133
|
+
return cached;
|
|
134
|
+
const chunk = this.chunks[index], buffer = Buffer.allocUnsafe(chunk.bytes);
|
|
135
|
+
let read = 0;
|
|
136
|
+
while (read < buffer.length) {
|
|
137
|
+
const size = readSync(this.fd, buffer, read, buffer.length - read, chunk.offset + read);
|
|
138
|
+
if (!size)
|
|
139
|
+
throw new Error("Unable to read transcript cache");
|
|
140
|
+
read += size;
|
|
141
|
+
}
|
|
142
|
+
const values = JSON.parse(buffer.toString("utf8"));
|
|
143
|
+
// Oversized single events are read on demand, never retained in the cache.
|
|
144
|
+
if (chunk.bytes <= this.maxChars * 2) {
|
|
145
|
+
this.cache.set(index, values);
|
|
146
|
+
if (this.cache.size > 2)
|
|
147
|
+
this.cache.delete(this.cache.keys().next().value);
|
|
148
|
+
}
|
|
149
|
+
return values;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -2,7 +2,7 @@ import type { PlanLimits } from "../core/types.js";
|
|
|
2
2
|
import type { TuiTheme } from "./branding.js";
|
|
3
3
|
import { type SessionUsageState } from "./session-usage.js";
|
|
4
4
|
import { type StatusData, type StatusOptions } from "./status-line.js";
|
|
5
|
-
export declare
|
|
5
|
+
export declare function sessionUsageExplanation(): string;
|
|
6
6
|
type UsageState = Pick<SessionUsageState, "limits" | "incomplete" | "missing" | "unsaved">;
|
|
7
7
|
export declare function subscriptionDetails(providerId: string, limits: PlanLimits | undefined, t: TuiTheme, now?: number): string[];
|
|
8
8
|
export declare function buildUsageFooter(d: StatusData, t: TuiTheme, state: UsageState, providerId: string, opts?: StatusOptions, now?: number): readonly string[];
|
package/dist/tui/usage-footer.js
CHANGED
|
@@ -4,7 +4,9 @@ import { buildStatusLine, DEFAULT_ORDER } from "./status-line.js";
|
|
|
4
4
|
import { fitLine, oneLine, terminalWidth } from "./terminal-text.js";
|
|
5
5
|
import { buildContextBar } from "./context-bar.js";
|
|
6
6
|
import { getLanguage, tr } from "./i18n.js";
|
|
7
|
-
export
|
|
7
|
+
export function sessionUsageExplanation() {
|
|
8
|
+
return tr("I token cumulati sono la somma delle chiamate della sessione, inclusi input ripetuti e cache: non sono il contesto di una singola richiesta. Talos seleziona informazioni rilevanti e gestisce la cronologia con recupero e compattazione secondo la configurazione. Questo non annulla i consumi registrati dal provider. ≥ indica un totale parziale: il consumo noto è almeno quello mostrato. Il contesto indicato è una stima locale, non una misura esatta del payload inviato.", "Cumulative tokens sum the session's calls, including repeated input and cache: they are not the context of a single request. Talos selects relevant information and manages history through retrieval and compaction according to configuration. This does not erase usage recorded by the provider. ≥ indicates a partial total: known usage is at least the amount shown. The displayed context is a local estimate, not an exact measurement of the payload sent.");
|
|
9
|
+
}
|
|
8
10
|
const shortLabel = (label) => label.replace("Limite 5 ore", "5h").replace("Settimanale", tr("7g", "7d")).replace("Finestra ", "");
|
|
9
11
|
const remainingPercent = (window) => window.status === "rejected" ? "0%"
|
|
10
12
|
: window.utilization !== undefined ? `${Math.round(Math.max(0, Math.min(1, 1 - window.utilization)) * 100)}%` : undefined;
|