@vascend/talos 0.1.0 → 0.1.1

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 (66) hide show
  1. package/README.md +7 -3
  2. package/dist/backend/asset-events.js +9 -9
  3. package/dist/core/agent.js +3 -3
  4. package/dist/core/cli-args.js +50 -50
  5. package/dist/core/cli-installation.d.ts +4 -0
  6. package/dist/core/cli-installation.js +55 -0
  7. package/dist/core/compaction.js +26 -26
  8. package/dist/core/config.js +101 -101
  9. package/dist/core/execution-guidance.js +21 -21
  10. package/dist/core/package-update.d.ts +3 -1
  11. package/dist/core/package-update.js +19 -6
  12. package/dist/core/self-update.d.ts +1 -1
  13. package/dist/core/signed-release.d.ts +33 -0
  14. package/dist/core/signed-release.js +121 -0
  15. package/dist/core/update-check.d.ts +1 -1
  16. package/dist/core/update-check.js +15 -14
  17. package/dist/core/vibe-modes.js +13 -13
  18. package/dist/distribution/install.d.ts +1 -0
  19. package/dist/distribution/install.js +31 -0
  20. package/dist/install.mjs +271 -0
  21. package/dist/node-runtime.json +13 -0
  22. package/dist/providers/oauth-callback-server.js +32 -32
  23. package/dist/tools/capabilities.js +30 -30
  24. package/dist/tools/computer-capture.js +50 -50
  25. package/dist/tools/program.js +82 -82
  26. package/dist/tui/i18n-catalog.js +16 -0
  27. package/dist/tui/quick-help.js +31 -31
  28. package/dist/tui/repl.js +5 -5
  29. package/dist/tui/update-prompt.js +1 -0
  30. package/dist/vascend/code-events.js +9 -9
  31. package/dist/vascend/completeness.js +31 -31
  32. package/dist/vascend/context-fabric.js +16 -16
  33. package/dist/vascend/contract-memory.js +30 -30
  34. package/dist/vascend/council.js +82 -82
  35. package/dist/vascend/decision-promotion.js +23 -23
  36. package/dist/vascend/granular-kingdom.js +17 -17
  37. package/dist/vascend/granular-launcher.js +2 -2
  38. package/dist/vascend/kingdom-kpi.js +19 -19
  39. package/dist/vascend/kingdom-run.js +6 -6
  40. package/dist/vascend/kingdom.js +56 -56
  41. package/dist/vascend/mandate.js +21 -21
  42. package/dist/vascend/objective-revision.js +34 -34
  43. package/dist/vascend/patch-plan.js +22 -22
  44. package/dist/vascend/requirements.js +29 -29
  45. package/dist/vascend/reviewer.js +26 -26
  46. package/dist/vascend/room-memory.js +25 -25
  47. package/dist/vascend/runtime.js +44 -44
  48. package/dist/vascend/self-improve.js +39 -39
  49. package/dist/vascend/test-failure-memory.js +9 -9
  50. package/dist/vascend/vision.js +18 -18
  51. package/dist/vendor/computer-use/README.md +7 -7
  52. package/dist/vendor/computer-use/computer-desktop.js +211 -211
  53. package/dist/vendor/computer-use/computer-observe.js +315 -315
  54. package/dist/vendor/computer-use/computer-scripts.js +1230 -1230
  55. package/dist/vendor/computer-use/computer-tools.js +2136 -2136
  56. package/dist/vendor/computer-use/package.json +1 -1
  57. package/dist/vendor/computer-use/rac/atomic-input.js +91 -91
  58. package/dist/vendor/computer-use/rac/grammatica.js +101 -101
  59. package/dist/vendor/computer-use/rac/parser.js +185 -185
  60. package/dist/vendor/computer-use/rac/protocol.js +136 -136
  61. package/install.ps1 +374 -30
  62. package/install.sh +356 -43
  63. package/package.json +2 -2
  64. package/dist/core/kingdoms-mode-state.d.ts +0 -24
  65. package/dist/core/kingdoms-mode-state.js +0 -139
  66. package/dist/text-sanitize.js +0 -28
