reslop 0.1.1 → 0.1.3

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 CHANGED
@@ -2,24 +2,39 @@
2
2
 
3
3
  ## [Unreleased][unreleased]
4
4
 
5
+ ## [0.1.3][] - 2026-09-12
6
+
7
+ - Showed added/removed and staged/total counts in the file list
8
+ - Highlighted JSX and TSX syntax, including
9
+ - Added vim-style j/k navigation and Ctrl scrolling
10
+ - Improved TUI/UX with background git and npm checks to avoid a freeze
11
+
12
+ ## [0.1.2][] - 2026-09-11
13
+
14
+ - Review each dependency once across package.json and package-lock
15
+ - Mark unused npm dependencies that are not imported or used
16
+ - Propose unused dependency removals and run npm uninstall
17
+ - Mark dependency review items and show npm audit findings
18
+ - Show npm outdated and npm audit updates as proposed diffs
19
+ - Propose a lockfile version bump for transitive dependencies
20
+
5
21
  ## [0.1.1][] - 2026-09-10
6
22
 
7
23
  - Open a GitHub pull request by URL and review its diff
8
24
  - Import GitHub pull request review comments into the local review
9
25
  - Improve TUI navigation and hotkeys
10
26
  - CLI simplification and optimisation
11
- - Dix diff highlighting for snake_case identifier changes
27
+ - Fix diff highlighting for snake_case identifier changes
12
28
  - Updated package metadata and README
13
29
 
14
30
  ## [0.1.0][] - 2026-09-07
15
31
 
16
- ### Added
17
-
18
- - Interactive terminal review of uncommitted git diffs with stage, unstage,
19
- revert, and skip
32
+ - Interactive review of uncommitted git diffs with stage, unstage, revert
20
33
  - Feedback and todos that produce a repair plan for an agent
21
34
  - Intra-line highlighting in unified, mixed, and side-by-side layouts
22
35
 
23
- [unreleased]: https://github.com/tshemsedinov/reslop/compare/v0.1.1...HEAD
36
+ [unreleased]: https://github.com/tshemsedinov/reslop/compare/v0.1.3...HEAD
37
+ [0.1.3]: https://github.com/tshemsedinov/reslop/compare/v0.1.2...v0.1.3
38
+ [0.1.2]: https://github.com/tshemsedinov/reslop/compare/v0.1.1...v0.1.2
24
39
  [0.1.1]: https://github.com/tshemsedinov/reslop/compare/v0.1.0...v0.1.1
25
40
  [0.1.0]: https://github.com/tshemsedinov/reslop/releases/tag/v0.1.0
package/README.md CHANGED
@@ -2,20 +2,22 @@
2
2
 
3
3
  > Turn generated changes into owned changes
4
4
 
5
+ Open a change, leave findings and todos, and prepare a repair plan
6
+ for the agent.
7
+
5
8
  ```text
6
9
  Review → Plan → Repair → Verify
7
10
  ```
8
11
 
9
- `0.1.x` implements Review: open a change, leave findings and todos, and
10
- prepare a repair plan for the agent. Plan, repair, and verify come later.
11
-
12
- - Prepare review findings and a repair plan for the agent.
13
- - Leave feedback, add todos.
14
- - Generate a plan the agent executes.
12
+ - Review uncommitted git diffs, a given commit, or a GitHub pull request.
13
+ - Stage, unstage, or revert each contiguous block of diff lines.
14
+ - Leave feedback and todos that become a repair plan for the agent.
15
+ - Import GitHub pull request review comments into the local plan for AI.
16
+ - Review each npm dependency once across `package.json` and the lockfile.
17
+ - Propose unused removals, npm audit fixes, and outdated updates as diffs.
15
18
 
16
- Walk uncommitted git changes, a given commit, or a GitHub pull request.
17
- Each contiguous block of diff lines can be staged, unstaged, reverted;
18
- add review and todos. Commit and pull request review is read-only.
19
+ Commit and pull request review is read-only. Applying a dependency
20
+ proposal stages the files and runs `npm i` or `npm uninstall`.
19
21
 
20
22
  Intra-line highlighting paints the words that actually changed in a
21
23
  stronger red/green. A close edit inside one word still marks only
@@ -46,23 +48,24 @@ Reviews go in `.review/YYYY-MM-DD-NN.md` with frontmatter `status`:
46
48
 
47
49
  ## Keys and buttons
48
50
 
