@lamemind/loom-deck 0.56.0 → 0.57.0
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 +34 -1
- package/dist/cli.js +65 -9
- package/dist/deck-model.js +98 -1
- package/dist/frame.js +122 -4
- package/dist/glyphs.js +25 -1
- package/dist/hooks.js +72 -1
- package/dist/inbox-views.js +67 -0
- package/dist/inbox.js +83 -1
- package/dist/input-modes.js +9 -5
- package/dist/input.js +85 -6
- package/dist/model.js +1 -1
- package/dist/mouse.js +17 -5
- package/dist/overlays/inbox.js +90 -0
- package/dist/overlays/wrap.js +144 -0
- package/dist/pane-header.js +27 -2
- package/dist/pane-views.js +1 -1
- package/dist/spawn.js +27 -0
- package/dist/tasks.js +17 -4
- package/dist/ui/inbox-screen.js +21 -0
- package/dist/ui/panes.js +68 -3
- package/dist/ui/preview.js +41 -3
- package/dist/ui/screens.js +57 -14
- package/dist/ui/wrap-screen.js +30 -0
- package/dist/viewport.js +60 -0
- package/dist/wrap-scan.js +30 -1
- package/package.json +1 -1
- package/scripts/deck-run +30 -9
package/dist/viewport.js
CHANGED
|
@@ -29,6 +29,12 @@ const MAX_DETAIL_LINES = 6;
|
|
|
29
29
|
// a un pane va scalata qui, o il frame sfonda `rows` e Ink passa a
|
|
30
30
|
// clearTerminal (frame-fantasma nello scrollback di VTE).
|
|
31
31
|
const TASKS_PANE_CHROME = 6; // 2 bordi + header "Tasks (n)" + riga sort + 2 righe meta
|
|
32
|
+
// T134 — vale per ENTRAMBI i pane dello slot destro: il pane inbox ha la stessa
|
|
33
|
+
// cornice (2 bordi + header) e uno solo dei due è montato alla volta, quindi
|
|
34
|
+
// `Budget.sessionRows` è la capienza del pane destro qualunque esso sia. Se un
|
|
35
|
+
// giorno l'inbox guadagnasse una riga fissa, questa costante deve sdoppiarsi e
|
|
36
|
+
// il budget guadagnare un ramo: una riga fissa non contata è ciò che fa sfondare
|
|
37
|
+
// `rows` e manda Ink nel ramo `clearTerminal`.
|
|
32
38
|
const SESSIONS_PANE_CHROME = 3; // 2 bordi + header "Sessions · …"
|
|
33
39
|
const PREVIEW_CHROME = 3; // marginTop + 2 bordi
|
|
34
40
|
/** Preview sessione: righe fisse = titolo + riga meta (size · turni · ultima
|
|
@@ -36,6 +42,12 @@ const PREVIEW_CHROME = 3; // marginTop + 2 bordi
|
|
|
36
42
|
* variabili, ciascuna al più MAX_SESSION_PREVIEW righe. */
|
|
37
43
|
const SESSION_DETAIL_FIXED = 2;
|
|
38
44
|
const MAX_SESSION_PREVIEW = 3;
|
|
45
|
+
/** T134 — preview inbox: nome del file + riga meta (natura, marcatori, branch,
|
|
46
|
+
* cappello, cifre, età). Righe TUTTE fisse, nessuna variabile: il corpo del
|
|
47
|
+
* file sta nel detail fullscreen, e mostrarne qui le prime righe costerebbe una
|
|
48
|
+
* lettura di file a ogni movimento di selezione per un'anteprima che il detail
|
|
49
|
+
* dà per intero. */
|
|
50
|
+
const INBOX_DETAIL_FIXED = 2;
|
|
39
51
|
/** Altezza di ciascuna modale, marginTop incluso. In flusso, non in overlay:
|
|
40
52
|
* spingono giù i pane, quindi il loro costo va scalato dal budget. */
|
|
41
53
|
export const MODAL_HEIGHT = {
|
|
@@ -73,6 +85,14 @@ export const MODAL_HEIGHT = {
|
|
|
73
85
|
// progetto è un documento lungo quanto un task file, quindi vale la stessa
|
|
74
86
|
// ragione delle altre quattro. La sua altezza la distribuisce `statusCapacity`.
|
|
75
87
|
status: 0,
|
|
88
|
+
// T134 — il detail di un file inbox: sesta sostitutiva. Un file di nozioni
|
|
89
|
+
// arriva a 28KB, cioè più lungo di ogni task file del progetto: la stessa
|
|
90
|
+
// ragione delle altre cinque. Altezza da `inboxDetailCapacity`.
|
|
91
|
+
inbox: 0,
|
|
92
|
+
// T134 — la lista hard-wrap: settima sostitutiva. Sul cappello lo scan trova
|
|
93
|
+
// 77 `WRAP` e 147 `misto`, cioè una lista che non entra in nessun box sopra i
|
|
94
|
+
// pane. Altezza da `wrapListCapacity`.
|
|
95
|
+
wrap: 0,
|
|
76
96
|
};
|
|
77
97
|
/**
|
|
78
98
|
* Distribuisce le righe disponibili fra lista task, lista sessioni e preview.
|
|
@@ -158,6 +178,16 @@ export function layoutBudget(input) {
|
|
|
158
178
|
previewCost = fixed + sessionFirstLines + sessionLastLines;
|
|
159
179
|
}
|
|
160
180
|
}
|
|
181
|
+
else if (input.preview === 'inbox') {
|
|
182
|
+
// Tutte righe fisse: o il blocco entra intero o non esiste. Non c'è una
|
|
183
|
+
// parte variabile da sacrificare per farlo stare, quindi non c'è nemmeno la
|
|
184
|
+
// domanda di quanto concedergli.
|
|
185
|
+
const fixed = PREVIEW_CHROME + INBOX_DETAIL_FIXED;
|
|
186
|
+
if (avail - floor - fixed >= 0) {
|
|
187
|
+
preview = true;
|
|
188
|
+
previewCost = fixed;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
161
191
|
// Ciò che resta va a ENTRAMBE le colonne: la preview sta sotto il blocco dei
|
|
162
192
|
// pane, quindi il suo costo lo pagano insieme una volta sola.
|
|
163
193
|
const listAvail = avail - previewCost;
|
|
@@ -272,6 +302,36 @@ const STATUS_CHROME = 8;
|
|
|
272
302
|
export function statusCapacity(rows) {
|
|
273
303
|
return Math.max(0, (rows || 24) - SLACK - STATUS_CHROME);
|
|
274
304
|
}
|
|
305
|
+
// T134 — cornice del detail di un file inbox. Gemella di STATUS_CHROME più una
|
|
306
|
+
// riga: il detail porta in fondo la riga dell'azione (quale skill partirà su
|
|
307
|
+
// `⏎`), che è l'unica cosa che l'utente deve leggere prima di premere.
|
|
308
|
+
// 2 bordi del box esterno
|
|
309
|
+
// 1 riga di testata (natura :: nome del file)
|
|
310
|
+
// 1 riga meta (marcatori · cifre · posizione nel testo)
|
|
311
|
+
// 1 riga hint
|
|
312
|
+
// 1 marginTop del box corpo
|
|
313
|
+
// 2 bordi del box corpo
|
|
314
|
+
// 1 marginTop della riga azione
|
|
315
|
+
// 1 riga azione
|
|
316
|
+
const INBOX_CHROME = 10;
|
|
317
|
+
/** Righe di file inbox che entrano nel terminale. */
|
|
318
|
+
export function inboxDetailCapacity(rows) {
|
|
319
|
+
return Math.max(0, (rows || 24) - SLACK - INBOX_CHROME);
|
|
320
|
+
}
|
|
321
|
+
// T134 — cornice della lista hard-wrap.
|
|
322
|
+
// 2 bordi del box esterno
|
|
323
|
+
// 1 riga di testata (conteggi + ora dell'ultimo scan)
|
|
324
|
+
// 1 riga hint
|
|
325
|
+
// 1 marginTop del box lista
|
|
326
|
+
// 2 bordi del box lista
|
|
327
|
+
// 1 marginTop del box path
|
|
328
|
+
// 2 bordi del box path
|
|
329
|
+
// 1 riga del campo path
|
|
330
|
+
const WRAP_CHROME = 12;
|
|
331
|
+
/** Righe di lista che entrano nel terminale. */
|
|
332
|
+
export function wrapListCapacity(rows) {
|
|
333
|
+
return Math.max(0, (rows || 24) - SLACK - WRAP_CHROME);
|
|
334
|
+
}
|
|
275
335
|
/**
|
|
276
336
|
* Righe scorse da una pressione di PagGiù/PagSu: METÀ della capienza visibile.
|
|
277
337
|
*
|
package/dist/wrap-scan.js
CHANGED
|
@@ -45,7 +45,11 @@ export function parseWrapTsv(stdout) {
|
|
|
45
45
|
if (m)
|
|
46
46
|
fields[m[1]] = m[2];
|
|
47
47
|
}
|
|
48
|
-
|
|
48
|
+
// `Number('')` vale 0, non NaN: senza il controllo sul campo VUOTO una
|
|
49
|
+
// colonna non stimabile (troppe poche righe candidate) si leggerebbe come
|
|
50
|
+
// `col=0`, cioè una misura che non esiste travestita da misura.
|
|
51
|
+
const raw = fields.col ?? '';
|
|
52
|
+
const column = raw === '' ? Number.NaN : Number(raw);
|
|
49
53
|
out.push({
|
|
50
54
|
verdict,
|
|
51
55
|
path: cells[1],
|
|
@@ -73,6 +77,31 @@ export function parseWrapTsv(stdout) {
|
|
|
73
77
|
export function wrapCount(files) {
|
|
74
78
|
return files.filter((f) => f.verdict === 'WRAP').length;
|
|
75
79
|
}
|
|
80
|
+
/** Quanti file `misto`: fuori dal contatore ma in lista, col proprio marker. */
|
|
81
|
+
export function mixedCount(files) {
|
|
82
|
+
return files.filter((f) => f.verdict === 'misto').length;
|
|
83
|
+
}
|
|
84
|
+
/** Radice di default dell'area di srotolamento: la project root intera (D4). */
|
|
85
|
+
export const WRAP_DEFAULT_PATH = '.';
|
|
86
|
+
/**
|
|
87
|
+
* Il prompt della sessione che srotola un path.
|
|
88
|
+
*
|
|
89
|
+
* CABLATO per decisione, non per fretta (D9): parametrizzarlo prima di aver
|
|
90
|
+
* visto come si comporta significherebbe scegliere i parametri a occhio. Le tre
|
|
91
|
+
* cose che dice sono le tre che rendono l'operazione reversibile e verificabile
|
|
92
|
+
* — backup fuori dal repo, rapporto, commit solo se il diff è chiaramente
|
|
93
|
+
* innocuo — e nessuna delle tre è una preferenza da esporre.
|
|
94
|
+
*
|
|
95
|
+
* Il `<path>` è l'unico buco. Arriva dal campo della lista e finisce dentro
|
|
96
|
+
* `--prompt` come argv singolo, quindi non passa da nessuna shell prima di
|
|
97
|
+
* `deck-run`, che lo quota ad apici singoli: non c'è quoting da fare qui.
|
|
98
|
+
*/
|
|
99
|
+
export function wrapPrompt(path) {
|
|
100
|
+
const target = path.trim() || WRAP_DEFAULT_PATH;
|
|
101
|
+
return (`lancia md-wrap modo apply su ${target} e backup in cartella tmp dedicata. ` +
|
|
102
|
+
'verifica risultato e fai rapporto. se le modifiche sono tutte chiaramente safe, ' +
|
|
103
|
+
'puoi committare direttamente');
|
|
104
|
+
}
|
|
76
105
|
/**
|
|
77
106
|
* Cartella della cache, una per utente e con `mode 0700` — stessa ragione del
|
|
78
107
|
* project status: `/tmp` è condivisa, e un file a nome prevedibile può essere
|
package/package.json
CHANGED
package/scripts/deck-run
CHANGED
|
@@ -26,8 +26,12 @@
|
|
|
26
26
|
# Il quarto asse (T108) è indipendente dagli altri tre: vale sul ramo bound come
|
|
27
27
|
# su --no-task, su una sessione nuova come su una ripresa.
|
|
28
28
|
#
|
|
29
|
-
# Con --no-task la sessione è NUDA: niente LOOM_TASK, niente
|
|
30
|
-
#
|
|
29
|
+
# Con --no-task la sessione è NUDA: niente LOOM_TASK, niente --session-id.
|
|
30
|
+
# Serve al lavoro spot che non appartiene a nessuna task.
|
|
31
|
+
# T134 — un prompt iniziale ce l'ha se glielo si passa LETTERALE (`--prompt`):
|
|
32
|
+
# il lavoro sulla doc — drenare un file inbox, srotolare l'hard-wrap di un path
|
|
33
|
+
# — non appartiene a nessuna task e non deve ereditarne una. I `--prompt-kind`
|
|
34
|
+
# del catalogo restano invece rifiutati con --no-task: nominano tutti un TaskID.
|
|
31
35
|
#
|
|
32
36
|
# Con --resume <sid> riprende una conversazione esistente; aggiungendo --fork la
|
|
33
37
|
# riprende RAMANDOLA (`--fork-session`): id nuovo, transcript copiato, l'origine
|
|
@@ -172,7 +176,9 @@ USAGE="uso: deck-run <TaskID> [--model <alias>] [--prompt-kind <kind>] [--sessio
|
|
|
172
176
|
checkpoint /loom-works:checkpoint-task <TaskID>
|
|
173
177
|
|
|
174
178
|
--prompt prompt LETTERALE, per chi lo ha già composto (o fatto
|
|
175
|
-
modificare). Esclusivo con --prompt-kind; vuoto = nessun
|
|
179
|
+
modificare). Esclusivo con --prompt-kind; vuoto = nessun
|
|
180
|
+
prompt. Ammesso anche con --no-task: un testo già scritto non
|
|
181
|
+
ha una task da nominare, a differenza dei kind del catalogo
|
|
176
182
|
|
|
177
183
|
--model modello della sessione: fable|opus|sonnet|haiku (default: opus)
|
|
178
184
|
valore ignoto → fallback sul default, con avviso su stderr
|
|
@@ -219,11 +225,21 @@ if [[ $NO_TASK -eq 1 && -n "$PROMPT_KIND" ]]; then
|
|
|
219
225
|
echo "$USAGE" >&2
|
|
220
226
|
exit 2
|
|
221
227
|
fi
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
228
|
+
# T134/D9 — `--prompt` con `--no-task` è AMMESSO, e il divieto che c'era qui è
|
|
229
|
+
# caduto. Il razionale del divieto valeva per il catalogo, non per il testo
|
|
230
|
+
# letterale: i sette kind nominano tutti il TaskID, quindi senza task non c'è
|
|
231
|
+
# nulla da chiedere loro; un prompt già composto dal chiamante non ha invece
|
|
232
|
+
# nessuna task da nominare — e ce ne sono di legittimi che non ne hanno una.
|
|
233
|
+
# Il caso che ha fatto cadere il divieto: il deck offre il drain di un file
|
|
234
|
+
# inbox e lo srotolamento dei `.md` di un path, due lavori che stanno sulla doc
|
|
235
|
+
# e non su una task; legarli a un cappello esporterebbe `LOOM_TASK`, farebbe
|
|
236
|
+
# iniettare in contesto il task file di un lavoro chiuso e metterebbe `· T<n>`
|
|
237
|
+
# nel titolo della tab (D10 preflight).
|
|
238
|
+
#
|
|
239
|
+
# Il divieto gemello su `--prompt-kind` RESTA. Toglierlo non è simmetrico:
|
|
240
|
+
# ogni template del catalogo interpola `{TASK}`, e senza task produrrebbe un
|
|
241
|
+
# prompt come `/loom-works:run-task ` con l'id vuoto — cioè una sessione che
|
|
242
|
+
# parte su un comando monco, che è il guasto che il divieto esiste per evitare.
|
|
227
243
|
# Due modi di dire la stessa cosa: accettarli insieme obbligherebbe a stabilire
|
|
228
244
|
# quale vince, cioè a scrivere una precedenza che nessun chiamante ha chiesto.
|
|
229
245
|
if [[ $PROMPT_GIVEN -eq 1 && -n "$PROMPT_KIND" ]]; then
|
|
@@ -528,7 +544,12 @@ PROMPT_ARG=""
|
|
|
528
544
|
# scelta di chi apre la sessione, non una proprietà della task né della ripresa
|
|
529
545
|
# (T108) — stesso layer di MODE_FLAG, che infatti gli sta accanto.
|
|
530
546
|
if [[ $NO_TASK -eq 1 ]]; then
|
|
531
|
-
|
|
547
|
+
# T134/D9 — il PROMPT_ARG entra anche qui: dal 134 una sessione nuda può
|
|
548
|
+
# nascere su un prompt letterale (drain di un file inbox, srotolamento di un
|
|
549
|
+
# path). Resta vuoto su ogni altro percorso `--no-task`, perché senza
|
|
550
|
+
# `--prompt` il ramo del catalogo non gira — `PROMPT_KIND` con `--no-task`
|
|
551
|
+
# è ancora rifiutato a monte.
|
|
552
|
+
_default_intab="${PROFILE_ENV}claude --name '${TITLE}' ${MODE_FLAG}${MODEL_FLAG}${SID_FLAG}${RES_FLAG}${FORK_FLAG}${PROMPT_ARG}"
|
|
532
553
|
else
|
|
533
554
|
_default_intab="${PROFILE_ENV}LOOM_TASK=${TASK} claude --name '${TITLE}' ${MODE_FLAG}${MODEL_FLAG}${SID_FLAG}${RES_FLAG}${FORK_FLAG}${PROMPT_ARG}"
|
|
534
555
|
fi
|