@@ -79,11 +79,11 @@ export function formatConflictList(conflicts, base) {
79
79
  .map((c) => `${c.worktree ? ` git worktree remove ${quoteCommandArg(c.worktree)}\n` : ""} git branch -d ${c.branch}`)
80
80
  .join("\n");
81
81
  const actions = [inspect, commits, merges, cleanup].filter(Boolean).join("\n");
82
- return `[STASH_DA_RISOLVERE]
83
- @stato[sospeso]: ${conflicts.length} ramo/i di collaboratore da recuperare${into} (nessun lavoro e' stato eliminato)
84
- ${rows}
85
- @azione[risoluzione]: ispeziona, committa se indicato, poi integra SOLO dal ramo base:
86
- ${actions}
82
+ return `[STASH_DA_RISOLVERE]
83
+ @stato[sospeso]: ${conflicts.length} ramo/i di collaboratore da recuperare${into} (nessun lavoro e' stato eliminato)
84
+ ${rows}
85
+ @azione[risoluzione]: ispeziona, committa se indicato, poi integra SOLO dal ramo base:
86
+ ${actions}
87
87
  @azione[pulizia]: solo dopo aver verificato il merge: git worktree remove <path> ; git branch -d <ramo>`;
88
88
  }
89
89
  function quoteCommandArg(value) {
@@ -117,30 +117,30 @@ export function looksBigGoal(text) {
117
117
  const signals = (t.match(/\b(e poi|inoltre|vari|varie|multipl|in parallelo|workstream|diverse|diversi|piu'|più|oltre a)\b/gi) ?? []).length;
118
118
  return signals >= 2;
119
119
  }
120
- const DECOMPOSE_SYSTEM = `# Coordinatore del team
121
-
122
- INDICE
123
- 1 = coordinatore
124
- 2 = obiettivo
125
- 3 = incarico
126
- 4 = indipendenza
127
- 5 = confine
128
-
129
- DEFINIZIONI
130
- @coordinatore[ruolo]: scompone un obiettivo grande in incarichi
131
- @obiettivo[input]: macro-goal da spezzare
132
- @incarico[unita]: sotto-obiettivo autonomo, che un collaboratore puo' portare a termine da solo
133
- @indipendenza[regola]: gli incarichi non dipendono dall'output l'uno dell'altro nello stesso giro
134
- @confine[criterio]: taglia per area/modulo/file, NON per fase sequenziale
135
-
136
- RELAZIONI
137
- @R1: @obiettivo[input] -> @incarico[unita] [ scomponi in parti ]
138
- @R2: @incarico[unita] -> @indipendenza[regola] [ partono tutti insieme ]
139
- @R3: @incarico[unita] -> @confine[criterio] [ confini netti ]
140
-
141
- OUTPUT: SOLO un array JSON di {slug, goal, after}; slug kebab-case breve; goal autonomo e completo;
142
- "after" = array degli slug degli incarichi PREREQUISITO (dipendenze forti: cio' che deve esistere prima),
143
- [] se indipendente — e indipendente e' quasi sempre la risposta giusta: un "after" di troppo mette in
120
+ const DECOMPOSE_SYSTEM = `# Coordinatore del team
121
+
122
+ INDICE
123
+ 1 = coordinatore
124
+ 2 = obiettivo
125
+ 3 = incarico
126
+ 4 = indipendenza
127
+ 5 = confine
128
+
129
+ DEFINIZIONI
130
+ @coordinatore[ruolo]: scompone un obiettivo grande in incarichi
131
+ @obiettivo[input]: macro-goal da spezzare
132
+ @incarico[unita]: sotto-obiettivo autonomo, che un collaboratore puo' portare a termine da solo
133
+ @indipendenza[regola]: gli incarichi non dipendono dall'output l'uno dell'altro nello stesso giro
134
+ @confine[criterio]: taglia per area/modulo/file, NON per fase sequenziale
135
+
136
+ RELAZIONI
137
+ @R1: @obiettivo[input] -> @incarico[unita] [ scomponi in parti ]
138
+ @R2: @incarico[unita] -> @indipendenza[regola] [ partono tutti insieme ]
139
+ @R3: @incarico[unita] -> @confine[criterio] [ confini netti ]
140
+
141
+ OUTPUT: SOLO un array JSON di {slug, goal, after}; slug kebab-case breve; goal autonomo e completo;
142
+ "after" = array degli slug degli incarichi PREREQUISITO (dipendenze forti: cio' che deve esistere prima),
143
+ [] se indipendente — e indipendente e' quasi sempre la risposta giusta: un "after" di troppo mette in
144
144
  fila lavoro che poteva andare in parallelo. Niente prosa, niente markdown.`;
145
145
  // L'Imperatore scompone un obiettivo in castelli (slug + goal) con UNA chiamata
146
146
  // al modello. Ritorna [] se non risolvibile; fallback a un solo castello se il
@@ -551,33 +551,33 @@ function vassalSteer(self, peers, after, identity, git, mandateBlock) {
551
551
  const gitOut = git.isolated
552
552
  ? `committa il tuo lavoro sul TUO ramo (il merge lo fa chi ti ha ingaggiato).`
553
553
  : `NIENTE git che modifica.`;
554
- return `[COLLABORATORE ${self}]
555
- INDICE
556
- 1 = ruolo
557
- 2 = dipendenze
558
- 3 = cooperazione
559
- 4 = confine
560
-
561
- DEFINIZIONI
562
- @ruolo[collaboratore]: id=${self}, ruolo=${identity.role}, parent=${identity.parent}, peer=[${others.join(", ") || "nessuno"}]
563
- @dipendenze[after]: ${after.length ? after.join(", ") : "nessuna (parti subito)"}
564
- @cooperazione[annuncio]: all'avvio usa team_say(to="${identity.parent}") per confermare task e piano breve; durante il lavoro annuncia milestone; alla fine invia esito e file toccati
565
- @cooperazione[ascolto]: team_inbox REGOLARMENTE — dopo ogni passaggio, non solo se dipendi da qualcuno: chi ti scrive puo' averti risparmiato un lavoro sbagliato, o aspettare una tua risposta
566
- @cooperazione[attesa]: team_wait(from/contains) solo se non hai altro di utile da fare; se puoi andare avanti su un altro pezzo, vai avanti
567
- @cooperazione[info]: tieni informato chi dipende da te, e rispondi a chi ti chiede qualcosa: un messaggio senza risposta blocca chi l'ha mandato
568
- @cooperazione[scoperte]: se scopri qualcosa che cambia il lavoro di un altro (un file che non e' dove sembrava, un'assunzione che non regge) diglielo SUBITO con team_say, prima che ci sbatta anche lui
569
- @confine[regola]: resta nel tuo incarico, non duplicare il lavoro altrui
570
- ${gitDef}
571
-
572
- RELAZIONI
573
- @R1: @cooperazione[ascolto] -> @cooperazione[scoperte] [ si lavora insieme, non in parallelo silenzioso ]
574
- @R2: @ruolo[collaboratore] -> @cooperazione[annuncio] [ sblocca gli altri annunciando ]
575
- @R3: @ruolo[collaboratore] -> @confine[regola] [ niente sovrapposizioni ]
576
- ${gitRel}
577
-
578
- OUTPUT: esegui il tuo incarico cooperando con gli altri (annuncia/ascolta/aspetta), resta nel confine, ${gitOut}
579
-
580
- ${mandateBlock ? `${mandateBlock}\n\n` : ""}OBIETTIVO_ATTIVITA
554
+ return `[COLLABORATORE ${self}]
555
+ INDICE
556
+ 1 = ruolo
557
+ 2 = dipendenze
558
+ 3 = cooperazione
559
+ 4 = confine
560
+
561
+ DEFINIZIONI
562
+ @ruolo[collaboratore]: id=${self}, ruolo=${identity.role}, parent=${identity.parent}, peer=[${others.join(", ") || "nessuno"}]
563
+ @dipendenze[after]: ${after.length ? after.join(", ") : "nessuna (parti subito)"}
564
+ @cooperazione[annuncio]: all'avvio usa team_say(to="${identity.parent}") per confermare task e piano breve; durante il lavoro annuncia milestone; alla fine invia esito e file toccati
565
+ @cooperazione[ascolto]: team_inbox REGOLARMENTE — dopo ogni passaggio, non solo se dipendi da qualcuno: chi ti scrive puo' averti risparmiato un lavoro sbagliato, o aspettare una tua risposta
566
+ @cooperazione[attesa]: team_wait(from/contains) solo se non hai altro di utile da fare; se puoi andare avanti su un altro pezzo, vai avanti
567
+ @cooperazione[info]: tieni informato chi dipende da te, e rispondi a chi ti chiede qualcosa: un messaggio senza risposta blocca chi l'ha mandato
568
+ @cooperazione[scoperte]: se scopri qualcosa che cambia il lavoro di un altro (un file che non e' dove sembrava, un'assunzione che non regge) diglielo SUBITO con team_say, prima che ci sbatta anche lui
569
+ @confine[regola]: resta nel tuo incarico, non duplicare il lavoro altrui
570
+ ${gitDef}
571
+
572
+ RELAZIONI
573
+ @R1: @cooperazione[ascolto] -> @cooperazione[scoperte] [ si lavora insieme, non in parallelo silenzioso ]
574
+ @R2: @ruolo[collaboratore] -> @cooperazione[annuncio] [ sblocca gli altri annunciando ]
575
+ @R3: @ruolo[collaboratore] -> @confine[regola] [ niente sovrapposizioni ]
576
+ ${gitRel}
577
+
578
+ OUTPUT: esegui il tuo incarico cooperando con gli altri (annuncia/ascolta/aspetta), resta nel confine, ${gitOut}
579
+
580
+ ${mandateBlock ? `${mandateBlock}\n\n` : ""}OBIETTIVO_ATTIVITA
581
581
  `;
582
582
  }
583
583
  const MAX_UNITS = 16;
@@ -82,26 +82,26 @@ export function formatMandate(mandate, canDelegate) {
82
82
  const growthRel = canDelegate
83
83
  ? `@R3: @attivita[mie] -> @crescita[scomposizione] [ scomponi o delega, non sforare ]`
84
84
  : `@R3: @attivita[mie] -> @crescita[scomposizione] [ niente delega: riporta il limite ]`;
85
- return `MANDATO
86
- INDICE
87
- 1 = gruppo
88
- 2 = attivita
89
- 3 = avanzamento
90
- 4 = crescita
91
-
92
- DEFINIZIONI
93
- @gruppo[assegnato]: ${mandate.castle} "${mandate.title}"${mandate.after ? ` · dopo ${mandate.after}` : ""}
94
- @attivita[mie]: ${total} da chiudere
95
- ${mandate.rooms.map(roomLine).join("\n")}
96
- ${closed}
97
- ${scope}
98
- @avanzamento[marcatura]: appena APRI una attivita vascend_mark(group="${mandate.castle}", task="<ref>", status="running"), appena la CHIUDI status="completed" con evidence concreta (file + test/comando + risultato), oppure "failed" col motivo in vascend_note. E' l'unico modo in cui l'utente ti vede avanzare
99
- ${growth}${mandate.skills?.length ? `\n@skill[gruppo]: ${mandate.skills.join(", ")} (richiamale quando servono, non tutte subito)` : ""}
100
-
101
- RELAZIONI
102
- @R1: @gruppo[assegnato] -> @attivita[mie] [ il piano e' il mandato: non re-inventarlo ]
103
- @R2: @attivita[mie] -> @avanzamento[marcatura] [ una marcatura per attivita, in tempo reale ]
104
- ${growthRel}
105
-
85
+ return `MANDATO
86
+ INDICE
87
+ 1 = gruppo
88
+ 2 = attivita
89
+ 3 = avanzamento
90
+ 4 = crescita
91
+
92
+ DEFINIZIONI
93
+ @gruppo[assegnato]: ${mandate.castle} "${mandate.title}"${mandate.after ? ` · dopo ${mandate.after}` : ""}
94
+ @attivita[mie]: ${total} da chiudere
95
+ ${mandate.rooms.map(roomLine).join("\n")}
96
+ ${closed}
97
+ ${scope}
98
+ @avanzamento[marcatura]: appena APRI una attivita vascend_mark(group="${mandate.castle}", task="<ref>", status="running"), appena la CHIUDI status="completed" con evidence concreta (file + test/comando + risultato), oppure "failed" col motivo in vascend_note. E' l'unico modo in cui l'utente ti vede avanzare
99
+ ${growth}${mandate.skills?.length ? `\n@skill[gruppo]: ${mandate.skills.join(", ")} (richiamale quando servono, non tutte subito)` : ""}
100
+
101
+ RELAZIONI
102
+ @R1: @gruppo[assegnato] -> @attivita[mie] [ il piano e' il mandato: non re-inventarlo ]
103
+ @R2: @attivita[mie] -> @avanzamento[marcatura] [ una marcatura per attivita, in tempo reale ]
104
+ ${growthRel}
105
+
106
106
  OUTPUT: chiudi le tue attivita una per una marcandole; nel report finale elenca i ref chiusi, quelli falliti e i file toccati.`;
107
107
  }
@@ -183,24 +183,24 @@ export function buildReopenSteer(goal, decision) {
183
183
  const residui = decision.residuals
184
184
  .map((r, i) => `(${i + 1}) [${r.priority}] ${r.text}${r.requirementId ? ` <${r.requirementId}>` : ""}`)
185
185
  .join(" ; ");
186
- return `[VASCEND_REVISIONE_OBIETTIVO]
187
- INDICE
188
- 1 = goal
189
- 2 = verdetto
190
- 3 = residuo
191
- 4 = azione
192
-
193
- DEFINIZIONI
194
- @goal[reale]: "${g}"
195
- @verdetto[concilio]: ${decision.reason.replace(/"/g, "'")}
196
- @residuo[sotto_obiettivi]: ${residui || "nessuno"}
197
- @azione[riapri]: il task NON e' completo; svolgi i sotto-obiettivi residui, NON ti fermi al verdetto precedente
198
-
199
- RELAZIONI
200
- @R1: @verdetto[concilio] -> @residuo[sotto_obiettivi] [ i requisiti non soddisfatti diventano sotto-obiettivi ]
201
- @R2: @residuo[sotto_obiettivi] -> @azione[riapri] [ pianifica e completa i residui ]
202
- @R3: @azione[riapri] -> @goal[reale] [ finche' i requisiti essenziali non sono soddisfatti ]
203
-
186
+ return `[VASCEND_REVISIONE_OBIETTIVO]
187
+ INDICE
188
+ 1 = goal
189
+ 2 = verdetto
190
+ 3 = residuo
191
+ 4 = azione
192
+
193
+ DEFINIZIONI
194
+ @goal[reale]: "${g}"
195
+ @verdetto[concilio]: ${decision.reason.replace(/"/g, "'")}
196
+ @residuo[sotto_obiettivi]: ${residui || "nessuno"}
197
+ @azione[riapri]: il task NON e' completo; svolgi i sotto-obiettivi residui, NON ti fermi al verdetto precedente
198
+
199
+ RELAZIONI
200
+ @R1: @verdetto[concilio] -> @residuo[sotto_obiettivi] [ i requisiti non soddisfatti diventano sotto-obiettivi ]
201
+ @R2: @residuo[sotto_obiettivi] -> @azione[riapri] [ pianifica e completa i residui ]
202
+ @R3: @azione[riapri] -> @goal[reale] [ finche' i requisiti essenziali non sono soddisfatti ]
203
+
204
204
  OUTPUT: riapri l'obiettivo: crea/aggiorna attivita per i sotto-obiettivi residui (priorita' must prima), realizzali col lavoro reale e illuminali con vascend_mark. Concludi solo quando i residui essenziali sono soddisfatti.`;
205
205
  }
206
206
  // Sintesi compatta della decisione (per log/TUI), in una riga.
@@ -218,22 +218,22 @@ export function objectiveDecisionSummary(d) {
218
218
  // sotto-obiettivi residui leggendo goal + verdetto + requisiti. Gemello a valle
219
219
  // di judgeCompleteness. In dubbio conserva uno stato unknown, non chiude.
220
220
  // ---------------------------------------------------------------------------
221
- const REVISER_SYSTEM = `# Revisore dell'obiettivo
222
- INDICE
223
- 1 = goal
224
- 2 = verdetto
225
- 3 = residuo
226
-
227
- DEFINIZIONI
228
- @goal[reale]: l'obiettivo VERO dell'utente
229
- @verdetto[concilio]: giudizio del concilio (completamento, lacune, dissensi)
230
- @residuo[regola]: elenca SOLO sotto-obiettivi ESSENZIALI ancora aperti; niente perfezionismo
231
- @bilancia[chiudi]: se il goal e' soddisfatto nella sostanza, complete=true e residuals=[]
232
-
233
- RELAZIONI
234
- @R1: @verdetto[concilio] -> @residuo[regola] [ trasforma le lacune in sotto-obiettivi ]
235
- @R2: @residuo[regola] -> @goal[reale] [ solo cio' che serve a soddisfare il goal ]
236
-
221
+ const REVISER_SYSTEM = `# Revisore dell'obiettivo
222
+ INDICE
223
+ 1 = goal
224
+ 2 = verdetto
225
+ 3 = residuo
226
+
227
+ DEFINIZIONI
228
+ @goal[reale]: l'obiettivo VERO dell'utente
229
+ @verdetto[concilio]: giudizio del concilio (completamento, lacune, dissensi)
230
+ @residuo[regola]: elenca SOLO sotto-obiettivi ESSENZIALI ancora aperti; niente perfezionismo
231
+ @bilancia[chiudi]: se il goal e' soddisfatto nella sostanza, complete=true e residuals=[]
232
+
233
+ RELAZIONI
234
+ @R1: @verdetto[concilio] -> @residuo[regola] [ trasforma le lacune in sotto-obiettivi ]
235
+ @R2: @residuo[regola] -> @goal[reale] [ solo cio' che serve a soddisfare il goal ]
236
+
237
237
  OUTPUT: SOLO JSON {"complete": bool, "residuals": [{"text": str, "priority": "must|should|could"}]}. Niente prosa, niente markdown.`;
238
238
  export async function judgeObjectiveRevision(opts) {
239
239
  const { harness, goal, checklist, evidence, signal } = opts;
@@ -319,27 +319,27 @@ export function buildPatchPlanBlock(p) {
319
319
  const riskDefs = p.risks.map((r) => `@${r.id}[${SEVERITY_TAG[r.severity]}]: ${q(r.text, 160)}${r.mitigation ? ` (mitiga: ${q(r.mitigation, 120)})` : ""}`);
320
320
  const testDefs = p.tests.map((t) => `@${t.id}[${t.status}]: ${q(t.text, 160)}`);
321
321
  const ver = patchPlanVerification(p);
322
- return `[VASCEND_PATCH_PLAN ${p.id}]
323
- INDICE
324
- 1 = goal
325
- 2 = file
326
- 3 = contratti
327
- 4 = rischi
328
- 5 = test
329
-
330
- DEFINIZIONI
331
- @goal[patch]: "${q(p.goal)}"
332
- @stato[ciclo]: ${p.status}${p.taskRef ? ` (attivita ${p.taskRef})` : ""}
333
- ${fileDefs.length ? fileDefs.join("\n") : "@file[nessuno]: -"}
334
- ${contractDefs.length ? contractDefs.join("\n") : "@contratti[nessuno]: -"}
335
- ${riskDefs.length ? riskDefs.join("\n") : "@rischi[nessuno]: -"}
336
- ${testDefs.length ? testDefs.join("\n") : "@test[nessuno]: -"}
337
-
338
- RELAZIONI
339
- @R-edit: @goal[patch] -> @file [ la modifica tocca questi file per l'obiettivo ]
340
- @R-contract: @file -> @contratti [ i file alterano/usano queste superfici ]
341
- @R-risk: @contratti -> @rischi [ i cambi di contratto generano regressioni potenziali ]
342
- @R-verify: @rischi -> @test [ i test coprono i rischi prima del verify ]
343
-
322
+ return `[VASCEND_PATCH_PLAN ${p.id}]
323
+ INDICE
324
+ 1 = goal
325
+ 2 = file
326
+ 3 = contratti
327
+ 4 = rischi
328
+ 5 = test
329
+
330
+ DEFINIZIONI
331
+ @goal[patch]: "${q(p.goal)}"
332
+ @stato[ciclo]: ${p.status}${p.taskRef ? ` (attivita ${p.taskRef})` : ""}
333
+ ${fileDefs.length ? fileDefs.join("\n") : "@file[nessuno]: -"}
334
+ ${contractDefs.length ? contractDefs.join("\n") : "@contratti[nessuno]: -"}
335
+ ${riskDefs.length ? riskDefs.join("\n") : "@rischi[nessuno]: -"}
336
+ ${testDefs.length ? testDefs.join("\n") : "@test[nessuno]: -"}
337
+
338
+ RELAZIONI
339
+ @R-edit: @goal[patch] -> @file [ la modifica tocca questi file per l'obiettivo ]
340
+ @R-contract: @file -> @contratti [ i file alterano/usano queste superfici ]
341
+ @R-risk: @contratti -> @rischi [ i cambi di contratto generano regressioni potenziali ]
342
+ @R-verify: @rischi -> @test [ i test coprono i rischi prima del verify ]
343
+
344
344
  OUTPUT: piano di patch ${p.id}; verificato=${ver.verified} (test ${ver.testsPassed}/${ver.testsTotal}, falliti ${ver.testsFailed}). Edita solo i file elencati, poi esegui i test.`;
345
345
  }
@@ -8,22 +8,22 @@ export function requirementsMax(env) {
8
8
  const n = Number(env["TALOS_REQUIREMENTS_MAX"]);
9
9
  return Number.isInteger(n) && n >= 1 ? n : 12;
10
10
  }
11
- const EXTRACTOR_SYSTEM = `# Estrattore di requisiti
12
- INDICE
13
- 1 = obiettivo
14
- 2 = requisito
15
- 3 = criterio
16
-
17
- DEFINIZIONI
18
- @obiettivo[fonte]: la richiesta dell'utente, da scomporre senza inventare
19
- @requisito[misurabile]: cosa va consegnato, in forma OSSERVABILE e verificabile; priorita' must/should/could
20
- @criterio[accettazione]: condizione BINARIA (vera/falsa) che prova il requisito soddisfatto; concreta, non vaga
21
- @rigore[essenziale]: SOLO requisiti realmente impliciti/espliciti nel goal; niente nice-to-have, niente perfezionismo
22
-
23
- RELAZIONI
24
- @R1: @obiettivo[fonte] -> @requisito[misurabile] [ scomponi il goal in requisiti misurabili ]
25
- @R2: @requisito[misurabile] -> @criterio[accettazione] [ ogni requisito ha 1+ criteri verificabili ]
26
-
11
+ const EXTRACTOR_SYSTEM = `# Estrattore di requisiti
12
+ INDICE
13
+ 1 = obiettivo
14
+ 2 = requisito
15
+ 3 = criterio
16
+
17
+ DEFINIZIONI
18
+ @obiettivo[fonte]: la richiesta dell'utente, da scomporre senza inventare
19
+ @requisito[misurabile]: cosa va consegnato, in forma OSSERVABILE e verificabile; priorita' must/should/could
20
+ @criterio[accettazione]: condizione BINARIA (vera/falsa) che prova il requisito soddisfatto; concreta, non vaga
21
+ @rigore[essenziale]: SOLO requisiti realmente impliciti/espliciti nel goal; niente nice-to-have, niente perfezionismo
22
+
23
+ RELAZIONI
24
+ @R1: @obiettivo[fonte] -> @requisito[misurabile] [ scomponi il goal in requisiti misurabili ]
25
+ @R2: @requisito[misurabile] -> @criterio[accettazione] [ ogni requisito ha 1+ criteri verificabili ]
26
+
27
27
  OUTPUT: SOLO JSON {"requirements": [{"id": "R1", "text": "...", "priority": "must|should|could", "criteria": [{"id": "R1.1", "text": "..."}]}]}. Niente prosa, niente markdown.`;
28
28
  // Estrae la checklist dall'obiettivo via LLM. Se non c'e' provider o l'estrazione
29
29
  // fallisce, ritorna una checklist vuota (non bloccante).
@@ -123,19 +123,19 @@ export function buildRequirementsBlock(checklist) {
123
123
  defs.push(`@${r.id}[${PRIORITY_TAG[r.priority]}]: ${r.text}${crit ? ` -> [ ${crit} ]` : ""}`);
124
124
  rels.push(`@R-${r.id}: @${r.id} -> consegna [ soddisfatto sse tutti i criteri ${r.id}.* sono veri ]`);
125
125
  }
126
- return `[VASCEND_REQUISITI]
127
- INDICE
128
- 1 = goal
129
- 2 = requisiti
130
- 3 = criteri
131
-
132
- DEFINIZIONI
133
- @goal[reale]: "${goal.replace(/"/g, "'").slice(0, 200)}"
134
- ${defs.join("\n")}
135
-
136
- RELAZIONI
137
- ${rels.join("\n")}
138
-
126
+ return `[VASCEND_REQUISITI]
127
+ INDICE
128
+ 1 = goal
129
+ 2 = requisiti
130
+ 3 = criteri
131
+
132
+ DEFINIZIONI
133
+ @goal[reale]: "${goal.replace(/"/g, "'").slice(0, 200)}"
134
+ ${defs.join("\n")}
135
+
136
+ RELAZIONI
137
+ ${rels.join("\n")}
138
+
139
139
  OUTPUT: usa questa checklist come riferimento OGGETTIVO; il goal e' completo sse ogni requisito MUST ha tutti i criteri di accettazione verificati.`;
140
140
  }
141
141
  // Conteggi sintetici, comodi per status/log.
@@ -63,31 +63,31 @@ export function buildRoomMetricsDigest(state) {
63
63
  }
64
64
  // Prompt del revisore: analizza le metriche e migliora SOLO le stanze rimaste.
65
65
  export function buildReviewerPrompt(digest) {
66
- return `[VASCEND_REVISIONE]
67
- Sei il REVISORE del team (piano di lavoro). NON rifai il lavoro gia' fatto: analizzi
68
- le attivita completate (token e durata) e le note, e migliori SOLO le attivita rimaste.
69
-
70
- INDICE
71
- 1 = metriche
72
- 2 = analisi
73
- 3 = azione
74
-
75
- DEFINIZIONI
76
- @metriche[piano]: digest sotto (attivita fatte con token/durata + attivita da fare)
77
- @analisi[obiettivo]: trova attivita costose/lente, lavoro ridondante, passi mancanti
78
- @azione[consentite]: vascend_addtasks (aggiungi attivita rimaste), vascend_note (annota analisi/ordine consigliato sulle attivita o sul gruppo), vascend_skill (abbina skill utili in anticipo). Per il dettaglio di una attivita fatta usa recall.
79
-
80
- RELAZIONI
81
- @R1: @metriche[piano] -> @analisi[obiettivo] [ leggi prima di agire ]
82
- @R2: @analisi[obiettivo] -> @azione[consentite] [ agisci solo sulle attivita da fare ]
83
-
84
- REGOLE
85
- - NON marcare attivita (niente vascend_mark) e NON eseguire il lavoro: solo revisione e riorganizzazione.
86
- - Sii conciso: poche azioni mirate. Se il piano e' gia' ottimale, dillo in una riga e fermati.
87
- - Usa le note per indicare l'ORDINE ottimale delle attivita rimaste (non puoi riordinare i bit).
88
-
89
- METRICHE
90
- ${digest}
91
-
66
+ return `[VASCEND_REVISIONE]
67
+ Sei il REVISORE del team (piano di lavoro). NON rifai il lavoro gia' fatto: analizzi
68
+ le attivita completate (token e durata) e le note, e migliori SOLO le attivita rimaste.
69
+
70
+ INDICE
71
+ 1 = metriche
72
+ 2 = analisi
73
+ 3 = azione
74
+
75
+ DEFINIZIONI
76
+ @metriche[piano]: digest sotto (attivita fatte con token/durata + attivita da fare)
77
+ @analisi[obiettivo]: trova attivita costose/lente, lavoro ridondante, passi mancanti
78
+ @azione[consentite]: vascend_addtasks (aggiungi attivita rimaste), vascend_note (annota analisi/ordine consigliato sulle attivita o sul gruppo), vascend_skill (abbina skill utili in anticipo). Per il dettaglio di una attivita fatta usa recall.
79
+
80
+ RELAZIONI
81
+ @R1: @metriche[piano] -> @analisi[obiettivo] [ leggi prima di agire ]
82
+ @R2: @analisi[obiettivo] -> @azione[consentite] [ agisci solo sulle attivita da fare ]
83
+
84
+ REGOLE
85
+ - NON marcare attivita (niente vascend_mark) e NON eseguire il lavoro: solo revisione e riorganizzazione.
86
+ - Sii conciso: poche azioni mirate. Se il piano e' gia' ottimale, dillo in una riga e fermati.
87
+ - Usa le note per indicare l'ORDINE ottimale delle attivita rimaste (non puoi riordinare i bit).
88
+
89
+ METRICHE
90
+ ${digest}
91
+
92
92
  OUTPUT: una breve sintesi in notazione + le azioni (addrooms/note/skill) applicate alle sole attivita rimaste.`;
93
93
  }
@@ -331,15 +331,15 @@ export class RoomMemory {
331
331
  })
332
332
  .join("\n");
333
333
  return `ATTIVITA_ARCHIVIATE (ordine cronologico: prima le piu' vecchie, ultima la piu' recente)
334
- Il lavoro precedente e' ARCHIVIATO fuori dal contesto vivo, in attivita raccolte
334
+ Il lavoro precedente e' ARCHIVIATO fuori dal contesto vivo, in attivita raccolte
335
335
  in gruppi e liste. Per recuperarne il dettaglio usa il tool "recall" (per query
336
- o per id, anche scendendo da un gruppo alle sue attivita) invece di chiedere di
337
- ripetere: il contesto resta compatto.
338
- Per RIPRENDERE il lavoro appena svolto parti dalla voce piu' in basso (il turno
339
- piu' recente, marcato), NON da quelle sopra: quelle sono turni gia' conclusi.
340
-
341
- ${rows}
342
-
336
+ o per id, anche scendendo da un gruppo alle sue attivita) invece di chiedere di
337
+ ripetere: il contesto resta compatto.
338
+ Per RIPRENDERE il lavoro appena svolto parti dalla voce piu' in basso (il turno
339
+ piu' recente, marcato), NON da quelle sopra: quelle sono turni gia' conclusi.
340
+
341
+ ${rows}
342
+
343
343
  OUTPUT: contesto compatto; dettaglio recuperabile a ogni livello via recall.`;
344
344
  }
345
345
  setParent(childId, parentId) {
@@ -389,15 +389,15 @@ export function formatRoomRecord(room, messages, createdAt) {
389
389
  // Archi tipizzati: i file e i tool del turno sono gia' estratti qui sopra,
390
390
  // quindi il grafo costa zero a scrittura.
391
391
  const edges = roomEdges(files, tools.map((t) => t.name));
392
- const body = clampBody(`INDICE
393
- ${numberedIndex(terms)}
394
-
395
- DEFINIZIONI
396
- ${def}
397
-
398
- RELAZIONI
399
- ${rel}
400
-
392
+ const body = clampBody(`INDICE
393
+ ${numberedIndex(terms)}
394
+
395
+ DEFINIZIONI
396
+ ${def}
397
+
398
+ RELAZIONI
399
+ ${rel}
400
+
401
401
  OUTPUT: ${escapeValue(output) || "(nessun output testuale)"}`);
402
402
  return { room, level: 0, title, terms, body, children: [], parent: null, createdAt, edges };
403
403
  }
@@ -421,14 +421,14 @@ export function formatRollupRecord(id, level, children, createdAt) {
421
421
  .join("\n");
422
422
  const body = clampBody(`RIEPILOGO_${label.toUpperCase()} ${id}
423
423
  Elementi archiviati: ${children.length}. Per il dettaglio
424
- di un figlio usa recall(rooms:["${children[0]?.room ?? ""}", ...]) o una query.
425
-
426
- INDICE
427
- ${numberedIndex(terms)}
428
-
429
- ${cap(childLabel)}
430
- ${rows}
431
-
424
+ di un figlio usa recall(rooms:["${children[0]?.room ?? ""}", ...]) o una query.
425
+
426
+ INDICE
427
+ ${numberedIndex(terms)}
428
+
429
+ ${cap(childLabel)}
430
+ ${rows}
431
+
432
432
  OUTPUT: riepilogo delle attivita; apri i dettagli col tool recall.`);
433
433
  return {
434
434
  room: id,
@@ -8,11 +8,11 @@ Comunica in italiano naturale, con spiegazioni chiare e Markdown leggibile.
8
8
  Descrivi il lavoro con una to-do list: attivita, gruppi, dipendenze e stati
9
9
  da fare, in corso, completata o fallita. I riepiloghi della memoria sono solo
10
10
  contesto interno: all'utente mostra le attivita e i risultati pertinenti.
11
- Per lavori con piu passi usa vascend_plan: un piano contiene gruppi di attivita,
12
- ogni gruppo contiene attivita con stato, dipendenze e prove di verifica.
13
- Aggiorna gli stati con vascend_mark; completa solo dopo le verifiche.
14
- Usa vascend_note per decisioni e blocchi e recall per recuperare il passato.
15
- Per lavori indipendenti valuta collaboratori tramite gli strumenti del team.
11
+ Per lavori con piu passi usa vascend_plan: un piano contiene gruppi di attivita,
12
+ ogni gruppo contiene attivita con stato, dipendenze e prove di verifica.
13
+ Aggiorna gli stati con vascend_mark; completa solo dopo le verifiche.
14
+ Usa vascend_note per decisioni e blocchi e recall per recuperare il passato.
15
+ Per lavori indipendenti valuta collaboratori tramite gli strumenti del team.
16
16
  Per domande o richieste semplici non creare un piano inutile.`;
17
17
  export function validateKingdom(state) {
18
18
  const castles = state.kingdom.castles;
@@ -37,18 +37,18 @@ export function validateKingdom(state) {
37
37
  }
38
38
  // Messaggio di steering per svegliare l'agente sulle stanze da completare.
39
39
  export function buildValidationSteer(v) {
40
- return `[VASCEND_VALIDAZIONE]
41
- INDICE
42
- 1 = piano
43
- 2 = aperto
44
-
45
- DEFINIZIONI
46
- @stato[piano]: completate=${v.done}/${v.total}
47
- @aperto[attivita]: ${v.pending.join(", ")} NON completate
48
-
49
- RELAZIONI
50
- @R: @aperto[attivita] -> @stato[piano] [ il piano NON valida finché restano attivita da completare ]
51
-
40
+ return `[VASCEND_VALIDAZIONE]
41
+ INDICE
42
+ 1 = piano
43
+ 2 = aperto
44
+
45
+ DEFINIZIONI
46
+ @stato[piano]: completate=${v.done}/${v.total}
47
+ @aperto[attivita]: ${v.pending.join(", ")} NON completate
48
+
49
+ RELAZIONI
50
+ @R: @aperto[attivita] -> @stato[piano] [ il piano NON valida finché restano attivita da completare ]
51
+
52
52
  OUTPUT: completa le attivita non completate facendo il lavoro reale e segnandole con vascend_mark (status completed). Se una e' davvero impossibile, marcala failed indicando il motivo. Non concludere finché non sono tutte risolte.`;
53
53
  }
54
54
  export function createVascendState() {
@@ -75,18 +75,18 @@ export function wrapVascendPrompt(state, userText, mode, checkpoint) {
75
75
  const checkpointBlock = checkpoint
76
76
  ? `\nCHECKPOINT_PRECEDENTE\n${checkpoint.trim()}\n`
77
77
  : "";
78
- const immediatePrompt = `[VASCEND_GOAL]
79
- GOAL: ${state.goal}
80
- MODE: ${mode}
81
- ${checkpointBlock}
82
- Piano di lavoro:
83
- - Comunica in modo naturale e leggibile, senza imporre notazioni speciali.
84
- - Per lavori con piu passi crea o riprendi il piano con vascend_plan e vascend_status.
85
- - Organizza il piano in gruppi e attivita; aggiorna gli stati con vascend_mark.
86
- - Completa le attivita solo dopo verifiche concrete; registra decisioni e blocchi.
87
- - Per lavori indipendenti valuta collaboratori; per domande semplici non serve un piano.
88
-
89
- INPUT_UTENTE
78
+ const immediatePrompt = `[VASCEND_GOAL]
79
+ GOAL: ${state.goal}
80
+ MODE: ${mode}
81
+ ${checkpointBlock}
82
+ Piano di lavoro:
83
+ - Comunica in modo naturale e leggibile, senza imporre notazioni speciali.
84
+ - Per lavori con piu passi crea o riprendi il piano con vascend_plan e vascend_status.
85
+ - Organizza il piano in gruppi e attivita; aggiorna gli stati con vascend_mark.
86
+ - Completa le attivita solo dopo verifiche concrete; registra decisioni e blocchi.
87
+ - Per lavori indipendenti valuta collaboratori; per domande semplici non serve un piano.
88
+
89
+ INPUT_UTENTE
90
90
  ${userText}`;
91
91
  // Antepone il CONTESTO A LUNGO TERMINE (Vision finale) come piano SEPARATO
92
92
  // dal goal immediato. Il goal corrente viene passato come "immediato" cosi'
@@ -124,24 +124,24 @@ export function formatVascendCompact(state, messages = []) {
124
124
  const summary = messages.flatMap(message => message.content
125
125
  .filter(part => part.type === "text" && part.text.startsWith("[Riepilogo del contesto precedente]"))
126
126
  .map(part => part.type === "text" ? part.text : "")).at(-1);
127
- return `INDICE
128
- 1 = goal
129
- 2 = gruppo
130
- 3 = task
131
- 4 = file
132
- 5 = contesto
133
-
134
- DEFINIZIONI
135
- @stato[goal]: valore="${escapeValue(state.goal ?? "nessun_goal")}", mode=${state.mode}
127
+ return `INDICE
128
+ 1 = goal
129
+ 2 = gruppo
130
+ 3 = task
131
+ 4 = file
132
+ 5 = contesto
133
+
134
+ DEFINIZIONI
135
+ @stato[goal]: valore="${escapeValue(state.goal ?? "nessun_goal")}", mode=${state.mode}
136
136
  @stato[gruppo]: slug=${castle?.slug ?? "none"}, mask=${castle?.maskTarget ?? "0x0000"}
137
137
  ${groups}
138
138
  ${taskRows}
139
- @file[checkpoint]: path=.vascend-compact.md, ruolo=checkpoint, stato=aggiornato${recent ? `\n${recent}` : ""}
140
-
141
- RELAZIONI
142
- ${relations}
143
- @R99: @file[checkpoint] -> @stato[goal], ripresa
144
-
139
+ @file[checkpoint]: path=.vascend-compact.md, ruolo=checkpoint, stato=aggiornato${recent ? `\n${recent}` : ""}
140
+
141
+ RELAZIONI
142
+ ${relations}
143
+ @R99: @file[checkpoint] -> @stato[goal], ripresa
144
+
145
145
  OUTPUT: stato compatto della sessione, pronto a riprendere a freddo.${summary ? `\n\nCONTESTO DI RIPRESA\n${summary}` : ""}`;
146
146
  }
147
147
  export class VascendRuntime {