reslop 0.1.7 → 0.1.9
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 +32 -1
- package/README.md +26 -38
- package/bin/reslop.js +3 -1
- package/lib/ansi.js +2 -0
- package/lib/capabilities.js +109 -0
- package/lib/cli.js +18 -14
- package/lib/deps/changes.js +422 -0
- package/lib/deps/items.js +134 -0
- package/lib/deps/manifest.js +152 -0
- package/lib/deps/merge.js +120 -0
- package/lib/deps/proposals.js +164 -0
- package/lib/deps/reports.js +180 -0
- package/lib/deps/rows.js +176 -0
- package/lib/deps/scan.js +138 -0
- package/lib/deps/usage.js +68 -0
- package/lib/deps/versions.js +119 -0
- package/lib/deps.js +117 -1345
- package/lib/diff/align.js +226 -0
- package/lib/diff/display.js +101 -0
- package/lib/diff/edit.js +47 -0
- package/lib/diff/inline.js +300 -0
- package/lib/diff/items.js +101 -0
- package/lib/diff/parse.js +156 -0
- package/lib/diff/patch.js +103 -0
- package/lib/diff.js +13 -932
- package/lib/editor.js +37 -0
- package/lib/files.js +118 -4
- package/lib/git/branches.js +383 -0
- package/lib/git/changes.js +164 -0
- package/lib/git/dependencies.js +489 -0
- package/lib/git/proc.js +162 -0
- package/lib/git/read.js +253 -0
- package/lib/git/run.js +100 -0
- package/lib/git.js +88 -1193
- package/lib/github.js +92 -222
- package/lib/gitlab.js +72 -216
- package/lib/highlight/bash.js +5 -9
- package/lib/highlight/core.js +1 -1
- package/lib/highlight/css.js +1 -3
- package/lib/highlight/csv.js +1 -3
- package/lib/highlight/dart.js +6 -20
- package/lib/highlight/dot.js +13 -13
- package/lib/highlight/html.js +1 -5
- package/lib/highlight/js.js +151 -115
- package/lib/highlight/json.js +1 -3
- package/lib/highlight/log.js +1 -3
- package/lib/highlight/txt.js +5 -10
- package/lib/highlight.js +4 -4
- package/lib/keys.js +67 -168
- package/lib/npm/commands.js +100 -0
- package/lib/remote/changes.js +37 -0
- package/lib/remote/headers.js +36 -0
- package/lib/remote/http.js +122 -0
- package/lib/remote/notes.js +94 -0
- package/lib/render/branches.js +240 -0
- package/lib/render/chrome.js +595 -0
- package/lib/render/commits.js +138 -0
- package/lib/render/diff.js +307 -0
- package/lib/render/files.js +186 -0
- package/lib/render/frame.js +202 -0
- package/lib/render/notes.js +201 -0
- package/lib/render/present.js +25 -0
- package/lib/render/primitives.js +200 -0
- package/lib/render.js +13 -1688
- package/lib/review/format.js +434 -0
- package/lib/review/storage.js +150 -0
- package/lib/review/store.js +178 -0
- package/lib/review/templates.js +49 -0
- package/lib/review.js +14 -747
- package/lib/select.js +3 -5
- package/lib/session/accessors.js +25 -0
- package/lib/session/actions.js +316 -0
- package/lib/session/branches.js +302 -0
- package/lib/session/change-actions.js +323 -0
- package/lib/session/commit.js +286 -0
- package/lib/session/compose.js +540 -0
- package/lib/session/dispatch.js +115 -0
- package/lib/session/files-pane.js +243 -0
- package/lib/session/items.js +282 -0
- package/lib/session/lifecycle.js +516 -0
- package/lib/session/load.js +85 -0
- package/lib/session/navigation.js +94 -0
- package/lib/session/ops.js +110 -0
- package/lib/session/origins.js +7 -0
- package/lib/session/pointer.js +161 -0
- package/lib/session/progress.js +29 -0
- package/lib/session/review.js +88 -0
- package/lib/session/templates.js +64 -0
- package/lib/session/terminal.js +169 -0
- package/lib/session/todos.js +269 -0
- package/lib/session/update.js +125 -0
- package/lib/session/view.js +131 -0
- package/lib/session/watch.js +219 -0
- package/lib/session.js +598 -2350
- package/lib/source.js +11 -11
- package/lib/sys.js +25 -4
- package/lib/wrap.js +4 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased][unreleased]
|
|
4
4
|
|
|
5
|
+
- Remove `r` reload hotkey and hint; auto-reload covers disk changes
|
|
6
|
+
- Improve branch list TUI/TUX
|
|
7
|
+
- Right-align the time column in the branch list
|
|
8
|
+
- Refresh the branch list after push, pull, and rebase
|
|
9
|
+
- Keep diff viewer order when staging or unstaging a block
|
|
10
|
+
- Add a commits list screen with commit operation
|
|
11
|
+
- Show staged/total rather than staged/unstaged in files list
|
|
12
|
+
- Show file ages in the file list right-aligned
|
|
13
|
+
- Sort the file list by path from the repo root
|
|
14
|
+
- Update file-list hotkeys and hints
|
|
15
|
+
- Fix dependency updates, locks and audit
|
|
16
|
+
|
|
17
|
+
## [0.1.8][] - 2026-09-17
|
|
18
|
+
|
|
19
|
+
- Simplify session controllers, input dispatch, and loading orchestration
|
|
20
|
+
- Enforce structural limits and session dependency direction on library files
|
|
21
|
+
- Show staged/unstaged +/- and staged/remaining totals in status line
|
|
22
|
+
- Jump by word with Ctrl+Left/Right in all text editors
|
|
23
|
+
- Support PgUp, PgDn, Home, and End in lists and multiline editors
|
|
24
|
+
- Support mouse click in submenu and confirmation choices on the hint line
|
|
25
|
+
- Fix TODO wrapped text; keep up/down navigation inside a multiline todos
|
|
26
|
+
- Fix identifier diffs as whole words compare, not just letters
|
|
27
|
+
- Keep reslop open when a local repo has no unstaged changes
|
|
28
|
+
- Fix invisible cursor movement in scrolling diffs
|
|
29
|
+
- Auto-reload worktree on disk changes, keeping the current UI state
|
|
30
|
+
- Fix disk watch paths on Windows
|
|
31
|
+
- Set git push upstream to `origin <branch>` when missing
|
|
32
|
+
- Save in-place diff edits to the reviewed file
|
|
33
|
+
|
|
5
34
|
## [0.1.7][] - 2026-09-16
|
|
6
35
|
|
|
7
36
|
- Make TODOs repo-wide, not per-file todos
|
|
@@ -66,7 +95,9 @@
|
|
|
66
95
|
- Feedback and todos that produce a repair plan for an agent
|
|
67
96
|
- Intra-line highlighting in unified, mixed, and side-by-side layouts
|
|
68
97
|
|
|
69
|
-
[unreleased]: https://github.com/tshemsedinov/reslop/compare/v0.1.
|
|
98
|
+
[unreleased]: https://github.com/tshemsedinov/reslop/compare/v0.1.9...HEAD
|
|
99
|
+
[0.1.9]: https://github.com/tshemsedinov/reslop/compare/v0.1.8...v0.1.9
|
|
100
|
+
[0.1.8]: https://github.com/tshemsedinov/reslop/compare/v0.1.7...v0.1.8
|
|
70
101
|
[0.1.7]: https://github.com/tshemsedinov/reslop/compare/v0.1.6...v0.1.7
|
|
71
102
|
[0.1.6]: https://github.com/tshemsedinov/reslop/compare/v0.1.5...v0.1.6
|
|
72
103
|
[0.1.5]: https://github.com/tshemsedinov/reslop/compare/v0.1.4...v0.1.5
|
package/README.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
# 👁️ reslop
|
|
1
|
+
# 👁️ reslop
|
|
2
|
+
|
|
3
|
+
## Review AI generated code and plan changes
|
|
2
4
|
|
|
3
5
|
[](https://github.com/tshemsedinov/reslop/actions?query=workflow%3A%22Testing+CI%22+branch%3Amain)
|
|
4
6
|
[](https://snyk.io/test/github/tshemsedinov/reslop)
|
|
@@ -16,15 +18,18 @@ for the agent.
|
|
|
16
18
|
Review → Plan → Repair → Verify
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
- Leave feedback, issues/todos, and in-place code proposals as a repair plan
|
|
20
|
-
- Review uncommitted git diffs, a given commit, a GitHub PR, or a GitLab MR
|
|
21
|
-
- Stage, unstage, or revert each contiguous block of diff lines
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
21
|
+
- Leave feedback, issues/todos, and in-place code proposals as a repair plan
|
|
22
|
+
- Review uncommitted git diffs, a given commit, a GitHub PR, or a GitLab MR
|
|
23
|
+
- Stage, unstage, or revert each contiguous block of diff lines
|
|
24
|
+
- Auto-reload local diffs when files change, keeping the current screen
|
|
25
|
+
- Import GitHub PR and GitLab MR review comments into the local plan for AI
|
|
26
|
+
- Commits list: commit, amend, fixup, and drop
|
|
27
|
+
- Branches: checkout, create, rebase, drop, pull, and push
|
|
28
|
+
- Review each npm dependency once across `package.json` and the lockfile
|
|
29
|
+
- Propose unused removals, npm audit fixes, and outdated updates as diffs
|
|
30
|
+
- Code highlighting and intra-line diffs: unified, mixed, and side-by-side
|
|
31
|
+
- Auto-update patch and minor releases; confirm a new major
|
|
32
|
+
- Work with git, npm and fetch in background
|
|
28
33
|
|
|
29
34
|
## Install
|
|
30
35
|
|
|
@@ -50,36 +55,19 @@ Reviews go in `.review/YYYY-MM-DD-NN.md` with frontmatter `status`:
|
|
|
50
55
|
- `partial`: AI started; some items remain
|
|
51
56
|
- `done`: all items marked `[x]`
|
|
52
57
|
|
|
53
|
-
## Hotkeys
|
|
54
|
-
|
|
55
|
-
| Key | Action |
|
|
56
|
-
| ------------------- | --------------------------------------------- |
|
|
57
|
-
| `a` / `u` / `d` | Stage / unstage / drop this diff |
|
|
58
|
-
| `c` | File list: `c` commit / `a` amend / `f` fixup |
|
|
59
|
-
| `b` | List branches; `n` new; `r` rebase; `d` drop |
|
|
60
|
-
| `p` / `s` | git pull/push |
|
|
61
|
-
| `f` / `t` / `e` | Feedback / repo todo / edit added lines |
|
|
62
|
-
| `r` | Reload diffs from disk |
|
|
63
|
-
| `m` | Mode: unified / mixed / side-by-side |
|
|
64
|
-
| `⏎` | Open the selected file |
|
|
65
|
-
| `→` / `j` | Next remaining diff / file |
|
|
66
|
-
| `←` / `k` | Previous remaining diff / file |
|
|
67
|
-
| `Ctrl-e` / `Ctrl-y` | Scroll one line down / up |
|
|
68
|
-
| `Ctrl-f` / `Ctrl-b` | Scroll page down / up |
|
|
69
|
-
| `Ctrl-d` / `Ctrl-u` | Scroll half-page down / up |
|
|
70
|
-
| `⌫` / `Del` | Remove the selected todo |
|
|
71
|
-
| `Esc` / `q` | Quit |
|
|
72
|
-
|
|
73
58
|
## Future
|
|
74
59
|
|
|
75
|
-
- Import issues from GitHub and GitLab
|
|
76
|
-
-
|
|
77
|
-
-
|
|
78
|
-
- Send
|
|
79
|
-
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
60
|
+
- Import issues from GitHub and GitLab
|
|
61
|
+
- Search, blame, and file history in the review
|
|
62
|
+
- Security and code-quality audit; propose a repair plan
|
|
63
|
+
- Send anonymized code blocks for expert review
|
|
64
|
+
- Send questions and the repair plan to experts for approval
|
|
65
|
+
- Ask experts
|
|
66
|
+
- Verify the codebase
|
|
67
|
+
- Apply refactoring skills
|
|
68
|
+
- Call agents, harnesses, and IDEs to execute prepared plans
|
|
69
|
+
- Squash, cherry-pick, and interactive rebase
|
|
70
|
+
- Merge, rename, and conflict resolution
|
|
83
71
|
|
|
84
72
|
## License
|
|
85
73
|
|
package/bin/reslop.js
CHANGED
package/lib/ansi.js
CHANGED
|
@@ -67,6 +67,7 @@ const THEME = {
|
|
|
67
67
|
buttonFg: [0x6a, 0x6a, 0x7e],
|
|
68
68
|
buttonBg: [0x2a, 0x2a, 0x40],
|
|
69
69
|
buttonHotFg: [0xff, 0xff, 0xff],
|
|
70
|
+
currentBg: [0xa8, 0xcc, 0xb4],
|
|
70
71
|
checkFg: [0xf4, 0xf4, 0xfc],
|
|
71
72
|
checkBg: [0x52, 0x52, 0x74],
|
|
72
73
|
checkDoneFg: [0xf0, 0xff, 0xf4],
|
|
@@ -75,6 +76,7 @@ const THEME = {
|
|
|
75
76
|
warnFg: [0xe8, 0xc8, 0x4a],
|
|
76
77
|
mutedFg: [0x7a, 0x7a, 0x8a],
|
|
77
78
|
shaFg: [0x56, 0x9c, 0xd6],
|
|
79
|
+
shaDarkFg: [0x15, 0x4a, 0x8c],
|
|
78
80
|
stagedDelLineFg: [0xa0, 0xa0, 0xa8],
|
|
79
81
|
stagedDelLineBg: [0x20, 0x20, 0x26],
|
|
80
82
|
stagedDelCharFg: [0xf0, 0xf0, 0xf4],
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
|
|
5
|
+
const READ_METHODS = [
|
|
6
|
+
'load',
|
|
7
|
+
'loadAsync',
|
|
8
|
+
'loadExtras',
|
|
9
|
+
'toplevel',
|
|
10
|
+
'resolveRev',
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const CHANGE_METHODS = [
|
|
14
|
+
'add',
|
|
15
|
+
'addAsync',
|
|
16
|
+
'unstage',
|
|
17
|
+
'revert',
|
|
18
|
+
'revertFile',
|
|
19
|
+
'edit',
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
const BRANCH_METHODS = [
|
|
23
|
+
'commit',
|
|
24
|
+
'commitAsync',
|
|
25
|
+
'hasStaged',
|
|
26
|
+
'lastMessage',
|
|
27
|
+
'listBranches',
|
|
28
|
+
'listCommits',
|
|
29
|
+
'currentBranch',
|
|
30
|
+
'checkout',
|
|
31
|
+
'checkoutAsync',
|
|
32
|
+
'createBranch',
|
|
33
|
+
'createBranchAsync',
|
|
34
|
+
'rebase',
|
|
35
|
+
'rebaseAsync',
|
|
36
|
+
'drop',
|
|
37
|
+
'dropAsync',
|
|
38
|
+
'dropCommit',
|
|
39
|
+
'dropCommitAsync',
|
|
40
|
+
'pull',
|
|
41
|
+
'pullAsync',
|
|
42
|
+
'push',
|
|
43
|
+
'pushAsync',
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const SOURCE_CAPS = {
|
|
47
|
+
local: { read: true, changes: true, branches: true, review: true },
|
|
48
|
+
commit: { read: true, changes: false, branches: false, review: true },
|
|
49
|
+
'github-pr': { read: true, changes: false, branches: false, review: true },
|
|
50
|
+
'gitlab-mr': { read: true, changes: false, branches: false, review: true },
|
|
51
|
+
'read-only': { read: true, changes: false, branches: false, review: true },
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const withReadOnly = (caps, readOnly) => {
|
|
55
|
+
if (!readOnly) return { ...caps };
|
|
56
|
+
return { ...caps, changes: false, branches: false };
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const capabilitiesFor = (kind, extra = {}) => {
|
|
60
|
+
const base = SOURCE_CAPS[kind] ?? SOURCE_CAPS.local;
|
|
61
|
+
return withReadOnly(base, extra.readOnly === true);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const copyMethods = (target, source, names) => {
|
|
65
|
+
for (const name of names) {
|
|
66
|
+
const method = source[name];
|
|
67
|
+
if (typeof method === 'function') target[name] = method;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const attachCapabilities = (impl, caps) => {
|
|
72
|
+
const source = { capabilities: { ...caps } };
|
|
73
|
+
if (caps.read) copyMethods(source, impl, READ_METHODS);
|
|
74
|
+
if (caps.changes) copyMethods(source, impl, CHANGE_METHODS);
|
|
75
|
+
if (caps.branches) copyMethods(source, impl, BRANCH_METHODS);
|
|
76
|
+
return source;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const sessionCapabilities = (options) => {
|
|
80
|
+
const readOnly = options.readOnly === true;
|
|
81
|
+
if (options.capabilities) return withReadOnly(options.capabilities, readOnly);
|
|
82
|
+
if (options.rev) return capabilitiesFor('commit', { readOnly });
|
|
83
|
+
const source = options.change && options.change.source;
|
|
84
|
+
if (source && SOURCE_CAPS[source]) {
|
|
85
|
+
return capabilitiesFor(source, { readOnly });
|
|
86
|
+
}
|
|
87
|
+
const repoCaps = options.repo && options.repo.capabilities;
|
|
88
|
+
if (repoCaps) return withReadOnly(repoCaps, readOnly);
|
|
89
|
+
return capabilitiesFor(readOnly ? 'read-only' : 'local');
|
|
90
|
+
};
|
|
91
|
+
|
|
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
|
+
module.exports = {
|
|
100
|
+
READ_METHODS,
|
|
101
|
+
CHANGE_METHODS,
|
|
102
|
+
BRANCH_METHODS,
|
|
103
|
+
SOURCE_CAPS,
|
|
104
|
+
capabilitiesFor,
|
|
105
|
+
withReadOnly,
|
|
106
|
+
attachCapabilities,
|
|
107
|
+
sessionCapabilities,
|
|
108
|
+
createReviewStorage,
|
|
109
|
+
};
|
package/lib/cli.js
CHANGED
|
@@ -8,6 +8,7 @@ const { githubToken, loadPullRequest } = require('./github.js');
|
|
|
8
8
|
const { gitlabToken, loadMergeRequest } = require('./gitlab.js');
|
|
9
9
|
const { selectChangeSource, createLoadedSource } = require('./source.js');
|
|
10
10
|
const { Session } = require('./session.js');
|
|
11
|
+
const { capabilitiesFor, attachCapabilities } = require('./capabilities.js');
|
|
11
12
|
|
|
12
13
|
const HEX_REV = /^[0-9a-f]{4,40}$/i;
|
|
13
14
|
const HEAD_REV = /^HEAD([~^].*)?$/i;
|
|
@@ -121,22 +122,20 @@ const sessionOptions = (proc, deps, args, env, extra) => ({
|
|
|
121
122
|
...extra,
|
|
122
123
|
});
|
|
123
124
|
|
|
124
|
-
const startSession = (options, extra = {}) => {
|
|
125
|
-
const session = new Session(options);
|
|
126
|
-
if (extra.load) session.load();
|
|
127
|
-
return session;
|
|
128
|
-
};
|
|
129
|
-
|
|
130
125
|
const openLocalSession = (proc, deps, args, selected, env) => {
|
|
131
126
|
const cwd = deps.cwd ?? proc.cwd();
|
|
132
|
-
const
|
|
127
|
+
const rawRepo = deps.repo ?? createGitRepo();
|
|
133
128
|
const statSync = deps.statSync ?? fs.statSync;
|
|
134
|
-
const scope = resolveScope(cwd, selected.paths,
|
|
135
|
-
const
|
|
129
|
+
const scope = resolveScope(cwd, selected.paths, rawRepo, statSync);
|
|
130
|
+
const kind = scope.rev ? 'commit' : 'local';
|
|
131
|
+
const capabilities = capabilitiesFor(kind, { readOnly: args.readOnly });
|
|
132
|
+
const repo = attachCapabilities(rawRepo, capabilities);
|
|
133
|
+
const session = new Session(
|
|
136
134
|
sessionOptions(proc, deps, args, env, {
|
|
137
135
|
repo,
|
|
138
136
|
paths: scope.paths,
|
|
139
137
|
rev: scope.rev,
|
|
138
|
+
capabilities,
|
|
140
139
|
}),
|
|
141
140
|
);
|
|
142
141
|
session.ensureRepo();
|
|
@@ -148,27 +147,32 @@ const remoteRepo = (deps, selected, env, cwd) => {
|
|
|
148
147
|
const remote = REMOTE_CHANGE[selected.kind];
|
|
149
148
|
const loader = deps[remote.load] ?? remote.fallback;
|
|
150
149
|
const token = remote.token(env);
|
|
151
|
-
const loadRemote = async () => {
|
|
150
|
+
const loadRemote = async (_cwd, _paths, options = {}) => {
|
|
152
151
|
const loaded = await loader(remote.target(selected), {
|
|
153
152
|
cwd,
|
|
154
153
|
paths: selected.paths,
|
|
155
154
|
token,
|
|
156
155
|
fetch: deps.fetch,
|
|
156
|
+
signal: options.signal,
|
|
157
157
|
});
|
|
158
158
|
const items = loaded.items ?? [];
|
|
159
159
|
return { ...loaded, items: [...items] };
|
|
160
160
|
};
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
return createLoadedSource({ items: [] }, selected.kind, {
|
|
162
|
+
loadAsync: loadRemote,
|
|
163
|
+
});
|
|
164
164
|
};
|
|
165
165
|
|
|
166
166
|
const openRemoteSession = (proc, deps, args, selected, env) => {
|
|
167
167
|
const cwd = deps.cwd ?? proc.cwd();
|
|
168
|
-
|
|
168
|
+
const capabilities = capabilitiesFor(selected.kind, {
|
|
169
|
+
readOnly: args.readOnly,
|
|
170
|
+
});
|
|
171
|
+
return new Session(
|
|
169
172
|
sessionOptions(proc, deps, args, env, {
|
|
170
173
|
repo: remoteRepo(deps, selected, env, cwd),
|
|
171
174
|
paths: selected.paths,
|
|
175
|
+
capabilities,
|
|
172
176
|
}),
|
|
173
177
|
);
|
|
174
178
|
};
|