@lamemind/loom-deck 0.7.0 → 0.8.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/cli.js +26 -2
- package/dist/config.js +17 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -10,7 +10,7 @@ import { dirname, join } from 'node:path';
|
|
|
10
10
|
import { resolveTasksPath, resolveTasksDir, loadTasks, loadTaskDetail, } from './tasks.js';
|
|
11
11
|
import { discoverProjectSessions } from './sessions.js';
|
|
12
12
|
import { appendTaskBinding, loadTaskBindings } from './task-index.js';
|
|
13
|
-
import { loadLaunch } from './config.js';
|
|
13
|
+
import { loadIdentity, loadLaunch } from './config.js';
|
|
14
14
|
import { applyView, cycleSort, describeSort, priName, progName, toggleHidden, PRI_ENTRIES, PROG_ENTRIES, } from './view.js';
|
|
15
15
|
import { initialDetail, progressText, writeTaskEdit, PRI_GLYPH, PRI_LABEL, PROG_GLYPH, } from './task-edit.js';
|
|
16
16
|
import { loadView, saveView, viewFilePath } from './view-store.js';
|
|
@@ -67,6 +67,22 @@ function runLaunch(entry, cwd) {
|
|
|
67
67
|
child.unref();
|
|
68
68
|
return child;
|
|
69
69
|
}
|
|
70
|
+
// T37 — surface STANDARD LAUNCH `terminal`: built-in e universale (nessuna
|
|
71
|
+
// dichiarazione in `launch[]`), ma di natura launch — fire-once, nessuno stato.
|
|
72
|
+
// Il deck gira già DENTRO una tab Ptyxis → `--tab` mette il terminale accanto a
|
|
73
|
+
// sé nella stessa finestra, invece di sparpagliare finestre.
|
|
74
|
+
// Nessun `-- CMD`: l'azione È aprire la shell (differenza dalle launch custom,
|
|
75
|
+
// che eseguono un comando dentro `bash -lic`).
|
|
76
|
+
// `-T <title>` col core `<owner> <name>` tiene la finestra matchabile da compass
|
|
77
|
+
// anche mentre la tab attiva è il terminale; senza identità nel file config si
|
|
78
|
+
// spawna senza titolo (la surface resta funzionante, il progetto risulta assente
|
|
79
|
+
// dal radar finché quella tab è in primo piano).
|
|
80
|
+
function spawnTerminal(cwd, title) {
|
|
81
|
+
const args = title ? ['--tab', '-T', title, '-d', cwd] : ['--tab', '-d', cwd];
|
|
82
|
+
const child = spawn('ptyxis', args, { cwd, detached: true, stdio: 'ignore' });
|
|
83
|
+
child.unref();
|
|
84
|
+
return child;
|
|
85
|
+
}
|
|
70
86
|
// Comando claude (override per ambienti dove non è su PATH; loom-deck → NPM).
|
|
71
87
|
const CLAUDE_CMD = process.env.LOOM_DECK_CLAUDE_CMD ?? 'claude';
|
|
72
88
|
// T30: create-task inline. Spawna CC HEADLESS (`-p`) con `--session-id` pinnato
|
|
@@ -286,6 +302,8 @@ function Deck({ cwd, tasksPath, tasksDir }) {
|
|
|
286
302
|
const [editRow, setEditRow] = useState(0);
|
|
287
303
|
// Voci launch del progetto (T32): lette una volta, raggiunte per indice 1..9.
|
|
288
304
|
const launch = useMemo(() => loadLaunch(cwd), [cwd]);
|
|
305
|
+
// Identità (T37): titolo delle tab terminale spawnate col tasto `t`.
|
|
306
|
+
const identity = useMemo(() => loadIdentity(cwd), [cwd]);
|
|
289
307
|
// La vista è una trasformazione DERIVATA, applicata a valle del load: il
|
|
290
308
|
// polling di tasks.md continua a funzionare senza saperne nulla.
|
|
291
309
|
const { visible: viewTasks, hidden: hiddenTasks } = useMemo(() => applyView(tasks, view), [tasks, view]);
|
|
@@ -604,6 +622,12 @@ function Deck({ cwd, tasksPath, tasksDir }) {
|
|
|
604
622
|
setNote('');
|
|
605
623
|
setMode('filter');
|
|
606
624
|
}
|
|
625
|
+
else if (input === 't') {
|
|
626
|
+
const title = identity ? `🖥️ ${identity.owner} ${identity.name} [term]` : null;
|
|
627
|
+
const child = spawnTerminal(cwd, title);
|
|
628
|
+
child.on('error', () => setNote('⚠ t → ptyxis non lanciabile'));
|
|
629
|
+
setNote(`t → terminale su ${projectName}`);
|
|
630
|
+
}
|
|
607
631
|
else if (input === 'w') {
|
|
608
632
|
// Salvataggio ESPLICITO: comporre una vista non tocca il disco, così
|
|
609
633
|
// sperimentare non sporca lo stato persistito.
|
|
@@ -634,7 +658,7 @@ function Deck({ cwd, tasksPath, tasksDir }) {
|
|
|
634
658
|
const parentLabel = isSpot ? 'spot' : selectedTaskId ?? '—';
|
|
635
659
|
const canSpawn = focus === 'tasks' && !isSpot;
|
|
636
660
|
const launchHint = launch.length > 0 ? `1-${Math.min(9, launch.length)} launch · ` : '';
|
|
637
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "loom-deck" }), mode === 'create' ? (_jsxs(Text, { dimColor: true, children: ["nuova task \u00B7 ", _jsx(Text, { color: "yellow", children: "\u23CE" }), " crea \u00B7 ", _jsx(Text, { color: "yellow", children: "esc" }), " annulla"] })) : mode === 'sort' ? (_jsxs(Text, { dimColor: true, children: ["sort \u00B7 ", _jsx(Text, { color: "yellow", children: "p" }), " pri ", _jsx(Text, { color: "yellow", children: "s" }), " stato", ' ', _jsx(Text, { color: "yellow", children: "i" }), " id (asc\u2192desc\u2192off) \u00B7 ", _jsx(Text, { color: "yellow", children: "\u23CE" }), " ok \u00B7", ' ', _jsx(Text, { color: "yellow", children: "esc" }), " annulla"] })) : mode === 'filter' ? (_jsxs(Text, { dimColor: true, children: ["filtri \u00B7 ", _jsx(Text, { color: "yellow", children: "\u2191\u2193\u2190\u2192" }), " naviga \u00B7 ", _jsx(Text, { color: "yellow", children: "spazio" }), ' ', "mostra/nascondi \u00B7 ", _jsx(Text, { color: "yellow", children: "\u23CE" }), " ok \u00B7 ", _jsx(Text, { color: "yellow", children: "esc" }), " annulla"] })) : mode === 'edit' ? (_jsxs(Text, { dimColor: true, children: ["edit \u00B7 ", _jsx(Text, { color: "yellow", children: "\u2191\u2193" }), " campo \u00B7 ", _jsx(Text, { color: "yellow", children: "\u2190\u2192" }), " valore \u00B7", ' ', _jsx(Text, { color: "yellow", children: "\u23CE" }), " salva+commit \u00B7 ", _jsx(Text, { color: "yellow", children: "esc" }), " annulla"] })) : (_jsxs(Text, { dimColor: true, children: ["\u2191\u2193 naviga \u00B7 \u2190\u2192 pane \u00B7 \u23CE ", canSpawn ? 'spawn' : '—', " \u00B7 C nuova \u00B7 E edit \u00B7 S sort \u00B7 F filtri \u00B7 w salva \u00B7 ", launchHint, "q esci \u00B7 focus: ", _jsx(Text, { color: "cyan", children: focus })] })), mode === 'create' ? (_jsxs(Box, { borderStyle: "round", borderColor: "yellow", paddingX: 1, marginTop: 1, children: [_jsx(Text, { color: "yellow", children: "C \u203A " }), _jsx(Text, { children: draft }), _jsx(Text, { inverse: true, children: " " })] })) : null, mode === 'sort' ? _jsx(SortModal, { sort: view.sort }) : null, mode === 'filter' ? _jsx(FilterModal, { view: view, cursor: filterCursor }) : null, mode === 'edit' && edit && selTask ? (_jsx(EditModal, { id: selTask.id, draft: edit, row: editRow })) : null, _jsxs(Box, { flexDirection: "row", marginTop: 1, children: [_jsx(TasksPane, { tasks: viewTasks, total: tasks.length, hidden: hiddenTasks, view: view, selected: selIndex, spotCount: spotCount, childCount: childCount, focused: focus === 'tasks', loadError: loadError, detail: detail }), _jsx(SessionsPane, { parentLabel: parentLabel, isSpot: isSpot, sessions: visibleSessions, total: childSessions.length, hidden: hiddenSessions, selectedId: selSessionId, focused: focus === 'sessions' })] }), note ? _jsx(Text, { color: "green", children: note }) : null] }));
|
|
661
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "loom-deck" }), mode === 'create' ? (_jsxs(Text, { dimColor: true, children: ["nuova task \u00B7 ", _jsx(Text, { color: "yellow", children: "\u23CE" }), " crea \u00B7 ", _jsx(Text, { color: "yellow", children: "esc" }), " annulla"] })) : mode === 'sort' ? (_jsxs(Text, { dimColor: true, children: ["sort \u00B7 ", _jsx(Text, { color: "yellow", children: "p" }), " pri ", _jsx(Text, { color: "yellow", children: "s" }), " stato", ' ', _jsx(Text, { color: "yellow", children: "i" }), " id (asc\u2192desc\u2192off) \u00B7 ", _jsx(Text, { color: "yellow", children: "\u23CE" }), " ok \u00B7", ' ', _jsx(Text, { color: "yellow", children: "esc" }), " annulla"] })) : mode === 'filter' ? (_jsxs(Text, { dimColor: true, children: ["filtri \u00B7 ", _jsx(Text, { color: "yellow", children: "\u2191\u2193\u2190\u2192" }), " naviga \u00B7 ", _jsx(Text, { color: "yellow", children: "spazio" }), ' ', "mostra/nascondi \u00B7 ", _jsx(Text, { color: "yellow", children: "\u23CE" }), " ok \u00B7 ", _jsx(Text, { color: "yellow", children: "esc" }), " annulla"] })) : mode === 'edit' ? (_jsxs(Text, { dimColor: true, children: ["edit \u00B7 ", _jsx(Text, { color: "yellow", children: "\u2191\u2193" }), " campo \u00B7 ", _jsx(Text, { color: "yellow", children: "\u2190\u2192" }), " valore \u00B7", ' ', _jsx(Text, { color: "yellow", children: "\u23CE" }), " salva+commit \u00B7 ", _jsx(Text, { color: "yellow", children: "esc" }), " annulla"] })) : (_jsxs(Text, { dimColor: true, children: ["\u2191\u2193 naviga \u00B7 \u2190\u2192 pane \u00B7 \u23CE ", canSpawn ? 'spawn' : '—', " \u00B7 C nuova \u00B7 E edit \u00B7 S sort \u00B7 F filtri \u00B7 w salva \u00B7 t term \u00B7 ", launchHint, "q esci \u00B7 focus: ", _jsx(Text, { color: "cyan", children: focus })] })), mode === 'create' ? (_jsxs(Box, { borderStyle: "round", borderColor: "yellow", paddingX: 1, marginTop: 1, children: [_jsx(Text, { color: "yellow", children: "C \u203A " }), _jsx(Text, { children: draft }), _jsx(Text, { inverse: true, children: " " })] })) : null, mode === 'sort' ? _jsx(SortModal, { sort: view.sort }) : null, mode === 'filter' ? _jsx(FilterModal, { view: view, cursor: filterCursor }) : null, mode === 'edit' && edit && selTask ? (_jsx(EditModal, { id: selTask.id, draft: edit, row: editRow })) : null, _jsxs(Box, { flexDirection: "row", marginTop: 1, children: [_jsx(TasksPane, { tasks: viewTasks, total: tasks.length, hidden: hiddenTasks, view: view, selected: selIndex, spotCount: spotCount, childCount: childCount, focused: focus === 'tasks', loadError: loadError, detail: detail }), _jsx(SessionsPane, { parentLabel: parentLabel, isSpot: isSpot, sessions: visibleSessions, total: childSessions.length, hidden: hiddenSessions, selectedId: selSessionId, focused: focus === 'sessions' })] }), note ? _jsx(Text, { color: "green", children: note }) : null] }));
|
|
638
662
|
}
|
|
639
663
|
const SORT_UI = { pri: 'pri', prog: 'stato', id: 'id' };
|
|
640
664
|
// Modali resi IN FLUSSO (come l'input box di create), non in overlay assoluto:
|
package/dist/config.js
CHANGED
|
@@ -39,3 +39,20 @@ export function loadLaunch(projectRoot) {
|
|
|
39
39
|
return [];
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
export function parseIdentity(raw) {
|
|
43
|
+
if (!raw || typeof raw !== 'object')
|
|
44
|
+
return null;
|
|
45
|
+
const { owner, name } = raw;
|
|
46
|
+
if (typeof owner !== 'string' || !owner || typeof name !== 'string' || !name)
|
|
47
|
+
return null;
|
|
48
|
+
return { owner, name };
|
|
49
|
+
}
|
|
50
|
+
/** File assente o malformato → nessuna identità. Mai un throw. */
|
|
51
|
+
export function loadIdentity(projectRoot) {
|
|
52
|
+
try {
|
|
53
|
+
return parseIdentity(JSON.parse(readFileSync(configFilePath(projectRoot), 'utf8')));
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
package/package.json
CHANGED