49
- | Key | Action |
50
- | ----------- | --------------------------------------- |
51
- | `a` | Stage this block (`git add`) |
52
- | `u` | Unstage this block (keep worktree) |
53
- | `r` | Restore this block to the last commit |
54
- | `s` | Skip (leave unstaged, drop from review) |
55
- | `←` | Previous remaining block |
56
- | `→` | Next remaining block |
57
- | `l` | File list (git status of this scope) |
58
- | `Esc` | Quit file list or a tool |
59
- | `m` | Cycle unified / mixed / side-by-side |
60
- | `f` | Feedback on this diff block |
61
- | `t` | New todo for this file |
62
- | `⌫` / `Del` | Remove the selected todo |
63
- | `⏎` | Open the selected file |
64
- | `q` | Quit |
65
- | `?` | Help |
51
+ | Key | Action |
52
+ | ------------------- | ---------------------------------------- |
53
+ | `a` | Stage this block (`git add`) |
54
+ | `u` | Unstage this block (keep worktree) |
55
+ | `r` | Restore this block to the last commit |
56
+ | `f` | Feedback on this diff block |
57
+ | `t` | New todo for this file |
58
+ | `l` | File list (git status of this scope) |
59
+ | `m` | Cycle unified / mixed / side-by-side |
60
+ | `⏎` | Open the selected file |
61
+ | `Esc` | Quit file list or a tool |
62
+ | `→` / `j` | Next remaining block / next file |
63
+ | `←` / `k` | Previous remaining block / previous file |
64
+ | `Ctrl-e` / `Ctrl-y` | Scroll one line down / up |
65
+ | `Ctrl-f` / `Ctrl-b` | Scroll page down / up |
66
+ | `Ctrl-d` / `Ctrl-u` | Scroll half-page down / up |
67
+ | `⌫` / `Del` | Remove the selected todo |
68
+ | `q` | Quit |
66
69
 
67
70
  ## License
68
71
 
package/bin/reslop.js CHANGED
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- const { run, errorMessage } = require('../lib/cli.js');
4
+ const { run, failLine } = require('../lib/cli.js');
5
5
  const { LEAVE_TERM } = require('../lib/session.js');
6
6
 
7
7
  const fail = (reason) => {
8
8
  try {
9
9
  process.stdout.write(LEAVE_TERM);
10
10
  } catch {}
11
- process.stderr.write(`reslop: ${errorMessage(reason)}\n`);
11
+ process.stderr.write(failLine(reason));
12
12
  process.exit(1);
13
13
  };
14
14
 
