@lamemind/loom-deck 0.61.1 → 0.62.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.
package/dist/actions.js CHANGED
@@ -15,8 +15,9 @@
15
15
  // `test/modes-smoke.test.ts` (`seleziona una task`, `terminale su`, `deck-run`,
16
16
  // `nessun push`, `eliminare N task?`, `scartate`): si copiano verbatim, non si
17
17
  // migliorano di passaggio.
18
- import { useRef } from 'react';
18
+ import { useMemo, useRef } from 'react';
19
19
  import { randomUUID } from 'node:crypto';
20
+ import { loadPromptCatalog, modelFor } from './prompt-catalog.js';
20
21
  import { appendNote, appendPin, appendSessionRecord, appendTaskBinding, } from './task-index.js';
21
22
  import { neighborId } from './session-list.js';
22
23
  import { cut, cutMiddle } from './width.js';
@@ -57,6 +58,9 @@ export function useDeckActions({ cwd, tasksPath, tasksDir, columns, model, setNo
57
58
  // prima dell'exec), ed è anche il comando da ripetere a mano per vedere
58
59
  // l'errore. Il salto fra le due dura i millisecondi che `deck-run` impiega a
59
60
  // comporre.
61
+ // T152 — stessa fonte del detail (sheet.ts): un file di sei righe accanto al
62
+ // codice, letto una volta per vita del deck.
63
+ const catalog = useMemo(() => loadPromptCatalog(), []);
60
64
  const spawnSeq = useRef(0);
61
65
  function noteSpawn(spawned) {
62
66
  noteCommand(spawned.cmd);
@@ -132,8 +136,11 @@ export function useDeckActions({ cwd, tasksPath, tasksDir, columns, model, setNo
132
136
  // invece deve restare vivo.
133
137
  function spawnTaskSession(kind, keyLabel) {
134
138
  const task = selectedTaskOr(keyLabel, 'spawnare');
139
+ // T152 — stesso catalogo del detail: senza, `^R` partirebbe sul default
140
+ // fisso mentre l'azione `run` del detail parte sul modello del kind, e le
141
+ // due superfici divergerebbero sullo stesso comando.
135
142
  if (task)
136
- spawnForTask(task.id, kind, MODEL_DEFAULT);
143
+ spawnForTask(task.id, kind, modelFor(catalog, kind) ?? MODEL_DEFAULT);
137
144
  }
138
145
  // T49 — resume di una conversazione in una nuova tab. Unico punto: lo chiamano
139
146
  // il `⏎` della lista sessioni e quello sulla riga-sessione della ricerca, che
@@ -282,8 +289,8 @@ export function useDeckActions({ cwd, tasksPath, tasksDir, columns, model, setNo
282
289
  * il giorno in cui una natura nuova apre la skill sbagliata.
283
290
  *
284
291
  * Sessione NUDA e modello esplicito: il drain lavora sulla doc, non sulla
285
- * task (D10 preflight), e `opus` passa nell'argv anche essendo il default,
286
- * come `permissionMode`.
292
+ * task (D10 preflight), e `MODEL_DEFAULT` passa nell'argv anche essendo il
293
+ * default, come `permissionMode`.
287
294
  */
288
295
  function drainInbox(file, prompt) {
289
296
  const spawned = spawnBare(cwd, prompt, MODEL_DEFAULT);
@@ -9,7 +9,7 @@
9
9
  // Molto più magro dello sheet: nessuna area di compilazione. Lo sheet ha
10
10
  // quattro righe perché quattro parametri dello spawn sono una scelta (azione,
11
11
  // prompt, modello, titolo); qui non ce n'è nessuna — la skill la decide la
12
- // natura (D8), il modello è `opus` per tutte e tre (D11 preflight), la sessione
12
+ // natura (D8), il modello è `MODEL_DEFAULT` per tutte e tre (D11 preflight), la sessione
13
13
  // nasce nuda (D10 preflight). Restano la lettura e un tasto.
14
14
  //
15
15
  // Lo spawn NON sta qui: arriva come callback `onDrain`, per lo stesso confine
@@ -21,7 +21,7 @@ import { sanitizeTyped } from '../glyphs.js';
21
21
  import { ACTION_HOTKEYS, DETAIL_ACTIONS, MODELS, MODEL_DEFAULT, specializeRecap, } from '../spawn.js';
22
22
  import { taskIsEpic } from '../tasks.js';
23
23
  import { fieldsKey } from '../fields.js';
24
- import { loadPromptCatalog, promptFor } from '../prompt-catalog.js';
24
+ import { loadPromptCatalog, modelFor, promptFor } from '../prompt-catalog.js';
25
25
  // T117 — le quattro righe dell'area di compilazione del detail, nell'ordine in
26
26
  // cui si leggono dall'alto. Gli indici sono nominati perché li usano insieme
27
27
  // l'handler dei tasti e la resa, e un `2` nudo in due file diversi è la
@@ -113,32 +113,39 @@ export function useSheetOverlay(deps) {
113
113
  // Calcolato qui e usato subito: `setEpic` non ha ancora aggiornato lo stato
114
114
  // quando `setPrompt` gira, quindi il valore locale è l'unico leggibile ora.
115
115
  const isEpic = taskIsEpic(next.id, next.text);
116
+ const kind = specializeRecap(DETAIL_ACTIONS[0].kind, isEpic);
116
117
  setSheet(next);
117
118
  setTop(0);
118
119
  setAction(0);
119
120
  setEpic(isEpic);
120
- setModel(MODEL_DEFAULT);
121
+ // T152 — il modello segue l'azione iniziale, come già il prompt: su una
122
+ // task Epic la prima azione specializza a `recap-epic`, che nel catalogo
123
+ // può portare un modello diverso da `recap`. Nessun kind fuori catalogo →
124
+ // MODEL_DEFAULT, lo stesso fallback che vale ovunque nel deck.
125
+ setModel(modelFor(catalog, kind) ?? MODEL_DEFAULT);
121
126
  setSpawnNote('');
122
- setPrompt(promptFor(catalog, specializeRecap(DETAIL_ACTIONS[0].kind, isEpic), next.id));
127
+ setPrompt(promptFor(catalog, kind, next.id));
123
128
  setCursor({ row: DROW.action, caret: 0 });
124
129
  setFind(null);
125
130
  setOccIdx(0);
126
131
  setNote('');
127
132
  setMode('detail');
128
133
  }
129
- /** Cambia l'azione e RISCRIVE il prompt col default del nuovo kind (D2).
134
+ /** Cambia l'azione e RISCRIVE prompt e modello col default del nuovo kind (D2).
130
135
  *
131
- * Nessuna preservazione del testo modificato a mano, e non è una svista: la
132
- * regola `initialDetail` del modale edit protegge da un cambio di sorgente
133
- * ACCIDENTALE, e col fuoco per riga quel caso non esiste `←→` cambiano
134
- * azione solo dalla riga azione, mentre sul campo prompt muovono il caret.
135
- * Senza il cambio accidentale la preservazione difenderebbe da nulla, e
136
- * costerebbe un campo che non torna più al default. */
136
+ * Nessuna preservazione della scelta manuale di modello, per la stessa
137
+ * ragione già scritta sul prompt: col fuoco per riga un cambio di azione
138
+ * ACCIDENTALE non esiste `←→` cambiano azione solo dalla riga azione
139
+ * quindi la preservazione difenderebbe da nulla e costerebbe un campo che
140
+ * non torna più al default della nuova azione (T152). */
137
141
  function selectAction(index) {
138
142
  setAction(index);
139
143
  const id = sheet?.id;
140
- if (id)
141
- setPrompt(promptFor(catalog, specializeRecap(DETAIL_ACTIONS[index].kind, epic), id));
144
+ if (!id)
145
+ return;
146
+ const kind = specializeRecap(DETAIL_ACTIONS[index].kind, epic);
147
+ setPrompt(promptFor(catalog, kind, id));
148
+ setModel(modelFor(catalog, kind) ?? MODEL_DEFAULT);
142
149
  }
143
150
  // Il ponte fra le quattro righe e i quattro stati. Le righe restano
144
151
  // TIPIZZATE dove vivono (`ModelKind`, indice dell'azione) invece di finire in
@@ -16,17 +16,25 @@
16
16
  import { readFileSync } from 'node:fs';
17
17
  import { fileURLToPath } from 'node:url';
18
18
  import { dirname, join } from 'node:path';
19
+ import { MODELS } from './spawn.js';
19
20
  /** Stessa risalita di `DECK_RUN`: src/ (dev) e dist/ (build) sono entrambi
20
21
  * figli della package root, quindi il sibling è un livello sopra. */
21
22
  export const PROMPT_CATALOG = join(dirname(fileURLToPath(import.meta.url)), '..', 'scripts', 'prompt-catalog');
22
23
  /**
23
- * Il catalogo come mappa kind → template, col placeholder `{TASK}` ancora
24
- * dentro.
24
+ * Il catalogo come mappa kind → entry, col placeholder `{TASK}` del template
25
+ * ancora dentro.
25
26
  *
26
27
  * File illeggibile → mappa VUOTA, non un fallback cablato: un default scritto
27
28
  * qui sarebbe esattamente la copia del catalogo che questo modulo esiste per non
28
29
  * avere, e divergerebbe in silenzio. L'assenza si vede — il campo prompt resta
29
30
  * vuoto — e uno spawn senza prompt è un esito benigno.
31
+ *
32
+ * Il taglio è su DUE tab, non uno: il primo separa il kind, l'ultimo separa un
33
+ * modello opzionale in coda — così una riga a due colonne (nessun secondo tab)
34
+ * lascia il template intatto. Un valore in terza colonna che non è un
35
+ * `ModelKind` viene scartato come se la colonna non ci fosse (P2 preflight
36
+ * T152): il chiamante cade sul proprio default, stesso esito bash del `case`
37
+ * di `deck-run` che degrada un modello ignoto.
30
38
  */
31
39
  export function loadPromptCatalog(path = PROMPT_CATALOG) {
32
40
  const out = new Map();
@@ -43,13 +51,27 @@ export function loadPromptCatalog(path = PROMPT_CATALOG) {
43
51
  const tab = line.indexOf('\t');
44
52
  if (tab < 0)
45
53
  continue;
46
- out.set(line.slice(0, tab).trim(), line.slice(tab + 1).trim());
54
+ const kind = line.slice(0, tab).trim();
55
+ const rest = line.slice(tab + 1);
56
+ const lastTab = rest.lastIndexOf('\t');
57
+ const template = (lastTab >= 0 ? rest.slice(0, lastTab) : rest).trim();
58
+ const rawModel = lastTab >= 0 ? rest.slice(lastTab + 1).trim() : '';
59
+ const model = MODELS.includes(rawModel)
60
+ ? rawModel
61
+ : undefined;
62
+ out.set(kind, model ? { template, model } : { template });
47
63
  }
48
64
  return out;
49
65
  }
50
66
  /** Il prompt di un kind su una task. Kind fuori catalogo (`none`, o un file
51
67
  * mutilo) → stringa vuota, che è la stessa cosa che `deck-run` fa con `none`. */
52
68
  export function promptFor(catalog, kind, taskId) {
53
- const template = catalog.get(kind);
69
+ const template = catalog.get(kind)?.template;
54
70
  return template ? template.replaceAll('{TASK}', taskId) : '';
55
71
  }
72
+ /** Il modello di un kind, gemello di `promptFor`. Kind fuori catalogo o riga
73
+ * priva del campo → `undefined`: il chiamante cade sul proprio default
74
+ * (`MODEL_DEFAULT`), mai su un valore inventato qui. */
75
+ export function modelFor(catalog, kind) {
76
+ return catalog.get(kind)?.model;
77
+ }
package/dist/spawn.js CHANGED
@@ -143,12 +143,26 @@ export function specializeRecap(kind, epic) {
143
143
  // cambiarlo sposta le voci sotto le dita di chi le ha imparate. Fino a T111 era
144
144
  // anche il binding delle cifre `1`-`4`, passate poi al campo nota.
145
145
  export const MODELS = ['fable', 'opus', 'sonnet', 'haiku'];
146
- // Default del selettore e di ogni percorso di spawn che non passa da lui
147
- // (`^K`/`^P`/`^R` dalla lista, resume, fork). Duplicato del default di deck-run
148
- // e non letto da lì: il deck deve poter MOSTRARE la selezione iniziale prima di
149
- // spawnare alcunché, e un valore che si conosce solo a spawn avvenuto non è
150
- // mostrabile.
151
- export const MODEL_DEFAULT = 'opus';
146
+ // Default del selettore e FALLBACK per ogni kind fuori catalogo (kind `none`,
147
+ // o un catalogo mutilo). Duplicato del default di deck-run e non letto da lì:
148
+ // il deck deve poter MOSTRARE la selezione iniziale prima di spawnare
149
+ // alcunché, e un valore che si conosce solo a spawn avvenuto non è mostrabile.
150
+ //
151
+ // T152 non è più IL default di `^K`/`^P`/`^R` dalla lista: quei percorsi
152
+ // leggono il catalogo come il detail (`modelFor`), e cadono qui solo quando il
153
+ // kind non ha una riga. Resta l'unico default che resume e fork usano per
154
+ // intero, perché lì il modello non è mai una funzione del kind — è quello
155
+ // della conversazione d'origine (T148).
156
+ export const MODEL_DEFAULT = 'fable';
157
+ // T152 — `recap-status-project` non è una chiave del catalogo (§Doc Impact,
158
+ // "le chiavi del catalogo sono i valori di --prompt-kind"): lo spawn headless
159
+ // non passa mai --prompt-kind, quindi una riga lì sarebbe irraggiungibile da
160
+ // ogni chiamante. Il default vive qui, accanto a MODEL_DEFAULT, e non nel
161
+ // catalogo. Resta `opus` mentre i tre recap del catalogo stanno su fable: è
162
+ // l'unico recap che gira in headless (`-p`), senza nessuno che ne legga
163
+ // l'esito mentre si forma e possa rilanciarlo — il testo prodotto è il
164
+ // deliverable, e viene riletto da disco anche giorni dopo.
165
+ export const PROJECT_STATUS_MODEL = 'opus';
152
166
  // T66 — le azioni del detail. Non sono un catalogo nuovo: ognuna è un
153
167
  // `--prompt-kind` già esistente più `checkpoint`, e tutte passano dallo stesso
154
168
  // `spawnForTask` dei CTRL della lista — una superficie in più, zero percorsi di
@@ -264,9 +278,9 @@ export function spawnDeck(id, cwd, sessionId, kind, model = MODEL_DEFAULT, spawn
264
278
  // volta sola, quindi una nota cambiata DOPO non ri-titola la tab già aperta.
265
279
  //
266
280
  // T148 — il modello viaggia SEMPRE, come in `deckArgs`: senza `--model`
267
- // `deck-run` risolve il proprio default fisso (`opus`) e lo passa comunque al
268
- // CLI, quindi una conversazione haiku ripresa senza il flag ripartirebbe in
269
- // opus (P2 preflight). Qui però non c'è un default fisso da cablare: chi
281
+ // `deck-run` risolve il proprio default (`MODEL_DEFAULT`) e lo passa comunque
282
+ // al CLI, quindi una conversazione haiku ripresa senza il flag ripartirebbe sul
283
+ // default (P2 preflight). Qui però non c'è un default da cablare: chi
270
284
  // chiama ha già risolto il valore — il modello della conversazione d'origine,
271
285
  // o quello scelto al suo posto — e lo passa come argomento obbligatorio.
272
286
  export function resumeArgs(taskId, sessionId, model, note) {
@@ -502,6 +516,8 @@ export function spawnProjectStatus(cwd, sessionId, onResult) {
502
516
  return spawnSkill('/loom-works:recap-status-project', cwd, sessionId, onResult, [
503
517
  '--permission-mode',
504
518
  'auto',
519
+ '--model',
520
+ PROJECT_STATUS_MODEL,
505
521
  ]);
506
522
  }
507
523
  // Comando della notifica desktop. L'override esiste per il collaudo del ramo
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lamemind/loom-deck",
3
- "version": "0.61.1",
3
+ "version": "0.62.1",
4
4
  "description": "Deck TUI Ink per-progetto della famiglia loom: legge tasks.md e spawna sessioni Claude Code bound via LOOM_TASK",
5
5
  "type": "module",
6
6
  "bin": {
package/scripts/deck-run CHANGED
@@ -60,7 +60,7 @@
60
60
  # LOOM_DECK_STATE_PROFILE PTYXIS_PROFILE annunciata a compass (default: bindings/claude
61
61
  # del progetto, letto da dconf; settata a vuoto = nessun annuncio)
62
62
  # LOOM_DECK_PERMISSION_MODE override del permissionMode del file config (default: campo file, poi 'manual')
63
- # LOOM_DECK_MODEL modello quando --model non è passato (default: opus)
63
+ # LOOM_DECK_MODEL modello quando --model non è passato (batte il catalogo, default: fable)
64
64
  #
65
65
  set -euo pipefail
66
66
 
@@ -180,7 +180,8 @@ USAGE="uso: deck-run <TaskID> [--model <alias>] [--prompt-kind <kind>] [--sessio
180
180
  prompt. Ammesso anche con --no-task: un testo già scritto non
181
181
  ha una task da nominare, a differenza dei kind del catalogo
182
182
 
183
- --model modello della sessione: fable|opus|sonnet|haiku (default: opus)
183
+ --model modello della sessione: fable|opus|sonnet|haiku
184
+ (default: il modello del kind in catalogo, o 'fable' fuori catalogo)
184
185
  valore ignoto → fallback sul default, con avviso su stderr
185
186
 
186
187
  --title-note nota della conversazione, appesa al titolo tab
@@ -353,11 +354,21 @@ case "${PERM_MODE:-}" in
353
354
  esac
354
355
  MODE_FLAG="--permission-mode ${PERM_MODE} "
355
356
 
356
- # ── modello (T108) ───────────────────────────────────────────────────────────
357
- # Precedenza: --model > env LOOM_DECK_MODEL > 'opus'. Nessun campo nel file
358
- # config: il default è unico per tutta la famiglia, e uno scalare per-progetto
359
- # aggiungerebbe una chiave allo schema del plugin per un valore che il selettore
360
- # del deck sovrascrive a ogni spawn.
357
+ # ── modello (T108 + T152) ────────────────────────────────────────────────────
358
+ # Precedenza: --model > env LOOM_DECK_MODEL > modello del kind nel catalogo >
359
+ # 'fable'. L'ultimo gradino è il gemello bash di `MODEL_DEFAULT` in spawn.ts e
360
+ # va tenuto allineato a mano: i due lati non si leggono a vicenda (il deck deve
361
+ # poter MOSTRARE la selezione iniziale prima che deck-run esista come processo),
362
+ # quindi un cambio qui senza l'altro fa partire dalla lista un modello diverso
363
+ # da quello che il detail aveva scritto a schermo.
364
+ # Fino a T152 il default era un valore unico per tutta la famiglia,
365
+ # perché il frontmatter `model:` delle skill riscriveva comunque il modello di
366
+ # sessione — un default configurabile qui non sarebbe servito a nulla. Da
367
+ # quando le skill non dichiarano più `model:`, il default DEVE viaggiare col
368
+ # kind: `run` costa quanto `preflight` solo se «vuole sonnet» è scritto da
369
+ # qualche parte che deck-run consulta, e quella parte è il catalogo che il
370
+ # deck TUI legge già per il testo del prompt (T117) — stessa fonte, stesso
371
+ # `kind`, niente seconda copia.
361
372
  # Il flag è passato SEMPRE, anche sul default, per la stessa ragione di
362
373
  # permissionMode: lo spawn resta leggibile nel process tree invece di dipendere
363
374
  # dal default del CLI, che cambia fra versioni.
@@ -366,12 +377,32 @@ MODE_FLAG="--permission-mode ${PERM_MODE} "
366
377
  # ferma DENTRO lo script (nessun template da scegliere, l'errore è del deck),
367
378
  # un modello ignoto arriverebbe al CLI e produrrebbe una tab con un comando che
368
379
  # fallisce all'avvio — cioè il guasto che permissionMode evita degradando.
380
+ _model_for_kind() { # <kind> → modello dichiarato in catalogo (3ª colonna), o niente
381
+ local want="$1" k t m
382
+ [[ -n "$want" && -f "$PROMPT_CATALOG" ]] || return 1
383
+ while IFS=$'\t' read -r k t m || [[ -n "$k" ]]; do
384
+ [[ -z "$k" || "$k" == \#* ]] && continue
385
+ [[ "$k" == "$want" && -n "$m" ]] && { printf '%s' "$m"; return 0; }
386
+ done < "$PROMPT_CATALOG"
387
+ return 1
388
+ }
389
+ # Kind di catalogo effettivo: SOLO quando la sessione è bound e senza prompt
390
+ # letterale — le due strade (--no-task, --prompt) non hanno una riga di
391
+ # catalogo da consultare, né per il prompt (sotto) né per il modello (qui).
392
+ # Riusato tal quale nella composizione del prompt: stesso guard, stesso valore.
393
+ CATALOG_KIND=""
394
+ if [[ $PROMPT_GIVEN -eq 0 && $NO_TASK -eq 0 ]]; then
395
+ CATALOG_KIND="${PROMPT_KIND:-recap}"
396
+ fi
369
397
  MODEL="${MODEL:-${LOOM_DECK_MODEL:-}}"
398
+ if [[ -z "$MODEL" && -n "$CATALOG_KIND" && "$CATALOG_KIND" != "none" ]]; then
399
+ MODEL="$(_model_for_kind "$CATALOG_KIND" || true)"
400
+ fi
370
401
  case "${MODEL:-}" in
371
402
  fable|opus|sonnet|haiku) ;;
372
- '') MODEL="opus" ;;
373
- *) echo "modello ignoto: '${MODEL}' → fallback 'opus' (usa fable|opus|sonnet|haiku)" >&2
374
- MODEL="opus" ;;
403
+ '') MODEL="fable" ;;
404
+ *) echo "modello ignoto: '${MODEL}' → fallback 'fable' (usa fable|opus|sonnet|haiku)" >&2
405
+ MODEL="fable" ;;
375
406
  esac
376
407
  MODEL_FLAG="--model ${MODEL} "
377
408
 
@@ -476,9 +507,12 @@ FORK_FLAG=""
476
507
  # (`T`, unico prefisso del contratto loom), quindi nessun prompt discrimina sulla
477
508
  # forma dell'id.
478
509
  _prompt_template() { # <kind> → template col placeholder {TASK}, o niente
479
- local want="$1" k t
510
+ local want="$1" k t m
480
511
  [[ -f "$PROMPT_CATALOG" ]] || return 1
481
- while IFS=$'\t' read -r k t || [[ -n "$k" ]]; do
512
+ # 3 variabili, non 2 (T152): da quando il catalogo porta una 3ª colonna
513
+ # modello, un `read -r k t` a due si mangerebbe il tab separatore e il
514
+ # modello dentro `t`, che è esattamente il template passato al CLI.
515
+ while IFS=$'\t' read -r k t m || [[ -n "$k" ]]; do
482
516
  [[ -z "$k" || "$k" == \#* ]] && continue
483
517
  [[ "$k" == "$want" ]] && { printf '%s' "$t"; return 0; }
484
518
  done < "$PROMPT_CATALOG"
@@ -503,7 +537,7 @@ elif [[ $NO_TASK -eq 1 ]]; then
503
537
  # volta e qui resta quindi inerte: senza task non ha nulla da nominare.
504
538
  PROMPT=""
505
539
  else
506
- _kind="${PROMPT_KIND:-recap}"
540
+ _kind="$CATALOG_KIND"
507
541
  if [[ "$_kind" == "none" ]]; then
508
542
  PROMPT=""
509
543
  else
@@ -1,28 +1,38 @@
1
1
  # Catalogo dei prompt iniziali di una sessione Claude aperta dal deck.
2
2
  #
3
- # Formato a righe: <kind><TAB><template>, con `{TASK}` interpolato col TaskID.
4
- # Righe vuote e righe che iniziano con `#` sono commenti.
3
+ # Formato a righe: <kind><TAB><template><TAB><modello>, con `{TASK}`
4
+ # interpolato col TaskID. Righe vuote e righe che iniziano con `#` sono
5
+ # commenti. Il modello è OPZIONALE: una riga a due colonne resta leggibile e
6
+ # chi la consulta cade sul proprio default (`MODEL_DEFAULT`/`fable`) — il campo
7
+ # esiste per i kind bound a una skill (T152), non per ogni riga del file.
5
8
  #
6
9
  # Perché un file dati e non un `case` dentro deck-run: due lati hanno bisogno
7
10
  # dello stesso testo — deck-run per comporre il comando in-tab, il deck TUI per
8
- # pre-riempire il campo prompt del detail con ciò che sta per essere eseguito.
9
- # Come codice, il secondo lato dovrebbe riscriverlo, e le due copie divergono
10
- # alla prima voce aggiunta da una parte sola.
11
+ # pre-riempire il campo prompt (e ora anche il modello) del detail con ciò che
12
+ # sta per essere eseguito. Come codice, il secondo lato dovrebbe riscriverlo, e
13
+ # le due copie divergono alla prima voce aggiunta da una parte sola.
11
14
  #
12
15
  # `none` non compare: nessun prompt non è un template vuoto, è l'assenza della
13
- # voce. Chi chiede un kind fuori da questo file riceve un prompt vuoto.
16
+ # voce. Chi chiede un kind fuori da questo file riceve un prompt vuoto e nessun
17
+ # modello (fallback sul default del chiamante).
14
18
  #
15
19
  # Vincolo sui template: nessun apice singolo. Il testo finisce dentro `'...'`
16
20
  # nel comando passato a `bash -lc`, e questo file è committato — un apice qui
17
21
  # sarebbe un errore di scrittura, non un input da quotare.
22
+ #
23
+ # Il criterio della colonna modello: lettura e conversazione stanno su fable
24
+ # (i tre recap, il preflight), la scrittura presidiata su opus (run e
25
+ # checkpoint, che toccano codice e committano). Cambiare una parola qui cambia
26
+ # il costo di OGNI sessione aperta su quel kind, da ogni superficie del deck —
27
+ # non è una preferenza di questo progetto, è il default di famiglia.
18
28
  # `recap` è il DISPATCHER: risolve la task, ne legge il Size e passa da sé alla
19
29
  # sotto-skill. Lo usa chi non sa se la task è un cappello — gli acceleratori
20
30
  # della lista, dove il deck ha in mano solo tasks.md, che il Size non ce l'ha.
21
31
  # Le due voci `recap-task`/`recap-epic` saltano quel giro: le sceglie il DETAIL,
22
32
  # che il task file l'ha già aperto e quindi il Size lo conosce.
23
- recap /loom-works:recap-status {TASK}
24
- recap-task /loom-works:recap-status-task {TASK}
25
- recap-epic /loom-works:recap-status-epic {TASK}
26
- preflight /loom-works:preflight-task {TASK}
27
- run /loom-works:run-task {TASK}
28
- checkpoint /loom-works:checkpoint-task {TASK}
33
+ recap /loom-works:recap-status {TASK} fable
34
+ recap-task /loom-works:recap-status-task {TASK} fable
35
+ recap-epic /loom-works:recap-status-epic {TASK} fable
36
+ preflight /loom-works:preflight-task {TASK} fable
37
+ run /loom-works:run-task {TASK} opus
38
+ checkpoint /loom-works:checkpoint-task {TASK} opus