reslop 0.2.6 → 0.3.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/CHANGELOG.md +27 -1
- package/README.md +16 -14
- package/bin/reslop.js +8 -5
- package/lib/agents/agents.js +504 -0
- package/lib/agents/allow.js +71 -0
- package/lib/agents/allow.json +16 -0
- package/lib/agents/models.js +460 -0
- package/lib/api.js +15 -12
- package/lib/cli.js +61 -66
- package/lib/{files.js → common/files.js} +51 -52
- package/lib/common/find.js +61 -0
- 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 +117 -51
- package/lib/dashboard/npm.js +133 -32
- package/lib/dashboard/tree.js +27 -30
- package/lib/{session → dashboard}/watch.js +41 -31
- package/lib/dashboard/workspace.js +151 -0
- 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} +123 -95
- package/lib/git/git.js +71 -0
- package/lib/git/worktree.js +475 -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 +240 -71
- package/lib/{editor.js → input/editor.js} +7 -8
- package/lib/{keys.js → input/keys.js} +36 -39
- package/lib/input/line-edit.js +77 -0
- package/lib/input/menu-pick.js +70 -0
- package/lib/render/agents.js +640 -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/dashboard/blocks.js +490 -0
- 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 +22 -8
- package/lib/render/footer.js +383 -0
- package/lib/render/frame.js +127 -25
- package/lib/render/header.js +176 -0
- package/lib/render/log.js +319 -0
- package/lib/render/menu.js +60 -0
- package/lib/render/notes.js +29 -13
- package/lib/render/npm.js +322 -196
- package/lib/render/packages.js +89 -0
- package/lib/render/primitives.js +109 -16
- package/lib/render/render.js +7 -11
- package/lib/render/repos.js +214 -0
- package/lib/render/status.js +370 -0
- package/lib/render/status.json +85 -0
- package/lib/render/{dash-table.js → table.js} +19 -61
- package/lib/render/tiles.js +203 -47
- 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} +46 -14
- 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 +9 -0
- package/lib/review/format.js +426 -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 +958 -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 +36 -44
- package/lib/session/change-actions.js +34 -100
- package/lib/session/commit.js +122 -56
- package/lib/session/compose.js +197 -146
- package/lib/session/dashboard.js +183 -37
- package/lib/session/dispatch.js +120 -22
- package/lib/session/files-pane.js +60 -24
- package/lib/session/find.js +81 -0
- package/lib/session/import.js +82 -0
- package/lib/session/items.js +8 -17
- package/lib/session/lifecycle.js +96 -66
- package/lib/session/load.js +2 -4
- package/lib/session/navigation.js +8 -3
- package/lib/session/npm/history.js +249 -0
- package/lib/session/npm/npm.js +815 -0
- package/lib/session/npm/packages.js +150 -0
- package/lib/session/ops.js +125 -34
- package/lib/session/pointer.js +216 -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} +166 -59
- 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 +72 -59
- package/lib/session/workspace.js +416 -0
- 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} +2 -2
- 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 -505
- package/lib/detect.js +0 -34
- package/lib/diff/edit.js +0 -33
- package/lib/git-worktree.js +0 -437
- package/lib/git.js +0 -79
- package/lib/npm-commands.js +0 -522
- package/lib/render/chrome.js +0 -628
- package/lib/render/dash-blocks.js +0 -245
- package/lib/render/present.js +0 -19
- package/lib/render/report.js +0 -43
- package/lib/review.js +0 -744
- 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,9 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const files = require('../files.js');
|
|
3
|
+
const files = require('../common/files.js');
|
|
4
4
|
const { listPath, isTaskItem, isTasksEntry, TASKS_FILE } = files;
|
|
5
|
-
const
|
|
6
|
-
const { LIST_PANES } = actions;
|
|
5
|
+
const { LIST_PANES } = require('../input/actions.js');
|
|
7
6
|
|
|
8
7
|
const freshListScroll = () =>
|
|
9
8
|
Object.fromEntries(LIST_PANES.map((pane) => [pane, 0]));
|
|
@@ -20,6 +19,8 @@ class Navigation {
|
|
|
20
19
|
this.branchCursor = 0;
|
|
21
20
|
this.commitCursor = 0;
|
|
22
21
|
this.npmCursor = 0;
|
|
22
|
+
this.packagesCursor = 0;
|
|
23
|
+
this.agentCursor = 0;
|
|
23
24
|
this.scroll = 0;
|
|
24
25
|
this.listScrollByPane = freshListScroll();
|
|
25
26
|
this.reviewPath = null;
|
|
@@ -28,9 +29,12 @@ class Navigation {
|
|
|
28
29
|
this.selection = null;
|
|
29
30
|
this.mouseAnchor = null;
|
|
30
31
|
this.pendingClick = null;
|
|
32
|
+
this.scrollDrag = null;
|
|
31
33
|
this.lastClick = null;
|
|
32
34
|
this.tasksOpen = false;
|
|
33
35
|
this.tasksFocus = 0;
|
|
36
|
+
this.find = null;
|
|
37
|
+
this.import = null;
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
clampIndex(length) {
|
|
@@ -96,6 +100,7 @@ class Navigation {
|
|
|
96
100
|
this.selection = null;
|
|
97
101
|
this.mouseAnchor = null;
|
|
98
102
|
this.pendingClick = null;
|
|
103
|
+
this.scrollDrag = null;
|
|
99
104
|
}
|
|
100
105
|
|
|
101
106
|
get listScroll() {
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { stripAnsi } = require('../../term/ansi.js');
|
|
4
|
+
const { buildDocument } = require('../../report/parse.js');
|
|
5
|
+
const report = require('../../report/render.js');
|
|
6
|
+
const { renderDocument, renderReport } = report;
|
|
7
|
+
const runStore = require('../../runs/runs.js');
|
|
8
|
+
const { Tracker, summarizeDocument } = runStore;
|
|
9
|
+
const { runName } = require('../../dashboard/model.js');
|
|
10
|
+
const { reduceOutput } = require('../../runs/output.js');
|
|
11
|
+
const { trimText, pad2 } = require('../../common/utilities.js');
|
|
12
|
+
|
|
13
|
+
const TESTS_RE = /^(?:TAP version \d+|\s*(?:not )?ok\b|[ℹi]\s+tests\s+\d+)/m;
|
|
14
|
+
|
|
15
|
+
const filteredOutput = (raw, root, status, rawFile) => {
|
|
16
|
+
const text = stripAnsi(`${raw ?? ''}`);
|
|
17
|
+
if (status === '' || !TESTS_RE.test(text)) {
|
|
18
|
+
const output = reduceOutput(raw, root, status);
|
|
19
|
+
return { output, log: output, result: null };
|
|
20
|
+
}
|
|
21
|
+
const doc = buildDocument(raw, '', root, status, 'test');
|
|
22
|
+
const result = summarizeDocument(doc);
|
|
23
|
+
const output = renderReport(doc);
|
|
24
|
+
const log = renderDocument(doc, rawFile);
|
|
25
|
+
return { output, log, result };
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const runLabel = (entry) =>
|
|
29
|
+
entry.kind === 'bin' ? `npm exec ${entry.name}` : `npm run ${entry.name}`;
|
|
30
|
+
|
|
31
|
+
const historyMark = (run) => {
|
|
32
|
+
if (run.status === 'running') return 'run';
|
|
33
|
+
if (run.status === 'stopped') return 'stop';
|
|
34
|
+
if (run.exit === 0 || run.exit === '0') return 'pass';
|
|
35
|
+
return 'fail';
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const historyCounts = (run) => {
|
|
39
|
+
const result = run.result;
|
|
40
|
+
if (result && typeof result.tests === 'number') {
|
|
41
|
+
const fail = result.failed ?? 0;
|
|
42
|
+
const ok = result.passed ?? Math.max(0, result.tests - fail);
|
|
43
|
+
return { done: result.tests, ok, fail, total: result.tests };
|
|
44
|
+
}
|
|
45
|
+
const progress = run.progress;
|
|
46
|
+
if (!progress) return null;
|
|
47
|
+
const ok = progress.done ?? 0;
|
|
48
|
+
const fail = progress.failed ?? 0;
|
|
49
|
+
if (!ok && !fail && !(progress.expected > 0)) return null;
|
|
50
|
+
const total = progress.expected > 0 ? progress.expected : null;
|
|
51
|
+
return { done: ok + fail, ok, fail, total };
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const countText = (value) => (typeof value === 'number' ? `${value}` : '');
|
|
55
|
+
|
|
56
|
+
const historyExit = (run, counts) => {
|
|
57
|
+
if (counts || run.status !== 'exited') return '';
|
|
58
|
+
if (run.exit === '' || run.exit === null || run.exit === undefined) return '';
|
|
59
|
+
return `exit ${run.exit}`;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const earlierTotal = (list, run) => {
|
|
63
|
+
let best = 0;
|
|
64
|
+
let at = -1;
|
|
65
|
+
for (const item of list) {
|
|
66
|
+
if (item === run || item.name !== run.name) continue;
|
|
67
|
+
if (item.status === 'running') continue;
|
|
68
|
+
const counts = historyCounts(item);
|
|
69
|
+
if (!counts || typeof counts.total !== 'number') continue;
|
|
70
|
+
const started = item.startedAt || 0;
|
|
71
|
+
if (started < at) continue;
|
|
72
|
+
at = started;
|
|
73
|
+
best = counts.total;
|
|
74
|
+
}
|
|
75
|
+
return best;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const noteTests = (run, list, text) => {
|
|
79
|
+
const plain = stripAnsi(`${text ?? ''}`);
|
|
80
|
+
if (!TESTS_RE.test(plain)) return;
|
|
81
|
+
const tracker = new Tracker();
|
|
82
|
+
tracker.feed(plain);
|
|
83
|
+
if (!Object.hasOwn(run, 'expected')) run.expected = earlierTotal(list, run);
|
|
84
|
+
run.progress = {
|
|
85
|
+
done: tracker.progress.done,
|
|
86
|
+
failed: tracker.progress.failed,
|
|
87
|
+
expected: run.expected,
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const RUN_KEEP = 50;
|
|
92
|
+
|
|
93
|
+
const LOG_GAP_MS = 2000;
|
|
94
|
+
|
|
95
|
+
const RESLOP_RUN = /^reslop(?:\.js)?\s+t\s+--\s+/;
|
|
96
|
+
|
|
97
|
+
const RESLOP_T = /reslop(?:\.js)?\s+t\s+--/;
|
|
98
|
+
|
|
99
|
+
const launchedReslop = (run) => {
|
|
100
|
+
if (run.externalId) return false;
|
|
101
|
+
const command = `${run.command ?? ''}`;
|
|
102
|
+
return RESLOP_T.test(command);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const historyName = (run) => {
|
|
106
|
+
const script = trimText(run.name);
|
|
107
|
+
if (script) return script;
|
|
108
|
+
return trimText(run.command).replace(RESLOP_RUN, '');
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const sameWindow = (left, right) => {
|
|
112
|
+
const start = Number(left.startedAt) || 0;
|
|
113
|
+
const end = Number(left.endedAt) || start;
|
|
114
|
+
const at = Number(right.startedAt) || 0;
|
|
115
|
+
const done = Number(right.endedAt) || at;
|
|
116
|
+
return done >= start - LOG_GAP_MS && at <= end + LOG_GAP_MS;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const logBase = (name) => {
|
|
120
|
+
const file = `${name ?? ''}`;
|
|
121
|
+
if (!file || file.includes('/') || file.includes('\\')) return '';
|
|
122
|
+
return file;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const externalStatus = (record) => {
|
|
126
|
+
if (record.status === 'running') return 'running';
|
|
127
|
+
if (record.status === 'aborted') return 'stopped';
|
|
128
|
+
return 'exited';
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const externalExit = (record) => {
|
|
132
|
+
if (record.status === 'running' || record.status === 'aborted') return '';
|
|
133
|
+
if (record.exit === null || record.exit === undefined) return '';
|
|
134
|
+
return record.exit;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const progressCount = (progress, key) => {
|
|
138
|
+
if (!progress || typeof progress[key] !== 'number') return 0;
|
|
139
|
+
return progress[key];
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const progressSame = (left, right) => {
|
|
143
|
+
const done = progressCount(left, 'done') === progressCount(right, 'done');
|
|
144
|
+
const leftFailed = progressCount(left, 'failed');
|
|
145
|
+
const rightFailed = progressCount(right, 'failed');
|
|
146
|
+
const failed = leftFailed === rightFailed;
|
|
147
|
+
const leftExpected = progressCount(left, 'expected');
|
|
148
|
+
const rightExpected = progressCount(right, 'expected');
|
|
149
|
+
const expected = leftExpected === rightExpected;
|
|
150
|
+
return done && failed && expected;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const resultSame = (left, right) => {
|
|
154
|
+
if (!left && !right) return true;
|
|
155
|
+
if (!left || !right) return false;
|
|
156
|
+
return (
|
|
157
|
+
left.tests === right.tests &&
|
|
158
|
+
left.passed === right.passed &&
|
|
159
|
+
left.failed === right.failed &&
|
|
160
|
+
left.errors === right.errors
|
|
161
|
+
);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const applyExternal = (run, record) => {
|
|
165
|
+
const status = externalStatus(record);
|
|
166
|
+
const exit = externalExit(record);
|
|
167
|
+
const endedAt = Number(record.endedAt) || 0;
|
|
168
|
+
const progress = record.progress ?? null;
|
|
169
|
+
const result = record.result ?? null;
|
|
170
|
+
const same =
|
|
171
|
+
run.status === status &&
|
|
172
|
+
run.exit === exit &&
|
|
173
|
+
(run.endedAt || 0) === endedAt &&
|
|
174
|
+
progressSame(run.progress, progress) &&
|
|
175
|
+
resultSame(run.result, result);
|
|
176
|
+
if (same) return false;
|
|
177
|
+
run.status = status;
|
|
178
|
+
run.exit = exit;
|
|
179
|
+
run.endedAt = endedAt;
|
|
180
|
+
run.progress = progress;
|
|
181
|
+
run.result = result;
|
|
182
|
+
return true;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const recordedItem = (record) => {
|
|
186
|
+
const script = trimText(record.script);
|
|
187
|
+
const command = trimText(record.command);
|
|
188
|
+
const name = runName({ command, script }).replace(RESLOP_RUN, '');
|
|
189
|
+
return {
|
|
190
|
+
name,
|
|
191
|
+
kind: script ? 'script' : 'command',
|
|
192
|
+
command,
|
|
193
|
+
status: externalStatus(record),
|
|
194
|
+
exit: externalExit(record),
|
|
195
|
+
startedAt: Number(record.startedAt) || 0,
|
|
196
|
+
endedAt: Number(record.endedAt) || 0,
|
|
197
|
+
logName: logBase(record.log),
|
|
198
|
+
rawName: logBase(record.raw),
|
|
199
|
+
externalId: `${record.id ?? ''}`,
|
|
200
|
+
result: record.result ?? null,
|
|
201
|
+
progress: record.progress ?? null,
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const whenLabel = (ms) => {
|
|
206
|
+
if (!ms) return '';
|
|
207
|
+
const date = new Date(ms);
|
|
208
|
+
const hh = pad2(date.getHours());
|
|
209
|
+
const mm = pad2(date.getMinutes());
|
|
210
|
+
const time = `${hh}:${mm}`;
|
|
211
|
+
const today = new Date();
|
|
212
|
+
const sameDay =
|
|
213
|
+
date.getFullYear() === today.getFullYear() &&
|
|
214
|
+
date.getMonth() === today.getMonth() &&
|
|
215
|
+
date.getDate() === today.getDate();
|
|
216
|
+
if (sameDay) return time;
|
|
217
|
+
const month = pad2(date.getMonth() + 1);
|
|
218
|
+
const day = pad2(date.getDate());
|
|
219
|
+
return `${month}-${day} ${time}`;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const elapsedText = (run, now) => {
|
|
223
|
+
const end = run.endedAt || now;
|
|
224
|
+
const ms = Math.max(0, end - (run.startedAt || end));
|
|
225
|
+
const sec = Math.round(ms / 1000);
|
|
226
|
+
if (sec < 60) return `${sec}s`;
|
|
227
|
+
const min = Math.floor(sec / 60);
|
|
228
|
+
const rest = sec % 60;
|
|
229
|
+
return `${min}m${pad2(rest)}s`;
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
module.exports = {
|
|
233
|
+
filteredOutput,
|
|
234
|
+
runLabel,
|
|
235
|
+
historyMark,
|
|
236
|
+
historyCounts,
|
|
237
|
+
countText,
|
|
238
|
+
historyExit,
|
|
239
|
+
noteTests,
|
|
240
|
+
RUN_KEEP,
|
|
241
|
+
launchedReslop,
|
|
242
|
+
historyName,
|
|
243
|
+
sameWindow,
|
|
244
|
+
logBase,
|
|
245
|
+
applyExternal,
|
|
246
|
+
recordedItem,
|
|
247
|
+
whenLabel,
|
|
248
|
+
elapsedText,
|
|
249
|
+
};
|