@lamemind/loom-deck 0.71.0 → 0.71.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
@@ -25,8 +25,8 @@ import { saveView, viewFilePath } from './view-store.js';
25
25
  import { onInTabCommand, runLaunch, spawnClaudeEmpty, spawnBare, spawnDeck, spawnDeckFork, spawnDeckResume, spawnTerminal, DECK_RUN, } from './spawn.js';
26
26
  import { resolveSpawnId } from './spawn-config.js';
27
27
  import { useTaskOps } from './task-ops.js';
28
- import { inboxWords } from './inbox.js';
29
- import { docWords } from './doc-tree.js';
28
+ import { inboxPrompt, inboxWords } from './inbox.js';
29
+ import { docTargetKind, docWords } from './doc-tree.js';
30
30
  import { wrapWords } from './wrap-scan.js';
31
31
  export function useDeckActions({ cwd, tasksPath, tasksDir, columns, model, overrides, catalog, setNote, }) {
32
32
  // La riga di stato di OGNI spawn di sessione Claude: il comando esatto, come
@@ -404,6 +404,23 @@ export function useDeckActions({ cwd, tasksPath, tasksDir, columns, model, overr
404
404
  * un comando che non si è riusciti a comporre.
405
405
  */
406
406
  function rebalanceSpawn(row) {
407
+ // La coda inbox PRIMA dei flag: un file inbox porta sempre il suo flag, e
408
+ // senza questo ramo cadrebbe nel ramo del rebalance con l'aria di essere un
409
+ // bersaglio legittimo. La skill è la stessa che offre il pane di destra —
410
+ // il prompt lo compone `inboxPrompt`, unico posto in cui vive la mappa
411
+ // natura → skill, esattamente come per il `⏎` del pane inbox.
412
+ const kind = docTargetKind(row, model.docsRoot);
413
+ if (kind !== 'doc') {
414
+ const f = kind === 'inbox-file' ? inboxFileAt(row.path) : null;
415
+ if (f)
416
+ return { prompt: inboxPrompt(f), hint: '' };
417
+ return {
418
+ prompt: '',
419
+ hint: kind === 'inbox-dir'
420
+ ? `${row.path} è la coda inbox: si drena un file alla volta, non si riorganizza`
421
+ : `${row.path} è un file inbox: la sua natura non è ancora stata misurata, aprilo dal pane di destra`,
422
+ };
423
+ }
407
424
  if (row.flags.length === 0) {
408
425
  return {
409
426
  prompt: '',
@@ -413,6 +430,13 @@ export function useDeckActions({ cwd, tasksPath, tasksDir, columns, model, overr
413
430
  const d = spawnDefaults('rebalance', { target: row.path, words: docWords(row.path) });
414
431
  return { prompt: d.prompt ?? '', hint: '' };
415
432
  }
433
+ /** Il file della coda inbox che sta dietro una riga dell'albero doc. Le due
434
+ * misure sono due scan distinti dello stesso script: l'albero conosce il
435
+ * path, la natura la sa solo la coda, e il prompt di drain è una funzione
436
+ * della natura. */
437
+ function inboxFileAt(path) {
438
+ return model.inboxAll.find((f) => f.path === path) ?? null;
439
+ }
416
440
  /**
417
441
  * T160 — apre la sessione che RIORGANIZZA la topologia attorno a un bersaglio.
418
442
  *
@@ -430,6 +454,15 @@ export function useDeckActions({ cwd, tasksPath, tasksDir, columns, model, overr
430
454
  function rebalanceDoc(row, prompt) {
431
455
  if (!prompt)
432
456
  return;
457
+ // Il bersaglio inbox prende la terna della riga `drain`, non quella di
458
+ // `rebalance`: il prompt da solo non basterebbe — modello e titolo della tab
459
+ // verrebbero comunque dalla riga sbagliata, e la conversazione si
460
+ // chiamerebbe «rebalance» mentre esegue un drain.
461
+ const f = inboxFileAt(row.path);
462
+ if (f) {
463
+ drainInbox(f, prompt);
464
+ return;
465
+ }
433
466
  const sid = randomUUID();
434
467
  const d = spawnDefaults('rebalance', { target: row.path, words: docWords(row.path) });
435
468
  const title = d.title ?? '';
@@ -587,12 +587,17 @@ export function useDeckModel({ cwd, tasksPath, tasksDir, bareModel: bareModelDef
587
587
  // modo del deck
588
588
  deckMode,
589
589
  // derivazioni del pane inbox
590
+ docsRoot,
590
591
  inboxScanned: inbox.scanned,
591
592
  inboxOk: inbox.ok,
592
593
  inboxViewId,
593
594
  inboxCounts,
594
595
  inboxStale,
595
596
  inboxFiles,
597
+ // La coda INTERA, non filtrata dalla vista: il pane doc la interroga per
598
+ // path e la vista attiva del pane inbox non c'entra niente con quale file
599
+ // l'albero stia mostrando.
600
+ inboxAll: inbox.files,
596
601
  selInboxPath,
597
602
  selInbox,
598
603
  // derivazioni del pane doc
package/dist/doc-tree.js CHANGED
@@ -363,6 +363,15 @@ export function countFlagged(data, flags) {
363
363
  const hit = (f) => f.some((x) => wanted.has(x));
364
364
  return data.dirs.filter((d) => hit(d.flags)).length + data.files.filter((f) => hit(f.flags)).length;
365
365
  }
366
+ export function inboxDirOf(docsRoot) {
367
+ return `${docsRoot}/inbox`;
368
+ }
369
+ export function docTargetKind(row, docsRoot) {
370
+ const dir = inboxDirOf(docsRoot);
371
+ if (row.kind === 'dir')
372
+ return row.path === dir ? 'inbox-dir' : 'doc';
373
+ return row.path.startsWith(`${dir}/`) || row.flags.includes('INBOX') ? 'inbox-file' : 'doc';
374
+ }
366
375
  /**
367
376
  * T160 — il buco `{words}` del titolo di una sessione di rebalance: il path reso
368
377
  * a parole.
@@ -73,13 +73,20 @@ export function DocPane({ rows, counts, activeView, paneCount, selectedPath, foc
73
73
  ? 'misura della doc fallita: plugin assente o script in errore'
74
74
  : docView(activeView).empty, width) })) : (rows.map((r) => {
75
75
  const sel = r.path === selectedPath;
76
- const indent = ' '.repeat(r.depth * INDENT_W);
76
+ // Il rientro sta FUORI da `cut`, che normalizza il whitespace e taglia
77
+ // gli estremi (`\s+ → spazio`, poi `trim`): passarglielo insieme al
78
+ // nome lo faceva sparire, e l'albero usciva piatto pur avendo le
79
+ // profondità giuste. Il budget si divide qui — prima le colonne del
80
+ // rientro, il resto al nome — e il rientro si ferma una colonna prima
81
+ // della fine, o su un pane strettissimo mangerebbe il nome intero.
82
+ const indentW = Math.min(r.depth * INDENT_W, Math.max(0, nameW - 1));
83
+ const indent = ' '.repeat(indentW);
77
84
  // La barra finale distingue una cartella da un file senza spendere una
78
85
  // colonna di marcatore: è la convenzione di `ls -F`, e su una riga che
79
86
  // porta già una colonna di flag un glifo in più sarebbe la terza cosa
80
87
  // da leggere prima del nome.
81
88
  const label = r.kind === 'dir' ? `${r.name}/` : r.name;
82
- const text = cut(indent + label, nameW);
89
+ const text = indent + cut(label, nameW - indentW);
83
90
  return (_jsxs(Text, { inverse: sel && focused, bold: sel && !focused, wrap: "truncate-end", children: [sel ? CARET : CARET_OFF, _jsx(Text, { color: flagColor(r), dimColor: r.flags.length === 0, children: flagCell(r.flags) }), ' ', _jsx(Text, { bold: r.kind === 'dir', dimColor: r.kind === 'file' && r.flags.length === 0, children: text })] }, r.path));
84
91
  }))] }));
85
92
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lamemind/loom-deck",
3
- "version": "0.71.0",
3
+ "version": "0.71.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": {