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
package/lib/session/unit.js
CHANGED
|
@@ -1,33 +1,23 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const { listPath, isTasksEntry } = files;
|
|
3
|
+
const { listPath, isTasksEntry } = require('../common/files.js');
|
|
5
4
|
const diff = require('../diff/diff.js');
|
|
6
5
|
const { unitLines, itemsForPath, blockLineIndex } = diff;
|
|
7
6
|
const { hunkLineRange, sameHunk, hunkKey } = diff;
|
|
8
7
|
const { fileOffset, splitEditor, mergeEditRows, fileLineIndex } = diff;
|
|
9
8
|
|
|
10
|
-
const fileText = (ui, rel) =>
|
|
11
|
-
if (!rel) return '';
|
|
12
|
-
const repo = ui.repo;
|
|
13
|
-
if (repo && typeof repo.fileText === 'function') {
|
|
14
|
-
return repo.fileText(ui.top, rel, ui.rev);
|
|
15
|
-
}
|
|
16
|
-
return '';
|
|
17
|
-
};
|
|
9
|
+
const fileText = (ui, rel) => ui.reads.textOf(rel);
|
|
18
10
|
|
|
19
11
|
const pathItems = (ui, rel) => itemsForPath(ui.items ?? [], rel);
|
|
20
12
|
|
|
21
|
-
const linesFor = (
|
|
22
|
-
ui
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
) => {
|
|
27
|
-
const text = overlay === null ? fileText(ui, rel) : overlay;
|
|
13
|
+
const linesFor = (ui, rel, overlay, base) => {
|
|
14
|
+
const live = ui.composer.liveFileText();
|
|
15
|
+
const shown = overlay === undefined ? live : overlay;
|
|
16
|
+
const seed = base === undefined ? null : base;
|
|
17
|
+
const text = shown === null ? fileText(ui, rel) : shown;
|
|
28
18
|
const group = pathItems(ui, rel);
|
|
29
|
-
if (
|
|
30
|
-
return mergeEditRows(
|
|
19
|
+
if (shown !== null && seed && seed.length) {
|
|
20
|
+
return mergeEditRows(seed, splitEditor(text));
|
|
31
21
|
}
|
|
32
22
|
return unitLines(text, group);
|
|
33
23
|
};
|
|
@@ -149,8 +139,8 @@ const moveUnitBlock = (ui, step) => {
|
|
|
149
139
|
nav.clearSelection();
|
|
150
140
|
};
|
|
151
141
|
|
|
152
|
-
const
|
|
153
|
-
|
|
142
|
+
const showFile = async (ui, entry) => {
|
|
143
|
+
await ui.reads.loadText(entry.path);
|
|
154
144
|
const nav = ui.nav;
|
|
155
145
|
nav.reviewPath = entry.path;
|
|
156
146
|
nav.tasksOpen = false;
|
|
@@ -170,12 +160,28 @@ const openUnitFile = (ui, entry) => {
|
|
|
170
160
|
ui.status = '';
|
|
171
161
|
};
|
|
172
162
|
|
|
173
|
-
const
|
|
174
|
-
if (
|
|
175
|
-
|
|
163
|
+
const openUnitFile = (ui, entry) => {
|
|
164
|
+
if (!entry || isTasksEntry(entry)) return;
|
|
165
|
+
ui.ops.hold(showFile(ui, entry));
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const applyFileScope = (ui, next, quiet) => {
|
|
176
169
|
ui.nav.fileScope = next;
|
|
177
170
|
ui.nav.restoreFileCursor(ui.fileList());
|
|
178
|
-
|
|
171
|
+
const label = next === 'file' ? 'file scope' : 'diff mode';
|
|
172
|
+
ui.status = quiet ? '' : label;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const listScope = async (ui, quiet) => {
|
|
176
|
+
await ui.reads.loadNames();
|
|
177
|
+
applyFileScope(ui, 'file', quiet);
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const setFileScope = (ui, next, quiet = false) => {
|
|
181
|
+
if (ui.nav.pane !== 'files') return;
|
|
182
|
+
if (ui.nav.fileScope === next) return;
|
|
183
|
+
if (next === 'file') return void ui.ops.hold(listScope(ui, quiet));
|
|
184
|
+
applyFileScope(ui, next, quiet);
|
|
179
185
|
};
|
|
180
186
|
|
|
181
187
|
const editCursor = (ui) => {
|
|
@@ -189,11 +195,9 @@ const editCursor = (ui) => {
|
|
|
189
195
|
const at = atBlock
|
|
190
196
|
? blockLineIndex(lines, item)
|
|
191
197
|
: viewLine(ui.nav, lines.length);
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
rows: lines,
|
|
196
|
-
};
|
|
198
|
+
const cursor = fileOffset(lines, at);
|
|
199
|
+
const rows = lines;
|
|
200
|
+
return { text, cursor, rows };
|
|
197
201
|
};
|
|
198
202
|
|
|
199
203
|
module.exports = {
|
|
@@ -201,6 +205,7 @@ module.exports = {
|
|
|
201
205
|
linesFor,
|
|
202
206
|
moveUnitBlock,
|
|
203
207
|
openUnitFile,
|
|
208
|
+
showFile,
|
|
204
209
|
setFileScope,
|
|
205
210
|
editCursor,
|
|
206
211
|
followFileCursor,
|
package/lib/session/update.js
CHANGED
|
@@ -1,7 +1,184 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const os = require('node:os');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
|
|
7
|
+
const { isHashObject } = require('metautil');
|
|
8
|
+
const utilities = require('../common/utilities.js');
|
|
9
|
+
const {
|
|
10
|
+
INSTALL_MS,
|
|
11
|
+
npmBin,
|
|
12
|
+
npmOpts,
|
|
13
|
+
runProc,
|
|
14
|
+
} = require('../common/process.js');
|
|
15
|
+
const { readJson } = utilities;
|
|
16
|
+
const { parseVersion, cmpVersion } = utilities;
|
|
17
|
+
const { oneLine, asText } = utilities;
|
|
18
|
+
|
|
19
|
+
const PKG = require('../../package.json');
|
|
20
|
+
|
|
21
|
+
const PKG_NAME = PKG.name;
|
|
22
|
+
const PKG_VERSION = PKG.version;
|
|
23
|
+
const PKG_DIR = path.resolve(__dirname, '../..');
|
|
24
|
+
const CHECK_INTERVAL_MS = 12 * 60 * 60 * 1000;
|
|
25
|
+
const FETCH_MS = 8000;
|
|
26
|
+
const REGISTRY = 'https://registry.npmjs.org';
|
|
27
|
+
|
|
28
|
+
const RELEASE = /^\d+\.\d+\.\d+$/;
|
|
29
|
+
const NO_TARGETS = { compatible: '', major: '' };
|
|
30
|
+
|
|
31
|
+
const isNpmInstall = (pkgDir) =>
|
|
32
|
+
path.basename(path.dirname(pkgDir)) === 'node_modules';
|
|
33
|
+
|
|
34
|
+
const cacheFile = (env = process.env) => {
|
|
35
|
+
if (env.XDG_CACHE_HOME) {
|
|
36
|
+
return path.join(env.XDG_CACHE_HOME, 'reslop', 'update.json');
|
|
37
|
+
}
|
|
38
|
+
if (process.platform === 'win32') {
|
|
39
|
+
const local =
|
|
40
|
+
env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
|
|
41
|
+
return path.join(local, 'reslop', 'update.json');
|
|
42
|
+
}
|
|
43
|
+
return path.join(os.homedir(), '.cache', 'reslop', 'update.json');
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const readCache = (file) => {
|
|
47
|
+
const data = readJson(file);
|
|
48
|
+
if (!isHashObject(data)) {
|
|
49
|
+
return { checkedAt: 0, compatible: '', major: '', skipped: '' };
|
|
50
|
+
}
|
|
51
|
+
const checkedAt = parseInt(data.checkedAt, 10) || 0;
|
|
52
|
+
const compatible = asText(data.compatible);
|
|
53
|
+
const latest = asText(data.latest);
|
|
54
|
+
const major = asText(data.major) || latest;
|
|
55
|
+
const handled = asText(data.handled);
|
|
56
|
+
const skipped = asText(data.skipped) || handled;
|
|
57
|
+
return { checkedAt, compatible, major, skipped };
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const writeCache = (file, data) => {
|
|
61
|
+
const { checkedAt, compatible, major, skipped } = data;
|
|
62
|
+
const body = JSON.stringify({ checkedAt, compatible, major, skipped });
|
|
63
|
+
try {
|
|
64
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
65
|
+
fs.writeFileSync(file, `${body}\n`);
|
|
66
|
+
} catch {
|
|
67
|
+
// ignore cache write errors
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const isFresh = (cache, now, interval = CHECK_INTERVAL_MS) => {
|
|
72
|
+
if (!cache.checkedAt || now < cache.checkedAt) return false;
|
|
73
|
+
return now - cache.checkedAt < interval;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const listVersions = (data) => {
|
|
77
|
+
if (!data || typeof data !== 'object') return [];
|
|
78
|
+
const names = [];
|
|
79
|
+
if (isHashObject(data.versions)) names.push(...Object.keys(data.versions));
|
|
80
|
+
const tags = data['dist-tags'];
|
|
81
|
+
if (tags && typeof tags.latest === 'string') names.push(tags.latest);
|
|
82
|
+
if (typeof data.version === 'string') names.push(data.version);
|
|
83
|
+
return [...new Set(names)].filter((name) => RELEASE.test(name));
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const newer = (best, name) => {
|
|
87
|
+
if (!best) return name;
|
|
88
|
+
return cmpVersion(parseVersion(name), parseVersion(best)) > 0 ? name : best;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const pickTargets = (current, names) => {
|
|
92
|
+
const from = parseVersion(current);
|
|
93
|
+
if (!from) return NO_TARGETS;
|
|
94
|
+
let compatible = '';
|
|
95
|
+
let major = '';
|
|
96
|
+
for (const name of names) {
|
|
97
|
+
const ver = parseVersion(name);
|
|
98
|
+
if (cmpVersion(ver, from) <= 0) continue;
|
|
99
|
+
if (ver.major === from.major) compatible = newer(compatible, name);
|
|
100
|
+
else if (ver.major > from.major) major = newer(major, name);
|
|
101
|
+
}
|
|
102
|
+
return { compatible, major };
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const planUpdate = (current, targets) => {
|
|
106
|
+
const from = parseVersion(current);
|
|
107
|
+
if (!from) return { action: 'none' };
|
|
108
|
+
const { compatible, major, skipped } = targets;
|
|
109
|
+
const compatVer = parseVersion(compatible);
|
|
110
|
+
if (compatVer && compatVer.major === from.major) {
|
|
111
|
+
if (cmpVersion(compatVer, from) > 0) {
|
|
112
|
+
return { action: 'install', current, latest: compatible };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const majorVer = parseVersion(major);
|
|
116
|
+
if (!majorVer || majorVer.major <= from.major) return { action: 'none' };
|
|
117
|
+
const skipVer = parseVersion(skipped);
|
|
118
|
+
if (skipVer && cmpVersion(majorVer, skipVer) <= 0) return { action: 'none' };
|
|
119
|
+
return { action: 'confirm', current, latest: major };
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const isEnabled = (options) => {
|
|
123
|
+
if (typeof options.enabled === 'boolean') return options.enabled;
|
|
124
|
+
return isNpmInstall(options.pkgDir ?? PKG_DIR);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const fetchTargets = async (current, options) => {
|
|
128
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
129
|
+
if (typeof fetchImpl !== 'function') return NO_TARGETS;
|
|
130
|
+
const url = `${REGISTRY}/${encodeURIComponent(PKG_NAME)}`;
|
|
131
|
+
const headers = { accept: 'application/json' };
|
|
132
|
+
const signal = options.signal ?? AbortSignal.timeout(FETCH_MS);
|
|
133
|
+
const response = await fetchImpl(url, { headers, signal });
|
|
134
|
+
if (!response || !response.ok) return NO_TARGETS;
|
|
135
|
+
const data = await response.json();
|
|
136
|
+
return pickTargets(current, listVersions(data));
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const installUpdate = async (version, options = {}) => {
|
|
140
|
+
if (typeof options.install === 'function') {
|
|
141
|
+
await options.install(version);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const timeout = options.timeout ?? INSTALL_MS;
|
|
145
|
+
const args = ['install', '-g', `${PKG_NAME}@${version}`];
|
|
146
|
+
const result = await runProc(npmBin(), args, npmOpts({ timeout }));
|
|
147
|
+
if (result.error) throw result.error;
|
|
148
|
+
if (result.status !== 0) {
|
|
149
|
+
throw new Error(oneLine(result.stderr, 'npm install failed'));
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const markSkipped = (version, options = {}) => {
|
|
154
|
+
const file = options.cacheFile ?? cacheFile(options.env);
|
|
155
|
+
writeCache(file, { ...readCache(file), skipped: version });
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const checkUpdate = async (options = {}) => {
|
|
159
|
+
if (!isEnabled(options)) return { action: 'skip' };
|
|
160
|
+
const now = Date.now();
|
|
161
|
+
const current = options.current ?? PKG_VERSION;
|
|
162
|
+
const file = options.cacheFile ?? cacheFile(options.env);
|
|
163
|
+
const cache = readCache(file);
|
|
164
|
+
if (isFresh(cache, now, options.interval)) {
|
|
165
|
+
const plan = planUpdate(current, cache);
|
|
166
|
+
return plan.action === 'install' ? { action: 'none' } : plan;
|
|
167
|
+
}
|
|
168
|
+
let targets = NO_TARGETS;
|
|
169
|
+
try {
|
|
170
|
+
targets = await fetchTargets(current, options);
|
|
171
|
+
} catch {
|
|
172
|
+
// ignore registry errors
|
|
173
|
+
}
|
|
174
|
+
if (!targets.compatible && !targets.major) {
|
|
175
|
+
writeCache(file, { ...cache, checkedAt: now });
|
|
176
|
+
return { action: 'none' };
|
|
177
|
+
}
|
|
178
|
+
const next = { ...cache, checkedAt: now, ...targets };
|
|
179
|
+
writeCache(file, next);
|
|
180
|
+
return planUpdate(current, next);
|
|
181
|
+
};
|
|
5
182
|
|
|
6
183
|
class UpdateCoordinator {
|
|
7
184
|
constructor(ui) {
|
|
@@ -62,13 +239,13 @@ class UpdateCoordinator {
|
|
|
62
239
|
}
|
|
63
240
|
|
|
64
241
|
async check() {
|
|
65
|
-
let plan;
|
|
242
|
+
let plan = null;
|
|
66
243
|
try {
|
|
67
244
|
plan = await checkUpdate(this.opts);
|
|
68
245
|
} catch {
|
|
69
|
-
|
|
246
|
+
// update check failed
|
|
70
247
|
}
|
|
71
|
-
if (this.ui.done) return;
|
|
248
|
+
if (!plan || this.ui.done) return;
|
|
72
249
|
if (plan.action === 'install') {
|
|
73
250
|
this.installPromise = this.install(plan.latest);
|
|
74
251
|
await this.installPromise;
|
|
@@ -89,4 +266,15 @@ class UpdateCoordinator {
|
|
|
89
266
|
}
|
|
90
267
|
}
|
|
91
268
|
|
|
92
|
-
module.exports = {
|
|
269
|
+
module.exports = {
|
|
270
|
+
CHECK_INTERVAL_MS,
|
|
271
|
+
isNpmInstall,
|
|
272
|
+
cacheFile,
|
|
273
|
+
readCache,
|
|
274
|
+
writeCache,
|
|
275
|
+
isFresh,
|
|
276
|
+
planUpdate,
|
|
277
|
+
checkUpdate,
|
|
278
|
+
markSkipped,
|
|
279
|
+
UpdateCoordinator,
|
|
280
|
+
};
|
package/lib/session/view.js
CHANGED
|
@@ -2,12 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
const path = require('node:path');
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const {
|
|
8
|
-
const { fileEntries, fileTotals } = files;
|
|
9
|
-
const review = require('../review.js');
|
|
10
|
-
const { noteCounts } = review;
|
|
5
|
+
const { fileEntries, fileTotals } = require('../common/files.js');
|
|
6
|
+
const { listedCommits } = require('./commit.js');
|
|
7
|
+
const { noteCounts } = require('../review/review.js');
|
|
11
8
|
const diff = require('../diff/diff.js');
|
|
12
9
|
const { unitLines, itemsForPath, splitEditor, mergeEditRows } = diff;
|
|
13
10
|
const unit = require('./unit.js');
|
|
@@ -43,18 +40,6 @@ const blankEntry = (rel) => ({
|
|
|
43
40
|
status: '',
|
|
44
41
|
});
|
|
45
42
|
|
|
46
|
-
const listedNames = (ui) => {
|
|
47
|
-
const repo = ui.repo;
|
|
48
|
-
if (!repo.listFiles) return [];
|
|
49
|
-
try {
|
|
50
|
-
return repo.listFiles(ui.top || ui.cwd, ui.paths ?? [], {
|
|
51
|
-
commit: ui.rev,
|
|
52
|
-
});
|
|
53
|
-
} catch {
|
|
54
|
-
return [];
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
43
|
const mergeUnitFiles = (entries, names) => {
|
|
59
44
|
const have = new Set();
|
|
60
45
|
for (const entry of entries) have.add(entry.path);
|
|
@@ -74,9 +59,8 @@ const fileList = (ui) => {
|
|
|
74
59
|
const from = sourceLabel ? 'pr' : 'commit';
|
|
75
60
|
const to = sourceLabel || ui.revShort;
|
|
76
61
|
const labeled = relabelStatus(entries, from, to);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return labeled;
|
|
62
|
+
if (ui.nav.fileScope !== 'file') return labeled;
|
|
63
|
+
return mergeUnitFiles(labeled, ui.reads.names);
|
|
80
64
|
};
|
|
81
65
|
|
|
82
66
|
const counts = (ui, notes = noteCounts(ui.review.store)) => {
|
|
@@ -87,6 +71,7 @@ const counts = (ui, notes = noteCounts(ui.review.store)) => {
|
|
|
87
71
|
commit: 0,
|
|
88
72
|
pr: 0,
|
|
89
73
|
tasks: 0,
|
|
74
|
+
tasksDone: 0,
|
|
90
75
|
feedback: 0,
|
|
91
76
|
code: 0,
|
|
92
77
|
};
|
|
@@ -96,11 +81,15 @@ const counts = (ui, notes = noteCounts(ui.review.store)) => {
|
|
|
96
81
|
}
|
|
97
82
|
next.feedback = notes.feedback;
|
|
98
83
|
next.tasks = notes.tasks;
|
|
84
|
+
next.tasksDone = notes.tasksDone;
|
|
99
85
|
next.code = notes.code;
|
|
100
86
|
return next;
|
|
101
87
|
};
|
|
102
88
|
|
|
103
|
-
const viewStatus = (ui) =>
|
|
89
|
+
const viewStatus = (ui) => {
|
|
90
|
+
if (ui.status || ui.busy) return ui.status || ui.busy;
|
|
91
|
+
return '';
|
|
92
|
+
};
|
|
104
93
|
|
|
105
94
|
const unitBodyLines = (ui) => {
|
|
106
95
|
if (ui.nav.pane !== 'unit') return [];
|
|
@@ -139,68 +128,92 @@ const commitRows = (ui) => {
|
|
|
139
128
|
return rows;
|
|
140
129
|
};
|
|
141
130
|
|
|
142
|
-
const
|
|
143
|
-
const {
|
|
144
|
-
const templates = composer.templates.shownTemplates();
|
|
145
|
-
const change = ui.change;
|
|
146
|
-
const sourceKind = (change && change.source) || '';
|
|
147
|
-
const notes = noteCounts(ui.review.store);
|
|
131
|
+
const navView = (ui) => {
|
|
132
|
+
const { nav } = ui;
|
|
148
133
|
return {
|
|
149
134
|
item: ui.current(),
|
|
150
135
|
index: nav.index,
|
|
151
136
|
total: ui.collection.items.length,
|
|
152
137
|
scroll: nav.scroll,
|
|
153
138
|
listScroll: nav.listScroll,
|
|
154
|
-
status: viewStatus(ui),
|
|
155
|
-
progressFrame: ui.progressFrame,
|
|
156
|
-
layout: ui.layout,
|
|
157
|
-
counts: counts(ui, notes),
|
|
158
139
|
selection: nav.selection,
|
|
159
140
|
pane: nav.pane,
|
|
160
141
|
fileScope: nav.fileScope,
|
|
161
|
-
files: fileList(ui),
|
|
162
142
|
fileCursor: nav.fileCursor,
|
|
143
|
+
find: nav.find,
|
|
144
|
+
import: nav.import,
|
|
163
145
|
reviewPath: nav.reviewPath,
|
|
164
146
|
unitLine: nav.unitLine,
|
|
147
|
+
branchCursor: nav.branchCursor,
|
|
148
|
+
commitCursor: nav.commitCursor,
|
|
149
|
+
packagesCursor: nav.packagesCursor,
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const dropNameOf = (ui) => {
|
|
154
|
+
const { packages, gitBranches, commits, npm } = ui;
|
|
155
|
+
const name = packages.dropName || gitBranches.dropName;
|
|
156
|
+
return name || commits.dropName || npm.dropName;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const repoView = (ui) => {
|
|
160
|
+
const { change, updater } = ui;
|
|
161
|
+
return {
|
|
162
|
+
status: viewStatus(ui),
|
|
163
|
+
progressFrame: ui.progressFrame,
|
|
164
|
+
layout: ui.layout,
|
|
165
|
+
lineNumbers: ui.lineNumbers === true,
|
|
166
|
+
counts: counts(ui, noteCounts(ui.review.store)),
|
|
167
|
+
files: fileList(ui),
|
|
165
168
|
unitLines: unitBodyLines(ui),
|
|
166
169
|
branch: ui.branch,
|
|
167
|
-
branches: gitBranches.branches,
|
|
168
|
-
branchCursor: nav.branchCursor,
|
|
170
|
+
branches: ui.gitBranches.branches,
|
|
169
171
|
commits: commitRows(ui),
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
npmCommands: npm.commands,
|
|
173
|
-
npmCursor: nav.npmCursor,
|
|
174
|
-
npmView: npm.viewing,
|
|
175
|
-
npmOutput: npm.output,
|
|
176
|
-
npmFollow: npm.followEnd,
|
|
177
|
-
npmScroll: npm.logScroll,
|
|
178
|
-
npmEditName: npm.editName,
|
|
179
|
-
npmEditField: npm.editField,
|
|
180
|
-
npmDraftName: npm.draftName,
|
|
181
|
-
npmDraftCommand: npm.draftCommand,
|
|
182
|
-
npmRunning: npm.running,
|
|
183
|
-
npmLogs: nav.pane === 'npm' ? npm.logLabel : '',
|
|
172
|
+
commitView: ui.commits.commitView,
|
|
173
|
+
quitWarning: ui.quitWarning || '',
|
|
184
174
|
repoName: repoNameOf(ui),
|
|
185
175
|
rev: ui.rev || '',
|
|
186
176
|
revShort: ui.revShort || '',
|
|
187
177
|
sourceLabel: ui.sourceLabel || '',
|
|
188
|
-
sourceKind,
|
|
178
|
+
sourceKind: (change && change.source) || '',
|
|
189
179
|
mode: ui.mode,
|
|
180
|
+
updateFrom: updater.from,
|
|
181
|
+
updateTo: updater.to,
|
|
182
|
+
dropName: dropNameOf(ui),
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const composeView = (composer) => {
|
|
187
|
+
const templates = composer.templates.shownTemplates();
|
|
188
|
+
return {
|
|
190
189
|
compose: composer.composeView(),
|
|
191
190
|
noteText: composer.idleNoteText(),
|
|
192
|
-
tasks: composer.tasks.taskTexts(),
|
|
193
|
-
taskSections: composer.tasks.taskSections(),
|
|
194
|
-
tasksFocus: composer.tasks.clampedTaskFocus(),
|
|
195
|
-
taskEdit: composer.tasks.taskEditView(),
|
|
196
191
|
codeOverlay: composer.codeOverlayView(),
|
|
197
192
|
templates,
|
|
198
193
|
templateIndex: composer.templates.clampedTemplateIndex(templates),
|
|
199
|
-
updateFrom: updater.from,
|
|
200
|
-
updateTo: updater.to,
|
|
201
|
-
dropName: gitBranches.dropName || commits.dropName || npm.dropName,
|
|
202
|
-
dashboard: nav.pane === 'dashboard' ? ui.dashboard.view() : null,
|
|
203
194
|
};
|
|
204
195
|
};
|
|
205
196
|
|
|
206
|
-
|
|
197
|
+
const screenView = (ui) => {
|
|
198
|
+
const { pane } = ui.nav;
|
|
199
|
+
return {
|
|
200
|
+
dashboard: pane === 'dashboard' ? ui.dashboard.view() : null,
|
|
201
|
+
packages: pane === 'packages' ? ui.dashboard.packagesView() : null,
|
|
202
|
+
repos: pane === 'repos' ? ui.workspace.view() : null,
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const view = (ui) => {
|
|
207
|
+
const { pane } = ui.nav;
|
|
208
|
+
return {
|
|
209
|
+
...navView(ui),
|
|
210
|
+
...repoView(ui),
|
|
211
|
+
...ui.npm.view(pane === 'npm'),
|
|
212
|
+
...ui.agents.view(pane === 'agents'),
|
|
213
|
+
...composeView(ui.composer),
|
|
214
|
+
...ui.composer.tasks.view(pane === 'tasks'),
|
|
215
|
+
...screenView(ui),
|
|
216
|
+
};
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
module.exports = { fileList, counts, unitBodyLines, view };
|