package/lib/ansi.js CHANGED
@@ -217,7 +217,6 @@ module.exports = {
217
217
  EL,
218
218
  THEME,
219
219
  CODE_FG,
220
- LOG_COL_FG,
221
220
  codeFg,
222
221
  fg,
223
222
  bg,
package/lib/cli.js CHANGED
@@ -21,8 +21,10 @@ const errorMessage = (reason) => {
21
21
  return `${reason}`;
22
22
  };
23
23
 
24
+ const failLine = (reason) => `reslop: ${errorMessage(reason)}\n`;
25
+
24
26
  const fail = (stderr, reason) => {
25
- stderr.write(`reslop: ${errorMessage(reason)}\n`);
27
+ stderr.write(failLine(reason));
26
28
  return 1;
27
29
  };
28
30
 
@@ -70,7 +72,7 @@ const resolveScope = (cwd, paths, repo, statSync = fs.statSync) => {
70
72
  if (pathExists(cwd, first, statSync)) {
71
73
  return { rev: null, paths };
72
74
  }
73
- const resolved = repo.resolveRev ? repo.resolveRev(cwd, first) : null;
75
+ const resolved = repo.resolveRev(cwd, first);
74
76
  if (resolved) {
75
77
  if (paths.length > 1) {
76
78
  throw new Error('use a commit or a path, not both');
@@ -85,30 +87,41 @@ const resolveScope = (cwd, paths, repo, statSync = fs.statSync) => {
85
87
 
86
88
  const isColorEnabled = (stdout, env) => stdout.isTTY === true && !env.NO_COLOR;
87
89
 
88
- const openLocalSession = (proc, deps, args, env) => {
89
- const stdout = proc.stdout;
90
- const repo = deps.repo ?? createGitRepo();
90
+ const sessionOptions = (proc, deps, args, env, extra) => ({
91
+ cwd: deps.cwd ?? proc.cwd(),
92
+ stdin: proc.stdin,
93
+ stdout: proc.stdout,
94
+ color: isColorEnabled(proc.stdout, env),
95
+ getSize: deps.getSize,
96
+ startPane: 'files',
97
+ newReview: args.newReview,
98
+ audit: true,
99
+ ...extra,
100
+ });
101
+
102
+ const startSession = (options, extra = {}) => {
103
+ const session = new Session(options);
104
+ if (extra.load) session.load();
105
+ return session;
106
+ };
107
+
108
+ const openLocalSession = (proc, deps, args, selected, env) => {
91
109
  const cwd = deps.cwd ?? proc.cwd();
110
+ const repo = deps.repo ?? createGitRepo();
92
111
  const statSync = deps.statSync ?? fs.statSync;
93
- const scope = resolveScope(cwd, args.paths, repo, statSync);
94
- const session = new Session({
95
- repo,
96
- cwd,
97
- paths: scope.paths,
98
- rev: scope.rev,
99
- stdin: proc.stdin,
100
- stdout,
101
- color: isColorEnabled(stdout, env),
102
- getSize: deps.getSize,
103
- startPane: 'files',
104
- newReview: args.newReview,
105
- });
106
- session.load();
112
+ const scope = resolveScope(cwd, selected.paths, repo, statSync);
113
+ const session = startSession(
114
+ sessionOptions(proc, deps, args, env, {
115
+ repo,
116
+ paths: scope.paths,
117
+ rev: scope.rev,
118
+ }),
119
+ );
120
+ session.ensureRepo();
107
121
  return session;
108
122
  };
109
123
 
110
124
  const openPullRequestSession = async (proc, deps, args, selected, env) => {
111
- const stdout = proc.stdout;
112
125
  const cwd = deps.cwd ?? proc.cwd();
113
126
  const loader = deps.loadPullRequest ?? loadPullRequest;
114
127
  const token = githubToken(env);
@@ -117,27 +130,20 @@ const openPullRequestSession = async (proc, deps, args, selected, env) => {
117
130
  paths: selected.paths,
118
131
  token,
119
132
  fetch: deps.fetch,
120
- env,
121
133
  });
122
134
  const change = loaded.change ?? null;
123
135
  const repository = change ? change.repository : '';
124
136
  const repo = deps.repo ?? createLoadedSource(loaded);
125
- const session = new Session({
126
- repo,
127
- cwd,
128
- paths: selected.paths,
129
- stdin: proc.stdin,
130
- stdout,
131
- color: isColorEnabled(stdout, env),
132
- getSize: deps.getSize,
133
- startPane: 'files',
134
- newReview: args.newReview,
135
- repoName: repository,
136
- sourceLabel: loaded.sourceLabel,
137
- change,
138
- });
139
- session.load();
140
- return session;
137
+ return startSession(
138
+ sessionOptions(proc, deps, args, env, {
139
+ repo,
140
+ paths: selected.paths,
141
+ repoName: repository,
142
+ sourceLabel: loaded.sourceLabel,
143
+ change,
144
+ }),
145
+ { load: true },
146
+ );
141
147
  };
142
148
 
143
149
  const loadSession = async (proc, deps, args) => {
@@ -146,7 +152,14 @@ const loadSession = async (proc, deps, args) => {
146
152
  if (selected.kind === 'github-pr') {
147
153
  return openPullRequestSession(proc, deps, args, selected, env);
148
154
  }
149
- return openLocalSession(proc, deps, args, env);
155
+ return openLocalSession(proc, deps, args, selected, env);
156
+ };
157
+
158
+ const runUi = async (session, proc) => {
159
+ const code = await session.startUi();
160
+ if (session.loadError) return fail(proc.stderr, session.loadError);
161
+ if (session.emptyReview) proc.stdout.write('nothing to review\n');
162
+ return code;
150
163
  };
151
164
 
152
165
  const run = async (proc, deps = {}) => {
@@ -164,22 +177,24 @@ const run = async (proc, deps = {}) => {
164
177
  } catch (error) {
165
178
  return fail(stderr, error);
166
179
  }
180
+ const tty = proc.stdin.isTTY === true && stdout.isTTY === true;
181
+ if (tty) return runUi(session, proc);
182
+ try {
183
+ await session.loadReady();
184
+ } catch (error) {
185
+ return fail(stderr, error);
186
+ }
167
187
  if (!session.items.length) {
168
188
  stdout.write('nothing to review\n');
169
189
  return 0;
170
190
  }
171
- if (!proc.stdin.isTTY || !stdout.isTTY) {
172
- stderr.write('reslop: interactive terminal required\n');
173
- return 1;
174
- }
175
- return session.startUi();
191
+ stderr.write('reslop: interactive terminal required\n');
192
+ return 1;
176
193
  };
177
194
 
178
195
  module.exports = {
179
- run,
196
+ failLine,
180
197
  parseArgv,
181
198
  resolveScope,
182
- looksLikeRev,
183
- selectChangeSource,
184
- errorMessage,
199
+ run,
185
200
  };
package/lib/clipboard.js CHANGED
@@ -39,4 +39,4 @@ const copyText = (text, stdout) => {
39
39
  return ok;
40
40
  };
41
41
 
42
- module.exports = { osc52, copyText, runClip };
42
+ module.exports = { osc52, copyText };