@lamemind/loom-deck 0.53.0 → 0.54.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/cli.js +7 -1
- package/dist/overlays/search.js +3 -3
- package/dist/overlays/sheet.js +3 -3
- package/dist/overlays/status.js +3 -3
- package/dist/ui/search-screen.js +1 -1
- package/dist/ui/status-screen.js +1 -1
- package/dist/viewport.js +14 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1638,7 +1638,13 @@ function Deck({ cwd, tasksPath, tasksDir }) {
|
|
|
1638
1638
|
if (budget.compact) {
|
|
1639
1639
|
return (_jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { bold: true, color: "cyan", children: "loom-deck" }), _jsxs(Text, { dimColor: true, children: [' ', "v", VERSION, " \u00B7 ", viewTasks.length, " task \u00B7 sel ", selectedTaskId ?? parentLabel, " \u00B7 terminale ", rows, "\u00D7", columns, ": troppo basso, allarga"] })] }));
|
|
1640
1640
|
}
|
|
1641
|
-
|
|
1641
|
+
// Segmento destro della testata: dimensione del terminale in CELLE
|
|
1642
|
+
// (colonne×righe, mai pixel — un processo dentro un terminale vede solo la
|
|
1643
|
+
// griglia di caratteri) e versione. La parte sinistra riceve un budget
|
|
1644
|
+
// derivato da questa stringa e non da una lunghezza fissa: la risoluzione
|
|
1645
|
+
// cambia a ogni resize, quindi anche la larghezza che occupa.
|
|
1646
|
+
const headerRight = `${columns}×${rows} · v${VERSION}`;
|
|
1647
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", children: [_jsx(StatusHeadline, { name: projectCore ?? projectName, label: status.label, building: status.building, failed: status.failed, cols: Math.max(4, columns - 4 - termWidth(headerRight) - 1) }), _jsx(Text, { dimColor: true, children: headerRight })] }), mode === 'create' ? (_jsxs(Text, { dimColor: true, wrap: "truncate-end", 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, wrap: "truncate-end", 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, wrap: "truncate-end", 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 === 'note' ? (_jsxs(Text, { dimColor: true, wrap: "truncate-end", children: ["titolo conversazione \u00B7 ", _jsx(Text, { color: "yellow", children: "^U" }), " svuota \u00B7", ' ', _jsx(Text, { color: "yellow", children: "\u23CE" }), " salva (vuoto = rimuove) \u00B7", ' ', _jsx(Text, { color: "yellow", children: "esc" }), " annulla"] })) : mode === 'purge' ? (_jsxs(Text, { dimColor: true, wrap: "truncate-end", children: ["elimina task \u00B7", ' ', purge?.ignored ? (_jsxs(_Fragment, { children: [_jsx(Text, { color: "yellow", children: "\u2190\u2192" }), " keep/purge dei file non tracciati \u00B7", ' '] })) : null, _jsx(Text, { color: "yellow", children: "\u23CE" }), " conferma \u00B7 ", _jsx(Text, { color: "yellow", children: "esc" }), " annulla"] })) : mode === 'edit' ? (_jsxs(Text, { dimColor: true, wrap: "truncate-end", children: ["edit \u00B7 ", _jsx(Text, { color: "yellow", children: "\u2191\u2193" }), " campo \u00B7 ", _jsx(Text, { color: "yellow", children: "\u2190\u2192" }), " valore, o cursore sul testo \u00B7 ", _jsx(Text, { color: "yellow", children: "^A/^E" }), " inizio/fine \u00B7", ' ', _jsx(Text, { color: "yellow", children: "^D" }), " canc \u00B7 ", _jsx(Text, { color: "yellow", children: "\u23CE" }), " salva+commit \u00B7", ' ', _jsx(Text, { color: "yellow", children: "esc" }), " annulla"] })) : (_jsx(Text, { dimColor: true, wrap: "truncate-end", children: keyLegend })), mode === 'normal' ? (_jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [launchSegments.map((s) => s.text).join(LAUNCH_SEP), legend.overflow > 0 ? (_jsxs(Text, { color: "yellow", children: [" \u00B7 +", legend.overflow, " fuori riga"] })) : null, legend.unreachable > 0 ? (_jsxs(Text, { color: "yellow", children: [" \u00B7 ", legend.unreachable, " oltre la 9\u00AA (non raggiungibili)"] })) : null] })) : null, 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 === 'note' ? (_jsxs(Box, { borderStyle: "round", borderColor: "yellow", paddingX: 1, marginTop: 1, children: [_jsx(Text, { color: "yellow", children: "\u270E \u203A " }), _jsx(Text, { children: noteDraft }), _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: editCursor.row, caret: editCursor.caret, columns: columns })) : null, mode === 'purge' && purge ? _jsx(PurgeModal, { draft: purge, columns: columns }) : null, _jsxs(Box, { flexDirection: "row", marginTop: 1, children: [_jsx(TasksPane, { tasks: windowTasks, counts: taskCounts, activeView: taskViewId, paneCount: paneTasks.length, view: view, selected: selIndex, spotCount: spotCount, allCount: sessions.length, idW: taskCols.id, tailW: taskCols.tail, focused: focus === 'tasks', loadError: loadError, windowStart: taskWin.start, above: taskWin.start, below: paneTasks.length - taskWin.end, columns: columns, data: taskRowData }), _jsx(SessionsPane, { parentLabel: parentLabel, isSpot: isSpot, isAll: isAll, bindings: bindings, taskW: sessionCols.task, ageW: sessionCols.age, rows: windowRows, counts: sessionCounts, activeView: sessionViewId, paneCount: sessionRows.length, selectedId: selSessionId ?? undefined, focused: focus === 'sessions', above: sessionWin.start, below: sessionRows.length - sessionWin.end, columns: columns, forkOf: forkOf, sessionNotes: sessionNotes, projectCore: projectCore, live: live })] }), budget.preview && previewKind === 'task' && detail ? (_jsx(PreviewPane, { kind: "task", detail: detail, maxLines: budget.detailLines, columns: columns })) : budget.preview && previewKind === 'session' && selSessionObj ? (_jsx(PreviewPane, { kind: "session", s: selSessionObj, firstLines: budget.sessionFirstLines, lastLines: budget.sessionLastLines, columns: columns, origin: forkOf.get(selSessionObj.sessionId) ?? null, note: sessionNotes.get(selSessionObj.sessionId) ?? '', live: live.get(selSessionObj.sessionId) ?? null })) : null, note ? _jsx(Text, { color: "green", wrap: "truncate-end", children: sanitize(note) }) : null] }));
|
|
1642
1648
|
}
|
|
1643
1649
|
const cwd = process.cwd();
|
|
1644
1650
|
// T116 — `exitOnCtrlC: false` toglie a Ink l'uscita immediata su `^C`: senza,
|
package/dist/overlays/search.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// eseguirli.
|
|
15
15
|
import { useEffect, useMemo, useState } from 'react';
|
|
16
16
|
import { buildRows, firstRowKey, moveRowSelection, rowIndexOfKey, searchSessions, selectedRow, DEFAULT_OPTIONS, } from '../search.js';
|
|
17
|
-
import { readerCapacity, searchListCapacity } from '../viewport.js';
|
|
17
|
+
import { pageStep, readerCapacity, searchListCapacity } from '../viewport.js';
|
|
18
18
|
import { wrapWithOffsets } from '../width.js';
|
|
19
19
|
import { searchExcerptWidth } from '../layout.js';
|
|
20
20
|
import { sanitizeTyped } from '../glyphs.js';
|
|
@@ -173,10 +173,10 @@ export function useSearchOverlay(deps) {
|
|
|
173
173
|
scrollReader(1);
|
|
174
174
|
}
|
|
175
175
|
else if (key.pageUp) {
|
|
176
|
-
scrollReader(-readerCap);
|
|
176
|
+
scrollReader(-pageStep(readerCap));
|
|
177
177
|
}
|
|
178
178
|
else if (key.pageDown) {
|
|
179
|
-
scrollReader(readerCap);
|
|
179
|
+
scrollReader(pageStep(readerCap));
|
|
180
180
|
}
|
|
181
181
|
else if (input === 'g') {
|
|
182
182
|
// Estremi su lettera e non su Home/End: Ink RICONOSCE quelle due (le
|
package/dist/overlays/sheet.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// Lo spawn della sessione dalla barra azioni NON sta qui: arriva come callback
|
|
13
13
|
// `onAction`, per lo stesso confine di `useSearchOverlay`.
|
|
14
14
|
import { useEffect, useMemo, useState } from 'react';
|
|
15
|
-
import { detailCapacity } from '../viewport.js';
|
|
15
|
+
import { detailCapacity, pageStep } from '../viewport.js';
|
|
16
16
|
import { wrapWithOffsets } from '../width.js';
|
|
17
17
|
import { scanText, topForOffset } from '../text-search.js';
|
|
18
18
|
import { parseMarkdown } from '../markdown.js';
|
|
@@ -256,11 +256,11 @@ export function useSheetOverlay(deps) {
|
|
|
256
256
|
return;
|
|
257
257
|
}
|
|
258
258
|
if (key.pageUp) {
|
|
259
|
-
scroll(-capacity);
|
|
259
|
+
scroll(-pageStep(capacity));
|
|
260
260
|
return;
|
|
261
261
|
}
|
|
262
262
|
if (key.pageDown) {
|
|
263
|
-
scroll(capacity);
|
|
263
|
+
scroll(pageStep(capacity));
|
|
264
264
|
return;
|
|
265
265
|
}
|
|
266
266
|
// Tutto il resto è dell'area di compilazione. Ciò che non consuma resta
|
package/dist/overlays/status.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// tasto renderebbe il gesto economico un effetto collaterale di quello caro.
|
|
12
12
|
import { useEffect, useMemo, useState } from 'react';
|
|
13
13
|
import { randomUUID } from 'node:crypto';
|
|
14
|
-
import { statusCapacity } from '../viewport.js';
|
|
14
|
+
import { pageStep, statusCapacity } from '../viewport.js';
|
|
15
15
|
import { cut, wrapWithOffsets } from '../width.js';
|
|
16
16
|
import { parseMarkdown } from '../markdown.js';
|
|
17
17
|
import { CLAUDE_CMD, notifyDone, spawnProjectStatus } from '../spawn.js';
|
|
@@ -127,10 +127,10 @@ export function useProjectStatus(deps) {
|
|
|
127
127
|
scroll(1);
|
|
128
128
|
}
|
|
129
129
|
else if (key.pageUp) {
|
|
130
|
-
scroll(-capacity);
|
|
130
|
+
scroll(-pageStep(capacity));
|
|
131
131
|
}
|
|
132
132
|
else if (key.pageDown) {
|
|
133
|
-
scroll(capacity);
|
|
133
|
+
scroll(pageStep(capacity));
|
|
134
134
|
}
|
|
135
135
|
else if (input === 'g') {
|
|
136
136
|
// `g`/`G` sugli estremi, come nel reader e nel detail: anche questa
|
package/dist/ui/search-screen.js
CHANGED
|
@@ -95,7 +95,7 @@ export function SearchPreviewPane({ p }) {
|
|
|
95
95
|
export function ReaderScreen({ hit, lines, top, total, capacity, bound, }) {
|
|
96
96
|
const last = Math.min(total, top + capacity);
|
|
97
97
|
const occ = [{ start: hit.matchStart, end: hit.matchEnd }];
|
|
98
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "loom-deck" }), _jsxs(Text, { dimColor: true, wrap: "truncate-end", children: ["reader \u00B7 ", _jsx(Text, { color: "cyan", children: hit.sessionId.slice(0, 8) }), " \u00B7 record ", hit.idx, " \u00B7", ' ', KIND_LABEL[hit.kind], bound ? ` · ${bound}` : '', " \u00B7 righe ", total === 0 ? 0 : top + 1, "-", last, " di ", total] }), _jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [_jsx(Text, { color: "yellow", children: "\u2191\u2193" }), " riga \u00B7 ", _jsx(Text, { color: "yellow", children: "PgUp/PgDn" }), " pagina \u00B7", ' ', _jsx(Text, { color: "yellow", children: "g" }), " inizio \u00B7 ", _jsx(Text, { color: "yellow", children: "G" }), " fine \u00B7", ' ', _jsx(Text, { color: "yellow", children: "esc" }), " torna alla lista"] }), _jsx(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, marginTop: 1, children: lines.map((l, i) => (_jsx(ReaderLine, { line: l, occ: occ, current: 0 }, top + i))) })] }));
|
|
98
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "loom-deck" }), _jsxs(Text, { dimColor: true, wrap: "truncate-end", children: ["reader \u00B7 ", _jsx(Text, { color: "cyan", children: hit.sessionId.slice(0, 8) }), " \u00B7 record ", hit.idx, " \u00B7", ' ', KIND_LABEL[hit.kind], bound ? ` · ${bound}` : '', " \u00B7 righe ", total === 0 ? 0 : top + 1, "-", last, " di ", total] }), _jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [_jsx(Text, { color: "yellow", children: "\u2191\u2193" }), " riga \u00B7 ", _jsx(Text, { color: "yellow", children: "PgUp/PgDn" }), " \u00BD pagina \u00B7", ' ', _jsx(Text, { color: "yellow", children: "g" }), " inizio \u00B7 ", _jsx(Text, { color: "yellow", children: "G" }), " fine \u00B7", ' ', _jsx(Text, { color: "yellow", children: "esc" }), " torna alla lista"] }), _jsx(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, marginTop: 1, children: lines.map((l, i) => (_jsx(ReaderLine, { line: l, occ: occ, current: 0 }, top + i))) })] }));
|
|
99
99
|
}
|
|
100
100
|
/** Una riga con le porzioni di match evidenziate. Gli offset sono quelli del
|
|
101
101
|
* testo sorgente, quindi un match a cavallo dell'a-capo si colora su entrambe
|
package/dist/ui/status-screen.js
CHANGED
|
@@ -52,5 +52,5 @@ export function StatusHeadline({ name, label, building, failed, cols, }) {
|
|
|
52
52
|
export function StatusScreen({ name, label, building, failed, view, lines, spans, top, total, capacity, columns, }) {
|
|
53
53
|
const last = Math.min(total, top + capacity);
|
|
54
54
|
const width = Math.max(20, (columns || 80) - 4);
|
|
55
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [_jsx(StatusHeadline, { name: name, label: label, building: building, failed: failed, cols: width }), _jsxs(Text, { dimColor: true, wrap: "truncate-end", children: ["generato alle ", _jsx(Text, { color: "cyan", children: fmtTime(view.mtime) }), " \u00B7 righe", ' ', total === 0 ? 0 : top + 1, "-", last, " di ", total, view.stale ? (_jsx(Text, { color: "yellow", children: " \u00B7 versione precedente, generazione in corso" })) : null] }), _jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [_jsx(Text, { color: "yellow", children: "\u2191\u2193" }), " riga \u00B7 ", _jsx(Text, { color: "yellow", children: "PgUp/PgDn" }), " pagina \u00B7", ' ', _jsx(Text, { color: "yellow", children: "g/G" }), " estremi \u00B7 ", _jsx(Text, { color: "yellow", children: "esc" }), " chiude"] }), _jsx(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, marginTop: 1, children: lines.map((l, i) => (_jsx(DetailLine, { line: l, spans: spans, occ: NO_OCC, current: -1 }, top + i))) })] }));
|
|
55
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [_jsx(StatusHeadline, { name: name, label: label, building: building, failed: failed, cols: width }), _jsxs(Text, { dimColor: true, wrap: "truncate-end", children: ["generato alle ", _jsx(Text, { color: "cyan", children: fmtTime(view.mtime) }), " \u00B7 righe", ' ', total === 0 ? 0 : top + 1, "-", last, " di ", total, view.stale ? (_jsx(Text, { color: "yellow", children: " \u00B7 versione precedente, generazione in corso" })) : null] }), _jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [_jsx(Text, { color: "yellow", children: "\u2191\u2193" }), " riga \u00B7 ", _jsx(Text, { color: "yellow", children: "PgUp/PgDn" }), " \u00BD pagina \u00B7", ' ', _jsx(Text, { color: "yellow", children: "g/G" }), " estremi \u00B7 ", _jsx(Text, { color: "yellow", children: "esc" }), " chiude"] }), _jsx(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, marginTop: 1, children: lines.map((l, i) => (_jsx(DetailLine, { line: l, spans: spans, occ: NO_OCC, current: -1 }, top + i))) })] }));
|
|
56
56
|
}
|
package/dist/viewport.js
CHANGED
|
@@ -272,6 +272,20 @@ const STATUS_CHROME = 8;
|
|
|
272
272
|
export function statusCapacity(rows) {
|
|
273
273
|
return Math.max(0, (rows || 24) - SLACK - STATUS_CHROME);
|
|
274
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* Righe scorse da una pressione di PagGiù/PagSu: METÀ della capienza visibile.
|
|
277
|
+
*
|
|
278
|
+
* Un salto di pagina intera non lascia nessuna riga in comune fra il prima e il
|
|
279
|
+
* dopo, quindi chi legge deve ricostruire da zero dove si trovava; con mezza
|
|
280
|
+
* pagina la metà già letta resta a schermo e fa da aggancio. È il compromesso
|
|
281
|
+
* dello scroll a mezza pagina classico (`^D`/`^U` di vi/less).
|
|
282
|
+
*
|
|
283
|
+
* Pavimento a 1: su un terminale bassissimo la capienza può valere 1 o 0, e un
|
|
284
|
+
* passo 0 renderebbe il tasto inerte invece che lento.
|
|
285
|
+
*/
|
|
286
|
+
export function pageStep(capacity) {
|
|
287
|
+
return Math.max(1, Math.floor(capacity / 2));
|
|
288
|
+
}
|
|
275
289
|
// T52 — cornice del pannello di anteprima sotto la lista occorrenze:
|
|
276
290
|
// marginTop + 2 bordi + riga meta.
|
|
277
291
|
const SEARCH_PREVIEW_CHROME = 4;
|
package/package.json
CHANGED