reslop 0.1.5 → 0.1.7
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 +20 -1
- package/README.md +33 -21
- package/lib/ansi.js +1 -0
- package/lib/cli.js +20 -16
- package/lib/detect.js +2 -40
- package/lib/files.js +38 -5
- package/lib/git.js +343 -18
- package/lib/highlight/bash.js +228 -0
- package/lib/highlight/core.js +194 -0
- package/lib/highlight/css.js +76 -0
- package/lib/highlight/csv.js +66 -0
- package/lib/highlight/dart.js +261 -0
- package/lib/highlight/dot.js +54 -0
- package/lib/highlight/html.js +90 -0
- package/lib/highlight/js.js +571 -0
- package/lib/highlight/json.js +54 -0
- package/lib/highlight/log.js +60 -0
- package/lib/highlight/txt.js +41 -0
- package/lib/highlight.js +32 -1299
- package/lib/keys.js +111 -31
- package/lib/render.js +578 -57
- package/lib/review.js +6 -63
- package/lib/session.js +843 -202
- package/lib/sys.js +4 -0
- package/lib/update.js +302 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased][unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.1.7][] - 2026-09-16
|
|
6
|
+
|
|
7
|
+
- Make TODOs repo-wide, not per-file todos
|
|
8
|
+
- Improve TODO screen and files screen TUI/TUX including hotkeys
|
|
9
|
+
- Implement branch rebase and drop
|
|
10
|
+
- Improve branch screen TUI/TUX
|
|
11
|
+
- Fix TODOs autosave bug with todo duplication
|
|
12
|
+
|
|
13
|
+
## [0.1.6][] - 2026-09-15
|
|
14
|
+
|
|
15
|
+
- Auto updates for patch/minor, y/n per new major
|
|
16
|
+
- Lists branches, new branch, git pull, git push
|
|
17
|
+
- Show TUI progress for long background operations
|
|
18
|
+
- Fix Windows spawn EINVAL when running `npm.cmd`
|
|
19
|
+
- Highlight Dart diffs; refactor syntax highlighting
|
|
20
|
+
- Multiple TUI/TUX improvements and fixes
|
|
21
|
+
|
|
5
22
|
## [0.1.5][] - 2026-09-14
|
|
6
23
|
|
|
7
24
|
- Added `r` to reload diffs from disk
|
|
@@ -49,7 +66,9 @@
|
|
|
49
66
|
- Feedback and todos that produce a repair plan for an agent
|
|
50
67
|
- Intra-line highlighting in unified, mixed, and side-by-side layouts
|
|
51
68
|
|
|
52
|
-
[unreleased]: https://github.com/tshemsedinov/reslop/compare/v0.1.
|
|
69
|
+
[unreleased]: https://github.com/tshemsedinov/reslop/compare/v0.1.7...HEAD
|
|
70
|
+
[0.1.7]: https://github.com/tshemsedinov/reslop/compare/v0.1.6...v0.1.7
|
|
71
|
+
[0.1.6]: https://github.com/tshemsedinov/reslop/compare/v0.1.5...v0.1.6
|
|
53
72
|
[0.1.5]: https://github.com/tshemsedinov/reslop/compare/v0.1.4...v0.1.5
|
|
54
73
|
[0.1.4]: https://github.com/tshemsedinov/reslop/compare/v0.1.3...v0.1.4
|
|
55
74
|
[0.1.3]: https://github.com/tshemsedinov/reslop/compare/v0.1.2...v0.1.3
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# 👁️ reslop — Review
|
|
1
|
+
# 👁️ reslop — Review AI generated code and plan changes
|
|
2
2
|
|
|
3
3
|
[](https://github.com/tshemsedinov/reslop/actions?query=workflow%3A%22Testing+CI%22+branch%3Amain)
|
|
4
4
|
[](https://snyk.io/test/github/tshemsedinov/reslop)
|
|
@@ -16,12 +16,15 @@ for the agent.
|
|
|
16
16
|
Review → Plan → Repair → Verify
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
- Leave feedback, issues/todos, and in-place code proposals as a repair plan.
|
|
19
20
|
- Review uncommitted git diffs, a given commit, a GitHub PR, or a GitLab MR.
|
|
20
21
|
- Stage, unstage, or revert each contiguous block of diff lines.
|
|
21
|
-
- Leave feedback, todos, and in-place code proposals that become a repair plan.
|
|
22
22
|
- Import GitHub PR and GitLab MR review comments into the local plan for AI.
|
|
23
|
+
- Commit, amend, or fixup staged changes from the file list.
|
|
24
|
+
- Branches: checkout, create, rebase, drop, pull and push.
|
|
23
25
|
- Review each npm dependency once across `package.json` and the lockfile.
|
|
24
26
|
- Propose unused removals, npm audit fixes, and outdated updates as diffs.
|
|
27
|
+
- Code highlighting, diff compare: unified, mixed, and side-by-side layouts.
|
|
25
28
|
|
|
26
29
|
## Install
|
|
27
30
|
|
|
@@ -49,25 +52,34 @@ Reviews go in `.review/YYYY-MM-DD-NN.md` with frontmatter `status`:
|
|
|
49
52
|
|
|
50
53
|
## Hotkeys
|
|
51
54
|
|
|
52
|
-
| Key | Action
|
|
53
|
-
| ------------------- |
|
|
54
|
-
| `a`
|
|
55
|
-
| `
|
|
56
|
-
| `
|
|
57
|
-
| `
|
|
58
|
-
| `f`
|
|
59
|
-
| `
|
|
60
|
-
| `
|
|
61
|
-
|
|
|
62
|
-
| `
|
|
63
|
-
|
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
| `Ctrl-
|
|
67
|
-
|
|
|
68
|
-
| `
|
|
69
|
-
|
|
70
|
-
|
|
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
|
+
## Future
|
|
74
|
+
|
|
75
|
+
- Import issues from GitHub and GitLab.
|
|
76
|
+
- Security and code-quality audit; propose a repair plan.
|
|
77
|
+
- Send anonymized code blocks for expert review.
|
|
78
|
+
- Send questions and the repair plan to experts for approval.
|
|
79
|
+
- Ask experts.
|
|
80
|
+
- Verify the codebase.
|
|
81
|
+
- Apply refactoring skills.
|
|
82
|
+
- Call agents, harnesses, and IDEs to execute prepared plans.
|
|
71
83
|
|
|
72
84
|
## License
|
|
73
85
|
|
package/lib/ansi.js
CHANGED
package/lib/cli.js
CHANGED
|
@@ -143,29 +143,33 @@ const openLocalSession = (proc, deps, args, selected, env) => {
|
|
|
143
143
|
return session;
|
|
144
144
|
};
|
|
145
145
|
|
|
146
|
-
const
|
|
146
|
+
const remoteRepo = (deps, selected, env, cwd) => {
|
|
147
|
+
if (deps.repo) return deps.repo;
|
|
147
148
|
const remote = REMOTE_CHANGE[selected.kind];
|
|
148
|
-
const cwd = deps.cwd ?? proc.cwd();
|
|
149
149
|
const loader = deps[remote.load] ?? remote.fallback;
|
|
150
150
|
const token = remote.token(env);
|
|
151
|
-
const
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
151
|
+
const loadRemote = async () => {
|
|
152
|
+
const loaded = await loader(remote.target(selected), {
|
|
153
|
+
cwd,
|
|
154
|
+
paths: selected.paths,
|
|
155
|
+
token,
|
|
156
|
+
fetch: deps.fetch,
|
|
157
|
+
});
|
|
158
|
+
const items = loaded.items ?? [];
|
|
159
|
+
return { ...loaded, items: [...items] };
|
|
160
|
+
};
|
|
161
|
+
const repo = createLoadedSource({ items: [] });
|
|
162
|
+
repo.loadAsync = loadRemote;
|
|
163
|
+
return repo;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const openRemoteSession = (proc, deps, args, selected, env) => {
|
|
167
|
+
const cwd = deps.cwd ?? proc.cwd();
|
|
160
168
|
return startSession(
|
|
161
169
|
sessionOptions(proc, deps, args, env, {
|
|
162
|
-
repo,
|
|
170
|
+
repo: remoteRepo(deps, selected, env, cwd),
|
|
163
171
|
paths: selected.paths,
|
|
164
|
-
repoName: repository,
|
|
165
|
-
sourceLabel: loaded.sourceLabel,
|
|
166
|
-
change,
|
|
167
172
|
}),
|
|
168
|
-
{ load: true },
|
|
169
173
|
);
|
|
170
174
|
};
|
|
171
175
|
|
package/lib/detect.js
CHANGED
|
@@ -2,40 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const path = require('node:path');
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
md: 'md',
|
|
7
|
-
markdown: 'md',
|
|
8
|
-
js: 'js',
|
|
9
|
-
javascript: 'js',
|
|
10
|
-
mjs: 'mjs',
|
|
11
|
-
cjs: 'js',
|
|
12
|
-
ts: 'ts',
|
|
13
|
-
typescript: 'ts',
|
|
14
|
-
jsx: 'jsx',
|
|
15
|
-
tsx: 'tsx',
|
|
16
|
-
json: 'json',
|
|
17
|
-
csv: 'csv',
|
|
18
|
-
html: 'html',
|
|
19
|
-
htm: 'html',
|
|
20
|
-
css: 'css',
|
|
21
|
-
sh: 'bash',
|
|
22
|
-
bash: 'bash',
|
|
23
|
-
shell: 'bash',
|
|
24
|
-
zsh: 'bash',
|
|
25
|
-
txt: 'txt',
|
|
26
|
-
text: 'txt',
|
|
27
|
-
plain: 'txt',
|
|
28
|
-
log: 'log',
|
|
29
|
-
env: 'dot',
|
|
30
|
-
ini: 'dot',
|
|
31
|
-
conf: 'dot',
|
|
32
|
-
cfg: 'dot',
|
|
33
|
-
yaml: 'dot',
|
|
34
|
-
yml: 'dot',
|
|
35
|
-
toml: 'dot',
|
|
36
|
-
py: 'py',
|
|
37
|
-
python: 'py',
|
|
38
|
-
};
|
|
5
|
+
const { mapLang } = require('./highlight.js');
|
|
39
6
|
|
|
40
7
|
const PROSE_BASENAMES = [
|
|
41
8
|
'license',
|
|
@@ -53,11 +20,6 @@ const fileExt = (filePath) => {
|
|
|
53
20
|
return base.slice(dot + 1).toLowerCase();
|
|
54
21
|
};
|
|
55
22
|
|
|
56
|
-
const mapLang = (name) => {
|
|
57
|
-
if (!name) return 'txt';
|
|
58
|
-
return LANG[name.toLowerCase()] || 'txt';
|
|
59
|
-
};
|
|
60
|
-
|
|
61
23
|
const isProseBasename = (base) => {
|
|
62
24
|
const name = (base || '').toLowerCase();
|
|
63
25
|
if (PROSE_BASENAMES.includes(name)) return true;
|
|
@@ -79,7 +41,7 @@ const detectLang = (filePath) => {
|
|
|
79
41
|
if (rule.test(base)) return rule.lang;
|
|
80
42
|
}
|
|
81
43
|
const ext = fileExt(base);
|
|
82
|
-
if (ext) return
|
|
44
|
+
if (ext) return mapLang(ext);
|
|
83
45
|
return 'dot';
|
|
84
46
|
};
|
|
85
47
|
|
package/lib/files.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const REVIEW_DIR = '.review';
|
|
4
4
|
const ORIGIN_ORDER = ['staged', 'unstaged', 'untracked', 'commit', 'pr'];
|
|
5
|
+
const TODO_FILE = 'TODOs';
|
|
6
|
+
const REPO_TODOS_LABEL = 'Repository TODOs and Issues';
|
|
5
7
|
|
|
6
8
|
const normalizePathSpec = (spec) =>
|
|
7
9
|
`${spec ?? ''}`.replaceAll('\\', '/').replace(/\/+$/, '');
|
|
@@ -21,14 +23,34 @@ const itemPath = (item) => {
|
|
|
21
23
|
return item.file.newPath || item.file.oldPath || '';
|
|
22
24
|
};
|
|
23
25
|
|
|
26
|
+
const isTodoItem = (item) => !!(item && item.origin === 'todo');
|
|
27
|
+
|
|
28
|
+
const isTodosEntry = (entry) => !!(entry && entry.kind === 'todos');
|
|
29
|
+
|
|
30
|
+
const repoTodosLabel = () => REPO_TODOS_LABEL;
|
|
31
|
+
|
|
32
|
+
const makeTodoItem = () => ({
|
|
33
|
+
origin: 'todo',
|
|
34
|
+
file: {
|
|
35
|
+
oldPath: TODO_FILE,
|
|
36
|
+
newPath: TODO_FILE,
|
|
37
|
+
isNew: false,
|
|
38
|
+
isDeleted: false,
|
|
39
|
+
isBinary: false,
|
|
40
|
+
preamble: [],
|
|
41
|
+
hunks: [],
|
|
42
|
+
},
|
|
43
|
+
hunk: null,
|
|
44
|
+
blockId: 'todo',
|
|
45
|
+
patchAdd: '',
|
|
46
|
+
patchRevert: '',
|
|
47
|
+
});
|
|
48
|
+
|
|
24
49
|
const fileStatus = (origins) => {
|
|
25
50
|
const present = new Set(origins);
|
|
26
51
|
const seen = ORIGIN_ORDER.filter((origin) => present.has(origin));
|
|
27
52
|
const key = seen.join('+');
|
|
28
|
-
if (!key)
|
|
29
|
-
if (present.has('todo')) return 'todo';
|
|
30
|
-
return '';
|
|
31
|
-
}
|
|
53
|
+
if (!key) return '';
|
|
32
54
|
if (key === 'staged+unstaged') return 'partial';
|
|
33
55
|
return key;
|
|
34
56
|
};
|
|
@@ -51,12 +73,14 @@ const fileEntries = (items) => {
|
|
|
51
73
|
const groups = new Map();
|
|
52
74
|
for (let i = 0; i < items.length; i++) {
|
|
53
75
|
const item = items[i];
|
|
76
|
+
if (isTodoItem(item)) continue;
|
|
54
77
|
const rel = itemPath(item);
|
|
55
78
|
if (!groups.has(rel)) {
|
|
56
79
|
groups.set(rel, {
|
|
57
80
|
path: rel,
|
|
58
81
|
origins: [],
|
|
59
82
|
firstIndex: i,
|
|
83
|
+
openIndex: i,
|
|
60
84
|
remaining: 0,
|
|
61
85
|
added: 0,
|
|
62
86
|
removed: 0,
|
|
@@ -72,7 +96,10 @@ const fileEntries = (items) => {
|
|
|
72
96
|
group.added += delta.added;
|
|
73
97
|
group.removed += delta.removed;
|
|
74
98
|
if (origin === 'staged') group.staged += 1;
|
|
75
|
-
if (origin === 'unstaged')
|
|
99
|
+
if (origin === 'unstaged') {
|
|
100
|
+
if (group.unstaged === 0) group.openIndex = i;
|
|
101
|
+
group.unstaged += 1;
|
|
102
|
+
}
|
|
76
103
|
}
|
|
77
104
|
const entries = [...groups.values()];
|
|
78
105
|
for (const group of entries) {
|
|
@@ -83,8 +110,14 @@ const fileEntries = (items) => {
|
|
|
83
110
|
|
|
84
111
|
module.exports = {
|
|
85
112
|
REVIEW_DIR,
|
|
113
|
+
TODO_FILE,
|
|
114
|
+
REPO_TODOS_LABEL,
|
|
86
115
|
isPathInScope,
|
|
87
116
|
itemPath,
|
|
117
|
+
isTodoItem,
|
|
118
|
+
isTodosEntry,
|
|
119
|
+
repoTodosLabel,
|
|
120
|
+
makeTodoItem,
|
|
88
121
|
fileStatus,
|
|
89
122
|
fileEntries,
|
|
90
123
|
};
|