@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.
Files changed (224) hide show
  1. package/dist/core/agent.d.ts +16 -3
  2. package/dist/core/agent.js +114 -34
  3. package/dist/core/background.d.ts +10 -3
  4. package/dist/core/background.js +55 -9
  5. package/dist/core/bootstrap.js +1 -0
  6. package/dist/core/compaction.js +1 -1
  7. package/dist/core/config-storage.d.ts +5 -0
  8. package/dist/core/config-storage.js +83 -0
  9. package/dist/core/config.d.ts +11 -2
  10. package/dist/core/config.js +24 -8
  11. package/dist/core/context-ledger.js +2 -1
  12. package/dist/core/context-policy.d.ts +1 -1
  13. package/dist/core/context-policy.js +10 -7
  14. package/dist/core/credentials.js +29 -30
  15. package/dist/core/effort.d.ts +1 -1
  16. package/dist/core/effort.js +5 -1
  17. package/dist/core/execution-guidance.d.ts +1 -1
  18. package/dist/core/execution-guidance.js +2 -0
  19. package/dist/core/file-coordination.d.ts +3 -0
  20. package/dist/core/file-coordination.js +28 -0
  21. package/dist/core/file-lease-store.d.ts +3 -0
  22. package/dist/core/file-lease-store.js +28 -12
  23. package/dist/core/fusion.d.ts +24 -0
  24. package/dist/core/fusion.js +80 -0
  25. package/dist/core/model-limits.d.ts +1 -0
  26. package/dist/core/model-limits.js +5 -1
  27. package/dist/core/permission-queue.js +15 -15
  28. package/dist/core/request-plan.js +4 -3
  29. package/dist/core/session-naming.js +4 -0
  30. package/dist/core/session.d.ts +4 -2
  31. package/dist/core/session.js +13 -4
  32. package/dist/core/settings.d.ts +2 -0
  33. package/dist/core/settings.js +5 -16
  34. package/dist/core/step-policy.d.ts +18 -0
  35. package/dist/core/step-policy.js +6 -0
  36. package/dist/core/tool-artifacts.d.ts +2 -0
  37. package/dist/core/tool-artifacts.js +21 -3
  38. package/dist/core/tool-result-index.js +29 -33
  39. package/dist/core/tool-result-store.js +6 -5
  40. package/dist/core/types.d.ts +10 -3
  41. package/dist/core/user-inbox.d.ts +9 -0
  42. package/dist/core/user-inbox.js +22 -3
  43. package/dist/core/user-input.js +1 -1
  44. package/dist/fusion/autopilot-fast.d.ts +59 -0
  45. package/dist/fusion/autopilot-fast.js +213 -0
  46. package/dist/fusion/autopilot.d.ts +75 -0
  47. package/dist/fusion/autopilot.js +308 -0
  48. package/dist/fusion/focus.d.ts +30 -0
  49. package/dist/fusion/focus.js +122 -0
  50. package/dist/fusion/gate.d.ts +30 -0
  51. package/dist/fusion/gate.js +95 -0
  52. package/dist/fusion/jev.d.ts +71 -0
  53. package/dist/fusion/jev.js +164 -0
  54. package/dist/fusion/receipts.d.ts +25 -0
  55. package/dist/fusion/receipts.js +34 -0
  56. package/dist/fusion/route.d.ts +25 -0
  57. package/dist/fusion/route.js +84 -0
  58. package/dist/fusion/run.d.ts +4 -0
  59. package/dist/fusion/run.js +186 -0
  60. package/dist/horizon/engine.d.ts +20 -1
  61. package/dist/horizon/engine.js +57 -0
  62. package/dist/horizon/index.d.ts +2 -2
  63. package/dist/horizon/index.js +1 -1
  64. package/dist/horizon/types.d.ts +29 -0
  65. package/dist/index.js +12 -0
  66. package/dist/providers/anthropic-oauth.d.ts +8 -3
  67. package/dist/providers/anthropic-oauth.js +13 -10
  68. package/dist/providers/anthropic.d.ts +9 -2
  69. package/dist/providers/anthropic.js +64 -21
  70. package/dist/providers/cli-models.d.ts +30 -0
  71. package/dist/providers/cli-models.js +194 -0
  72. package/dist/providers/model-effort.js +1 -1
  73. package/dist/providers/openai-oauth.d.ts +8 -3
  74. package/dist/providers/openai-oauth.js +9 -3
  75. package/dist/providers/openrouter-manual-fallback.d.ts +3 -1
  76. package/dist/providers/openrouter-manual-fallback.js +20 -20
  77. package/dist/providers/registry.js +3 -2
  78. package/dist/providers/retry.d.ts +3 -0
  79. package/dist/providers/retry.js +44 -1
  80. package/dist/remote/cifratura.d.ts +12 -0
  81. package/dist/remote/cifratura.js +66 -0
  82. package/dist/remote/index.d.ts +15 -0
  83. package/dist/remote/index.js +65 -0
  84. package/dist/remote/relay-client.d.ts +58 -0
  85. package/dist/remote/relay-client.js +315 -0
  86. package/dist/remote/sessione-remota.d.ts +60 -0
  87. package/dist/remote/sessione-remota.js +266 -0
  88. package/dist/sdk.d.ts +7 -2
  89. package/dist/sdk.js +3 -1
  90. package/dist/tools/builtin.js +41 -20
  91. package/dist/tools/capabilities.d.ts +3 -1
  92. package/dist/tools/capabilities.js +5 -2
  93. package/dist/tools/computer-use.js +2 -1
  94. package/dist/tools/pagination.js +1 -1
  95. package/dist/tools/program.js +34 -21
  96. package/dist/tools/team-tools.js +11 -6
  97. package/dist/tui/account-entry.js +14 -9
  98. package/dist/tui/agent-label.d.ts +2 -0
  99. package/dist/tui/agent-label.js +5 -0
  100. package/dist/tui/agent-sessions-screen.d.ts +12 -2
  101. package/dist/tui/agent-sessions-screen.js +62 -16
  102. package/dist/tui/agent-sessions.d.ts +14 -0
  103. package/dist/tui/agent-sessions.js +67 -6
  104. package/dist/tui/bottom-input.d.ts +46 -2
  105. package/dist/tui/bottom-input.js +358 -59
  106. package/dist/tui/branding.js +8 -4
  107. package/dist/tui/capability-lists.d.ts +10 -0
  108. package/dist/tui/capability-lists.js +41 -0
  109. package/dist/tui/command-output-registry.js +4 -0
  110. package/dist/tui/command-transcript.d.ts +1 -1
  111. package/dist/tui/command-transcript.js +17 -21
  112. package/dist/tui/commands.js +4 -1
  113. package/dist/tui/compaction-status.d.ts +7 -0
  114. package/dist/tui/compaction-status.js +39 -0
  115. package/dist/tui/config-recovery.d.ts +12 -0
  116. package/dist/tui/config-recovery.js +54 -0
  117. package/dist/tui/context-meter.d.ts +3 -0
  118. package/dist/tui/context-meter.js +35 -8
  119. package/dist/tui/diff.d.ts +9 -0
  120. package/dist/tui/diff.js +43 -19
  121. package/dist/tui/fusion-menu.d.ts +5 -0
  122. package/dist/tui/fusion-menu.js +89 -0
  123. package/dist/tui/i18n-catalog.js +312 -1
  124. package/dist/tui/live-command.d.ts +1 -0
  125. package/dist/tui/live-command.js +9 -0
  126. package/dist/tui/live-output.d.ts +1 -0
  127. package/dist/tui/live-output.js +11 -0
  128. package/dist/tui/model-details.js +13 -12
  129. package/dist/tui/model-picker.js +17 -7
  130. package/dist/tui/model-selection.js +19 -10
  131. package/dist/tui/native-scrollback.js +5 -0
  132. package/dist/tui/prompt-queue.d.ts +3 -0
  133. package/dist/tui/prompt-queue.js +19 -1
  134. package/dist/tui/provider-label.d.ts +2 -0
  135. package/dist/tui/provider-label.js +9 -0
  136. package/dist/tui/provider-menu.js +25 -24
  137. package/dist/tui/queue-screen.js +2 -1
  138. package/dist/tui/remote-command.d.ts +7 -0
  139. package/dist/tui/remote-command.js +79 -0
  140. package/dist/tui/repl.d.ts +8 -2
  141. package/dist/tui/repl.js +355 -311
  142. package/dist/tui/review-store.d.ts +1 -0
  143. package/dist/tui/review-store.js +28 -7
  144. package/dist/tui/review-team.js +4 -3
  145. package/dist/tui/runtime-error.d.ts +2 -0
  146. package/dist/tui/runtime-error.js +26 -0
  147. package/dist/tui/selector-mouse.d.ts +1 -0
  148. package/dist/tui/selector-mouse.js +1 -1
  149. package/dist/tui/selector.d.ts +7 -0
  150. package/dist/tui/selector.js +19 -2
  151. package/dist/tui/session-controls.d.ts +26 -0
  152. package/dist/tui/session-controls.js +65 -0
  153. package/dist/tui/session-naming-notice.js +5 -3
  154. package/dist/tui/session-replay.d.ts +1 -0
  155. package/dist/tui/session-replay.js +101 -32
  156. package/dist/tui/session-transcript-layout.d.ts +9 -0
  157. package/dist/tui/session-transcript-layout.js +41 -0
  158. package/dist/tui/startup.js +63 -33
  159. package/dist/tui/status-line.d.ts +1 -1
  160. package/dist/tui/status-line.js +20 -12
  161. package/dist/tui/talos-art-data.d.ts +1 -0
  162. package/dist/tui/talos-art-data.js +2 -0
  163. package/dist/tui/talos-art.d.ts +1 -0
  164. package/dist/tui/talos-art.js +9 -0
  165. package/dist/tui/task-labels.d.ts +1 -0
  166. package/dist/tui/task-labels.js +8 -0
  167. package/dist/tui/terminal-text.d.ts +2 -1
  168. package/dist/tui/terminal-text.js +28 -2
  169. package/dist/tui/theme.js +2 -2
  170. package/dist/tui/tool-presentation.d.ts +3 -0
  171. package/dist/tui/tool-presentation.js +98 -0
  172. package/dist/tui/tool-style.js +4 -0
  173. package/dist/tui/transcript-store.d.ts +25 -0
  174. package/dist/tui/transcript-store.js +151 -0
  175. package/dist/tui/usage-footer.d.ts +1 -1
  176. package/dist/tui/usage-footer.js +3 -1
  177. package/dist/tui/vascend-id.d.ts +49 -0
  178. package/dist/tui/vascend-id.js +321 -0
  179. package/dist/tui/web-login-screen.js +4 -3
  180. package/dist/tui/web-login.d.ts +7 -15
  181. package/dist/tui/web-login.js +38 -78
  182. package/dist/tui/worker-transcripts.d.ts +31 -0
  183. package/dist/tui/worker-transcripts.js +91 -0
  184. package/dist/vascend/candidate-collector.d.ts +6 -5
  185. package/dist/vascend/candidate-collector.js +44 -43
  186. package/dist/vascend/context-lint.js +32 -2
  187. package/dist/vascend/context-market-selection.js +12 -5
  188. package/dist/vascend/context-pack-render.js +10 -4
  189. package/dist/vascend/context-packet-mirrors.d.ts +8 -0
  190. package/dist/vascend/context-packet-mirrors.js +24 -0
  191. package/dist/vascend/context-plan-events.d.ts +4 -0
  192. package/dist/vascend/context-plan-events.js +44 -0
  193. package/dist/vascend/context-snapshot.js +4 -2
  194. package/dist/vascend/context-store-reader.d.ts +20 -0
  195. package/dist/vascend/context-store-reader.js +46 -0
  196. package/dist/vascend/file-lock.d.ts +1 -0
  197. package/dist/vascend/file-lock.js +26 -0
  198. package/dist/vascend/granular-kingdom.d.ts +1 -0
  199. package/dist/vascend/granular-kingdom.js +22 -15
  200. package/dist/vascend/kingdom-bus.d.ts +1 -0
  201. package/dist/vascend/kingdom-bus.js +3 -0
  202. package/dist/vascend/kingdom-channel.d.ts +2 -0
  203. package/dist/vascend/kingdom-channel.js +3 -0
  204. package/dist/vascend/kingdom-live.d.ts +32 -4
  205. package/dist/vascend/kingdom-live.js +149 -13
  206. package/dist/vascend/kingdom-run.d.ts +5 -1
  207. package/dist/vascend/kingdom-run.js +6 -2
  208. package/dist/vascend/kingdom.d.ts +3 -0
  209. package/dist/vascend/kingdom.js +20 -13
  210. package/dist/vascend/memory-packet.d.ts +2 -1
  211. package/dist/vascend/memory-packet.js +31 -44
  212. package/dist/vascend/plan-store.d.ts +3 -1
  213. package/dist/vascend/plan-store.js +6 -4
  214. package/dist/vascend/room-memory.d.ts +10 -1
  215. package/dist/vascend/room-memory.js +42 -2
  216. package/dist/vascend/runtime.d.ts +3 -11
  217. package/dist/vascend/runtime.js +11 -123
  218. package/dist/vascend/session-search.js +2 -0
  219. package/dist/vascend/team-session.js +3 -2
  220. package/dist/vascend/vision.d.ts +3 -1
  221. package/dist/vascend/vision.js +6 -4
  222. package/dist/vascend/worker-session.d.ts +20 -0
  223. package/dist/vascend/worker-session.js +83 -0
  224. package/package.json +1 -1
