reslop 0.2.7 → 0.3.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/CHANGELOG.md +30 -1
- package/README.md +16 -14
- package/bin/reslop.js +8 -5
- package/lib/agents/agents.js +573 -0
- package/lib/agents/allow.js +71 -0
- package/lib/agents/allow.json +17 -0
- package/lib/agents/models.js +467 -0
- package/lib/api.js +15 -12
- package/lib/cli.js +43 -68
- package/lib/{files.js → common/files.js} +48 -55
- package/lib/{find.js → common/find.js} +1 -1
- package/lib/common/format.js +101 -0
- package/lib/{utilities.js → common/process.js} +7 -95
- package/lib/common/tasks.json +27 -0
- package/lib/common/utilities.js +112 -0
- package/lib/dashboard/git.js +9 -16
- package/lib/dashboard/model.js +90 -49
- package/lib/dashboard/npm.js +17 -13
- package/lib/dashboard/tree.js +27 -30
- package/lib/{session → dashboard}/watch.js +36 -31
- package/lib/{workspace.js → dashboard/workspace.js} +23 -38
- package/lib/{deps.js → deps/deps.js} +31 -45
- package/lib/{deps-diff.js → deps/diff.js} +35 -25
- package/lib/{manifest.js → deps/manifest.js} +47 -30
- package/lib/diff/align.js +1 -2
- package/lib/diff/diff.js +2 -2
- package/lib/diff/display.js +29 -5
- package/lib/diff/inline.js +10 -14
- package/lib/diff/items.js +6 -4
- package/lib/diff/patch.js +39 -3
- package/lib/diff/unit.js +45 -16
- package/lib/{git-branches.js → git/branches.js} +53 -48
- package/lib/{git-deps.js → git/deps.js} +151 -95
- package/lib/git/git.js +71 -0
- package/lib/git/worktree.js +504 -0
- package/lib/highlight/bash.js +1 -2
- package/lib/highlight/csv.js +1 -2
- package/lib/highlight/dot.js +1 -2
- package/lib/{highlight.js → highlight/highlight.js} +42 -11
- package/lib/highlight/html.js +20 -18
- package/lib/highlight/json.js +1 -2
- package/lib/highlight/log.js +1 -2
- package/lib/highlight/txt.js +1 -2
- package/lib/{session → input}/actions.js +114 -48
- package/lib/{editor.js → input/editor.js} +16 -8
- package/lib/{keys.js → input/keys.js} +24 -45
- package/lib/input/line-edit.js +78 -0
- package/lib/input/menu-pick.js +70 -0
- package/lib/render/agents.js +642 -0
- package/lib/render/branches.js +4 -5
- package/lib/render/commits.js +54 -64
- package/lib/render/{dash-activity.js → dashboard/activity.js} +25 -40
- package/lib/render/{dash-blocks.js → dashboard/blocks.js} +131 -137
- package/lib/render/{dashboard.js → dashboard/dashboard.js} +25 -22
- package/lib/render/diff.js +166 -45
- package/lib/render/field.js +131 -0
- package/lib/render/files.js +9 -14
- package/lib/render/footer.js +385 -0
- package/lib/render/frame.js +123 -25
- package/lib/render/header.js +176 -0
- package/lib/render/log.js +320 -0
- package/lib/render/menu.js +60 -0
- package/lib/render/notes.js +16 -11
- package/lib/render/npm.js +322 -196
- package/lib/render/packages.js +9 -13
- package/lib/render/primitives.js +101 -15
- package/lib/render/render.js +7 -11
- package/lib/render/repos.js +13 -25
- package/lib/render/status.js +370 -0
- package/lib/render/status.json +85 -0
- package/lib/render/{dash-table.js → table.js} +13 -60
- package/lib/render/tiles.js +109 -48
- package/lib/render/unit.js +32 -13
- package/lib/{report-model.js → report/model.js} +4 -6
- package/lib/{report-parse.js → report/parse.js} +9 -14
- package/lib/{report-render.js → report/render.js} +48 -19
- package/lib/{report-run.js → report/run.js} +42 -30
- package/lib/{report-test.js → report/test.js} +56 -55
- package/lib/{report-tools.js → report/tools.js} +24 -33
- package/lib/review/agent-instructions.md +14 -0
- package/lib/review/format.js +420 -0
- package/lib/{review-merge.js → review/merge.js} +9 -8
- package/lib/review/review.js +190 -0
- package/lib/review/store.js +281 -0
- package/lib/review/templates.js +83 -0
- package/lib/runs/commands.js +14 -0
- package/lib/runs/logs.js +299 -0
- package/lib/runs/output.js +174 -0
- package/lib/runs/process.js +113 -0
- package/lib/{runs.js → runs/runs.js} +84 -36
- package/lib/runs/scripts.js +150 -0
- package/lib/session/agents/agents.js +976 -0
- package/lib/session/agents/job.js +320 -0
- package/lib/session/agents/jobs.js +355 -0
- package/lib/session/agents/options.js +153 -0
- package/lib/session/agents/plans.js +83 -0
- package/lib/session/branches.js +33 -40
- package/lib/session/change-actions.js +34 -100
- package/lib/session/commit.js +91 -52
- package/lib/session/compose.js +189 -147
- package/lib/session/dashboard.js +23 -22
- package/lib/session/dispatch.js +86 -21
- package/lib/session/files-pane.js +47 -26
- package/lib/session/find.js +16 -29
- package/lib/session/import.js +93 -0
- package/lib/session/items.js +8 -17
- package/lib/session/lifecycle.js +78 -72
- package/lib/session/load.js +2 -4
- package/lib/session/navigation.js +6 -3
- package/lib/session/npm/history.js +250 -0
- package/lib/session/npm/npm.js +836 -0
- package/lib/session/{packages.js → npm/packages.js} +21 -14
- package/lib/session/ops.js +125 -34
- package/lib/session/pointer.js +202 -10
- package/lib/session/prefs.js +112 -0
- package/lib/session/reads.js +109 -0
- package/lib/session/review.js +28 -10
- package/lib/session/run-panel.js +40 -0
- package/lib/{session.js → session/session.js} +158 -63
- package/lib/session/tasks.js +321 -66
- package/lib/session/templates.js +1 -1
- package/lib/session/terminal.js +94 -12
- package/lib/session/unit.js +35 -30
- package/lib/session/update.js +194 -6
- package/lib/session/view.js +65 -65
- package/lib/session/workspace.js +39 -78
- package/lib/{capabilities.js → source/capabilities.js} +3 -12
- package/lib/{github.js → source/github.js} +102 -32
- package/lib/{gitlab.js → source/gitlab.js} +87 -10
- package/lib/{remote.js → source/remote.js} +144 -40
- package/lib/source/review-threads.graphql +20 -0
- package/lib/source/source.js +74 -0
- package/lib/term/ansi.js +396 -0
- package/lib/{clipboard.js → term/clipboard.js} +3 -6
- package/lib/{select.js → term/select.js} +4 -3
- package/lib/term/themes/dark.json +122 -0
- package/lib/term/themes/light.json +122 -0
- package/lib/term/wide.txt +21 -0
- package/lib/{wrap.js → term/wrap.js} +4 -4
- package/package.json +2 -2
- package/lib/ansi.js +0 -545
- package/lib/detect.js +0 -34
- package/lib/diff/edit.js +0 -33
- package/lib/git-worktree.js +0 -455
- package/lib/git.js +0 -79
- package/lib/npm-commands.js +0 -522
- package/lib/render/chrome.js +0 -806
- package/lib/render/present.js +0 -19
- package/lib/render/report.js +0 -43
- package/lib/render/search.js +0 -25
- package/lib/review.js +0 -745
- package/lib/session/accessors.js +0 -26
- package/lib/session/edit-click.js +0 -57
- package/lib/session/npm.js +0 -452
- package/lib/session/progress.js +0 -41
- package/lib/source.js +0 -36
- package/lib/update.js +0 -192
- /package/lib/{git-reword-todo.js → git/reword-todo.js} +0 -0
|
@@ -1,28 +1,25 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
const
|
|
6
|
-
const {
|
|
7
|
-
const
|
|
8
|
-
const {
|
|
9
|
-
const
|
|
10
|
-
const {
|
|
11
|
-
const {
|
|
12
|
-
const tiles = require('./tiles.js');
|
|
13
|
-
const { seg, barSegments, spinner } = tiles;
|
|
14
|
-
const table = require('./dash-table.js');
|
|
15
|
-
const { num, size, delta, waiting, cell, cellSegs, flexCell } = table;
|
|
16
|
-
const { tableLines, pickGroups, labelOf, stat, pairRows } = table;
|
|
3
|
+
const { shortAge, num, size } = require('../../common/format.js');
|
|
4
|
+
const { TOP_PACKAGES } = require('../../dashboard/npm.js');
|
|
5
|
+
const { clamp } = require('../../common/utilities.js');
|
|
6
|
+
const { visibleWidth, truncateVisible } = require('../../term/ansi.js');
|
|
7
|
+
const { minuteOf } = require('../../dashboard/model.js');
|
|
8
|
+
const { seg, barSegments, spinner } = require('../tiles.js');
|
|
9
|
+
const table = require('../table.js');
|
|
10
|
+
const { delta, waiting, notice, cell } = table;
|
|
11
|
+
const { cellSegs, flexCell, tableLines, pickGroups, labelOf } = table;
|
|
17
12
|
const { titleAside, captionOver } = table;
|
|
13
|
+
const { cmpText, hasRange, inRange } = require('../../deps/manifest.js');
|
|
18
14
|
|
|
19
15
|
const BAR_W = 6;
|
|
20
16
|
const FOLDER = '📁';
|
|
21
17
|
const MARK_GAP = 1;
|
|
22
|
-
const ACTIVITY_LABEL = 'activity
|
|
18
|
+
const ACTIVITY_LABEL = 'activity';
|
|
23
19
|
const PULSE = '∙';
|
|
20
|
+
const TRACE = '─';
|
|
24
21
|
const ACTIVITY_MARK = [
|
|
25
|
-
['fail', '
|
|
22
|
+
['fail', '⨯'],
|
|
26
23
|
['commit', '◉'],
|
|
27
24
|
['pass', '*'],
|
|
28
25
|
['abort', '!'],
|
|
@@ -30,6 +27,17 @@ const ACTIVITY_MARK = [
|
|
|
30
27
|
['rebase', '↻'],
|
|
31
28
|
['npm', '✦'],
|
|
32
29
|
];
|
|
30
|
+
const MARK_TONE = {
|
|
31
|
+
'⨯': 'error',
|
|
32
|
+
'◉': 'key',
|
|
33
|
+
'*': 'add',
|
|
34
|
+
'!': 'error',
|
|
35
|
+
'⎇': 'sha',
|
|
36
|
+
'↻': 'sha',
|
|
37
|
+
'✦': 'key',
|
|
38
|
+
'+': 'add',
|
|
39
|
+
'-': 'del',
|
|
40
|
+
};
|
|
33
41
|
const UNKNOWN = '…';
|
|
34
42
|
|
|
35
43
|
const share = (value, total) => (total > 0 ? value / total : 0);
|
|
@@ -84,14 +92,15 @@ const filesTotal = (data, ctx) => {
|
|
|
84
92
|
const filesBlock = (model, width, height, ctx, tile) => {
|
|
85
93
|
const data = model.files;
|
|
86
94
|
if (!data.ready) return waiting('scanning…');
|
|
95
|
+
if (!data.total.files) return notice('no files');
|
|
87
96
|
const picked = pickGroups(data.dirs, data.exts, height - 1);
|
|
88
97
|
const labels = [
|
|
89
98
|
cell(''),
|
|
90
99
|
cell(''),
|
|
91
|
-
cell('files', '
|
|
92
|
-
cell('size', '
|
|
93
|
-
cell('lines', '
|
|
94
|
-
cell(''),
|
|
100
|
+
cell('files', 'caption', 'r'),
|
|
101
|
+
cell('size', 'caption', 'r'),
|
|
102
|
+
cell('lines', 'caption', 'r'),
|
|
103
|
+
cell('share', 'caption', 'r'),
|
|
95
104
|
];
|
|
96
105
|
const rows = [labels];
|
|
97
106
|
for (const group of picked.dirs) rows.push(fileRow(group, true, data));
|
|
@@ -138,14 +147,6 @@ const heatIndex = (level) => {
|
|
|
138
147
|
return 0;
|
|
139
148
|
};
|
|
140
149
|
|
|
141
|
-
const heatColor = (index) => {
|
|
142
|
-
if (index === 1) return THEME.heat1;
|
|
143
|
-
if (index === 2) return THEME.heat2;
|
|
144
|
-
if (index === 3) return THEME.heat3;
|
|
145
|
-
if (index === 4) return THEME.heat4;
|
|
146
|
-
return null;
|
|
147
|
-
};
|
|
148
|
-
|
|
149
150
|
const markGlyph = (marks) => {
|
|
150
151
|
const list = marks ?? [];
|
|
151
152
|
for (const [kind, glyph] of ACTIVITY_MARK) {
|
|
@@ -165,63 +166,56 @@ const diffGlyph = (bucket) => {
|
|
|
165
166
|
|
|
166
167
|
const pulseGlyph = (level) => {
|
|
167
168
|
const index = heatIndex(level);
|
|
168
|
-
if (index >= 4) return '
|
|
169
|
+
if (index >= 4) return '●';
|
|
169
170
|
if (index >= 3) return '•';
|
|
170
171
|
return '◦';
|
|
171
172
|
};
|
|
172
173
|
|
|
173
|
-
const activityCell = (bucket, blink,
|
|
174
|
+
const activityCell = (bucket, blink, pulse) => {
|
|
174
175
|
const level = bucket ? bucket.level : 0;
|
|
175
176
|
const glyph = markGlyph(bucket ? bucket.marks : null);
|
|
176
|
-
const index = heatIndex(level);
|
|
177
177
|
const mark = glyph || diffGlyph(bucket);
|
|
178
178
|
const phase = blink ? pulseGlyph(level) : PULSE;
|
|
179
|
-
const ch = pulse ? phase : mark ||
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
item.bg = bg;
|
|
186
|
-
return item;
|
|
179
|
+
const ch = pulse ? phase : mark || TRACE;
|
|
180
|
+
if (blink) return seg(ch, 'key', true);
|
|
181
|
+
if (!pulse && mark) {
|
|
182
|
+
return seg(ch, MARK_TONE[mark] || 'sha', Boolean(glyph));
|
|
183
|
+
}
|
|
184
|
+
return seg(ch, 'sha');
|
|
187
185
|
};
|
|
188
186
|
|
|
189
187
|
const activityCells = (activity, ctx, width) => {
|
|
190
188
|
const minutes = activity && activity.minutes ? activity.minutes : [];
|
|
191
189
|
const byAt = new Map();
|
|
192
|
-
let start = null;
|
|
193
190
|
for (const row of minutes) {
|
|
194
191
|
byAt.set(row.at, row);
|
|
195
|
-
if (start === null || row.at < start) start = row.at;
|
|
196
192
|
}
|
|
197
193
|
const current = minuteOf(ctx.now);
|
|
198
194
|
const flash = Boolean(activity && activity.live);
|
|
199
195
|
const on = Math.abs(ctx.frame ?? 0) % 2 === 1;
|
|
196
|
+
const body = Math.max(0, width - 2);
|
|
200
197
|
const cells = [];
|
|
201
|
-
for (let i = 0; i <
|
|
202
|
-
const at = current - (
|
|
203
|
-
const last = i ===
|
|
198
|
+
for (let i = 0; i < body; i++) {
|
|
199
|
+
const at = current - (body - 1 - i);
|
|
200
|
+
const last = i === body - 1;
|
|
204
201
|
const pulse = flash && last;
|
|
205
202
|
const blink = pulse && on;
|
|
206
|
-
|
|
207
|
-
cells.push(activityCell(byAt.get(at), blink, track, pulse));
|
|
203
|
+
cells.push(activityCell(byAt.get(at), blink, pulse));
|
|
208
204
|
}
|
|
209
|
-
return cells;
|
|
205
|
+
return [seg(' ', 'muted'), ...cells, seg(' ', 'muted')];
|
|
210
206
|
};
|
|
211
207
|
|
|
212
208
|
const activityFooter = (data, width, ctx) => {
|
|
213
|
-
const
|
|
214
|
-
|
|
209
|
+
const lineWidth = width + 1;
|
|
210
|
+
const room = lineWidth - ACTIVITY_LABEL.length;
|
|
211
|
+
if (room < 3) return null;
|
|
215
212
|
const cells = activityCells(data.activity, ctx, room);
|
|
216
|
-
return [seg(ACTIVITY_LABEL, '
|
|
213
|
+
return [seg(ACTIVITY_LABEL, 'sha'), ...cells];
|
|
217
214
|
};
|
|
218
215
|
|
|
219
216
|
const diffsBlock = (model, width, height, ctx, tile) => {
|
|
220
217
|
const data = model.diffs;
|
|
221
|
-
if (!data.files)
|
|
222
|
-
const rows = pairRows([stat('changes', 'working tree clean', 'muted')], 1);
|
|
223
|
-
return { badge: [], lines: tableLines(rows, width) };
|
|
224
|
-
}
|
|
218
|
+
if (!data.files) return notice('working tree clean');
|
|
225
219
|
const footer = activityFooter(data, width, ctx);
|
|
226
220
|
const room = footer ? height - 1 : height;
|
|
227
221
|
const picked = pickGroups(data.dirs, data.exts, room);
|
|
@@ -229,37 +223,28 @@ const diffsBlock = (model, width, height, ctx, tile) => {
|
|
|
229
223
|
for (const group of picked.dirs) rows.push(diffRow(group, true));
|
|
230
224
|
for (const group of picked.exts) rows.push(diffRow(group, false));
|
|
231
225
|
const lines = tableLines(rows, width, 2, true);
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
footerFlush: true,
|
|
237
|
-
};
|
|
226
|
+
const titleLine = captionOver(tile, lines[0]);
|
|
227
|
+
const body = lines.slice(1);
|
|
228
|
+
const footerFlush = true;
|
|
229
|
+
return { titleLine, lines: body, footer, footerFlush };
|
|
238
230
|
};
|
|
239
231
|
|
|
240
|
-
const
|
|
241
|
-
seg(`${label}: `, 'muted'),
|
|
242
|
-
seg(`${value}`, 'text'),
|
|
243
|
-
];
|
|
232
|
+
const compactSize = (bytes) => size(bytes).replaceAll(' ', '');
|
|
244
233
|
|
|
245
|
-
const
|
|
234
|
+
const alertSegs = (value, tone, mark) => {
|
|
246
235
|
if (!value) return [];
|
|
247
|
-
return [seg('
|
|
236
|
+
return [seg(' '), seg(mark, tone), seg(` ${value}`, tone, true)];
|
|
248
237
|
};
|
|
249
238
|
|
|
250
239
|
const npmAside = (data) => {
|
|
251
240
|
const modules = data.modules;
|
|
241
|
+
const bytes = compactSize(modules.bytes);
|
|
242
|
+
const counts = `deps:${data.deps} dev:${data.dev}`;
|
|
243
|
+
const text = `${counts} all:${modules.count}/${bytes}`;
|
|
252
244
|
return [
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
...
|
|
256
|
-
seg(' '),
|
|
257
|
-
...countSegs('all', modules.count),
|
|
258
|
-
seg(' (', 'muted'),
|
|
259
|
-
seg(size(modules.bytes), 'text'),
|
|
260
|
-
seg(')', 'muted'),
|
|
261
|
-
...markSegs(data.audit, 'error', '🚨 '),
|
|
262
|
-
...markSegs(data.outdated, 'warn', '⚠️ '),
|
|
245
|
+
seg(text, 'caption'),
|
|
246
|
+
...alertSegs(data.audit, 'error', '🚨'),
|
|
247
|
+
...alertSegs(data.outdated, 'warn', '⚠️'),
|
|
263
248
|
];
|
|
264
249
|
};
|
|
265
250
|
|
|
@@ -273,38 +258,6 @@ const npmStatus = (data) => {
|
|
|
273
258
|
return text;
|
|
274
259
|
};
|
|
275
260
|
|
|
276
|
-
const cmpText = (left, right) => {
|
|
277
|
-
const a = parseVersion(left);
|
|
278
|
-
const b = parseVersion(right);
|
|
279
|
-
if (!a || !b) return null;
|
|
280
|
-
return cmpVersion(a, b);
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
const boundHolds = (cmp, op) => {
|
|
284
|
-
if (op === '<') return cmp < 0;
|
|
285
|
-
if (op === '<=') return cmp <= 0;
|
|
286
|
-
if (op === '>') return cmp > 0;
|
|
287
|
-
return cmp >= 0;
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
const inClause = (version, clause) => {
|
|
291
|
-
const ver = parseVersion(version);
|
|
292
|
-
if (!ver) return false;
|
|
293
|
-
const bounds = [...clause.matchAll(/(>=|<=|>|<)\s*(\d+\.\d+\.\d+)/g)];
|
|
294
|
-
if (!bounds.length) return false;
|
|
295
|
-
for (const match of bounds) {
|
|
296
|
-
const bound = parseVersion(match[2]);
|
|
297
|
-
if (!bound) return false;
|
|
298
|
-
if (!boundHolds(cmpVersion(ver, bound), match[1])) return false;
|
|
299
|
-
}
|
|
300
|
-
return true;
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
const inRange = (version, range) =>
|
|
304
|
-
`${range ?? ''}`.split('||').some((clause) => inClause(version, clause));
|
|
305
|
-
|
|
306
|
-
const hasRange = (range) => /[<>]=?\s*\d+\.\d+\.\d+/.test(`${range ?? ''}`);
|
|
307
|
-
|
|
308
261
|
const vulnTone = (text, pkg) => {
|
|
309
262
|
if (!pkg.audit || !text || text === UNKNOWN) return '';
|
|
310
263
|
const fix = pkg.fix || '';
|
|
@@ -369,19 +322,17 @@ const nameTone = (pkg) => {
|
|
|
369
322
|
const packageName = (pkg) => {
|
|
370
323
|
const segs = [seg(pkg.name, nameTone(pkg))];
|
|
371
324
|
if (pkg.chain) segs.push(seg(` 🢒 ${pkg.chain}`, 'chain'));
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
measure: visibleWidth(pkg.name),
|
|
378
|
-
};
|
|
325
|
+
const align = 'l';
|
|
326
|
+
const flex = true;
|
|
327
|
+
const keep = true;
|
|
328
|
+
const measure = visibleWidth(pkg.name);
|
|
329
|
+
return { segs, align, flex, keep, measure };
|
|
379
330
|
};
|
|
380
331
|
|
|
381
332
|
const versionCell = (text, pkg) => cell(text, versionTone(text, pkg), 'r');
|
|
382
333
|
|
|
383
334
|
const packageHead = () => {
|
|
384
|
-
const title = flexCell('');
|
|
335
|
+
const title = flexCell('name');
|
|
385
336
|
title.keep = true;
|
|
386
337
|
return [
|
|
387
338
|
title,
|
|
@@ -410,7 +361,8 @@ const packageRow = (pkg, marks) => {
|
|
|
410
361
|
const packageLines = (packages, width, limit) => {
|
|
411
362
|
const all = limit === null;
|
|
412
363
|
const headed = packages.length > 0 && (all || limit > 1);
|
|
413
|
-
const
|
|
364
|
+
const head = headed ? 1 : 0;
|
|
365
|
+
const room = all ? packages.length : Math.max(0, limit - head);
|
|
414
366
|
const shown = packages.slice(0, room);
|
|
415
367
|
const rows = shown.map((pkg) => packageRow(pkg, all));
|
|
416
368
|
if (headed) rows.unshift(packageHead());
|
|
@@ -424,6 +376,7 @@ const npmContent = (data, width, limit, ctx, tile) => {
|
|
|
424
376
|
const titleLine = titleAside(tile, npmAside(data), width, badge);
|
|
425
377
|
const listed = data.modules && data.modules.packages;
|
|
426
378
|
const packages = listed ? listed : [];
|
|
379
|
+
if (!packages.length) return notice('no packages', titleLine);
|
|
427
380
|
const short = limit === null ? packages : packages.slice(0, TOP_PACKAGES);
|
|
428
381
|
return { titleLine, lines: packageLines(short, width, limit) };
|
|
429
382
|
};
|
|
@@ -431,23 +384,42 @@ const npmContent = (data, width, limit, ctx, tile) => {
|
|
|
431
384
|
const npmBlock = (model, width, height, ctx, tile) =>
|
|
432
385
|
npmContent(model.npm, width, height, ctx, tile);
|
|
433
386
|
|
|
434
|
-
const
|
|
387
|
+
const NAME_GAP = 2;
|
|
388
|
+
const RATIO_GAP = 1;
|
|
435
389
|
|
|
436
390
|
const ratioLabel = (done, total) => `${done}/${total}`;
|
|
437
391
|
|
|
438
392
|
const taskSpecs = (data) => {
|
|
439
|
-
const rows = [
|
|
393
|
+
const rows = [];
|
|
440
394
|
for (const kind of data.kinds) {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
bold: false,
|
|
446
|
-
});
|
|
395
|
+
const { title, done, total } = kind;
|
|
396
|
+
const bold = false;
|
|
397
|
+
const row = { title, done, total, bold };
|
|
398
|
+
rows.push(row);
|
|
447
399
|
}
|
|
400
|
+
const title = 'Total';
|
|
401
|
+
const titleTone = 'add';
|
|
402
|
+
const { done, total } = data;
|
|
403
|
+
const bold = true;
|
|
404
|
+
const row = { title, titleTone, done, total, bold };
|
|
405
|
+
rows.push(row);
|
|
448
406
|
return rows;
|
|
449
407
|
};
|
|
450
408
|
|
|
409
|
+
const taskRows = (specs, room) => {
|
|
410
|
+
if (room < 1) return [];
|
|
411
|
+
const total = specs.at(-1);
|
|
412
|
+
const kinds = specs.slice(0, -1).slice(0, room - 1);
|
|
413
|
+
return [...kinds, total];
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
const planAside = (tile, plan, width) => {
|
|
417
|
+
if (!plan) return [];
|
|
418
|
+
const room = Math.max(0, width - tile.title.length - 1);
|
|
419
|
+
const shown = truncateVisible(plan, room);
|
|
420
|
+
return shown ? [seg(shown, 'caption')] : [];
|
|
421
|
+
};
|
|
422
|
+
|
|
451
423
|
const widest = (rows, read) => {
|
|
452
424
|
let width = 0;
|
|
453
425
|
for (const row of rows) {
|
|
@@ -458,32 +430,54 @@ const widest = (rows, read) => {
|
|
|
458
430
|
};
|
|
459
431
|
|
|
460
432
|
const taskBarWidth = (width, nameW, ratioW) => {
|
|
461
|
-
const room = width - nameW - ratioW -
|
|
433
|
+
const room = width - nameW - ratioW - NAME_GAP - RATIO_GAP;
|
|
462
434
|
return room > 0 ? room : 0;
|
|
463
435
|
};
|
|
464
436
|
|
|
437
|
+
const taskBarSegments = (ratio, width) => {
|
|
438
|
+
if (width < 1) return [];
|
|
439
|
+
if (width < 3) return [seg(' '.repeat(width), 'muted')];
|
|
440
|
+
const inner = width - 2;
|
|
441
|
+
const clamped = clamp(Number.isFinite(ratio) ? ratio : 0, 0, 1);
|
|
442
|
+
const on = Math.round(clamped * inner);
|
|
443
|
+
const off = inner - on;
|
|
444
|
+
const parts = [seg(' ', 'muted')];
|
|
445
|
+
if (on) parts.push(seg(TRACE.repeat(on), 'add'));
|
|
446
|
+
if (off) parts.push(seg(' '.repeat(off), 'muted'));
|
|
447
|
+
parts.push(seg(' ', 'muted'));
|
|
448
|
+
return parts;
|
|
449
|
+
};
|
|
450
|
+
|
|
465
451
|
const taskLine = (row, barW) => {
|
|
466
452
|
const tone = row.bold ? 'text' : 'muted';
|
|
467
|
-
const
|
|
453
|
+
const titleTone = row.titleTone ?? 'text';
|
|
454
|
+
const titleBold = row.titleTone ? false : row.bold;
|
|
455
|
+
const line = [cell(row.title, titleTone, 'l', titleBold)];
|
|
468
456
|
if (barW > 0) {
|
|
469
|
-
|
|
457
|
+
const ratio = share(row.done, row.total);
|
|
458
|
+
line.push(cellSegs(taskBarSegments(ratio, barW)));
|
|
470
459
|
}
|
|
471
|
-
|
|
460
|
+
const count = cell(ratioLabel(row.done, row.total), tone, 'r', row.bold);
|
|
461
|
+
count.gap = RATIO_GAP;
|
|
462
|
+
line.push(count);
|
|
472
463
|
return line;
|
|
473
464
|
};
|
|
474
465
|
|
|
475
466
|
const tasksBlock = (model, width, height, ctx, tile) => {
|
|
476
|
-
const
|
|
467
|
+
const data = model.tasks;
|
|
468
|
+
if (!data.total) {
|
|
469
|
+
const aside = planAside(tile, data.plan, width);
|
|
470
|
+
return notice('no tasks', titleAside(tile, aside, width));
|
|
471
|
+
}
|
|
472
|
+
const specs = taskSpecs(data);
|
|
477
473
|
const nameW = widest(specs, (row) => row.title);
|
|
478
474
|
const ratioW = widest(specs, (row) => ratioLabel(row.done, row.total));
|
|
479
475
|
const barW = taskBarWidth(width, nameW, ratioW);
|
|
480
|
-
const
|
|
481
|
-
const
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
lines: lines.slice(1, 1 + shown),
|
|
486
|
-
};
|
|
476
|
+
const visible = taskRows(specs, Math.max(0, height));
|
|
477
|
+
const rows = visible.map((row) => taskLine(row, barW));
|
|
478
|
+
const lines = tableLines(rows, width, NAME_GAP);
|
|
479
|
+
const aside = planAside(tile, data.plan, width);
|
|
480
|
+
return { titleLine: titleAside(tile, aside, width), lines };
|
|
487
481
|
};
|
|
488
482
|
|
|
489
483
|
module.exports = {
|
|
@@ -1,30 +1,33 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const tiles = require('./tiles.js');
|
|
3
|
+
const { paintBodyFill, paneResult } = require('../primitives.js');
|
|
4
|
+
const tiles = require('../tiles.js');
|
|
6
5
|
const { layoutTiles, paintTile, composeBands, tileHits, pageFill } = tiles;
|
|
7
|
-
const blocks = require('./
|
|
6
|
+
const blocks = require('./blocks.js');
|
|
8
7
|
const { filesBlock, diffsBlock, npmBlock, tasksBlock } = blocks;
|
|
9
|
-
const activity = require('./
|
|
8
|
+
const activity = require('./activity.js');
|
|
10
9
|
const { commitsBlock, branchesBlock, runsBlock } = activity;
|
|
10
|
+
const { agentsBlock } = require('../agents.js');
|
|
11
|
+
const { DASH_TILES } = require('../../input/actions.js');
|
|
11
12
|
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
{
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
13
|
+
const TILE_VIEW = {
|
|
14
|
+
files: { rank: 3, size: 'normal', build: filesBlock },
|
|
15
|
+
diffs: { rank: 0, size: 'normal', build: diffsBlock },
|
|
16
|
+
tasks: { rank: 4, size: 'normal', build: tasksBlock },
|
|
17
|
+
branches: { rank: 5, size: 'wide', build: branchesBlock },
|
|
18
|
+
commits: { rank: 2, size: 'wide', build: commitsBlock },
|
|
19
|
+
run: { rank: 1, size: 'normal', build: runsBlock },
|
|
20
|
+
npm: { rank: 6, size: 'normal', build: npmBlock },
|
|
21
|
+
agents: { rank: 7, size: 'normal', build: agentsBlock },
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const TILES = DASH_TILES.map(({ id, key }) => {
|
|
25
|
+
const title = id;
|
|
26
|
+
const view = TILE_VIEW[id];
|
|
27
|
+
return { id, key, title, ...view };
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const TILE_BY_ID = Object.fromEntries(TILES.map((tile) => [tile.id, tile]));
|
|
28
31
|
const MARGIN_MIN_H = 12;
|
|
29
32
|
|
|
30
33
|
const paintTiles = (model, bands, color) => {
|
|
@@ -32,7 +35,7 @@ const paintTiles = (model, bands, color) => {
|
|
|
32
35
|
const ctx = { now: model.now, frame: model.frame };
|
|
33
36
|
for (const band of bands) {
|
|
34
37
|
for (const place of band.tiles) {
|
|
35
|
-
const tile = TILE_BY_ID
|
|
38
|
+
const tile = TILE_BY_ID[place.id];
|
|
36
39
|
const inner = Math.max(0, place.w - 2);
|
|
37
40
|
const room = Math.max(0, band.h - 1);
|
|
38
41
|
const content = tile.build(model, inner, room, ctx, tile);
|