@lamemind/loom-deck 0.10.0 → 0.11.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 +19 -12
- package/dist/sessions.js +18 -3
- package/dist/viewport.js +27 -8
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -768,6 +768,11 @@ function Deck({ cwd, tasksPath, tasksDir }) {
|
|
|
768
768
|
// T49 — il detail pane sessione esiste solo con il focus sul pane: è
|
|
769
769
|
// l'hover, non uno stato persistente; navigando le task non ruba righe.
|
|
770
770
|
hasSessionDetail: canResume,
|
|
771
|
+
// Riservo righe di preview solo per i blocchi che davvero renderizzano: il
|
|
772
|
+
// primo prompt aggiunge info solo con un titolo custom (senza, titolo ===
|
|
773
|
+
// primo prompt); l'ultima risposta solo se il modello ha già risposto.
|
|
774
|
+
sessionHasFirstPreview: canResume && Boolean(selSessionObj?.customTitle),
|
|
775
|
+
sessionHasLastPreview: canResume && Boolean(selSessionObj?.lastReply),
|
|
771
776
|
});
|
|
772
777
|
// Finestre di rendering. Le liste "logiche" (viewTasks, visibleSessions)
|
|
773
778
|
// restano intere: navigazione, selezione e spawn continuano a ragionare su
|
|
@@ -782,7 +787,7 @@ function Deck({ cwd, tasksPath, tasksDir }) {
|
|
|
782
787
|
if (budget.compact) {
|
|
783
788
|
return (_jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { bold: true, color: "cyan", children: "loom-deck" }), _jsxs(Text, { dimColor: true, children: [' ', "\u00B7 ", viewTasks.length, " task \u00B7 sel ", selectedTaskId ?? 'spot', " \u00B7 terminale ", rows, "\u00D7", columns, ": troppo basso, allarga"] })] }));
|
|
784
789
|
}
|
|
785
|
-
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, 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 === '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 \u00B7", ' ', _jsx(Text, { color: "yellow", children: "\u23CE" }), " salva+commit \u00B7 ", _jsx(Text, { color: "yellow", children: "esc" }), " annulla"] })) : (_jsxs(Text, { dimColor: true, wrap: "truncate-end", children: ["\u2191\u2193 naviga \u00B7 \u2190\u2192 pane \u00B7 \u23CE ", canSpawn ? 'spawn' : canResume ? 'resume' : '—', " \u00B7 C nuova \u00B7 E edit \u00B7 S sort \u00B7 F filtri \u00B7 w salva \u00B7 t term \u00B7 c claude \u00B7 q esci \u00B7 focus:", ' ', _jsx(Text, { color: "cyan", children: focus })] })), mode === 'normal' && launch.length > 0 ? (_jsxs(Text, { dimColor: true, wrap: "truncate-end", children: ["launch ", legend.shown, 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 === '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: windowTasks, filtered: viewTasks.length, total: tasks.length, hidden: hiddenTasks, view: view, selected: selIndex, spotCount: spotCount, childCount: childCount, focused: focus === 'tasks', loadError: loadError, detail: detail, windowStart: taskWin.start, above: taskWin.start, below: viewTasks.length - taskWin.end, detailLines: budget.detailLines, columns: columns }), _jsx(SessionsPane, { parentLabel: parentLabel, isSpot: isSpot, sessions: windowSessions, total: childSessions.length, hidden: hiddenSessions, selectedId: selSessionId, focused: focus === 'sessions', above: sessionWin.start, below: visibleSessions.length - sessionWin.end, detail: budget.sessionDetail ? selSessionObj : null,
|
|
790
|
+
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, 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 === '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 \u00B7", ' ', _jsx(Text, { color: "yellow", children: "\u23CE" }), " salva+commit \u00B7 ", _jsx(Text, { color: "yellow", children: "esc" }), " annulla"] })) : (_jsxs(Text, { dimColor: true, wrap: "truncate-end", children: ["\u2191\u2193 naviga \u00B7 \u2190\u2192 pane \u00B7 \u23CE ", canSpawn ? 'spawn' : canResume ? 'resume' : '—', " \u00B7 C nuova \u00B7 E edit \u00B7 S sort \u00B7 F filtri \u00B7 w salva \u00B7 t term \u00B7 c claude \u00B7 q esci \u00B7 focus:", ' ', _jsx(Text, { color: "cyan", children: focus })] })), mode === 'normal' && launch.length > 0 ? (_jsxs(Text, { dimColor: true, wrap: "truncate-end", children: ["launch ", legend.shown, 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 === '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: windowTasks, filtered: viewTasks.length, total: tasks.length, hidden: hiddenTasks, view: view, selected: selIndex, spotCount: spotCount, childCount: childCount, focused: focus === 'tasks', loadError: loadError, detail: detail, windowStart: taskWin.start, above: taskWin.start, below: viewTasks.length - taskWin.end, detailLines: budget.detailLines, columns: columns }), _jsx(SessionsPane, { parentLabel: parentLabel, isSpot: isSpot, sessions: windowSessions, total: childSessions.length, hidden: hiddenSessions, selectedId: selSessionId, focused: focus === 'sessions', above: sessionWin.start, below: visibleSessions.length - sessionWin.end, detail: budget.sessionDetail ? selSessionObj : null, firstLines: budget.sessionFirstLines, lastLines: budget.sessionLastLines, columns: columns })] }), note ? _jsx(Text, { color: "green", wrap: "truncate-end", children: normalizeEmoji(note) }) : null] }));
|
|
786
791
|
}
|
|
787
792
|
const SORT_UI = { pri: 'pri', prog: 'stato', id: 'id' };
|
|
788
793
|
// Modali resi IN FLUSSO (come l'input box di create), non in overlay assoluto:
|
|
@@ -827,23 +832,25 @@ function TasksPane({ tasks, filtered, total, hidden, view, selected, spotCount,
|
|
|
827
832
|
return (_jsxs(Text, { inverse: sel && focused, bold: sel && !focused, dimColor: !sel && isDone(task.prog), wrap: "truncate-end", children: [sel ? CARET : CARET_OFF, task.id, " ", forceEmojiWidth(task.pri), " ", displayProg(task.prog), " ", task.desc, n > 0 ? ` (${n})` : ''] }, task.id));
|
|
828
833
|
})), detail && detailLines > 0 ? (_jsx(DetailPane, { detail: detail, maxLines: detailLines, columns: columns })) : null] }));
|
|
829
834
|
}
|
|
830
|
-
function SessionsPane({ parentLabel, isSpot, sessions, total, hidden, selectedId, focused, above, below, detail,
|
|
835
|
+
function SessionsPane({ parentLabel, isSpot, sessions, total, hidden, selectedId, focused, above, below, detail, firstLines, lastLines, columns, }) {
|
|
831
836
|
return (_jsxs(Box, { flexDirection: "column", width: "50%", borderStyle: "single", borderColor: focused ? 'cyan' : 'gray', paddingX: 1, children: [_jsxs(Text, { bold: true, color: focused ? 'cyan' : undefined, wrap: "truncate-end", children: ["Sessions \u00B7 ", parentLabel, " (", total, ")", hidden > 0 ? _jsxs(Text, { dimColor: true, children: [" \u00B7 +", hidden, " pi\u00F9 vecchie"] }) : null, above > 0 ? _jsxs(Text, { dimColor: true, children: [" \u00B7 \u2191", above] }) : null, below > 0 ? _jsxs(Text, { dimColor: true, children: [" \u00B7 \u2193", below] }) : null] }), total === 0 ? (_jsx(Text, { color: "yellow", wrap: "truncate-end", children: isSpot ? 'nessuna sessione libera' : 'nessuna sessione legata a questa task' })) : (sessions.map((s) => {
|
|
832
837
|
const sel = s.sessionId === selectedId;
|
|
833
838
|
return (_jsxs(Text, { inverse: sel && focused, bold: sel && !focused, wrap: "truncate-end", children: [sel ? CARET : CARET_OFF, isSpot ? _jsx(Text, { dimColor: true, children: "\u25CB" }) : _jsx(Text, { color: "green", children: "\uD83D\uDD17" }), ' ', truncate(s.title, 44), ' ', _jsxs(Text, { dimColor: true, children: ["\u00B7 ", s.gitBranch || '-', " \u00B7 ", relTime(s.ts)] })] }, s.sessionId));
|
|
834
|
-
})), detail ? (_jsx(SessionDetailPane, { s: detail,
|
|
839
|
+
})), detail ? (_jsx(SessionDetailPane, { s: detail, firstLines: firstLines, lastLines: lastLines, columns: columns })) : null] }));
|
|
835
840
|
}
|
|
836
841
|
// T49 — detail pane della sessione selezionata (hover), gemello del DetailPane
|
|
837
842
|
// task. Tutti i campi vengono dal parse già cached dell'adapter (mtime-keyed):
|
|
838
|
-
// il pannello non costa I/O al movimento di selezione.
|
|
839
|
-
//
|
|
840
|
-
//
|
|
841
|
-
//
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
843
|
+
// il pannello non costa I/O al movimento di selezione. Mostra "da dove parte,
|
|
844
|
+
// dove è arrivata": il primo prompt utente (`» `) e l'ultima risposta del
|
|
845
|
+
// modello (`« `). La preview del primo prompt compare SOLO con un titolo custom
|
|
846
|
+
// — senza, il titolo È già il primo prompt e la riga lo duplicherebbe (D4
|
|
847
|
+
// preflight). Le righe rese non superano mai il riservato dal budget
|
|
848
|
+
// (`firstLines`/`lastLines`); renderne meno è sicuro (frame più corto).
|
|
849
|
+
function SessionDetailPane({ s, firstLines, lastLines, columns, }) {
|
|
850
|
+
const width = detailTextWidth(columns);
|
|
851
|
+
const first = s.customTitle && firstLines > 0 ? wrapLines(s.firstPrompt, width, firstLines) : [];
|
|
852
|
+
const last = s.lastReply && lastLines > 0 ? wrapLines(s.lastReply, width, lastLines) : [];
|
|
853
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, borderStyle: "single", borderColor: "gray", paddingX: 1, children: [_jsx(Text, { bold: true, wrap: "truncate-end", children: s.title }), _jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [fmtSize(s.sizeBytes), " \u00B7 ", s.turns, " turni \u00B7 ", fmtDateTime(s.ts)] }), first.map((line, i) => (_jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [i === 0 ? '» ' : ' ', line] }, `f${i}`))), last.map((line, i) => (_jsxs(Text, { dimColor: true, wrap: "truncate-end", children: [i === 0 ? '« ' : ' ', line] }, `l${i}`)))] }));
|
|
847
854
|
}
|
|
848
855
|
/**
|
|
849
856
|
* Righe non-wrappabili del dettaglio (titolo + meta + commit) e loro conteggio.
|
package/dist/sessions.js
CHANGED
|
@@ -20,7 +20,12 @@ function cleanPreview(s) {
|
|
|
20
20
|
.replace(/\s+/g, ' ')
|
|
21
21
|
.trim();
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
// Estrae il primo blocco di testo dal `message` di un record. Funziona sia sui
|
|
24
|
+
// record `type:user` sia sugli `type:assistant`: entrambi portano `content` come
|
|
25
|
+
// stringa o array di blocchi, e un blocco di testo è `{type:'text', text}`. Il
|
|
26
|
+
// nome è generico apposta — l'ultima risposta del modello (T49 first+last) esce
|
|
27
|
+
// dallo stesso estrattore del primo prompt utente.
|
|
28
|
+
function extractText(message) {
|
|
24
29
|
if (!message || typeof message !== 'object')
|
|
25
30
|
return '';
|
|
26
31
|
const content = message.content;
|
|
@@ -58,6 +63,7 @@ function parseSessionFile(path, mtime, sizeBytes) {
|
|
|
58
63
|
let parentUuid = null;
|
|
59
64
|
let customTitle = '';
|
|
60
65
|
let firstUserText = '';
|
|
66
|
+
let lastAssistantText = '';
|
|
61
67
|
let turns = 0;
|
|
62
68
|
for (const line of content.split('\n')) {
|
|
63
69
|
if (!line.trim())
|
|
@@ -82,14 +88,22 @@ function parseSessionFile(path, mtime, sizeBytes) {
|
|
|
82
88
|
customTitle = d.customTitle; // last-wins
|
|
83
89
|
if (d.type === 'user') {
|
|
84
90
|
// T49: turno = prompt umano. I tool_result viaggiano anch'essi come
|
|
85
|
-
// type:user ma senza blocchi text →
|
|
86
|
-
const t =
|
|
91
|
+
// type:user ma senza blocchi text → extractText '' li esclude.
|
|
92
|
+
const t = extractText(d.message);
|
|
87
93
|
if (t) {
|
|
88
94
|
turns++;
|
|
89
95
|
if (!firstUserText)
|
|
90
96
|
firstUserText = t;
|
|
91
97
|
}
|
|
92
98
|
}
|
|
99
|
+
else if (d.type === 'assistant') {
|
|
100
|
+
// Ultima risposta del modello: last-wins (come customTitle), niente
|
|
101
|
+
// early-stop — l'ultima riga assistant con testo è quella buona. I
|
|
102
|
+
// record assistant di solo tool_use danno '' e non sovrascrivono.
|
|
103
|
+
const t = extractText(d.message);
|
|
104
|
+
if (t)
|
|
105
|
+
lastAssistantText = t;
|
|
106
|
+
}
|
|
93
107
|
}
|
|
94
108
|
if (!cwd)
|
|
95
109
|
return null; // nessuna riga con cwd → non è una sessione di progetto valida
|
|
@@ -105,6 +119,7 @@ function parseSessionFile(path, mtime, sizeBytes) {
|
|
|
105
119
|
turns,
|
|
106
120
|
customTitle,
|
|
107
121
|
firstPrompt: firstUserText,
|
|
122
|
+
lastReply: lastAssistantText,
|
|
108
123
|
};
|
|
109
124
|
}
|
|
110
125
|
// Discovery read-only delle sessioni del SOLO progetto corrente (D2 preflight
|
package/dist/viewport.js
CHANGED
|
@@ -63,7 +63,8 @@ const TASKS_PANE_CHROME = 5; // 2 bordi + header "Tasks (n)" + riga sort + riga
|
|
|
63
63
|
const SESSIONS_PANE_CHROME = 3; // 2 bordi + header "Sessions · …"
|
|
64
64
|
const DETAIL_CHROME = 3; // marginTop + 2 bordi
|
|
65
65
|
/** Detail pane sessione (T49): righe fisse = titolo + riga meta (size · turni ·
|
|
66
|
-
* ultima attività).
|
|
66
|
+
* ultima attività). Le preview (primo prompt + ultima risposta) sono variabili,
|
|
67
|
+
* ciascuna al più MAX_SESSION_PREVIEW righe. */
|
|
67
68
|
const SESSION_DETAIL_FIXED = 2;
|
|
68
69
|
const MAX_SESSION_PREVIEW = 2;
|
|
69
70
|
/** Gemello di MIN_TASK_ROWS: sotto questa soglia la lista sessioni non serve
|
|
@@ -108,24 +109,34 @@ export function layoutBudget(input) {
|
|
|
108
109
|
sessionRows: 0,
|
|
109
110
|
detailLines: 0,
|
|
110
111
|
sessionDetail: false,
|
|
111
|
-
|
|
112
|
+
sessionFirstLines: 0,
|
|
113
|
+
sessionLastLines: 0,
|
|
112
114
|
compact: true,
|
|
113
115
|
};
|
|
114
116
|
}
|
|
115
117
|
// Detail pane sessione (T49): stesso schema del dettaglio task — prima la
|
|
116
|
-
// lista minima, poi la cornice,
|
|
118
|
+
// lista minima, poi la cornice, le preview solo con lo spazio che avanza.
|
|
117
119
|
// A differenza del dettaglio task il box regge anche senza righe variabili:
|
|
118
|
-
// titolo + meta sono il valore,
|
|
120
|
+
// titolo + meta sono il valore, le preview (primo prompt + ultima risposta)
|
|
121
|
+
// sono bonus. Priorità al primo prompt, poi l'ultima risposta prende ciò che
|
|
122
|
+
// resta: su terminale stretto cade prima l'ultima risposta, non il primo.
|
|
123
|
+
// Riservo righe solo per le preview che davvero renderizzeranno (i due
|
|
124
|
+
// `has…Preview`), così non sottraggo righe alla lista per un blocco vuoto.
|
|
119
125
|
let sessionDetail = false;
|
|
120
126
|
let sessionDetailCost = 0;
|
|
121
|
-
let
|
|
127
|
+
let sessionFirstLines = 0;
|
|
128
|
+
let sessionLastLines = 0;
|
|
122
129
|
if (input.hasSessionDetail) {
|
|
123
130
|
const fixed = DETAIL_CHROME + SESSION_DETAIL_FIXED;
|
|
124
131
|
const spare = avail - SESSIONS_PANE_CHROME - MIN_SESSION_ROWS - fixed;
|
|
125
132
|
if (spare >= 0) {
|
|
126
133
|
sessionDetail = true;
|
|
127
|
-
|
|
128
|
-
|
|
134
|
+
if (input.sessionHasFirstPreview)
|
|
135
|
+
sessionFirstLines = Math.min(MAX_SESSION_PREVIEW, spare);
|
|
136
|
+
if (input.sessionHasLastPreview) {
|
|
137
|
+
sessionLastLines = Math.min(MAX_SESSION_PREVIEW, spare - sessionFirstLines);
|
|
138
|
+
}
|
|
139
|
+
sessionDetailCost = fixed + sessionFirstLines + sessionLastLines;
|
|
129
140
|
}
|
|
130
141
|
}
|
|
131
142
|
const sessionRows = Math.max(0, avail - SESSIONS_PANE_CHROME - sessionDetailCost);
|
|
@@ -143,7 +154,15 @@ export function layoutBudget(input) {
|
|
|
143
154
|
}
|
|
144
155
|
}
|
|
145
156
|
const taskRows = Math.max(0, avail - TASKS_PANE_CHROME - detailChrome - detailLines);
|
|
146
|
-
return {
|
|
157
|
+
return {
|
|
158
|
+
taskRows,
|
|
159
|
+
sessionRows,
|
|
160
|
+
detailLines,
|
|
161
|
+
sessionDetail,
|
|
162
|
+
sessionFirstLines,
|
|
163
|
+
sessionLastLines,
|
|
164
|
+
compact: false,
|
|
165
|
+
};
|
|
147
166
|
}
|
|
148
167
|
/**
|
|
149
168
|
* Finestra scorrevole su una lista più lunga della capienza.
|
package/package.json
CHANGED