@@ -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
- // The native renderer refreshes this header when the settings change.
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 width = Math.max(2, d.width - 2);
17
- const preferred = Math.max(46, terminalWidth(oneLine(d.cwd)) + 11, terminalWidth(modelLabel(d, t, 200)) + 26, terminalWidth(oneLine(d.sessionLabel ?? "")) + 11);
18
- const inner = Math.max(2, Math.min(68, preferred, width - 4));
19
- const permission = permissionLabel(d.permissions);
20
- const permissionPaint = d.permissions === "auto" ? t.yellow : t.muted;
21
- const title = t.muted(">_ ") + t.bold(t.silver("Vascend Talos")) + t.muted(` (v${TALOS_VERSION})`);
22
- const body = [fitLine(title, inner), ""];
23
- const labelWidth = Math.max(11, tr("permessi:", "permissions:").length + 1);
24
- const stacked = inner < 40;
25
- const field = (label, value, paint) => {
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(...wrapText(oneLine(value), Math.max(2, inner - 2), true).map(line => " " + paint(line)));
63
+ body.push(...rows.map(line => " " + line));
29
64
  }
30
65
  else {
31
- const rows = wrapText(oneLine(value), inner - labelWidth, true);
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
- if (stacked) {
36
- body.push(t.muted(tr("modello:", "model:")), " " + modelLabel(d, t, inner - 2));
37
- }
38
- else {
39
- let model = modelLabel(d, t, inner - labelWidth);
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("chat:", d.sessionLabel, t.silver);
49
- if (width < 12)
50
- return body.map(line => fitLine(line, width));
51
- const edge = (left, right) => " " + t.frame(left + "─".repeat(inner + 2) + right);
52
- return [edge("╭", "╮"), ...body.map(line => " " + t.frame("│ ") + padLine(line, inner) + t.frame(" │")), edge("╰", "╯")];
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(fitLine(oneLine(d.cwd), remaining));
60
- return fitLine(" " + line, Math.max(1, d.width - 1));
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;
@@ -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
- // Task shell in background (Ctrl+B): mostra quanti sono in esecuzione sul
108
- // totale. Nascosto quando non ci sono task. Live: si aggiorna a ogni frame
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 || !b.total)
111
+ if (!b || b.running <= 0)
113
112
  return null;
114
- const head = b.running > 0
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 lines = [
210
- { text: tr("Suggerimento: /help guida · /chats chat recenti", "Tip: /help commands · /chats recent chats"), paint: theme.muted },
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
- return "\n" + lines.flatMap(({ text, paint }) => wrapText(text, Math.max(2, width - 3), true).map((line) => " " + paint(line))).join("\n") + "\n\n";
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
+ }
@@ -1,2 +1,3 @@
1
1
  import type { VascendTaskStatus } from "../vascend/runtime.js";
2
+ export declare function taskActivityLabel(task: string, status: "running" | "completed" | "failed"): string;
2
3
  export declare const TASK_STATUS_LABELS: Readonly<Record<VascendTaskStatus, string>>;
@@ -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 wrapText(value: string, width: number, wordWrap?: boolean): string[];
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
- export function wrapText(value, width, wordWrap = false) {
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: "#30445e",
90
- userMessageBg: "#252c19",
89
+ selectedBg: "#292929",
90
+ userMessageBg: "#2b2b2b",
91
91
  userMessageText: CHAT_TEXT,
92
92
  attachmentRef: "#28aacc",
93
93
  customMessageBg: "#12151b",
@@ -0,0 +1,3 @@
1
+ import type { ToolCallPart } from "../core/types.js";
2
+ export declare function toolLabel(name: string): string;
3
+ export declare function toolArg(call: ToolCallPart): string;
@@ -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
+ }
@@ -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 const SESSION_USAGE_EXPLANATION = "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. \u2265 indica un totale parziale: il consumo noto \u00E8 almeno quello mostrato. Il contesto indicato \u00E8 una stima locale, non una misura esatta del payload inviato.";
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[];
@@ -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 const SESSION_USAGE_EXPLANATION = "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.";
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;