@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
@@ -14,14 +14,20 @@ export function renderModelPicker(opts) {
14
14
  const current = (option) => option && (opts.currentKey !== undefined
15
15
  ? (option.key ?? String(option.value)) === opts.currentKey
16
16
  : opts.current !== undefined && option.value === opts.current);
17
- const lines = [row(t.bold(`/model ${opts.title}`)), divider,
17
+ const lines = [row(t.chatText("› /model ")), divider,
18
18
  row(t.muted("/ ") + (opts.query ? t.silver(oneLine(opts.query)) : t.muted(tr("Cerca", "Search")))), ""];
19
19
  const providerWidth = width >= 50 ? Math.min(24, Math.floor(width * 0.27)) : 0;
20
- const labelWidth = Math.max(1, width - providerWidth - 5);
20
+ const contextWidth = width >= 75 ? 12 : 0;
21
+ const reasoningWidth = width >= 100 ? 14 : 0;
22
+ const labelWidth = Math.max(1, width - providerWidth - contextWidth - reasoningWidth - 5);
21
23
  for (const [offset, option] of opts.options.slice(start, start + page).entries()) {
22
24
  const active = start + offset === index;
23
- const text = `${active ? "›" : " "}${current(option) ? "●" : " "} `
24
- + padLine(oneLine(option.label), labelWidth)
25
+ const name = `${active ? "›" : " "}${current(option) ? "●" : " "} `
26
+ + padLine(oneLine(option.label), labelWidth);
27
+ const text = (active ? (t.markdownLink ?? t.accent)(name) : name)
28
+ + (contextWidth ? padLine(option.modelInfo?.context !== undefined
29
+ ? ` ${(option.modelInfo.context / 1000).toLocaleString("en-US", { maximumFractionDigits: 1 })}k ctx` : " —", contextWidth) : "")
30
+ + (reasoningWidth ? padLine(option.modelInfo?.reasoning === true ? " Reasoning" : "", reasoningWidth) : "")
25
31
  + (providerWidth ? " " + fitLine(oneLine(option.group ?? ""), providerWidth) : "");
26
32
  lines.push(row(active ? t.selected(padLine(text, width)) : t.silver(text)));
27
33
  }
@@ -34,10 +40,14 @@ export function renderModelPicker(opts) {
34
40
  if (selected && height >= 12) {
35
41
  lines.push(divider, row(t.accent(oneLine(selected.label))
36
42
  + (current(selected) ? t.muted(" · " + tr("Attuale", "Current")) : "")));
37
- if (selected.group)
38
- lines.push(row(t.muted(oneLine(selected.group))));
43
+ const info = selected.modelInfo;
44
+ if (info && width >= 45 && height - lines.length >= 5) {
45
+ const cell = Math.floor(width / 3);
46
+ const price = (value) => value === undefined ? "—" : `$${value.toLocaleString("en-US", { maximumFractionDigits: 4 })} / 1M`;
47
+ lines.push(row(t.muted(padLine("Input", cell) + padLine(tr("Input cache", "Cached input"), cell) + "Output")), row(t.bold(padLine(price(info.cost["input"]), cell) + padLine(price(info.cost["cache_read"]), cell) + price(info.cost["output"]))), row(t.dim(tr("Listino API · non il costo dell’abbonamento", "API list price · not subscription charges"))));
48
+ }
39
49
  const detailSpace = Math.max(0, height - lines.length - 2);
40
- lines.push(...wrapText(selected.detail, width, true).slice(0, detailSpace).map(text => row(t.silver(text))));
50
+ lines.push(...wrapText(selected.detail, width, true).slice(0, detailSpace).map(text => row(t.muted(text))));
41
51
  }
42
52
  const footer = row(t.muted(width >= 55
43
53
  ? tr("↑↓ scegli · Invio conferma · Tab dettagli · Esc annulla", "↑↓ select · Enter confirm · Tab details · Esc cancel")
@@ -1,22 +1,31 @@
1
+ import { tr } from "./i18n.js";
1
2
  import { saveGlobalSettings } from "../core/settings.js";
2
3
  import { cachedModelCatalog, loadModelsDev } from "../providers/models-dev.js";
3
4
  import { modelEfforts } from "../providers/model-effort.js";
4
5
  import { selectOption } from "./selector.js";
5
6
  import { notifyStatus } from "./command-feedback.js";
6
- const descriptions = {
7
- "": "Impostazione predefinita del provider", none: "Reasoning disattivato", minimal: "Ragionamento minimo",
8
- low: "Ragionamento leggero", medium: "Ragionamento intermedio", high: "Ragionamento approfondito",
9
- xhigh: "Ragionamento molto approfondito", max: "Massimo livello disponibile per questo modello",
10
- };
7
+ function effortDescriptions() {
8
+ return {
9
+ "": tr("Impostazione predefinita del provider", "Provider default"),
10
+ none: tr("Reasoning disattivato", "Reasoning disabled"),
11
+ minimal: tr("Ragionamento minimo", "Minimal reasoning"),
12
+ low: tr("Ragionamento leggero", "Light reasoning"),
13
+ medium: tr("Ragionamento intermedio", "Medium reasoning"),
14
+ high: tr("Ragionamento approfondito", "Deep reasoning"),
15
+ xhigh: tr("Ragionamento molto approfondito", "Very deep reasoning"),
16
+ max: tr("Massimo livello disponibile per questo modello", "Highest level available for this model"),
17
+ };
18
+ }
11
19
  export async function pickEffort(fullModel, harness, ctl, theme, terminalColumns, select = selectOption) {
12
20
  const metadata = cachedModelCatalog(harness.env).get(fullModel);
13
21
  const levels = modelEfforts(fullModel, metadata);
22
+ const descriptions = effortDescriptions();
14
23
  const selected = await select({
15
24
  title: `${metadata?.name ?? fullModel.split("/").pop()} · effort`,
16
- hint: levels.length > 1 ? "Un livello maggiore può richiedere più tempo e token. Esc annulla la scelta del modello."
17
- : metadata?.reasoning === false ? "Questo modello non supporta reasoning."
18
- : "Nessun controllo effort verificato per questo modello e provider: usa il predefinito.",
19
- options: levels.map(level => ({ key: level, label: level || "default", detail: descriptions[level], value: level })),
25
+ hint: levels.length > 1 ? tr("Un livello maggiore può richiedere più tempo e token. Esc annulla la scelta del modello.", "A higher level may take more time and tokens. Esc cancels model selection.")
26
+ : metadata?.reasoning === false ? tr("Questo modello non supporta reasoning.", "This model does not support reasoning.")
27
+ : tr("Nessun controllo effort verificato per questo modello e provider: usa il predefinito.", "No verified effort control for this model and provider: use the default."),
28
+ options: levels.map(level => ({ key: level, label: level || tr("predefinito", "default"), detail: descriptions[level], value: level })),
20
29
  currentKey: levels.includes(harness.config.effort) ? harness.config.effort : "",
21
30
  ctl, theme, terminalColumns,
22
31
  });
@@ -25,7 +34,7 @@ export async function pickEffort(fullModel, harness, ctl, theme, terminalColumns
25
34
  export async function applyModelChoice(model, harness, ctl, theme, terminalColumns, select = selectOption) {
26
35
  const resolved = harness.providers.resolve(model);
27
36
  if (!resolved) {
28
- notifyStatus(ctl, `Provider non configurato per ${model}`, true);
37
+ notifyStatus(ctl, tr("Provider non configurato per {p0}", "Provider not configured for {p0}", { p0: model }), true);
29
38
  return false;
30
39
  }
31
40
  const fullModel = `${resolved.provider.id}/${resolved.modelId}`;
@@ -78,6 +78,11 @@ export class NativeScrollback {
78
78
  if (!committed.length && !resized) {
79
79
  while (start < frame.length && start < this.frame.length && frame[start] === this.frame[start])
80
80
  start++;
81
+ // Cursor-down cannot create a row below the terminal's bottom edge: it
82
+ // clamps to the last row. Repaint from an existing row so an appended
83
+ // input line (wrap, clipboard hint) advances with CRLF and scrolls.
84
+ if (frame.length > this.frame.length)
85
+ start = Math.min(start, Math.max(0, this.frame.length - 1));
81
86
  }
82
87
  const changed = committed.length > 0 || resized || start < Math.max(frame.length, this.frame.length);
83
88
  if (!changed && row === this.cursorRow && col === this.cursorCol)
@@ -20,6 +20,8 @@ export declare class PromptQueue {
20
20
  private holding;
21
21
  readonly inbox: UserInbox;
22
22
  constructor(prepare?: (text: string) => readonly ContentPart[], onChange?: () => void, persistence?: QueuePersistence | undefined, restoreInput?: (entry: QueuedPrompt) => QueuedPrompt);
23
+ /** Rilascia una coda worker dopo la chiusura definitiva della sua sessione. */
24
+ dispose(): void;
23
25
  get length(): number;
24
26
  get teamRequestCount(): number;
25
27
  get blocked(): boolean;
@@ -37,6 +39,7 @@ export declare class PromptQueue {
37
39
  add(text: string, delivery?: PromptDelivery, parts?: readonly ContentPart[], id?: string): QueuedPrompt;
38
40
  update(id: string, text: string): boolean;
39
41
  remove(id: string): boolean;
42
+ recallLast(): QueuedPrompt | undefined;
40
43
  move(id: string, offset: number): boolean;
41
44
  moveFirst(id: string): boolean;
42
45
  setDelivery(id: string, delivery: PromptDelivery): boolean;
@@ -40,8 +40,9 @@ export class PromptQueue {
40
40
  const parts = typeof input === "string" ? queue.prepare(input) : input;
41
41
  return queue.add(pendingText({ id: "", parts, queuedAt: 0 }), "during-turn", parts, id).id;
42
42
  },
43
- promote: id => queue.moveFirst(id),
43
+ promote: id => queue.sendNow(id),
44
44
  get pending() { return queue.entries.filter(e => queue.ready(e)).length; },
45
+ get queued() { return queue.entries.length; },
45
46
  onImmediate(listener) {
46
47
  queue.immediateListeners.add(listener);
47
48
  if (queue.immediatePending)
@@ -61,6 +62,12 @@ export class PromptQueue {
61
62
  },
62
63
  };
63
64
  }
65
+ /** Rilascia una coda worker dopo la chiusura definitiva della sua sessione. */
66
+ dispose() {
67
+ this.entries = [];
68
+ this.delivered.clear();
69
+ this.immediateListeners.clear();
70
+ }
64
71
  get length() { return this.entries.length; }
65
72
  get teamRequestCount() { return this.entries.filter(e => !e.text.trimStart().startsWith("/")).length; }
66
73
  get blocked() { return this.paused || this.held; }
@@ -128,6 +135,17 @@ export class PromptQueue {
128
135
  this.changed();
129
136
  return true;
130
137
  }
138
+ // Estrae atomicamente l'ultimo messaggio ancora in attesa. Il composer lo
139
+ // usa per riportarlo nell'input con Freccia su: rimuoverlo prima evita che la
140
+ // versione originale e quella modificata possano essere consegnate entrambe.
141
+ recallLast() {
142
+ const entry = this.entries[this.entries.length - 1];
143
+ if (!entry)
144
+ return undefined;
145
+ this.entries = this.entries.slice(0, -1);
146
+ this.changed();
147
+ return entry;
148
+ }
131
149
  move(id, offset) {
132
150
  const from = this.entries.findIndex(e => e.id === id);
133
151
  if (from < 0)
@@ -0,0 +1,2 @@
1
+ import type { Provider } from "../core/types.js";
2
+ export declare function providerLabel(provider: Pick<Provider, "id" | "label">): string;
@@ -0,0 +1,9 @@
1
+ import { tr } from "./i18n.js";
2
+ // Resolve display text when rendering so an existing provider follows language changes.
3
+ export function providerLabel(provider) {
4
+ if (provider.id === "claude-code")
5
+ return `Claude Code (${tr("abbonamento", "subscription")})`;
6
+ if (provider.id === "chatgpt")
7
+ return `ChatGPT (${tr("abbonamento", "subscription")})`;
8
+ return provider.label ?? provider.id;
9
+ }
@@ -1,3 +1,4 @@
1
+ import { tr } from "./i18n.js";
1
2
  // Logica del menu provider navigabile (/provider). Parte PURA, senza
2
3
  // dipendenze dalla TUI: calcola lo stato dei provider e incapsula le azioni di
3
4
  // persistenza (salva chiave, salva endpoint, rimuovi). La UI in repl.ts si
@@ -88,34 +89,34 @@ export function providerRows(env, registry, currentModel) {
88
89
  // Riepilogo di stato a una riga, da mostrare nel picker accanto al nome.
89
90
  export function rowStatusLabel(row) {
90
91
  if (row.active)
91
- return "attivo";
92
+ return tr("attivo", "active");
92
93
  if (row.source === "local")
93
- return "locale";
94
+ return tr("locale", "local");
94
95
  if (row.source === "env")
95
- return "configurato (env)";
96
+ return tr("configurato (env)", "configured (env)");
96
97
  if (row.source === "saved")
97
- return "configurato";
98
- return "da configurare";
98
+ return tr("configurato", "configured");
99
+ return tr("da configurare", "not configured");
99
100
  }
100
101
  // Suggerimento d'aiuto per ottenere la chiave del provider.
101
102
  export function providerKeyHint(spec) {
102
103
  switch (spec.id) {
103
104
  case "openrouter":
104
- return "ottieni la chiave su https://openrouter.ai/keys (sk-or-...) o usa il login OAuth";
105
+ return tr("ottieni la chiave su https://openrouter.ai/keys (sk-or-...) o usa il login OAuth", "Get a key at https://openrouter.ai/keys (sk-or-...) or sign in with OAuth");
105
106
  case "anthropic":
106
- return "ottieni la chiave su https://console.anthropic.com/settings/keys (sk-ant-...)";
107
+ return tr("ottieni la chiave su https://console.anthropic.com/settings/keys (sk-ant-...)", "Get a key at https://console.anthropic.com/settings/keys (sk-ant-...)");
107
108
  case "openai":
108
- return "ottieni la chiave su https://platform.openai.com/api-keys (sk-...)";
109
+ return tr("ottieni la chiave su https://platform.openai.com/api-keys (sk-...)", "Get a key at https://platform.openai.com/api-keys (sk-...)");
109
110
  case "ollama":
110
- return "provider locale: imposta solo l'endpoint (default http://localhost:11434/v1)";
111
+ return tr("provider locale: imposta solo l'endpoint (default http://localhost:11434/v1)", "Local provider: set the endpoint only (default http://localhost:11434/v1)");
111
112
  case "lmstudio":
112
- return "provider locale: avvia il server di LM Studio (default http://127.0.0.1:1234/v1)";
113
+ return tr("provider locale: avvia il server di LM Studio (default http://127.0.0.1:1234/v1)", "Local provider: start the LM Studio server (default http://127.0.0.1:1234/v1)");
113
114
  case "opensource":
114
- return "collega l'endpoint /v1 di Unsloth, vLLM, llama.cpp o qualsiasi server OpenAI-compatible";
115
+ return tr("collega l'endpoint /v1 di Unsloth, vLLM, llama.cpp o qualsiasi server OpenAI-compatible", "Connect the /v1 endpoint of Unsloth, vLLM, llama.cpp or any OpenAI-compatible server");
115
116
  case "xai":
116
- return "ottieni la chiave xAI per Grok su https://console.x.ai (XAI_API_KEY)";
117
+ return tr("ottieni la chiave xAI per Grok su https://console.x.ai (XAI_API_KEY)", "Get an xAI key for Grok at https://console.x.ai (XAI_API_KEY)");
117
118
  default:
118
- return spec.envKey ? `imposta la API key (variabile ${spec.envKey})` : "provider locale: nessuna chiave";
119
+ return spec.envKey ? tr("imposta la API key (variabile {p0})", "Set the API key ({p0} variable)", { p0: spec.envKey }) : tr("provider locale: nessuna chiave", "Local provider: no key required");
119
120
  }
120
121
  }
121
122
  // Salva la API key di un provider sul file globale. Validazione di forma
@@ -123,21 +124,21 @@ export function providerKeyHint(spec) {
123
124
  export function saveProviderKey(env, providerId, apiKey) {
124
125
  const key = apiKey.trim();
125
126
  if (!key)
126
- return { ok: false, error: "API key vuota" };
127
+ return { ok: false, error: tr("API key vuota", "Empty API key") };
127
128
  const ok = saveCredential(env, providerId, { apiKey: key });
128
- return ok ? { ok: true } : { ok: false, error: "impossibile salvare (config globale disattivata?)" };
129
+ return ok ? { ok: true } : { ok: false, error: tr("impossibile salvare (config globale disattivata?)", "Unable to save (global configuration disabled?)") };
129
130
  }
130
131
  // Salva/aggiorna l'endpoint (baseUrl) di un provider. Una stringa vuota
131
132
  // rimuove l'override e ripristina il default del catalogo.
132
133
  export function saveProviderBaseUrl(env, providerId, baseUrl) {
133
134
  const ok = saveCredential(env, providerId, { baseUrl: baseUrl.trim() });
134
- return ok ? { ok: true } : { ok: false, error: "impossibile salvare l'endpoint" };
135
+ return ok ? { ok: true } : { ok: false, error: tr("impossibile salvare l'endpoint", "Unable to save the endpoint") };
135
136
  }
136
137
  // Rimuove la credenziale salvata di un provider. Non tocca le env esportate
137
138
  // dall'utente (quelle hanno precedenza e restano).
138
139
  export function removeProvider(env, providerId) {
139
140
  const ok = deleteCredential(env, providerId);
140
- return ok ? { ok: true } : { ok: false, error: "impossibile rimuovere la credenziale" };
141
+ return ok ? { ok: true } : { ok: false, error: tr("impossibile rimuovere la credenziale", "Unable to remove the credential") };
141
142
  }
142
143
  // Indica se la chiave di un provider e' stata salvata da noi (rimovibile dal
143
144
  // menu) o proviene da una env esportata dall'utente (non rimovibile dal menu).
@@ -152,24 +153,24 @@ export function actionsFor(env, row) {
152
153
  if (row.needsKey) {
153
154
  out.push({
154
155
  action: "set-key",
155
- label: row.source === "saved" || row.source === "env" ? "aggiorna API key" : "imposta API key",
156
+ label: row.source === "saved" || row.source === "env" ? tr("aggiorna API key", "update API key") : tr("imposta API key", "set API key"),
156
157
  detail: providerKeyHint(row.spec),
157
158
  });
158
159
  if (row.id === "openrouter") {
159
- out.push({ action: "oauth", label: "accedi con OAuth (browser)", detail: "autorizza su openrouter.ai senza incollare la chiave" });
160
+ out.push({ action: "oauth", label: tr("accedi con OAuth (browser)", "sign in with OAuth (browser)"), detail: tr("autorizza su openrouter.ai senza incollare la chiave", "authorize on openrouter.ai without pasting a key") });
160
161
  }
161
162
  }
162
163
  out.push({
163
164
  action: "set-endpoint",
164
- label: "imposta endpoint (baseUrl)",
165
- detail: row.baseUrl ? `attuale: ${row.baseUrl}` : "endpoint API personalizzato",
165
+ label: tr("imposta endpoint (baseUrl)", "set endpoint (baseUrl)"),
166
+ detail: row.baseUrl ? tr("attuale: {p0}", "current: {p0}", { p0: row.baseUrl }) : tr("endpoint API personalizzato", "custom API endpoint"),
166
167
  });
167
168
  if (row.configured) {
168
- out.push({ action: "use-model", label: "scegli un modello di questo provider", detail: "apre il picker dei modelli" });
169
+ out.push({ action: "use-model", label: tr("scegli un modello di questo provider", "choose a model from this provider"), detail: tr("apre il picker dei modelli", "opens the model picker") });
169
170
  }
170
171
  if (isRemovable(env, row.id)) {
171
- out.push({ action: "remove", label: "rimuovi credenziale salvata", detail: "elimina chiave/endpoint dal config" });
172
+ out.push({ action: "remove", label: tr("rimuovi credenziale salvata", "remove saved credential"), detail: tr("elimina chiave/endpoint dal config", "removes the key/endpoint from configuration") });
172
173
  }
173
- out.push({ action: "back", label: "← torna all'elenco", detail: "" });
174
+ out.push({ action: "back", label: tr("← torna all'elenco", "← back to the list"), detail: "" });
174
175
  return out;
175
176
  }
@@ -20,7 +20,8 @@ export function queuePreview(queue, width, style = PLAIN_QUEUE_STYLE, idle = fal
20
20
  const shortMode = immediate ? next.teamBatchId ? tr("invio al team", "to team") : tr("invio", "sending") : paused ? tr("pausa", "paused")
21
21
  : next.delivery === "during-turn" ? tr("dopo risposta/operazione", "after response/tool") : tr("dopo risposta", "after response");
22
22
  const short = queue.length === 1 ? `${noun} · ${shortMode}` : `${queue.length} · ${shortMode}`;
23
- const keys = [paused && idle ? tr("Invio riprende", "Enter resume") : !immediate && !next.text.trimStart().startsWith("/") ? tr("Alt+S subito", "Alt+S send now") : "",
23
+ const keys = [tr("↑ modifica ultimo", "↑ edit last"),
24
+ paused && idle ? tr("Invio riprende", "Enter resume") : !immediate && !next.text.trimStart().startsWith("/") ? tr("Alt+S subito", "Alt+S send now") : "",
24
25
  "Alt+Q", queue.teamRequestCount >= 3 ? "Alt+T team" : ""].filter(Boolean);
25
26
  const max = Math.max(0, width - 1);
26
27
  let hint = ` (${keys.join(" · ")})`;
@@ -0,0 +1,7 @@
1
+ import type { TuiTheme } from "./branding.js";
2
+ interface Uscita {
3
+ write(text: string): void;
4
+ writeConversation?(text: string): void;
5
+ }
6
+ export declare function comandoRemoto(args: string, out: Uscita, theme: TuiTheme, env: NodeJS.ProcessEnv, cwd: string, avvisa: (testo: string) => void): Promise<void>;
7
+ export {};
@@ -0,0 +1,79 @@
1
+ // /remote: accende, mostra o spegne il controllo remoto (telefono, web).
2
+ // /remote accende (o mostra il link se e' gia' acceso)
3
+ // /remote status stato del collegamento e dispositivi collegati
4
+ // /remote off chiude la sessione per tutti
5
+ import { copyText } from "./clipboard-text.js";
6
+ import { tr } from "./i18n.js";
7
+ import { leggiSessione } from "./vascend-id.js";
8
+ import { RelayError, avviaRemoto, fermaRemoto, sessioneRemota } from "../remote/index.js";
9
+ function messaggioErrore(e) {
10
+ const code = e instanceof RelayError ? e.code : "rete";
11
+ switch (code) {
12
+ case "piano": return tr("Il controllo remoto è incluso nei piani Pro, Pro Max, Team ed Enterprise.", "Remote control is included in the Pro, Pro Max, Team and Enterprise plans.");
13
+ case "token": return tr("Serve un nuovo accesso per il controllo remoto: esci con /logout e riapri Talos.", "Remote control needs a new sign-in: run /logout and open Talos again.");
14
+ case "troppe_sessioni": return tr("Troppe sessioni remote aperte: chiudine qualcuna e riprova.", "Too many remote sessions open: close some and try again.");
15
+ case "occupato": return tr("Il servizio è occupato: riprova tra poco.", "The service is busy: try again shortly.");
16
+ default: return tr("Servizio del controllo remoto non raggiungibile: controlla la rete e riprova.", "Remote control service unreachable: check the network and try again.");
17
+ }
18
+ }
19
+ function statoLeggibile(stato) {
20
+ switch (stato) {
21
+ case "collegato": return tr("collegato", "connected");
22
+ case "connessione": return tr("in collegamento", "connecting");
23
+ case "attesa": return tr("rete persa, riprovo", "network lost, retrying");
24
+ default: return tr("chiuso", "closed");
25
+ }
26
+ }
27
+ export async function comandoRemoto(args, out, theme, env, cwd, avvisa) {
28
+ const azione = args.trim().toLowerCase();
29
+ const attiva = sessioneRemota();
30
+ if (azione === "off" || azione === "stop") {
31
+ const chiusa = await fermaRemoto();
32
+ out.write(chiusa
33
+ ? theme.green(`\n ${tr("Controllo remoto chiuso per tutti i dispositivi.", "Remote control closed on every device.")}\n`)
34
+ : theme.dim(`\n ${tr("Il controllo remoto non è attivo.", "Remote control is not active.")}\n`));
35
+ return;
36
+ }
37
+ if (azione === "status" || azione === "stato") {
38
+ out.write(attiva
39
+ ? `\n ${tr("Controllo remoto: {stato}, dispositivi collegati: {n}", "Remote control: {stato}, connected devices: {n}", { stato: statoLeggibile(attiva.statoRelay()), n: String(attiva.dispositivi()) })}\n`
40
+ : theme.dim(`\n ${tr("Il controllo remoto non è attivo. /remote per accenderlo.", "Remote control is not active. /remote to turn it on.")}\n`));
41
+ return;
42
+ }
43
+ if (azione && azione !== "on") {
44
+ out.write(theme.yellow(`\n ${tr("Uso: /remote, /remote status, /remote off", "Usage: /remote, /remote status, /remote off")}\n`));
45
+ return;
46
+ }
47
+ if (!leggiSessione(env)) {
48
+ out.write(theme.yellow(`\n ${tr("Il controllo remoto usa il tuo account Vascend: accedi riaprendo Talos.", "Remote control uses your Vascend account: sign in by opening Talos again.")}\n`));
49
+ return;
50
+ }
51
+ let sessione;
52
+ try {
53
+ sessione = attiva ?? await avviaRemoto(env, cwd, {
54
+ onStato: (stato, motivo) => {
55
+ if (stato === "chiuso")
56
+ avvisa(tr("Controllo remoto chiuso: {motivo}", "Remote control closed: {motivo}", { motivo: motivo ?? statoLeggibile(stato) }));
57
+ else if (stato === "attesa")
58
+ avvisa(tr("Controllo remoto: rete persa, riprovo", "Remote control: network lost, retrying"));
59
+ },
60
+ onPresenza: (n) => avvisa(tr("Controllo remoto: dispositivi collegati: {n}", "Remote control: connected devices: {n}", { n: String(n) })),
61
+ });
62
+ }
63
+ catch (e) {
64
+ out.write(theme.yellow(`\n ${messaggioErrore(e)}\n`));
65
+ return;
66
+ }
67
+ const copiato = await copyText(sessione.link).catch(() => false);
68
+ // Il link va in chat per intero, non in un riquadro che lo spezza.
69
+ const scrivi = out.writeConversation?.bind(out) ?? out.write.bind(out);
70
+ scrivi([
71
+ "",
72
+ ` ${theme.green(tr("Controllo remoto attivo", "Remote control on"))}`,
73
+ ` ${tr("Apri il link sul telefono, con lo stesso account Vascend:", "Open the link on your phone, with the same Vascend account:")}`,
74
+ ` ${sessione.link}`,
75
+ ` ${theme.dim(copiato ? tr("Copiato negli appunti. Il link contiene la chiave della sessione: non condividerlo.", "Copied to the clipboard. The link holds the session key: do not share it.") : tr("Il link contiene la chiave della sessione: non condividerlo.", "The link holds the session key: do not share it."))}`,
76
+ ` ${theme.dim(tr("/remote status per lo stato, /remote off per chiudere.", "/remote status for the state, /remote off to close."))}`,
77
+ "",
78
+ ].join("\n"));
79
+ }
@@ -11,6 +11,7 @@ interface ReplDeps {
11
11
  readonly recoverQueue?: boolean;
12
12
  }
13
13
  export interface InputControl {
14
+ cyclePermissionMode?(): void;
14
15
  writeConversation?(text: string): void;
15
16
  clearConversation?(): void;
16
17
  replayConversation?(renderer: (columns: number) => string): void;
@@ -22,12 +23,14 @@ export interface InputControl {
22
23
  pauseQueuedMessages?(): void;
23
24
  readonly review?: ReviewStore;
24
25
  showReview?(section?: string): void;
26
+ showAgents?(): void;
25
27
  pause(): void;
26
28
  resume(): void;
27
29
  write(text: string): void;
28
30
  replaceTail?(lines: readonly string[], count: number): void;
29
31
  refresh?(): void;
30
32
  setStatus(label: string | null): void;
33
+ readonly busyCommands?: boolean;
31
34
  setCompacting?(active: boolean): void;
32
35
  showSessionNaming?(title: string): void;
33
36
  setSessionNaming?(phase: "start" | "end", title: string): void;
@@ -73,9 +76,12 @@ export declare function endActiveTurnInbox(): void;
73
76
  export declare function deliverToActiveTurn(raw: string, parts?: readonly ContentPart[]): boolean;
74
77
  export declare function createSerialReadlineQueue(options: SerialReadlineQueueOptions): SerialReadlineQueue;
75
78
  export declare function startRepl(deps: ReplDeps): Promise<void>;
76
- export declare function makeSink(theme: TuiTheme, terminalColumns: () => number, cwd: string, env: NodeJS.ProcessEnv, ctl: InputControl, plan?: {
79
+ export type TranscriptControl = Pick<InputControl, "write" | "setStatus" | "setTokens" | "logLength" | "refresh" | "setCompacting" | "setStatusTool" | "setRoomStatus" | "setSessionNaming" | "setLogLine" | "getLogLine" | "acceptQueuedMessage" | "pauseQueuedMessages" | "queueQuestion" | "review">;
80
+ export declare function makeSink(theme: TuiTheme, terminalColumns: () => number, cwd: string, env: NodeJS.ProcessEnv, ctl: TranscriptControl, plan?: {
77
81
  sdir: string;
78
82
  sid: string;
79
- }): (event: AgentEvent) => void;
83
+ }, replay?: boolean): ((event: AgentEvent) => void) & {
84
+ preview: () => string;
85
+ };
80
86
  export declare function gitSummary(command: string): string | null;
81
87
  export declare function oneLinePreview(text: string, max: number): string;