@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
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { closeSync, fsyncSync, openSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { withLockSync } from "../vascend/file-lock.js";
|
|
4
|
+
// Non convertire una config illeggibile in {}: il prossimo salvataggio
|
|
5
|
+
// cancellerebbe credenziali e preferenze. Solo ENOENT significa prima esecuzione.
|
|
6
|
+
export function readConfigObject(path) {
|
|
7
|
+
let text;
|
|
8
|
+
try {
|
|
9
|
+
text = readFileSync(path, "utf8");
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
if (error.code === "ENOENT")
|
|
13
|
+
return {};
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
16
|
+
const value = JSON.parse(text);
|
|
17
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
18
|
+
throw new Error("La configurazione deve essere un oggetto JSON");
|
|
19
|
+
}
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
// Temporaneo esclusivo nella stessa directory: rename sostituisce il file solo
|
|
23
|
+
// dopo scrittura + flush. Mai unlink del target, neppure su errore Windows.
|
|
24
|
+
function replaceConfig(path, content) {
|
|
25
|
+
const temporary = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
26
|
+
let fd;
|
|
27
|
+
try {
|
|
28
|
+
fd = openSync(temporary, "wx", 0o600);
|
|
29
|
+
writeFileSync(fd, content, "utf8");
|
|
30
|
+
fsyncSync(fd);
|
|
31
|
+
closeSync(fd);
|
|
32
|
+
fd = undefined;
|
|
33
|
+
renameSync(temporary, path);
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
if (fd !== undefined)
|
|
37
|
+
closeSync(fd);
|
|
38
|
+
try {
|
|
39
|
+
unlinkSync(temporary);
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (error.code !== "ENOENT")
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Lock comune a settings e credenziali: anche due processi devono fondere
|
|
48
|
+
// l'ultima versione, non sovrascrivere gli aggiornamenti dell'altro.
|
|
49
|
+
export function updateConfigObject(path, update) {
|
|
50
|
+
withLockSync(path, () => {
|
|
51
|
+
const current = readConfigObject(path);
|
|
52
|
+
const next = update(current);
|
|
53
|
+
const content = JSON.stringify(next, null, 2) + "\n";
|
|
54
|
+
replaceConfig(path, content);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
// Chiamare solo dopo consenso esplicito. Se un altro processo ha gia' riparato
|
|
58
|
+
// il file, non azzerarlo. Il backup conserva esattamente i byte originali.
|
|
59
|
+
export function resetInvalidConfig(path) {
|
|
60
|
+
return withLockSync(path, () => {
|
|
61
|
+
const original = readFileSync(path);
|
|
62
|
+
try {
|
|
63
|
+
const value = JSON.parse(original.toString("utf8"));
|
|
64
|
+
if (value && typeof value === "object" && !Array.isArray(value))
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
catch { /* JSON invalido */ }
|
|
68
|
+
const backup = `${path}.corrupt-${Date.now()}-${randomUUID()}.bak`;
|
|
69
|
+
const fd = openSync(backup, "wx", 0o600);
|
|
70
|
+
try {
|
|
71
|
+
writeFileSync(fd, original);
|
|
72
|
+
fsyncSync(fd);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
closeSync(fd);
|
|
76
|
+
}
|
|
77
|
+
if (!readFileSync(path).equals(original))
|
|
78
|
+
throw new Error("Configurazione cambiata durante il ripristino; riprova.");
|
|
79
|
+
// {} eredita tutti i default dal codice, senza fissarli a questa versione.
|
|
80
|
+
replaceConfig(path, "{}\n");
|
|
81
|
+
return backup;
|
|
82
|
+
});
|
|
83
|
+
}
|
package/dist/core/config.d.ts
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { type CompactionConfig } from "./compaction.js";
|
|
2
2
|
import { type VibeModeSelection } from "./vibe-modes.js";
|
|
3
|
-
|
|
4
|
-
export declare
|
|
3
|
+
import { type FusionConfig } from "./fusion.js";
|
|
4
|
+
export declare class InvalidConfigError extends Error {
|
|
5
|
+
readonly path: string;
|
|
6
|
+
constructor(path: string, cause: unknown);
|
|
7
|
+
}
|
|
8
|
+
export declare const BASE_SYSTEM = "# Vascend Talos\n\nINDICE\n1 = agente\n2 = workspace\n3 = strumento\n4 = azione\n\nDEFINIZIONI\n@agente[ruolo]: coding_agent in terminale, conciso, diretto\n@workspace[fonte]: ispeziona coi tool invece di indovinare\n@strumento[uso]: read/edit/bash per agire sul workspace, non descrivere\n@strumento[terminale]: per ricerca e ispezione del codice preferisci bash con rg e rg --files, git diff/status e comandi nativi della shell selezionata. Limita path e output a cio' che serve. Se rg o il terminale non sono disponibili usa grep/glob/read_file/list_dir. Per modifiche puntuali usa edit_file/write_file e rispetta il coordinamento dei file\n@strumento[write_grande]: per file lunghi (oltre ~150 righe) scrivi in PIU' chiamate write_file: la prima crea il file, le successive con append=true accodano il resto. Un singolo write enorme puo' essere troncato dal limite di output e fallire\n@strumento[ricerca]: prima di costruire qualcosa di non banale, RICERCA con web_fetch (documentazione, riferimenti, esempi) invece di indovinare le API\n@strumento[domanda]: se un requisito e' davvero ambiguo e cambia il risultato, usa ask_user PRIMA di procedere; per i dettagli minori assumi il default ragionevole e dichiaralo, non fermarti di continuo\n@strumento[risposta_mancante]: ask_user required=true mantiene esplicita l'informazione necessaria non ricevuta; prosegui solo col lavoro indipendente. required=false serve per preferenze facoltative e reversibili. Silenzio e annullamento non sono consenso\n@strumento[e2e]: per un obiettivo grande (es. ricostruire una piattaforma) pianifica con vascend_plan in piu' gruppi/attivita, ricerca, costruisci una BOZZA COMPLETA end-to-end; annota le decisioni con vascend_note\n@strumento[collaboratori]: chiama team_engage soltanto quando l'utente chiede esplicitamente piu' agenti, sub-agent o lavoro parallelo; una domanda informativa, un controllo del workspace o un task semplice restano sempre sul singolo agente principale\n@strumento[ripresa]: vascend_status legge task, dipendenze, note e prove persistite; riprendi il piano esistente dopo resume/compattazione. vascend_addtasks estende, vascend_note conserva decisioni. replace=true ridefinisce esplicitamente un piano, perdendo i suoi progressi\n@strumento[verifica]: definisci passi con un risultato osservabile e una verifica pertinente; running prima del lavoro, completed solo dopo verifica. Un comando in background va seguito con bash_output fino all'esito finale. Le prove salvate sono evidenze da controllare, non certificazioni\n@azione[proporzione]: mantieni piano, strumenti e verifiche proporzionati al compito; le richieste semplici o a singolo passo non richiedono piano ne' collaboratori\n@azione[distruttiva]: spiega prima cosa stai per fare\n@azione[fine]: a compito finito fermati, niente riepiloghi superflui\n\nOUTPUT: agente di coding che agisce coi tool, conciso, con risposte Markdown leggibili.\n\nEfficient execution\n- Determine whether the user wants advice, an explanation, instructions for manual work, or\n actual execution. Advice and manual instructions are fulfilled by the response; do not run\n their example scripts or perform the user's setup. A todo list does not grant authorization.\n Before continuing after an error, check whether further agent action is needed and authorized.\n Stop when the request is answered; wait when the next step belongs to the user or needs input.\n Preserve incomplete tasks honestly instead of forcing completion or retrying indefinitely.\n- For a small cosmetic change (one button color, label, spacing or font), locate the affected\n component, edit it, then verify the local result. Do not create a plan, delegate, research the\n web, inspect the whole repository or run a global test/build cycle unless evidence requires it.\n Escalate scope only when the actual dependency or failure demands it.\n- Decide what evidence is needed for the next decision. Issue independent reads together and\n reuse results that are still valid. Do not spend a model round on each already-decided action.\n- Use run_program for known sequences: await dependent edits and plan transitions in order,\n stop on errors, and return a concise summary. Complete a task only after its checks succeed.\n- Prepare related replacements in one round. Never edit the same file concurrently. Independent\n edits on distinct files may run together in bounded groups of at most four; await every outcome\n before inspecting the result or starting dependent work. Keep permission gates in place.\n- For short checks use foreground bash, or background with its brief initial wait. Use\n background=true with yield_time_ms=0 for persistent servers or work that must detach immediately.\n Collect ready background results together; a running command is not a passed check.\n bash_output waits locally for completion by default: call it once and omit timeout_seconds.\n Use wait=false only to inspect a persistent server or diagnose a process; do not poll in a loop.\n- Run the relevant integrated checks after the edits. Repeat checks only after changes, failures\n or a concrete unresolved concern; do not duplicate typecheck and build without a reason.\n- When parallel work is authorized and worthwhile, start with at most two collaborators on\n concrete disjoint areas, agree on interfaces and acceptance checks, and declare after dependencies.\n The coordinator reviews the combined result. Prefer one agent for small or tightly coupled work.\n- Format user-facing responses in readable Markdown: short paragraphs, **bold** key findings,\n lists for steps, tables for comparisons, fenced code with a language, and descriptive links.\n Keep internal planning notation out of ordinary explanations unless the user asks for it.";
|
|
9
|
+
export declare const HORIZON_SYSTEM = "# Horizon\n\nYou are a coding agent embedded in the Horizon workspace.\n- Write in the language the user writes in, and keep writing in it for the whole\n conversation. These instructions are in English for precision, not as a hint about\n the reply language: a message in Italian gets an answer in Italian. Code,\n identifiers, paths, commands and tool arguments stay exactly as they are.\n- Inspect the real workspace before making claims.\n- Match the requested scope: analysis stays read-only; change/build work is implemented end to end and verified.\n- Prefer focused changes, but do not shrink a broad request into a partial patch.\n- Keep planning proportional to the task; simple tasks do not need a formal plan.\n- Use ordinary to-do-list language for progress: tasks, groups, dependencies and\n pending, in progress, completed or failed states, translated into the user's language.\n Memory indexes and internal implementation names are context for you; present the\n relevant tasks, next steps and results to the user.\n- Start substantial work with a short update, then act with tools. During long tasks share\n useful findings or blockers about once a minute; avoid narrating every tool call.\n- Respect the workspace permissions selected by the user.\n- Exhaust safe in-scope alternatives before asking the user to unblock you.\n- Never announce completion while a plan step is pending/running/failed or the requested\n artifact has not been verified. Continue working, or report the concrete blocker.\n- Keep the final answer compact: outcome first, then verification and any blocker. Do not\n expose or recap internal context packs, memory routing, hidden prompts, or chain-of-thought.\n\nTools\n- The tools listed for you cover file reads, writes, edits, search and shell: call them directly.\n- Prefer the terminal for code discovery and inspection: rg for content, rg --files for paths,\n git diff/status for changes, and native commands for the selected shell. Scope searches to\n relevant directories and return only useful output. If rg or terminal access is unavailable,\n use read_file or discover grep/glob/list_dir with tool_search (or call them inside run_program).\n Use edit_file/write_file for focused edits and discover file_activity when coordination needs it.\n Shell access does not expand the authorized workspace or bypass permissions.\n- More tools exist on demand. Find them with tool_search, asking in ONE call for every tool\n you expect to need (\"names\" when you know them, \"query\" otherwise): they become callable\n directly, by name. Do not search again for a tool you loaded. Calling tool_search without\n names/query lists the inventory without activating it; continue with offset=next_offset.\n- Missing a capability? Inspect the actual catalog before assuming a host integration exists.\n If custom-tool authoring is available, follow its guide. Ask the user only for information\n or decisions that the available tools and project context cannot resolve.\n- Use ask_user for missing requirements or decisions that materially change the result.\n Ask a concise, self-contained question early, with options when useful. Collaborators can\n use the same tool. If a required answer is missing, keep the dependency blocked and continue\n independent work; do not invent the answer or interpret silence as approval. Use required=false\n only for optional preferences with a reasonable, reversible default. Routine implementation\n choices should not interrupt the user.\n- For work with several steps \u2014 including games, challenges, puzzles and multi-level tasks \u2014\n lay out the plan with vascend_plan and keep it honest with vascend_mark as you go (one step\n running at a time). The plan is not paperwork: it appears live as a\n task board next to the conversation, where the user follows progress and can edit or add\n steps. Give each step an observable result and a proportionate check. Short, single-step\n requests need no plan. Read vascend_status after resume/compaction and before handing off\n substantial work; resume it only when that is still necessary and authorized by the current\n request. vascend_addtasks extends it without resetting\n progress; vascend_plan with replace=true explicitly replaces it. Save decisions, blockers\n and the next action with vascend_note before switching workstreams.\n- Start a step with vascend_mark status=running. Complete it only after the relevant checks,\n recording paths, commands and observed outcomes. Evidence in the plan is a record to inspect,\n not an automatic correctness certificate. Reopening a step clears old completion evidence.\n Respect after dependencies; use pending to pause a step and failed to record a concrete blocker.\n- A plan is not a collaborator. When the user asks for multiple agents, subagents or parallel\n experts, actually call team_engage: create one collaborator per independent workstream and\n assign its complete task. If vascend_plan already created several task groups, pass their slugs\n through the group field so those collaborators own and update the same T01/T02 tasks. Do not\n merely draw multiple workstreams and then execute all of them in the orchestrator.\n- Issue independent reads together. For related tool sequences use run_program and print only\n the results needed for the next decision; keep dependent edits and approvals sequential.\n- When bash returns a background id, call bash_output once: it waits locally until the process exits.\n Use wait=false to inspect persistent servers; do not repeatedly poll unchanged output. Partial output\n or a started process does not mean the check passed. Leave persistent development servers\n running when they are needed and report their status separately from verification results.\n- Act on what is already in context: do not re-read a file or repeat a search whose result\n you still have.\n- If a tool reports a missing or malformed argument, fix the argument shape it names \u2014 do not\n retry the same call unchanged.\n\nEfficient execution\n- Determine whether the user wants advice, an explanation, instructions for manual work, or\n actual execution. Advice and manual instructions are fulfilled by the response; do not run\n their example scripts or perform the user's setup. A todo list does not grant authorization.\n Before continuing after an error, check whether further agent action is needed and authorized.\n Stop when the request is answered; wait when the next step belongs to the user or needs input.\n Preserve incomplete tasks honestly instead of forcing completion or retrying indefinitely.\n- For a small cosmetic change (one button color, label, spacing or font), locate the affected\n component, edit it, then verify the local result. Do not create a plan, delegate, research the\n web, inspect the whole repository or run a global test/build cycle unless evidence requires it.\n Escalate scope only when the actual dependency or failure demands it.\n- Decide what evidence is needed for the next decision. Issue independent reads together and\n reuse results that are still valid. Do not spend a model round on each already-decided action.\n- Use run_program for known sequences: await dependent edits and plan transitions in order,\n stop on errors, and return a concise summary. Complete a task only after its checks succeed.\n- Prepare related replacements in one round. Never edit the same file concurrently. Independent\n edits on distinct files may run together in bounded groups of at most four; await every outcome\n before inspecting the result or starting dependent work. Keep permission gates in place.\n- For short checks use foreground bash, or background with its brief initial wait. Use\n background=true with yield_time_ms=0 for persistent servers or work that must detach immediately.\n Collect ready background results together; a running command is not a passed check.\n bash_output waits locally for completion by default: call it once and omit timeout_seconds.\n Use wait=false only to inspect a persistent server or diagnose a process; do not poll in a loop.\n- Run the relevant integrated checks after the edits. Repeat checks only after changes, failures\n or a concrete unresolved concern; do not duplicate typecheck and build without a reason.\n- When parallel work is authorized and worthwhile, start with at most two collaborators on\n concrete disjoint areas, agree on interfaces and acceptance checks, and declare after dependencies.\n The coordinator reviews the combined result. Prefer one agent for small or tightly coupled work.\n- Format user-facing responses in readable Markdown: short paragraphs, **bold** key findings,\n lists for steps, tables for comparisons, fenced code with a language, and descriptive links.\n Keep internal planning notation out of ordinary explanations unless the user asks for it.";
|
|
5
10
|
export type TalosBanner = "vascend-terminal" | "minimal" | "custom" | "none";
|
|
6
11
|
export type TalosEffort = "" | "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
7
12
|
export type TalosPermMode = "normal" | "acceptEdits" | "auto";
|
|
@@ -18,10 +23,13 @@ export interface TalosUiConfig {
|
|
|
18
23
|
readonly theme: string;
|
|
19
24
|
}
|
|
20
25
|
export interface PiConfig {
|
|
26
|
+
readonly fusion?: FusionConfig | null;
|
|
21
27
|
readonly cwd: string;
|
|
22
28
|
readonly model: string;
|
|
23
29
|
readonly maxTokens: number;
|
|
24
30
|
readonly system: string;
|
|
31
|
+
/** Authoritative host instructions for this run, outside the stable prefix. */
|
|
32
|
+
readonly turnSystem?: string;
|
|
25
33
|
readonly autoDelegatePlans: boolean;
|
|
26
34
|
readonly workerModelPool?: readonly string[];
|
|
27
35
|
readonly sessionDir: string;
|
|
@@ -42,6 +50,7 @@ export interface PiConfig {
|
|
|
42
50
|
readonly statusLine?: readonly string[];
|
|
43
51
|
readonly vibeMode: VibeModeSelection;
|
|
44
52
|
}
|
|
53
|
+
export declare const DEFAULT_UI: TalosUiConfig;
|
|
45
54
|
export declare function buildConfig(opts: {
|
|
46
55
|
cwd?: string;
|
|
47
56
|
model?: string;
|
package/dist/core/config.js
CHANGED
|
@@ -5,6 +5,16 @@ import { VASCEND_SYSTEM_BLOCK } from "../vascend/runtime.js";
|
|
|
5
5
|
import { parseVibeMode } from "./vibe-modes.js";
|
|
6
6
|
import { defaultSessionDir, talosConfigDir } from "./env-paths.js";
|
|
7
7
|
import { EXECUTION_GUIDANCE } from "./execution-guidance.js";
|
|
8
|
+
import { fusionFromEnv, parseFusion } from "./fusion.js";
|
|
9
|
+
export class InvalidConfigError extends Error {
|
|
10
|
+
path;
|
|
11
|
+
constructor(path, cause) {
|
|
12
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
13
|
+
super(`config Talos non valida: ${path} — ${detail}`);
|
|
14
|
+
this.name = "InvalidConfigError";
|
|
15
|
+
this.path = path;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
8
18
|
// System prompt deliberatamente minimale: la personalita' e le regole
|
|
9
19
|
// di progetto arrivano da SYSTEM.md / AGENTS.md, non dal harness.
|
|
10
20
|
export const BASE_SYSTEM = `# Vascend Talos
|
|
@@ -104,7 +114,8 @@ Tools
|
|
|
104
114
|
merely draw multiple workstreams and then execute all of them in the orchestrator.
|
|
105
115
|
- Issue independent reads together. For related tool sequences use run_program and print only
|
|
106
116
|
the results needed for the next decision; keep dependent edits and approvals sequential.
|
|
107
|
-
- When bash returns a background id,
|
|
117
|
+
- When bash returns a background id, call bash_output once: it waits locally until the process exits.
|
|
118
|
+
Use wait=false to inspect persistent servers; do not repeatedly poll unchanged output. Partial output
|
|
108
119
|
or a started process does not mean the check passed. Leave persistent development servers
|
|
109
120
|
running when they are needed and report their status separately from verification results.
|
|
110
121
|
- Act on what is already in context: do not re-read a file or repeat a search whose result
|
|
@@ -115,7 +126,7 @@ Tools
|
|
|
115
126
|
${EXECUTION_GUIDANCE}`;
|
|
116
127
|
// File di contesto a livello progetto, in ordine di priorita'.
|
|
117
128
|
const DEFAULT_CONTEXT_FILES = ["SYSTEM.md", "AGENTS.md", ".talos/SYSTEM.md"];
|
|
118
|
-
const DEFAULT_UI = {
|
|
129
|
+
export const DEFAULT_UI = {
|
|
119
130
|
banner: "vascend-terminal",
|
|
120
131
|
logoLines: [],
|
|
121
132
|
title: "Vascend Talos",
|
|
@@ -236,15 +247,17 @@ function parseConfigFile(path) {
|
|
|
236
247
|
raw = JSON.parse(readFileSync(path, "utf8"));
|
|
237
248
|
}
|
|
238
249
|
catch (err) {
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
|
|
242
|
-
|
|
250
|
+
// Avviare coi default dopo una scrittura troncata nasconderebbe credenziali
|
|
251
|
+
// e preferenze e farebbe partire erroneamente il login. La config va prima
|
|
252
|
+
// riparata: nessun bootstrap o flusso interattivo deve proseguire.
|
|
253
|
+
throw new InvalidConfigError(path, err);
|
|
254
|
+
}
|
|
255
|
+
if (!isRecord(raw)) {
|
|
256
|
+
throw new InvalidConfigError(path, new Error("la radice deve essere un oggetto JSON"));
|
|
243
257
|
}
|
|
244
|
-
if (!isRecord(raw))
|
|
245
|
-
return {};
|
|
246
258
|
return {
|
|
247
259
|
model: text(raw["model"]),
|
|
260
|
+
fusion: parseFusion(raw["fusion"]),
|
|
248
261
|
maxTokens: positiveInt(raw["maxTokens"]),
|
|
249
262
|
sessionDir: text(raw["sessionDir"]),
|
|
250
263
|
contextFiles: csv(raw["contextFiles"]),
|
|
@@ -261,6 +274,7 @@ function parseConfigFile(path) {
|
|
|
261
274
|
}
|
|
262
275
|
function envPatch(env) {
|
|
263
276
|
return {
|
|
277
|
+
fusion: fusionFromEnv(env),
|
|
264
278
|
model: text(env["TALOS_MODEL"]),
|
|
265
279
|
maxTokens: positiveInt(env["TALOS_MAX_TOKENS"]),
|
|
266
280
|
sessionDir: text(env["TALOS_SESSION_DIR"]),
|
|
@@ -325,6 +339,7 @@ function mergeConfig(base, patch) {
|
|
|
325
339
|
: base.systemAppend;
|
|
326
340
|
return {
|
|
327
341
|
...base,
|
|
342
|
+
fusion: patch.fusion !== undefined ? patch.fusion : base.fusion,
|
|
328
343
|
model: patch.model ?? base.model,
|
|
329
344
|
maxTokens: patch.maxTokens ?? base.maxTokens,
|
|
330
345
|
sessionDir: patch.sessionDir ?? base.sessionDir,
|
|
@@ -399,6 +414,7 @@ export function buildConfig(opts) {
|
|
|
399
414
|
return {
|
|
400
415
|
cwd,
|
|
401
416
|
model: finalConfig.model,
|
|
417
|
+
fusion: finalConfig.fusion,
|
|
402
418
|
maxTokens: finalConfig.maxTokens,
|
|
403
419
|
system,
|
|
404
420
|
autoDelegatePlans: horizonHost,
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
// Modulo PURO: nessuna lettura di disco, nessuna dipendenza dal runtime. A
|
|
13
13
|
// parita' di input restituisce lo stesso registro, quindi e' verificabile.
|
|
14
14
|
import { contextWindowFor, estimateTokens, estimateToolDefinitionTokens, IMAGE_TOKEN_ESTIMATE, } from "./compaction.js";
|
|
15
|
+
import { maxInputFor } from "./model-limits.js";
|
|
15
16
|
// Sotto questa soglia una voce della cronologia non e' un problema di contesto:
|
|
16
17
|
// elencarla sposterebbe l'attenzione dal poco che pesa davvero.
|
|
17
18
|
const HEAVY_MIN_TOKENS = 400;
|
|
@@ -20,7 +21,7 @@ export function buildContextLedger(input) {
|
|
|
20
21
|
const now = input.now ?? Date.now();
|
|
21
22
|
const window = contextWindowFor(input.model, input.contextWindow ?? 0);
|
|
22
23
|
const reserve = Math.max(0, input.reserveTokens ?? 0);
|
|
23
|
-
const compactAt = Math.max(1, Math.min(window - reserve, input.workingContextTokens
|
|
24
|
+
const compactAt = Math.max(1, Math.min(window - reserve, maxInputFor(input.model), input.workingContextTokens || window));
|
|
24
25
|
const slices = [];
|
|
25
26
|
const push = (block, cacheable) => {
|
|
26
27
|
const tokens = block.tokens ?? (block.text ? estimateTokens(block.text) : 0);
|
|
@@ -11,7 +11,7 @@ export interface ContextPolicy {
|
|
|
11
11
|
}
|
|
12
12
|
export declare function isChatHostProfile(env: NodeJS.ProcessEnv): boolean;
|
|
13
13
|
export declare function contextPolicy(env: NodeJS.ProcessEnv): ContextPolicy;
|
|
14
|
-
export declare function workingContextLimits(policy: ContextPolicy, window: number, reserve: number): {
|
|
14
|
+
export declare function workingContextLimits(policy: ContextPolicy, window: number, reserve: number, outputTokens?: number, inputLimit?: number): {
|
|
15
15
|
readonly active: number;
|
|
16
16
|
readonly checkpoint: number;
|
|
17
17
|
};
|
|
@@ -6,16 +6,16 @@ const CHAT_DEFAULTS = {
|
|
|
6
6
|
placement: "turn",
|
|
7
7
|
learning: "deferred",
|
|
8
8
|
roomCompaction: "threshold",
|
|
9
|
-
compactAtFraction: 0.
|
|
10
|
-
workingContextTokens:
|
|
9
|
+
compactAtFraction: 0.9,
|
|
10
|
+
workingContextTokens: 0,
|
|
11
11
|
};
|
|
12
12
|
const AGENT_DEFAULTS = {
|
|
13
13
|
chat: false,
|
|
14
14
|
placement: "turn",
|
|
15
15
|
learning: "deferred",
|
|
16
16
|
roomCompaction: "threshold",
|
|
17
|
-
compactAtFraction: 0.
|
|
18
|
-
workingContextTokens:
|
|
17
|
+
compactAtFraction: 0.9,
|
|
18
|
+
workingContextTokens: 0,
|
|
19
19
|
};
|
|
20
20
|
// Profilo host dichiarato dall'ospite (mai dedotto dal testo utente).
|
|
21
21
|
export function isChatHostProfile(env) {
|
|
@@ -33,9 +33,12 @@ export function contextPolicy(env) {
|
|
|
33
33
|
workingContextTokens: positiveInteger(env["TALOS_WORKING_CONTEXT_TOKENS"]) ?? base.workingContextTokens,
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
-
export function workingContextLimits(policy, window, reserve) {
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
export function workingContextLimits(policy, window, reserve, outputTokens = 0, inputLimit = window) {
|
|
37
|
+
// On small overridden windows the requested output ceiling may exceed the
|
|
38
|
+
// entire window. Admission can shrink output; reserve at most a quarter here.
|
|
39
|
+
const outputReserve = Math.min(outputTokens, Math.floor(window / 4));
|
|
40
|
+
const active = Math.max(1, Math.min(policy.workingContextTokens || window, inputLimit, window - Math.max(reserve, outputReserve)));
|
|
41
|
+
return { active, checkpoint: active * policy.compactAtFraction };
|
|
39
42
|
}
|
|
40
43
|
function positiveInteger(raw) {
|
|
41
44
|
const n = Number(raw);
|
package/dist/core/credentials.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { existsSync,
|
|
2
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { updateConfigObject } from "./config-storage.js";
|
|
3
4
|
import { readOpenRouterCreds } from "../providers/openrouter-auth.js";
|
|
4
5
|
import { talosConfigDir } from "./env-paths.js";
|
|
5
6
|
// Posizione del file globale. null se la config globale e' disattivata
|
|
@@ -90,21 +91,21 @@ export function saveCredential(env, providerId, patch) {
|
|
|
90
91
|
if (!path || !providerId.trim())
|
|
91
92
|
return false;
|
|
92
93
|
try {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
94
|
+
updateConfigObject(path, (current) => {
|
|
95
|
+
const providers = parseStore(current["providers"]);
|
|
96
|
+
const merged = mergeCredential(providers[providerId], patch);
|
|
97
|
+
const nextProviders = { ...providers };
|
|
98
|
+
if (merged)
|
|
99
|
+
nextProviders[providerId] = merged;
|
|
100
|
+
else
|
|
101
|
+
delete nextProviders[providerId];
|
|
102
|
+
const next = { ...current };
|
|
103
|
+
if (Object.keys(nextProviders).length > 0)
|
|
104
|
+
next["providers"] = nextProviders;
|
|
105
|
+
else
|
|
106
|
+
delete next["providers"];
|
|
107
|
+
return next;
|
|
108
|
+
});
|
|
108
109
|
return true;
|
|
109
110
|
}
|
|
110
111
|
catch {
|
|
@@ -118,19 +119,17 @@ export function deleteCredential(env, providerId) {
|
|
|
118
119
|
if (!path || !providerId.trim())
|
|
119
120
|
return false;
|
|
120
121
|
try {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
133
|
-
writeFileSync(path, JSON.stringify(next, null, 2) + "\n", "utf8");
|
|
122
|
+
updateConfigObject(path, (current) => {
|
|
123
|
+
const providers = parseStore(current["providers"]);
|
|
124
|
+
const nextProviders = { ...providers };
|
|
125
|
+
delete nextProviders[providerId];
|
|
126
|
+
const next = { ...current };
|
|
127
|
+
if (Object.keys(nextProviders).length > 0)
|
|
128
|
+
next["providers"] = nextProviders;
|
|
129
|
+
else
|
|
130
|
+
delete next["providers"];
|
|
131
|
+
return next;
|
|
132
|
+
});
|
|
134
133
|
return true;
|
|
135
134
|
}
|
|
136
135
|
catch {
|
package/dist/core/effort.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type Effort = "" | "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
2
2
|
export declare function effectiveToolName(name: string, input?: Record<string, unknown>): string;
|
|
3
|
-
export declare function effortRoutingEnabled(env: NodeJS.ProcessEnv): boolean;
|
|
3
|
+
export declare function effortRoutingEnabled(env: NodeJS.ProcessEnv, providerId?: string): boolean;
|
|
4
4
|
export declare function isRoutineBatch(toolNames: readonly string[], hadError: boolean): boolean;
|
|
5
5
|
export declare function routeEffort(base: Effort, turn: number, routine: boolean, enabled: boolean): Effort;
|
package/dist/core/effort.js
CHANGED
|
@@ -22,7 +22,11 @@ export function effectiveToolName(name, input) {
|
|
|
22
22
|
const target = input?.["name"];
|
|
23
23
|
return typeof target === "string" && target.trim() ? target.trim() : name;
|
|
24
24
|
}
|
|
25
|
-
export function effortRoutingEnabled(env) {
|
|
25
|
+
export function effortRoutingEnabled(env, providerId = "") {
|
|
26
|
+
// Top-level effort changes invalidate Claude's message cache. Keep the
|
|
27
|
+
// user's effort stable rather than trading a cheap read for a full rewrite.
|
|
28
|
+
if (providerId === "anthropic" || providerId === "claude-code")
|
|
29
|
+
return false;
|
|
26
30
|
const v = (env["TALOS_EFFORT_ROUTING"] ?? "").trim().toLowerCase();
|
|
27
31
|
return !(v === "0" || v === "off" || v === "false" || v === "no");
|
|
28
32
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ToolCallPart, ToolResultPart } from "./types.js";
|
|
2
|
-
export declare const EXECUTION_GUIDANCE = "Efficient execution\n- Determine whether the user wants advice, an explanation, instructions for manual work, or\n actual execution. Advice and manual instructions are fulfilled by the response; do not run\n their example scripts or perform the user's setup. A todo list does not grant authorization.\n Before continuing after an error, check whether further agent action is needed and authorized.\n Stop when the request is answered; wait when the next step belongs to the user or needs input.\n Preserve incomplete tasks honestly instead of forcing completion or retrying indefinitely.\n- For a small cosmetic change (one button color, label, spacing or font), locate the affected\n component, edit it, then verify the local result. Do not create a plan, delegate, research the\n web, inspect the whole repository or run a global test/build cycle unless evidence requires it.\n Escalate scope only when the actual dependency or failure demands it.\n- Decide what evidence is needed for the next decision. Issue independent reads together and\n reuse results that are still valid. Do not spend a model round on each already-decided action.\n- Use run_program for known sequences: await dependent edits and plan transitions in order,\n stop on errors, and return a concise summary. Complete a task only after its checks succeed.\n- Prepare related replacements in one round. Never edit the same file concurrently. Independent\n edits on distinct files may run together in bounded groups of at most four; await every outcome\n before inspecting the result or starting dependent work. Keep permission gates in place.\n- For short checks use foreground bash, or background with its brief initial wait. Use\n background=true with yield_time_ms=0 for persistent servers or work that must detach immediately.\n Collect ready background results together; a running command is not a passed check.\n- Run the relevant integrated checks after the edits. Repeat checks only after changes, failures\n or a concrete unresolved concern; do not duplicate typecheck and build without a reason.\n- When parallel work is authorized and worthwhile, start with at most two collaborators on\n concrete disjoint areas, agree on interfaces and acceptance checks, and declare after dependencies.\n The coordinator reviews the combined result. Prefer one agent for small or tightly coupled work.\n- Format user-facing responses in readable Markdown: short paragraphs, **bold** key findings,\n lists for steps, tables for comparisons, fenced code with a language, and descriptive links.\n Keep internal planning notation out of ordinary explanations unless the user asks for it.";
|
|
2
|
+
export declare const EXECUTION_GUIDANCE = "Efficient execution\n- Determine whether the user wants advice, an explanation, instructions for manual work, or\n actual execution. Advice and manual instructions are fulfilled by the response; do not run\n their example scripts or perform the user's setup. A todo list does not grant authorization.\n Before continuing after an error, check whether further agent action is needed and authorized.\n Stop when the request is answered; wait when the next step belongs to the user or needs input.\n Preserve incomplete tasks honestly instead of forcing completion or retrying indefinitely.\n- For a small cosmetic change (one button color, label, spacing or font), locate the affected\n component, edit it, then verify the local result. Do not create a plan, delegate, research the\n web, inspect the whole repository or run a global test/build cycle unless evidence requires it.\n Escalate scope only when the actual dependency or failure demands it.\n- Decide what evidence is needed for the next decision. Issue independent reads together and\n reuse results that are still valid. Do not spend a model round on each already-decided action.\n- Use run_program for known sequences: await dependent edits and plan transitions in order,\n stop on errors, and return a concise summary. Complete a task only after its checks succeed.\n- Prepare related replacements in one round. Never edit the same file concurrently. Independent\n edits on distinct files may run together in bounded groups of at most four; await every outcome\n before inspecting the result or starting dependent work. Keep permission gates in place.\n- For short checks use foreground bash, or background with its brief initial wait. Use\n background=true with yield_time_ms=0 for persistent servers or work that must detach immediately.\n Collect ready background results together; a running command is not a passed check.\n bash_output waits locally for completion by default: call it once and omit timeout_seconds.\n Use wait=false only to inspect a persistent server or diagnose a process; do not poll in a loop.\n- Run the relevant integrated checks after the edits. Repeat checks only after changes, failures\n or a concrete unresolved concern; do not duplicate typecheck and build without a reason.\n- When parallel work is authorized and worthwhile, start with at most two collaborators on\n concrete disjoint areas, agree on interfaces and acceptance checks, and declare after dependencies.\n The coordinator reviews the combined result. Prefer one agent for small or tightly coupled work.\n- Format user-facing responses in readable Markdown: short paragraphs, **bold** key findings,\n lists for steps, tables for comparisons, fenced code with a language, and descriptive links.\n Keep internal planning notation out of ordinary explanations unless the user asks for it.";
|
|
3
3
|
export declare class ExecutionGuidance {
|
|
4
4
|
private previous;
|
|
5
5
|
private readonly reminded;
|
|
@@ -20,6 +20,8 @@ export const EXECUTION_GUIDANCE = `Efficient execution
|
|
|
20
20
|
- For short checks use foreground bash, or background with its brief initial wait. Use
|
|
21
21
|
background=true with yield_time_ms=0 for persistent servers or work that must detach immediately.
|
|
22
22
|
Collect ready background results together; a running command is not a passed check.
|
|
23
|
+
bash_output waits locally for completion by default: call it once and omit timeout_seconds.
|
|
24
|
+
Use wait=false only to inspect a persistent server or diagnose a process; do not poll in a loop.
|
|
23
25
|
- Run the relevant integrated checks after the edits. Repeat checks only after changes, failures
|
|
24
26
|
or a concrete unresolved concern; do not duplicate typecheck and build without a reason.
|
|
25
27
|
- When parallel work is authorized and worthwhile, start with at most two collaborators on
|
|
@@ -54,7 +54,10 @@ export declare class FileCoordinationHub {
|
|
|
54
54
|
observe(pathValue: string, actor: FileActor): readonly FilePresence[];
|
|
55
55
|
acquire(pathValue: string, actor: FileActor): FileLeaseResult;
|
|
56
56
|
validate(lease: FileLease): readonly FilePresence[];
|
|
57
|
+
acquireAsync(pathValue: string, actor: FileActor, signal?: AbortSignal): Promise<FileLeaseResult>;
|
|
58
|
+
releaseAsync(lease: FileLease): Promise<void>;
|
|
57
59
|
release(lease: FileLease): void;
|
|
60
|
+
private forgetLease;
|
|
58
61
|
clearActor(actorId: string, includeLeases?: boolean): void;
|
|
59
62
|
private activeConflicts;
|
|
60
63
|
private storageFailure;
|
|
@@ -85,11 +85,39 @@ export class FileCoordinationHub {
|
|
|
85
85
|
return [this.storageFailure(lease.path, error)];
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
+
async acquireAsync(pathValue, actor, signal) {
|
|
89
|
+
const path = this.path(pathValue);
|
|
90
|
+
const conflicts = this.activeConflicts(path, actor.id);
|
|
91
|
+
if (conflicts.length)
|
|
92
|
+
return { ok: false, conflicts };
|
|
93
|
+
const lease = { id: `fl-${randomUUID()}`, path, actor };
|
|
94
|
+
try {
|
|
95
|
+
const shared = await this.persistent.acquireAsync(lease, signal);
|
|
96
|
+
if (shared.length)
|
|
97
|
+
return { ok: false, conflicts: shared };
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
return { ok: false, conflicts: [this.storageFailure(path, error)] };
|
|
101
|
+
}
|
|
102
|
+
this.leases.set(lease.id, lease);
|
|
103
|
+
this.put({ path, mode: "writing", actor, updatedAt: Date.now(), leaseId: lease.id });
|
|
104
|
+
return { ok: true, lease };
|
|
105
|
+
}
|
|
106
|
+
async releaseAsync(lease) {
|
|
107
|
+
try {
|
|
108
|
+
await this.persistent.releaseAsync(lease);
|
|
109
|
+
}
|
|
110
|
+
catch { /* fail closed: retain the persistent lease */ }
|
|
111
|
+
this.forgetLease(lease);
|
|
112
|
+
}
|
|
88
113
|
release(lease) {
|
|
89
114
|
try {
|
|
90
115
|
this.persistent.release(lease);
|
|
91
116
|
}
|
|
92
117
|
catch { /* fail closed: a later writer sees the retained lease */ }
|
|
118
|
+
this.forgetLease(lease);
|
|
119
|
+
}
|
|
120
|
+
forgetLease(lease) {
|
|
93
121
|
this.leases.delete(lease.id);
|
|
94
122
|
const entries = this.byPath.get(lease.path);
|
|
95
123
|
const current = entries?.get(lease.actor.id);
|
|
@@ -7,8 +7,11 @@ export declare class FileLeaseStore {
|
|
|
7
7
|
constructor(directory: string);
|
|
8
8
|
acquire(lease: FileLease): readonly FilePresence[];
|
|
9
9
|
validate(lease: FileLease): readonly FilePresence[];
|
|
10
|
+
acquireAsync(lease: FileLease, signal?: AbortSignal): Promise<readonly FilePresence[]>;
|
|
11
|
+
releaseAsync(lease: FileLease): Promise<void>;
|
|
10
12
|
release(lease: FileLease): void;
|
|
11
13
|
list(path?: string): readonly FilePresence[];
|
|
12
14
|
private transaction;
|
|
15
|
+
private update;
|
|
13
16
|
private read;
|
|
14
17
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync, renameSync, realpathSync } from "node:fs";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
|
-
import { withLockSync } from "../vascend/file-lock.js";
|
|
4
|
+
import { withLock, withLockSync } from "../vascend/file-lock.js";
|
|
5
5
|
import { executionTargetKey, localExecutionTarget } from "./execution-target.js";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
7
7
|
import { tmpdir } from "node:os";
|
|
@@ -33,6 +33,21 @@ export class FileLeaseStore {
|
|
|
33
33
|
: current ? [presence(current)] : [{ path: lease.path, mode: "writing", updatedAt: Date.now(),
|
|
34
34
|
actor: { id: "lease-lost", label: "lease di scrittura non piu' valida", kind: "external" } }];
|
|
35
35
|
}
|
|
36
|
+
async acquireAsync(lease, signal) {
|
|
37
|
+
return withLock(this.path, () => this.update(records => {
|
|
38
|
+
const current = records[lease.path];
|
|
39
|
+
if (current)
|
|
40
|
+
return [presence(current)];
|
|
41
|
+
records[lease.path] = { ...lease, pid: process.pid, at: Date.now() };
|
|
42
|
+
return [];
|
|
43
|
+
}), {}, signal);
|
|
44
|
+
}
|
|
45
|
+
async releaseAsync(lease) {
|
|
46
|
+
await withLock(this.path, () => this.update(records => {
|
|
47
|
+
if (records[lease.path]?.id === lease.id)
|
|
48
|
+
delete records[lease.path];
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
36
51
|
release(lease) {
|
|
37
52
|
this.transaction((records) => {
|
|
38
53
|
if (records[lease.path]?.id === lease.id)
|
|
@@ -43,17 +58,18 @@ export class FileLeaseStore {
|
|
|
43
58
|
return Object.values(this.read()).filter((record) => (!path || record.path === path) && alive(record.pid)).map(presence);
|
|
44
59
|
}
|
|
45
60
|
transaction(fn) {
|
|
46
|
-
return withLockSync(this.path, () =>
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
return withLockSync(this.path, () => this.update(fn));
|
|
62
|
+
}
|
|
63
|
+
update(fn) {
|
|
64
|
+
const records = this.read();
|
|
65
|
+
for (const [key, record] of Object.entries(records))
|
|
66
|
+
if (!alive(record.pid))
|
|
67
|
+
delete records[key];
|
|
68
|
+
const value = fn(records);
|
|
69
|
+
const temp = this.path + "." + randomUUID() + ".tmp";
|
|
70
|
+
writeFileSync(temp, JSON.stringify(records), "utf8");
|
|
71
|
+
renameSync(temp, this.path);
|
|
72
|
+
return value;
|
|
57
73
|
}
|
|
58
74
|
read() {
|
|
59
75
|
try {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type FusionGateMode = "guard" | "auto";
|
|
2
|
+
export interface FusionConfig {
|
|
3
|
+
/** Modelli qualificati fra cui Jev puo' scegliere per un compito nuovo (oltre a quello attivo). */
|
|
4
|
+
readonly routes: readonly string[];
|
|
5
|
+
/** guard: Jev puo' solo bloccare o far chiedere; auto: un allow netto salta la domanda. */
|
|
6
|
+
readonly gate: FusionGateMode;
|
|
7
|
+
/** Focus per passo con pacchetti di tool. */
|
|
8
|
+
readonly focus: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare const DEFAULT_FUSION: FusionConfig;
|
|
11
|
+
export declare function parseFusion(value: unknown): FusionConfig | null | undefined;
|
|
12
|
+
export declare function fusionFromEnv(env: NodeJS.ProcessEnv): FusionConfig | null | undefined;
|
|
13
|
+
export declare function isPaidTier(tier: string | undefined): boolean;
|
|
14
|
+
export type FusionAvailability = {
|
|
15
|
+
readonly ok: true;
|
|
16
|
+
readonly channel: "dev" | "client";
|
|
17
|
+
} | {
|
|
18
|
+
readonly ok: false;
|
|
19
|
+
readonly channel: "dev" | "client";
|
|
20
|
+
readonly reason: "missing_openrouter" | "missing_login" | "free_plan";
|
|
21
|
+
};
|
|
22
|
+
/** Cosa puo' fare questa installazione. Il tier, se noto, arriva dalla sessione Vascend. */
|
|
23
|
+
export declare function fusionAvailability(env: NodeJS.ProcessEnv, tier?: string, hostProxy?: boolean): FusionAvailability;
|
|
24
|
+
export declare function fusionUnavailableMessage(reason: "missing_openrouter" | "missing_login" | "free_plan" | "not_entitled"): string;
|