reslop 0.1.9 → 0.2.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 +25 -1
- package/README.md +3 -1
- package/bin/reslop.js +2 -2
- package/lib/ansi.js +148 -5
- package/lib/api.js +4 -2
- package/lib/capabilities.js +13 -14
- package/lib/cli.js +38 -49
- package/lib/clipboard.js +1 -1
- package/lib/{deps/changes.js → deps-diff.js} +309 -19
- package/lib/deps.js +498 -29
- package/lib/detect.js +1 -7
- package/lib/diff/align.js +7 -10
- package/lib/diff/diff.js +53 -0
- package/lib/diff/display.js +5 -4
- package/lib/diff/inline.js +26 -21
- package/lib/diff/items.js +6 -4
- package/lib/diff/patch.js +1 -3
- package/lib/diff/unit.js +392 -0
- package/lib/files.js +5 -8
- package/lib/{git/branches.js → git-branches.js} +191 -11
- package/lib/{git/dependencies.js → git-deps.js} +111 -38
- package/lib/git-reword-todo.js +20 -0
- package/lib/git.js +606 -68
- package/lib/github.js +28 -197
- package/lib/gitlab.js +24 -195
- package/lib/highlight/bash.js +1 -3
- package/lib/highlight/css.js +1 -3
- package/lib/highlight/js.js +11 -14
- package/lib/highlight.js +6 -9
- package/lib/keys.js +14 -8
- package/lib/manifest.js +330 -0
- package/lib/remote.js +374 -0
- package/lib/render/branches.js +18 -100
- package/lib/render/chrome.js +71 -14
- package/lib/render/commits.js +69 -60
- package/lib/render/diff.js +20 -20
- package/lib/render/files.js +6 -34
- package/lib/render/frame.js +36 -13
- package/lib/render/notes.js +26 -8
- package/lib/render/primitives.js +99 -11
- package/lib/{render.js → render/render.js} +8 -8
- package/lib/render/unit.js +41 -0
- package/lib/review-merge.js +270 -0
- package/lib/review.js +782 -14
- package/lib/select.js +5 -10
- package/lib/session/accessors.js +9 -1
- package/lib/session/actions.js +61 -18
- package/lib/session/branches.js +116 -128
- package/lib/session/change-actions.js +202 -123
- package/lib/session/commit.js +201 -115
- package/lib/session/compose.js +181 -15
- package/lib/session/dispatch.js +110 -60
- package/lib/session/files-pane.js +156 -148
- package/lib/session/items.js +22 -30
- package/lib/session/lifecycle.js +151 -54
- package/lib/session/load.js +19 -33
- package/lib/session/navigation.js +12 -1
- package/lib/session/ops.js +28 -41
- package/lib/session/pointer.js +57 -57
- package/lib/session/review.js +23 -37
- package/lib/session/terminal.js +6 -12
- package/lib/session/todos.js +37 -13
- package/lib/session/unit.js +208 -0
- package/lib/session/update.js +33 -46
- package/lib/session/view.js +78 -9
- package/lib/session/watch.js +128 -24
- package/lib/session.js +22 -246
- package/lib/source.js +3 -3
- package/lib/update.js +40 -75
- package/lib/{git/proc.js → utilities.js} +75 -11
- package/lib/wrap.js +1 -3
- package/package.json +2 -2
- package/lib/deps/items.js +0 -134
- package/lib/deps/manifest.js +0 -152
- package/lib/deps/merge.js +0 -120
- package/lib/deps/proposals.js +0 -164
- package/lib/deps/reports.js +0 -180
- package/lib/deps/rows.js +0 -176
- package/lib/deps/scan.js +0 -138
- package/lib/deps/usage.js +0 -68
- package/lib/deps/versions.js +0 -119
- package/lib/diff.js +0 -33
- package/lib/git/changes.js +0 -164
- package/lib/git/read.js +0 -253
- package/lib/git/run.js +0 -100
- package/lib/npm/commands.js +0 -100
- package/lib/remote/changes.js +0 -37
- package/lib/remote/headers.js +0 -36
- package/lib/remote/http.js +0 -122
- package/lib/remote/notes.js +0 -94
- package/lib/review/format.js +0 -434
- package/lib/review/storage.js +0 -150
- package/lib/review/store.js +0 -178
- package/lib/review/templates.js +0 -49
- package/lib/session/origins.js +0 -7
- package/lib/sys.js +0 -84
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased][unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.2.1][] - 2026-09-23
|
|
6
|
+
|
|
7
|
+
- Type a new commit message at the top of the list
|
|
8
|
+
- Improve `fixup!` functions: create and apply
|
|
9
|
+
- Reword the selected commit message with `r`
|
|
10
|
+
- Add light theme: `-light` option and `l` hotkey to switch
|
|
11
|
+
- Support checkbox state in TODOs, UI for state change
|
|
12
|
+
- Reload the file list when leaving todos, branches, or commits
|
|
13
|
+
- Let agents run `editing` reviews and leave `done` files unchanged
|
|
14
|
+
- Skip npm audit and outdated unless package files changed
|
|
15
|
+
- Sync and merge TODOs with file instead of overwriting it
|
|
16
|
+
|
|
17
|
+
## [0.2.0][] - 2026-09-22
|
|
18
|
+
|
|
19
|
+
- Add a full-size file editor
|
|
20
|
+
- Optimize codebase and reorganize code structure
|
|
21
|
+
- Add pull and push on the commits list screen
|
|
22
|
+
- Fix disk watcher startup on macOS
|
|
23
|
+
- Fix Windows temp-path comparison and same-size file reload polling
|
|
24
|
+
|
|
25
|
+
## [0.1.9][] - 2026-09-19
|
|
26
|
+
|
|
5
27
|
- Remove `r` reload hotkey and hint; auto-reload covers disk changes
|
|
6
28
|
- Improve branch list TUI/TUX
|
|
7
29
|
- Right-align the time column in the branch list
|
|
@@ -95,7 +117,9 @@
|
|
|
95
117
|
- Feedback and todos that produce a repair plan for an agent
|
|
96
118
|
- Intra-line highlighting in unified, mixed, and side-by-side layouts
|
|
97
119
|
|
|
98
|
-
[unreleased]: https://github.com/tshemsedinov/reslop/compare/v0.1
|
|
120
|
+
[unreleased]: https://github.com/tshemsedinov/reslop/compare/v0.2.1...HEAD
|
|
121
|
+
[0.2.1]: https://github.com/tshemsedinov/reslop/compare/v0.2.0...v0.2.1
|
|
122
|
+
[0.2.0]: https://github.com/tshemsedinov/reslop/compare/v0.1.9...v0.2.0
|
|
99
123
|
[0.1.9]: https://github.com/tshemsedinov/reslop/compare/v0.1.8...v0.1.9
|
|
100
124
|
[0.1.8]: https://github.com/tshemsedinov/reslop/compare/v0.1.7...v0.1.8
|
|
101
125
|
[0.1.7]: https://github.com/tshemsedinov/reslop/compare/v0.1.6...v0.1.7
|
package/README.md
CHANGED
|
@@ -20,10 +20,11 @@ Review → Plan → Repair → Verify
|
|
|
20
20
|
|
|
21
21
|
- Leave feedback, issues/todos, and in-place code proposals as a repair plan
|
|
22
22
|
- Review uncommitted git diffs, a given commit, a GitHub PR, or a GitLab MR
|
|
23
|
+
- File-scope review mode: not just diffs, with editor mode
|
|
23
24
|
- Stage, unstage, or revert each contiguous block of diff lines
|
|
24
25
|
- Auto-reload local diffs when files change, keeping the current screen
|
|
25
26
|
- Import GitHub PR and GitLab MR review comments into the local plan for AI
|
|
26
|
-
- Commits list: commit, amend, fixup, and
|
|
27
|
+
- Commits list: commit, amend, fixup, reword, drop, pull, and push
|
|
27
28
|
- Branches: checkout, create, rebase, drop, pull, and push
|
|
28
29
|
- Review each npm dependency once across `package.json` and the lockfile
|
|
29
30
|
- Propose unused removals, npm audit fixes, and outdated updates as diffs
|
|
@@ -47,6 +48,7 @@ Works on Linux, macOS, and Windows. On Windows use Windows Terminal.
|
|
|
47
48
|
- `reslop https://github.com/metarhia/metacom/pull/555` GitHub/GitLab PR/MR
|
|
48
49
|
- `reslop -n` start a new review even if the latest is still editing
|
|
49
50
|
- `reslop -r` read-only mode
|
|
51
|
+
- `reslop -light` light color theme (default dark)
|
|
50
52
|
|
|
51
53
|
Reviews go in `.review/YYYY-MM-DD-NN.md` with frontmatter `status`:
|
|
52
54
|
|
package/bin/reslop.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const { run,
|
|
4
|
+
const { run, errorMessage } = require('../lib/cli.js');
|
|
5
5
|
const { LEAVE_TERM } = require('../lib/session.js');
|
|
6
6
|
|
|
7
7
|
const fail = (reason) => {
|
|
@@ -10,7 +10,7 @@ const fail = (reason) => {
|
|
|
10
10
|
} catch {
|
|
11
11
|
// ignore
|
|
12
12
|
}
|
|
13
|
-
process.stderr.write(
|
|
13
|
+
process.stderr.write(`reslop: ${errorMessage(reason)}\n`);
|
|
14
14
|
process.exit(1);
|
|
15
15
|
};
|
|
16
16
|
|
package/lib/ansi.js
CHANGED
|
@@ -40,7 +40,7 @@ const WIDE_CP = [
|
|
|
40
40
|
0x1fae9, 0x1faf0, 0x1faf8, 0x20000, 0x2fffd, 0x30000, 0x3fffd,
|
|
41
41
|
];
|
|
42
42
|
|
|
43
|
-
const
|
|
43
|
+
const DARK_UI = {
|
|
44
44
|
delLineFg: [0xcc, 0x7a, 0x7a],
|
|
45
45
|
delLineBg: [0x3a, 0x1a, 0x1a],
|
|
46
46
|
delCharFg: [0xff, 0xff, 0xff],
|
|
@@ -87,7 +87,7 @@ const THEME = {
|
|
|
87
87
|
stagedAddCharBg: [0x4e, 0x4e, 0x58],
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
-
const
|
|
90
|
+
const DARK_CODE = {
|
|
91
91
|
keyword: [197, 134, 192],
|
|
92
92
|
control: [197, 134, 192],
|
|
93
93
|
storage: [86, 156, 214],
|
|
@@ -122,7 +122,7 @@ const CODE_FG = {
|
|
|
122
122
|
logDebug: [140, 160, 180],
|
|
123
123
|
};
|
|
124
124
|
|
|
125
|
-
const
|
|
125
|
+
const DARK_LOG_COLS = [
|
|
126
126
|
[210, 210, 220],
|
|
127
127
|
[120, 180, 220],
|
|
128
128
|
[180, 160, 220],
|
|
@@ -133,6 +133,143 @@ const LOG_COL_FG = [
|
|
|
133
133
|
[200, 170, 140],
|
|
134
134
|
];
|
|
135
135
|
|
|
136
|
+
const LIGHT_UI = {
|
|
137
|
+
delLineFg: [0xb3, 0x1d, 0x28],
|
|
138
|
+
delLineBg: [0xff, 0xeb, 0xe9],
|
|
139
|
+
delCharFg: [0x1f, 0x23, 0x28],
|
|
140
|
+
delCharBg: [0xff, 0xc1, 0xc0],
|
|
141
|
+
addLineFg: [0x1a, 0x7f, 0x37],
|
|
142
|
+
addLineBg: [0xe6, 0xff, 0xec],
|
|
143
|
+
addCharFg: [0x1f, 0x23, 0x28],
|
|
144
|
+
addCharBg: [0xab, 0xf2, 0xbc],
|
|
145
|
+
ctxFg: [0x57, 0x60, 0x6a],
|
|
146
|
+
ctxBg: [0xff, 0xff, 0xff],
|
|
147
|
+
splitGutterFg: [0xea, 0xee, 0xf2],
|
|
148
|
+
splitGutterBg: [0xea, 0xee, 0xf2],
|
|
149
|
+
headerFg: [0x24, 0x29, 0x2f],
|
|
150
|
+
headerBg: [0xd8, 0xde, 0xe4],
|
|
151
|
+
headerChromeFg: [0x42, 0x4a, 0x53],
|
|
152
|
+
headerRepoFg: [0x24, 0x29, 0x2f],
|
|
153
|
+
headerDirFg: [0x57, 0x60, 0x6a],
|
|
154
|
+
headerSlashFg: [0x8c, 0x95, 0x9f],
|
|
155
|
+
headerFileFg: [0x1f, 0x23, 0x28],
|
|
156
|
+
headerMetaFg: [0x42, 0x4a, 0x53],
|
|
157
|
+
chromeFg: [0x24, 0x29, 0x2f],
|
|
158
|
+
chromeBg: [0xf0, 0xf2, 0xf5],
|
|
159
|
+
noteBg: [0xe8, 0xf0, 0xfe],
|
|
160
|
+
buttonFg: [0x57, 0x60, 0x6a],
|
|
161
|
+
buttonBg: [0xe1, 0xe5, 0xea],
|
|
162
|
+
buttonHotFg: [0x0f, 0x14, 0x19],
|
|
163
|
+
currentBg: [0xac, 0xe1, 0xc2],
|
|
164
|
+
checkFg: [0x1f, 0x23, 0x28],
|
|
165
|
+
checkBg: [0xc8, 0xcf, 0xd8],
|
|
166
|
+
checkDoneFg: [0x0f, 0x3d, 0x1f],
|
|
167
|
+
checkDoneBg: [0xab, 0xf2, 0xbc],
|
|
168
|
+
errorFg: [0xcf, 0x22, 0x2e],
|
|
169
|
+
warnFg: [0x9a, 0x67, 0x00],
|
|
170
|
+
mutedFg: [0x6e, 0x77, 0x81],
|
|
171
|
+
shaFg: [0x05, 0x50, 0xae],
|
|
172
|
+
shaDarkFg: [0x0b, 0x3d, 0x70],
|
|
173
|
+
stagedDelLineFg: [0x57, 0x60, 0x6a],
|
|
174
|
+
stagedDelLineBg: [0xf3, 0xf4, 0xf6],
|
|
175
|
+
stagedDelCharFg: [0x1f, 0x23, 0x28],
|
|
176
|
+
stagedDelCharBg: [0xd8, 0xdc, 0xe1],
|
|
177
|
+
stagedAddLineFg: [0x42, 0x4a, 0x53],
|
|
178
|
+
stagedAddLineBg: [0xea, 0xec, 0xef],
|
|
179
|
+
stagedAddCharFg: [0x0f, 0x14, 0x19],
|
|
180
|
+
stagedAddCharBg: [0xcc, 0xd1, 0xd7],
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const LIGHT_CODE = {
|
|
184
|
+
keyword: [175, 0, 219],
|
|
185
|
+
control: [175, 0, 219],
|
|
186
|
+
storage: [0, 0, 255],
|
|
187
|
+
literal: [0, 0, 255],
|
|
188
|
+
string: [163, 21, 21],
|
|
189
|
+
template: [163, 21, 21],
|
|
190
|
+
escape: [238, 0, 0],
|
|
191
|
+
interpolation: [0, 16, 128],
|
|
192
|
+
number: [9, 134, 88],
|
|
193
|
+
comment: [0, 128, 0],
|
|
194
|
+
function: [121, 94, 38],
|
|
195
|
+
method: [121, 94, 38],
|
|
196
|
+
className: [38, 127, 153],
|
|
197
|
+
type: [38, 127, 153],
|
|
198
|
+
interface: [38, 127, 153],
|
|
199
|
+
property: [0, 16, 128],
|
|
200
|
+
variable: [0, 16, 128],
|
|
201
|
+
parameter: [0, 16, 128],
|
|
202
|
+
constant: [0, 112, 193],
|
|
203
|
+
operator: [60, 60, 60],
|
|
204
|
+
punct: [60, 60, 60],
|
|
205
|
+
regex: [129, 31, 63],
|
|
206
|
+
decorator: [121, 94, 38],
|
|
207
|
+
tag: [128, 0, 0],
|
|
208
|
+
attr: [229, 0, 0],
|
|
209
|
+
plain: [31, 31, 31],
|
|
210
|
+
punctDim: [140, 140, 140],
|
|
211
|
+
logDate: [60, 60, 70],
|
|
212
|
+
logError: [205, 49, 49],
|
|
213
|
+
logWarn: [160, 110, 0],
|
|
214
|
+
logInfo: [0, 90, 180],
|
|
215
|
+
logDebug: [100, 110, 125],
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const LIGHT_LOG_COLS = [
|
|
219
|
+
[60, 60, 70],
|
|
220
|
+
[0, 95, 150],
|
|
221
|
+
[110, 70, 170],
|
|
222
|
+
[30, 120, 60],
|
|
223
|
+
[150, 95, 20],
|
|
224
|
+
[170, 50, 90],
|
|
225
|
+
[20, 120, 120],
|
|
226
|
+
[130, 90, 50],
|
|
227
|
+
];
|
|
228
|
+
|
|
229
|
+
const PALETTES = {
|
|
230
|
+
dark: { ui: DARK_UI, code: DARK_CODE, logCols: DARK_LOG_COLS },
|
|
231
|
+
light: { ui: LIGHT_UI, code: LIGHT_CODE, logCols: LIGHT_LOG_COLS },
|
|
232
|
+
};
|
|
233
|
+
const THEME_NAMES = Object.keys(PALETTES);
|
|
234
|
+
|
|
235
|
+
const applyColors = (into, from) => {
|
|
236
|
+
for (const key of Object.keys(from)) {
|
|
237
|
+
const src = from[key];
|
|
238
|
+
let dst = into[key];
|
|
239
|
+
if (!dst) {
|
|
240
|
+
dst = [0, 0, 0];
|
|
241
|
+
into[key] = dst;
|
|
242
|
+
}
|
|
243
|
+
dst[0] = src[0];
|
|
244
|
+
dst[1] = src[1];
|
|
245
|
+
dst[2] = src[2];
|
|
246
|
+
}
|
|
247
|
+
return into;
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const cloneColors = (colors) => {
|
|
251
|
+
const into = Array.isArray(colors) ? [] : {};
|
|
252
|
+
return applyColors(into, colors);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const THEME = cloneColors(DARK_UI);
|
|
256
|
+
const CODE_FG = cloneColors(DARK_CODE);
|
|
257
|
+
const LOG_COL_FG = cloneColors(DARK_LOG_COLS);
|
|
258
|
+
let currentTheme = 'dark';
|
|
259
|
+
|
|
260
|
+
const setTheme = (name) => {
|
|
261
|
+
if (!Object.hasOwn(PALETTES, name)) {
|
|
262
|
+
throw new Error(`unknown theme ${name}`);
|
|
263
|
+
}
|
|
264
|
+
const palette = PALETTES[name];
|
|
265
|
+
applyColors(THEME, palette.ui);
|
|
266
|
+
applyColors(CODE_FG, palette.code);
|
|
267
|
+
applyColors(LOG_COL_FG, palette.logCols);
|
|
268
|
+
currentTheme = name;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
const themeName = () => currentTheme;
|
|
272
|
+
|
|
136
273
|
const codeFg = (style) => {
|
|
137
274
|
if (typeof style !== 'string') return CODE_FG.plain;
|
|
138
275
|
if (Object.hasOwn(CODE_FG, style)) return CODE_FG[style];
|
|
@@ -158,8 +295,10 @@ const paint = (text, fgRgb, bgRgb, color, bold) => {
|
|
|
158
295
|
const stripAnsi = (text) => text.replace(ANSI_RE, '');
|
|
159
296
|
|
|
160
297
|
const graphemes = (text) => {
|
|
161
|
-
const parts =
|
|
162
|
-
|
|
298
|
+
const parts = new Array(text.length);
|
|
299
|
+
let n = 0;
|
|
300
|
+
for (const { segment } of SEGMENTER.segment(text)) parts[n++] = segment;
|
|
301
|
+
parts.length = n;
|
|
163
302
|
return parts;
|
|
164
303
|
};
|
|
165
304
|
|
|
@@ -220,6 +359,10 @@ module.exports = {
|
|
|
220
359
|
EL,
|
|
221
360
|
THEME,
|
|
222
361
|
CODE_FG,
|
|
362
|
+
PALETTES,
|
|
363
|
+
THEME_NAMES,
|
|
364
|
+
setTheme,
|
|
365
|
+
themeName,
|
|
223
366
|
codeFg,
|
|
224
367
|
fg,
|
|
225
368
|
bg,
|
package/lib/api.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const ansi = require('./ansi.js');
|
|
4
|
-
const diff = require('./diff.js');
|
|
4
|
+
const diff = require('./diff/diff.js');
|
|
5
5
|
const git = require('./git.js');
|
|
6
6
|
const keys = require('./keys.js');
|
|
7
|
-
const render = require('./render.js');
|
|
7
|
+
const render = require('./render/render.js');
|
|
8
8
|
const highlight = require('./highlight.js');
|
|
9
9
|
const detect = require('./detect.js');
|
|
10
10
|
const github = require('./github.js');
|
|
@@ -16,6 +16,8 @@ const cli = require('./cli.js');
|
|
|
16
16
|
module.exports = {
|
|
17
17
|
THEME: ansi.THEME,
|
|
18
18
|
CODE_FG: ansi.CODE_FG,
|
|
19
|
+
THEME_NAMES: ansi.THEME_NAMES,
|
|
20
|
+
setTheme: ansi.setTheme,
|
|
19
21
|
ACTIONS: keys.ACTIONS,
|
|
20
22
|
diffChars: diff.diffChars,
|
|
21
23
|
parseDiff: diff.parseDiff,
|
package/lib/capabilities.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const fs = require('node:fs');
|
|
4
|
-
|
|
5
3
|
const READ_METHODS = [
|
|
6
4
|
'load',
|
|
7
5
|
'loadAsync',
|
|
8
6
|
'loadExtras',
|
|
9
7
|
'toplevel',
|
|
10
8
|
'resolveRev',
|
|
9
|
+
'listFiles',
|
|
10
|
+
'fileText',
|
|
11
11
|
];
|
|
12
12
|
|
|
13
13
|
const CHANGE_METHODS = [
|
|
@@ -17,6 +17,8 @@ const CHANGE_METHODS = [
|
|
|
17
17
|
'revert',
|
|
18
18
|
'revertFile',
|
|
19
19
|
'edit',
|
|
20
|
+
'writeFile',
|
|
21
|
+
'stagePath',
|
|
20
22
|
];
|
|
21
23
|
|
|
22
24
|
const BRANCH_METHODS = [
|
|
@@ -24,6 +26,7 @@ const BRANCH_METHODS = [
|
|
|
24
26
|
'commitAsync',
|
|
25
27
|
'hasStaged',
|
|
26
28
|
'lastMessage',
|
|
29
|
+
'commitMessage',
|
|
27
30
|
'listBranches',
|
|
28
31
|
'listCommits',
|
|
29
32
|
'currentBranch',
|
|
@@ -37,6 +40,10 @@ const BRANCH_METHODS = [
|
|
|
37
40
|
'dropAsync',
|
|
38
41
|
'dropCommit',
|
|
39
42
|
'dropCommitAsync',
|
|
43
|
+
'applyFixup',
|
|
44
|
+
'applyFixupAsync',
|
|
45
|
+
'reword',
|
|
46
|
+
'rewordAsync',
|
|
40
47
|
'pull',
|
|
41
48
|
'pullAsync',
|
|
42
49
|
'push',
|
|
@@ -46,9 +53,9 @@ const BRANCH_METHODS = [
|
|
|
46
53
|
const SOURCE_CAPS = {
|
|
47
54
|
local: { read: true, changes: true, branches: true, review: true },
|
|
48
55
|
commit: { read: true, changes: false, branches: false, review: true },
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
pr: { read: true, changes: false, branches: false, review: true },
|
|
57
|
+
mr: { read: true, changes: false, branches: false, review: true },
|
|
58
|
+
readonly: { read: true, changes: false, branches: false, review: true },
|
|
52
59
|
};
|
|
53
60
|
|
|
54
61
|
const withReadOnly = (caps, readOnly) => {
|
|
@@ -86,16 +93,9 @@ const sessionCapabilities = (options) => {
|
|
|
86
93
|
}
|
|
87
94
|
const repoCaps = options.repo && options.repo.capabilities;
|
|
88
95
|
if (repoCaps) return withReadOnly(repoCaps, readOnly);
|
|
89
|
-
return capabilitiesFor(readOnly ? '
|
|
96
|
+
return capabilitiesFor(readOnly ? 'readonly' : 'local');
|
|
90
97
|
};
|
|
91
98
|
|
|
92
|
-
const createReviewStorage = (io = {}) => ({
|
|
93
|
-
readdirSync: io.readdirSync ?? fs.readdirSync,
|
|
94
|
-
readFileSync: io.readFileSync ?? fs.readFileSync,
|
|
95
|
-
writeFileSync: io.writeFileSync ?? fs.writeFileSync,
|
|
96
|
-
mkdirSync: io.mkdirSync ?? fs.mkdirSync,
|
|
97
|
-
});
|
|
98
|
-
|
|
99
99
|
module.exports = {
|
|
100
100
|
READ_METHODS,
|
|
101
101
|
CHANGE_METHODS,
|
|
@@ -105,5 +105,4 @@ module.exports = {
|
|
|
105
105
|
withReadOnly,
|
|
106
106
|
attachCapabilities,
|
|
107
107
|
sessionCapabilities,
|
|
108
|
-
createReviewStorage,
|
|
109
108
|
};
|
package/lib/cli.js
CHANGED
|
@@ -1,29 +1,32 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const fs = require('node:fs');
|
|
4
3
|
const path = require('node:path');
|
|
5
4
|
|
|
5
|
+
const { exists } = require('metautil');
|
|
6
|
+
|
|
6
7
|
const { createGitRepo } = require('./git.js');
|
|
7
8
|
const { githubToken, loadPullRequest } = require('./github.js');
|
|
8
9
|
const { gitlabToken, loadMergeRequest } = require('./gitlab.js');
|
|
9
10
|
const { selectChangeSource, createLoadedSource } = require('./source.js');
|
|
10
11
|
const { Session } = require('./session.js');
|
|
11
12
|
const { capabilitiesFor, attachCapabilities } = require('./capabilities.js');
|
|
13
|
+
const { setTheme } = require('./ansi.js');
|
|
12
14
|
|
|
13
15
|
const HEX_REV = /^[0-9a-f]{4,40}$/i;
|
|
14
16
|
const HEAD_REV = /^HEAD([~^].*)?$/i;
|
|
15
17
|
const RANGE_REV = /[~^]/;
|
|
16
18
|
|
|
17
|
-
const USAGE =
|
|
19
|
+
const USAGE =
|
|
20
|
+
'Usage: reslop [-n] [-r] [-light] [path | commit | pr-url | mr-url]';
|
|
18
21
|
|
|
19
22
|
const REMOTE_CHANGE = {
|
|
20
|
-
|
|
23
|
+
pr: {
|
|
21
24
|
load: 'loadPullRequest',
|
|
22
25
|
fallback: loadPullRequest,
|
|
23
26
|
token: githubToken,
|
|
24
27
|
target: (selected) => selected.pr,
|
|
25
28
|
},
|
|
26
|
-
|
|
29
|
+
mr: {
|
|
27
30
|
load: 'loadMergeRequest',
|
|
28
31
|
fallback: loadMergeRequest,
|
|
29
32
|
token: gitlabToken,
|
|
@@ -38,16 +41,8 @@ const errorMessage = (reason) => {
|
|
|
38
41
|
return `${reason}`;
|
|
39
42
|
};
|
|
40
43
|
|
|
41
|
-
const failLine = (reason) => `reslop: ${errorMessage(reason)}\n`;
|
|
42
|
-
|
|
43
44
|
const fail = (stderr, reason) => {
|
|
44
|
-
stderr.write(
|
|
45
|
-
return 1;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const failUsage = (stderr, reason) => {
|
|
49
|
-
fail(stderr, reason);
|
|
50
|
-
stderr.write(`${USAGE}\n`);
|
|
45
|
+
stderr.write(`reslop: ${errorMessage(reason)}\n`);
|
|
51
46
|
return 1;
|
|
52
47
|
};
|
|
53
48
|
|
|
@@ -55,6 +50,7 @@ const parseArgv = (argv) => {
|
|
|
55
50
|
const paths = [];
|
|
56
51
|
let newReview = false;
|
|
57
52
|
let readOnly = false;
|
|
53
|
+
let theme = 'dark';
|
|
58
54
|
for (const arg of argv) {
|
|
59
55
|
if (arg === '-n') {
|
|
60
56
|
newReview = true;
|
|
@@ -64,12 +60,16 @@ const parseArgv = (argv) => {
|
|
|
64
60
|
readOnly = true;
|
|
65
61
|
continue;
|
|
66
62
|
}
|
|
63
|
+
if (arg === '-light') {
|
|
64
|
+
theme = 'light';
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
67
|
if (arg.startsWith('-')) {
|
|
68
68
|
throw new Error(`unknown option ${arg}`);
|
|
69
69
|
}
|
|
70
70
|
paths.push(arg);
|
|
71
71
|
}
|
|
72
|
-
return { paths, newReview, readOnly };
|
|
72
|
+
return { paths, newReview, readOnly, theme };
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
const looksLikeRev = (spec) => {
|
|
@@ -79,19 +79,10 @@ const looksLikeRev = (spec) => {
|
|
|
79
79
|
return RANGE_REV.test(spec);
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
-
const
|
|
83
|
-
try {
|
|
84
|
-
statSync(path.resolve(cwd, rel));
|
|
85
|
-
return true;
|
|
86
|
-
} catch {
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const resolveScope = (cwd, paths, repo, statSync = fs.statSync) => {
|
|
82
|
+
const resolveScope = async (cwd, paths, repo) => {
|
|
92
83
|
if (!paths.length) return { rev: null, paths };
|
|
93
84
|
const first = paths[0];
|
|
94
|
-
if (
|
|
85
|
+
if (await exists(path.resolve(cwd, first))) {
|
|
95
86
|
return { rev: null, paths };
|
|
96
87
|
}
|
|
97
88
|
const resolved = repo.resolveRev(cwd, first);
|
|
@@ -107,14 +98,11 @@ const resolveScope = (cwd, paths, repo, statSync = fs.statSync) => {
|
|
|
107
98
|
return { rev: null, paths };
|
|
108
99
|
};
|
|
109
100
|
|
|
110
|
-
const isColorEnabled = (stdout, env) => stdout.isTTY === true && !env.NO_COLOR;
|
|
111
|
-
|
|
112
101
|
const sessionOptions = (proc, deps, args, env, extra) => ({
|
|
113
102
|
cwd: deps.cwd ?? proc.cwd(),
|
|
114
103
|
stdin: proc.stdin,
|
|
115
104
|
stdout: proc.stdout,
|
|
116
|
-
color:
|
|
117
|
-
getSize: deps.getSize,
|
|
105
|
+
color: proc.stdout.isTTY === true && !env.NO_COLOR,
|
|
118
106
|
startPane: 'files',
|
|
119
107
|
newReview: args.newReview,
|
|
120
108
|
readOnly: args.readOnly,
|
|
@@ -122,22 +110,21 @@ const sessionOptions = (proc, deps, args, env, extra) => ({
|
|
|
122
110
|
...extra,
|
|
123
111
|
});
|
|
124
112
|
|
|
125
|
-
const openLocalSession = (proc, deps, args, selected, env) => {
|
|
113
|
+
const openLocalSession = async (proc, deps, args, selected, env) => {
|
|
126
114
|
const cwd = deps.cwd ?? proc.cwd();
|
|
127
115
|
const rawRepo = deps.repo ?? createGitRepo();
|
|
128
|
-
const
|
|
129
|
-
const scope = resolveScope(cwd, selected.paths, rawRepo, statSync);
|
|
116
|
+
const scope = await resolveScope(cwd, selected.paths, rawRepo);
|
|
130
117
|
const kind = scope.rev ? 'commit' : 'local';
|
|
131
118
|
const capabilities = capabilitiesFor(kind, { readOnly: args.readOnly });
|
|
132
119
|
const repo = attachCapabilities(rawRepo, capabilities);
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
);
|
|
120
|
+
const extra = {
|
|
121
|
+
repo,
|
|
122
|
+
paths: scope.paths,
|
|
123
|
+
rev: scope.rev,
|
|
124
|
+
capabilities,
|
|
125
|
+
};
|
|
126
|
+
const options = sessionOptions(proc, deps, args, env, extra);
|
|
127
|
+
const session = new Session(options);
|
|
141
128
|
session.ensureRepo();
|
|
142
129
|
return session;
|
|
143
130
|
};
|
|
@@ -168,13 +155,12 @@ const openRemoteSession = (proc, deps, args, selected, env) => {
|
|
|
168
155
|
const capabilities = capabilitiesFor(selected.kind, {
|
|
169
156
|
readOnly: args.readOnly,
|
|
170
157
|
});
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
);
|
|
158
|
+
const repo = remoteRepo(deps, selected, env, cwd);
|
|
159
|
+
const extra = { repo, paths: selected.paths, capabilities };
|
|
160
|
+
const options = sessionOptions(proc, deps, args, env, extra);
|
|
161
|
+
const session = new Session(options);
|
|
162
|
+
session.ensureRepo();
|
|
163
|
+
return session;
|
|
178
164
|
};
|
|
179
165
|
|
|
180
166
|
const loadSession = async (proc, deps, args) => {
|
|
@@ -200,8 +186,11 @@ const run = async (proc, deps = {}) => {
|
|
|
200
186
|
try {
|
|
201
187
|
args = parseArgv(proc.argv.slice(2));
|
|
202
188
|
} catch (error) {
|
|
203
|
-
|
|
189
|
+
fail(stderr, error);
|
|
190
|
+
stderr.write(`${USAGE}\n`);
|
|
191
|
+
return 1;
|
|
204
192
|
}
|
|
193
|
+
setTheme(args.theme);
|
|
205
194
|
let session;
|
|
206
195
|
try {
|
|
207
196
|
session = await loadSession(proc, deps, args);
|
|
@@ -224,7 +213,7 @@ const run = async (proc, deps = {}) => {
|
|
|
224
213
|
};
|
|
225
214
|
|
|
226
215
|
module.exports = {
|
|
227
|
-
|
|
216
|
+
errorMessage,
|
|
228
217
|
parseArgv,
|
|
229
218
|
resolveScope,
|
|
230
219
|
run,
|
package/lib/clipboard.js
CHANGED