reslop 0.2.7 → 0.3.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 +30 -1
- package/README.md +16 -14
- package/bin/reslop.js +8 -5
- package/lib/agents/agents.js +573 -0
- package/lib/agents/allow.js +71 -0
- package/lib/agents/allow.json +17 -0
- package/lib/agents/models.js +467 -0
- package/lib/api.js +15 -12
- package/lib/cli.js +43 -68
- package/lib/{files.js → common/files.js} +48 -55
- package/lib/{find.js → common/find.js} +1 -1
- 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 +90 -49
- package/lib/dashboard/npm.js +17 -13
- package/lib/dashboard/tree.js +27 -30
- package/lib/{session → dashboard}/watch.js +36 -31
- package/lib/{workspace.js → dashboard/workspace.js} +23 -38
- 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} +151 -95
- package/lib/git/git.js +71 -0
- package/lib/git/worktree.js +504 -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 +114 -48
- package/lib/{editor.js → input/editor.js} +16 -8
- package/lib/{keys.js → input/keys.js} +24 -45
- package/lib/input/line-edit.js +78 -0
- package/lib/input/menu-pick.js +70 -0
- package/lib/render/agents.js +642 -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/{dash-blocks.js → dashboard/blocks.js} +131 -137
- 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 +9 -14
- package/lib/render/footer.js +385 -0
- package/lib/render/frame.js +123 -25
- package/lib/render/header.js +176 -0
- package/lib/render/log.js +320 -0
- package/lib/render/menu.js +60 -0
- package/lib/render/notes.js +16 -11
- package/lib/render/npm.js +322 -196
- package/lib/render/packages.js +9 -13
- package/lib/render/primitives.js +101 -15
- package/lib/render/render.js +7 -11
- package/lib/render/repos.js +13 -25
- package/lib/render/status.js +370 -0
- package/lib/render/status.json +85 -0
- package/lib/render/{dash-table.js → table.js} +13 -60
- package/lib/render/tiles.js +109 -48
- 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} +48 -19
- 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 +14 -0
- package/lib/review/format.js +420 -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 +976 -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 +33 -40
- package/lib/session/change-actions.js +34 -100
- package/lib/session/commit.js +91 -52
- package/lib/session/compose.js +189 -147
- package/lib/session/dashboard.js +23 -22
- package/lib/session/dispatch.js +86 -21
- package/lib/session/files-pane.js +47 -26
- package/lib/session/find.js +16 -29
- package/lib/session/import.js +93 -0
- package/lib/session/items.js +8 -17
- package/lib/session/lifecycle.js +78 -72
- package/lib/session/load.js +2 -4
- package/lib/session/navigation.js +6 -3
- package/lib/session/npm/history.js +250 -0
- package/lib/session/npm/npm.js +836 -0
- package/lib/session/{packages.js → npm/packages.js} +21 -14
- package/lib/session/ops.js +125 -34
- package/lib/session/pointer.js +202 -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} +158 -63
- 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 +65 -65
- package/lib/session/workspace.js +39 -78
- 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} +4 -3
- 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 -545
- package/lib/detect.js +0 -34
- package/lib/diff/edit.js +0 -33
- package/lib/git-worktree.js +0 -455
- package/lib/git.js +0 -79
- package/lib/npm-commands.js +0 -522
- package/lib/render/chrome.js +0 -806
- package/lib/render/present.js +0 -19
- package/lib/render/report.js +0 -43
- package/lib/render/search.js +0 -25
- package/lib/review.js +0 -745
- 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/dispatch.js
CHANGED
|
@@ -1,33 +1,30 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
const
|
|
6
|
-
const { hasStagedChanges, listedCommits } = commit;
|
|
7
|
-
const actions = require('./actions.js');
|
|
3
|
+
const { COMPOSE_LEAVE } = require('./compose.js');
|
|
4
|
+
const { listedCommits } = require('./commit.js');
|
|
5
|
+
const actions = require('../input/actions.js');
|
|
8
6
|
const { LIST_PANES, DASH_BLOCKS, DASH_ALLOWED, CONFIRM_MODE } = actions;
|
|
9
7
|
const { REPOS_ALLOWED } = actions;
|
|
10
8
|
const { disabledActions, actionFromKey, confirmKey, lineHasDiff } = actions;
|
|
11
|
-
const
|
|
12
|
-
const { onCommand } = changeActions;
|
|
9
|
+
const { onCommand } = require('./change-actions.js');
|
|
13
10
|
const filesPane = require('./files-pane.js');
|
|
14
|
-
const
|
|
15
|
-
const {
|
|
16
|
-
const
|
|
17
|
-
const {
|
|
11
|
+
const { handlePointer } = require('./pointer.js');
|
|
12
|
+
const { FIND_PANES, startFind, onFindKey } = require('./find.js');
|
|
13
|
+
const { startImport, stopImport, onImportKey } = require('./import.js');
|
|
14
|
+
const { unitBodyLines } = require('./view.js');
|
|
18
15
|
|
|
19
16
|
const currentTarget = (ui) => {
|
|
20
17
|
if (ui.pane === 'files') return ui.fileCursorEntry();
|
|
21
18
|
if (ui.pane === 'branches') return ui.branches[ui.branchCursor];
|
|
22
19
|
if (ui.pane === 'commits') {
|
|
23
20
|
const entry = listedCommits(ui.commits.commits)[ui.commitCursor];
|
|
24
|
-
const canCommit =
|
|
21
|
+
const canCommit = ui.commits.staged;
|
|
25
22
|
const unstagedCurrent = !ui.rev && !ui.revShort;
|
|
26
23
|
return { ...entry, canCommit, unstagedCurrent };
|
|
27
24
|
}
|
|
28
25
|
if (ui.pane !== 'unit') return ui.current();
|
|
29
26
|
const item = ui.current();
|
|
30
|
-
const lines = ui
|
|
27
|
+
const lines = unitBodyLines(ui);
|
|
31
28
|
if (!lines.length) return item;
|
|
32
29
|
const line = lines[ui.nav.unitLine] ?? null;
|
|
33
30
|
const lineDiff = lineHasDiff(line);
|
|
@@ -53,6 +50,7 @@ const HANDLERS = {
|
|
|
53
50
|
next: filesPane.onNext,
|
|
54
51
|
prev: filesPane.onPrev,
|
|
55
52
|
layout: filesPane.onLayout,
|
|
53
|
+
lines: filesPane.onLineNumbers,
|
|
56
54
|
theme: filesPane.onTheme,
|
|
57
55
|
files: filesPane.onFiles,
|
|
58
56
|
open: (ui) => {
|
|
@@ -97,6 +95,10 @@ const HANDLERS = {
|
|
|
97
95
|
if (ui.pane === 'tasks') return void ui.composer.tasks.removeFocusedTask();
|
|
98
96
|
ui.gitBranches.onDropBranch();
|
|
99
97
|
},
|
|
98
|
+
taskUp: (ui) => ui.composer.tasks.moveIssue(-1),
|
|
99
|
+
taskDown: (ui) => ui.composer.tasks.moveIssue(1),
|
|
100
|
+
plan: (ui) => ui.composer.tasks.togglePlanMenu(),
|
|
101
|
+
import: (ui) => startImport(ui),
|
|
100
102
|
npm: (ui) => ui.npm.open(),
|
|
101
103
|
npmEdit: (ui) => ui.npm.edit(),
|
|
102
104
|
npmNew: (ui) => ui.npm.create(),
|
|
@@ -106,9 +108,17 @@ const HANDLERS = {
|
|
|
106
108
|
packageWanted: (ui) => ui.packages.updateWanted(),
|
|
107
109
|
packageLatest: (ui) => ui.packages.updateLatest(),
|
|
108
110
|
npmLogs: (ui) => ui.npm.askLogs(),
|
|
109
|
-
npmStop: (ui) => ui.npm.
|
|
111
|
+
npmStop: (ui) => ui.npm.stop(),
|
|
110
112
|
npmVerbose: (ui) => ui.npm.toggleVerbose(),
|
|
111
113
|
npmRerun: (ui) => ui.npm.rerun(),
|
|
114
|
+
agentModel: (ui) => ui.agents.openPick('model'),
|
|
115
|
+
agentEffort: (ui) => ui.agents.openPick('effort'),
|
|
116
|
+
agentFast: (ui) => ui.agents.toggleFast(),
|
|
117
|
+
agentContext: (ui) => ui.agents.openPick('context'),
|
|
118
|
+
agentReview: (ui) => ui.agents.openPick('plan'),
|
|
119
|
+
agentContinue: (ui) => ui.agents.continueSession(),
|
|
120
|
+
agentStop: (ui) => ui.agents.stop(),
|
|
121
|
+
agentRerun: (ui) => ui.agents.rerun(),
|
|
112
122
|
quit: (ui) => ui.onQuit(),
|
|
113
123
|
repoLeft: (ui) => ui.workspace.move(-1, 0),
|
|
114
124
|
repoRight: (ui) => ui.workspace.move(1, 0),
|
|
@@ -119,10 +129,15 @@ const HANDLERS = {
|
|
|
119
129
|
|
|
120
130
|
const dispatchAction = (ui, action) => {
|
|
121
131
|
if (CONFIRM_MODE.includes(ui.mode)) return;
|
|
132
|
+
if (ui.mode === 'import') stopImport(ui);
|
|
133
|
+
if (action === 'lines' && (ui.pane === 'diff' || ui.pane === 'unit')) {
|
|
134
|
+
return void filesPane.onLineNumbers(ui);
|
|
135
|
+
}
|
|
122
136
|
if (ui.mode === 'compose') {
|
|
123
137
|
if (!COMPOSE_LEAVE.includes(action)) return;
|
|
124
|
-
const
|
|
125
|
-
|
|
138
|
+
const after = () => dispatchAction(ui, action);
|
|
139
|
+
const result = ui.composer.saveCompose({ after });
|
|
140
|
+
if (result.kind === 'saving') return;
|
|
126
141
|
}
|
|
127
142
|
const pane = ui.pane;
|
|
128
143
|
if (pane === 'repos' && !REPOS_ALLOWED.includes(action)) return;
|
|
@@ -137,8 +152,7 @@ const dispatchAction = (ui, action) => {
|
|
|
137
152
|
|
|
138
153
|
const CONFIRMATIONS = {
|
|
139
154
|
confirmQuit: {
|
|
140
|
-
|
|
141
|
-
editing: (ui) => ui.finishQuit('editing'),
|
|
155
|
+
confirm: (ui) => ui.confirmQuit(),
|
|
142
156
|
cancel: (ui) => ui.cancelQuit(),
|
|
143
157
|
},
|
|
144
158
|
confirmUpdate: {
|
|
@@ -164,6 +178,7 @@ const CONFIRMATIONS = {
|
|
|
164
178
|
cancel: (ui) => ui.gitBranches.cancelPush(),
|
|
165
179
|
},
|
|
166
180
|
confirmCommit: {
|
|
181
|
+
update: (ui) => ui.commits.chooseCommit('update'),
|
|
167
182
|
commit: (ui) => ui.commits.chooseCommit('commit'),
|
|
168
183
|
amend: (ui) => ui.commits.chooseCommit('amend'),
|
|
169
184
|
fixup: (ui) => ui.commits.chooseCommit('fixup'),
|
|
@@ -179,6 +194,7 @@ const confirmChoice = (ui, key) => {
|
|
|
179
194
|
|
|
180
195
|
const NPM_VIEW_KEYS = {
|
|
181
196
|
escape: (ui) => ui.npm.closeView(),
|
|
197
|
+
s: (ui) => ui.npm.stop(),
|
|
182
198
|
r: (ui) => ui.npm.rerun(),
|
|
183
199
|
v: (ui) => ui.npm.toggleVerbose(),
|
|
184
200
|
e: () => {},
|
|
@@ -190,31 +206,80 @@ const NPM_LIST_KEYS = {
|
|
|
190
206
|
'ctrl-down': (ui) => ui.npm.reorder(1),
|
|
191
207
|
up: (ui) => ui.npm.move(-1),
|
|
192
208
|
down: (ui) => ui.npm.move(1),
|
|
209
|
+
right: (ui) => ui.npm.focusRuns(),
|
|
210
|
+
left: (ui) => ui.npm.focusCommands(),
|
|
211
|
+
tab: (ui) => ui.npm.toggleFocus(),
|
|
212
|
+
'shift-tab': (ui) => ui.npm.toggleFocus(),
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const AGENT_VIEW_KEYS = {
|
|
216
|
+
escape: (ui) => ui.agents.closeView(),
|
|
217
|
+
s: (ui) => ui.agents.stop(),
|
|
218
|
+
r: (ui) => ui.agents.rerun(),
|
|
219
|
+
e: () => {},
|
|
220
|
+
m: () => {},
|
|
221
|
+
a: () => {},
|
|
222
|
+
t: () => {},
|
|
223
|
+
f: () => {},
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const AGENT_LIST_KEYS = {
|
|
227
|
+
right: (ui) => ui.agents.focusRuns(),
|
|
228
|
+
left: (ui) => ui.agents.focusCli(),
|
|
229
|
+
tab: (ui) => ui.agents.toggleFocus(),
|
|
230
|
+
'shift-tab': (ui) => ui.agents.toggleFocus(),
|
|
193
231
|
};
|
|
194
232
|
|
|
195
233
|
const npmKey = (ui, key) => {
|
|
196
234
|
if (ui.pane !== 'npm') return null;
|
|
197
|
-
if (ui.npm.viewing
|
|
198
|
-
return NPM_VIEW_KEYS[key];
|
|
235
|
+
if (ui.npm.viewing) {
|
|
236
|
+
if (Object.hasOwn(NPM_VIEW_KEYS, key)) return NPM_VIEW_KEYS[key];
|
|
237
|
+
if (key === 'up' || key === 'down') return NPM_LIST_KEYS[key];
|
|
238
|
+
return null;
|
|
199
239
|
}
|
|
200
240
|
return Object.hasOwn(NPM_LIST_KEYS, key) ? NPM_LIST_KEYS[key] : null;
|
|
201
241
|
};
|
|
202
242
|
|
|
243
|
+
const agentKey = (ui, key) => {
|
|
244
|
+
if (ui.pane !== 'agents') return null;
|
|
245
|
+
if (ui.agents.pick) return () => ui.agents.onPickKey(key);
|
|
246
|
+
const keys = ui.agents.viewing ? AGENT_VIEW_KEYS : AGENT_LIST_KEYS;
|
|
247
|
+
return Object.hasOwn(keys, key) ? keys[key] : null;
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const planMenuKey = (ui, key) => {
|
|
251
|
+
if (!ui.composer.tasks.planOpen || ui.pane !== 'tasks') return false;
|
|
252
|
+
ui.composer.tasks.onPlanKey(key);
|
|
253
|
+
return true;
|
|
254
|
+
};
|
|
255
|
+
|
|
203
256
|
const handleKey = (ui, key) => {
|
|
204
257
|
if (CONFIRM_MODE.includes(ui.mode)) return void confirmChoice(ui, key);
|
|
258
|
+
if (planMenuKey(ui, key)) return;
|
|
259
|
+
if (ui.pane === 'tasks' && (key === 'ctrl-up' || key === 'ctrl-down')) {
|
|
260
|
+
if (ui.mode === 'import') stopImport(ui);
|
|
261
|
+
const delta = key === 'ctrl-up' ? -1 : 1;
|
|
262
|
+
return void ui.composer.tasks.moveIssue(delta);
|
|
263
|
+
}
|
|
264
|
+
if (key === 'ctrl-l' && (ui.pane === 'diff' || ui.pane === 'unit')) {
|
|
265
|
+
return void filesPane.onLineNumbers(ui);
|
|
266
|
+
}
|
|
205
267
|
if (ui.mode === 'compose') {
|
|
206
268
|
return void ui.runComposeCommand(ui.composer.handleKey(key));
|
|
207
269
|
}
|
|
208
270
|
if (ui.mode === 'find') return void onFindKey(ui, key);
|
|
271
|
+
if (ui.mode === 'import') return void onImportKey(ui, key);
|
|
209
272
|
if (key === '/' && FIND_PANES.includes(ui.pane)) return void startFind(ui);
|
|
210
273
|
const onNpmKey = npmKey(ui, key);
|
|
211
274
|
if (onNpmKey) return void onNpmKey(ui);
|
|
275
|
+
const onAgentKey = agentKey(ui, key);
|
|
276
|
+
if (onAgentKey) return void onAgentKey(ui);
|
|
212
277
|
if (key === 'escape') return void filesPane.onEscape(ui);
|
|
213
278
|
const tasks = ui.composer.tasks;
|
|
214
279
|
const toggle = key === ' ';
|
|
215
280
|
if (toggle && tasks.toggleFocusedTask()) return;
|
|
216
281
|
if (tasks.typeIntoTask(key)) return;
|
|
217
|
-
const action = actionFromKey(key, ui.pane
|
|
282
|
+
const action = actionFromKey(key, ui.pane);
|
|
218
283
|
if (action) ui.dispatch(action);
|
|
219
284
|
};
|
|
220
285
|
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const {
|
|
6
|
-
const {
|
|
7
|
-
const
|
|
8
|
-
const {
|
|
9
|
-
const
|
|
10
|
-
const actions = require('./actions.js');
|
|
11
|
-
const { LIST_PANES } = actions;
|
|
12
|
-
const { setFileScope, openUnitFile, moveUnitBlock } = unit;
|
|
3
|
+
const { clamp } = require('../common/utilities.js');
|
|
4
|
+
const { THEME_NAMES, setTheme, themeName } = require('../term/ansi.js');
|
|
5
|
+
const { isTasksEntry, TASKS_FILE } = require('../common/files.js');
|
|
6
|
+
const { logViewRows } = require('../render/log.js');
|
|
7
|
+
const { setFileScope, openUnitFile, moveUnitBlock } = require('./unit.js');
|
|
8
|
+
const { LIST_PANES } = require('../input/actions.js');
|
|
9
|
+
const { saveUiPrefs, LAYOUT_LABEL } = require('./prefs.js');
|
|
13
10
|
|
|
14
11
|
const LAYOUTS = ['unified', 'mixed', 'side'];
|
|
15
12
|
|
|
@@ -31,12 +28,8 @@ const syncFileCursor = (ui) => {
|
|
|
31
28
|
|
|
32
29
|
const showFiles = (ui) => {
|
|
33
30
|
const nav = ui.nav;
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
nav.pane === 'branches' ||
|
|
37
|
-
nav.pane === 'commits' ||
|
|
38
|
-
nav.pane === 'npm' ||
|
|
39
|
-
nav.pane === 'packages';
|
|
31
|
+
const listed = nav.pane !== 'files' && LIST_PANES.includes(nav.pane);
|
|
32
|
+
const held = nav.tasksOpen === true || listed;
|
|
40
33
|
nav.pane = 'files';
|
|
41
34
|
nav.resetListScroll('files');
|
|
42
35
|
nav.clearSelection();
|
|
@@ -67,15 +60,22 @@ const showDashboard = (ui) => {
|
|
|
67
60
|
ui.dashboard.enter();
|
|
68
61
|
};
|
|
69
62
|
|
|
70
|
-
const HOME_CHILDREN = ['files', 'branches', 'commits', 'npm', 'packages'];
|
|
71
|
-
|
|
72
63
|
const returnsHome = (ui) => {
|
|
73
64
|
if (!ui.dashboardHome) return false;
|
|
74
65
|
const { pane, tasksOpen } = ui.nav;
|
|
75
|
-
return
|
|
66
|
+
return LIST_PANES.includes(pane) || tasksOpen === true;
|
|
76
67
|
};
|
|
77
68
|
|
|
78
69
|
const onEscape = (ui) => {
|
|
70
|
+
if (ui.nav.pane === 'agents' && ui.agents.pick) {
|
|
71
|
+
return void ui.agents.closePick();
|
|
72
|
+
}
|
|
73
|
+
if (ui.nav.pane === 'agents' && ui.agents.viewing) {
|
|
74
|
+
return void ui.agents.closeView();
|
|
75
|
+
}
|
|
76
|
+
if (ui.nav.pane === 'npm' && ui.npm.viewing) {
|
|
77
|
+
return void ui.npm.closeView();
|
|
78
|
+
}
|
|
79
79
|
if (ui.nav.pane === 'repos') return void ui.onQuit();
|
|
80
80
|
if (ui.nav.pane === 'dashboard' && ui.workspaceRoot) {
|
|
81
81
|
return void ui.workspace.show();
|
|
@@ -112,6 +112,7 @@ const onOpenFile = (ui) => {
|
|
|
112
112
|
}
|
|
113
113
|
if (ui.nav.pane === 'commits') return void ui.commits.onShowDiff();
|
|
114
114
|
if (ui.nav.pane === 'npm') return void ui.npm.run();
|
|
115
|
+
if (ui.nav.pane === 'agents') return void ui.agents.start();
|
|
115
116
|
if (ui.nav.pane !== 'files') {
|
|
116
117
|
if (ui.nav.tasksOpen) ui.composer.tasks.editFocusedTask();
|
|
117
118
|
return;
|
|
@@ -144,7 +145,7 @@ const onFileMove = (ui, delta) => {
|
|
|
144
145
|
}
|
|
145
146
|
const last = list.length - 1;
|
|
146
147
|
const moved = ui.nav.fileCursor + delta;
|
|
147
|
-
const next =
|
|
148
|
+
const next = clamp(moved, 0, last);
|
|
148
149
|
if (next === ui.nav.fileCursor) return;
|
|
149
150
|
ui.nav.fileCursor = next;
|
|
150
151
|
const entry = list[next];
|
|
@@ -191,7 +192,8 @@ const scrollStep = (ui, fraction) => {
|
|
|
191
192
|
const fallback = Math.max(1, rows - 4);
|
|
192
193
|
const bodyH = frame?.bodyH ?? fallback;
|
|
193
194
|
const viewing = ui.nav.pane === 'npm' && ui.npm.viewing;
|
|
194
|
-
const
|
|
195
|
+
const agentLog = ui.nav.pane === 'agents' && ui.agents.viewing;
|
|
196
|
+
const viewRows = viewing || agentLog ? logViewRows(bodyH) : bodyH;
|
|
195
197
|
const height = Math.max(1, viewRows);
|
|
196
198
|
const span = Math.floor(height * Math.abs(fraction));
|
|
197
199
|
const n = Math.max(1, span);
|
|
@@ -200,6 +202,10 @@ const scrollStep = (ui, fraction) => {
|
|
|
200
202
|
};
|
|
201
203
|
|
|
202
204
|
const onScroll = (ui, delta) => {
|
|
205
|
+
if (ui.composer.tasks.planOpen && ui.nav.pane === 'tasks') {
|
|
206
|
+
const step = delta < 0 ? -1 : 1;
|
|
207
|
+
return void ui.composer.tasks.movePlan(step);
|
|
208
|
+
}
|
|
203
209
|
if (ui.nav.pane === 'dashboard') return;
|
|
204
210
|
if (ui.nav.pane === 'files') return void onFileMove(ui, delta);
|
|
205
211
|
if (ui.nav.pane === 'branches') {
|
|
@@ -209,12 +215,13 @@ const onScroll = (ui, delta) => {
|
|
|
209
215
|
return void ui.commits.onCommitMove(delta);
|
|
210
216
|
}
|
|
211
217
|
if (ui.nav.pane === 'npm') return void ui.npm.move(delta);
|
|
218
|
+
if (ui.nav.pane === 'agents') return void ui.agents.move(delta);
|
|
212
219
|
if (ui.nav.pane === 'packages') {
|
|
213
220
|
const count = ui.dashboard.packageCount();
|
|
214
221
|
const nav = ui.nav;
|
|
215
222
|
const next = nav.packagesCursor + delta;
|
|
216
223
|
const last = Math.max(0, count - 1);
|
|
217
|
-
nav.packagesCursor =
|
|
224
|
+
nav.packagesCursor = clamp(next, 0, last);
|
|
218
225
|
ui.status = '';
|
|
219
226
|
return;
|
|
220
227
|
}
|
|
@@ -253,10 +260,22 @@ const onLayout = (ui) => {
|
|
|
253
260
|
const i = LAYOUTS.indexOf(ui.layout);
|
|
254
261
|
const next = (i < 0 ? 0 : i + 1) % LAYOUTS.length;
|
|
255
262
|
ui.layout = LAYOUTS[next];
|
|
256
|
-
|
|
257
|
-
ui.status = name;
|
|
263
|
+
ui.status = LAYOUT_LABEL[ui.layout] || ui.layout;
|
|
258
264
|
ui.nav.scroll = 0;
|
|
259
265
|
ui.nav.clearSelection();
|
|
266
|
+
saveUiPrefs(ui.top || ui.cwd, { layout: ui.layout });
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
const saveLineNumbers = (ui) => {
|
|
270
|
+
const shown = ui.lineNumbers === true;
|
|
271
|
+
saveUiPrefs(ui.top || ui.cwd, { lineNumbers: shown });
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const onLineNumbers = (ui) => {
|
|
275
|
+
ui.lineNumbers = ui.lineNumbers !== true;
|
|
276
|
+
ui.status = ui.lineNumbers ? 'line numbers' : 'no line numbers';
|
|
277
|
+
saveLineNumbers(ui);
|
|
278
|
+
ui.composer.syncCodeScroll();
|
|
260
279
|
};
|
|
261
280
|
|
|
262
281
|
const onTheme = (ui) => {
|
|
@@ -264,12 +283,13 @@ const onTheme = (ui) => {
|
|
|
264
283
|
const next = THEME_NAMES[(i + 1) % THEME_NAMES.length];
|
|
265
284
|
setTheme(next);
|
|
266
285
|
ui.status = next;
|
|
286
|
+
saveUiPrefs(ui.top || ui.cwd, { theme: next });
|
|
267
287
|
};
|
|
268
288
|
|
|
269
289
|
const onHome = (ui) => onJump(ui, false);
|
|
270
290
|
const onEnd = (ui) => onJump(ui, true);
|
|
271
|
-
const onFileScope = (ui) => setFileScope(ui, 'file');
|
|
272
|
-
const onDiffScope = (ui) => setFileScope(ui, 'diff');
|
|
291
|
+
const onFileScope = (ui, quiet) => setFileScope(ui, 'file', quiet === true);
|
|
292
|
+
const onDiffScope = (ui, quiet) => setFileScope(ui, 'diff', quiet === true);
|
|
273
293
|
|
|
274
294
|
module.exports = {
|
|
275
295
|
fileCursorEntry,
|
|
@@ -287,6 +307,7 @@ module.exports = {
|
|
|
287
307
|
onHome,
|
|
288
308
|
onEnd,
|
|
289
309
|
onLayout,
|
|
310
|
+
onLineNumbers,
|
|
290
311
|
onTheme,
|
|
291
312
|
onFileScope,
|
|
292
313
|
onDiffScope,
|
package/lib/session/find.js
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
const
|
|
6
|
-
const { fileMatches } = find;
|
|
3
|
+
const { isTasksEntry, TASKS_FILE } = require('../common/files.js');
|
|
4
|
+
const { fileMatches } = require('../common/find.js');
|
|
5
|
+
const { lineKey, lineField } = require('../input/line-edit.js');
|
|
7
6
|
|
|
8
7
|
const FIND_PANES = ['files', 'diff'];
|
|
9
8
|
|
|
10
|
-
const isTypeKey = (key) =>
|
|
11
|
-
Boolean(key) && key.length === 1 && key.charCodeAt(0) >= 32;
|
|
12
|
-
|
|
13
9
|
const startFind = (ui) => {
|
|
14
10
|
if (ui.mode !== 'review') return;
|
|
15
11
|
if (!FIND_PANES.includes(ui.pane)) return;
|
|
16
12
|
ui.mode = 'find';
|
|
17
|
-
|
|
13
|
+
const find = lineField('query');
|
|
14
|
+
find.at = 0;
|
|
15
|
+
ui.nav.find = find;
|
|
18
16
|
ui.status = '';
|
|
19
17
|
};
|
|
20
18
|
|
|
@@ -56,21 +54,6 @@ const showHit = (ui, jump) => {
|
|
|
56
54
|
focusMatch(ui, hits[at], jump);
|
|
57
55
|
};
|
|
58
56
|
|
|
59
|
-
const typeFind = (ui, key) => {
|
|
60
|
-
const state = ui.nav.find;
|
|
61
|
-
state.query += key;
|
|
62
|
-
state.at = 0;
|
|
63
|
-
showHit(ui, true);
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const eraseFind = (ui) => {
|
|
67
|
-
const state = ui.nav.find;
|
|
68
|
-
if (!state.query) return void stopFind(ui);
|
|
69
|
-
state.query = state.query.slice(0, -1);
|
|
70
|
-
state.at = 0;
|
|
71
|
-
showHit(ui, true);
|
|
72
|
-
};
|
|
73
|
-
|
|
74
57
|
const moveFind = (ui, delta) => {
|
|
75
58
|
const state = ui.nav.find;
|
|
76
59
|
if (!state.query) return;
|
|
@@ -83,12 +66,16 @@ const onFindKey = (ui, key) => {
|
|
|
83
66
|
ui.mode = 'review';
|
|
84
67
|
return;
|
|
85
68
|
}
|
|
86
|
-
if (key === 'ctrl-c') return void ui.onQuit();
|
|
87
69
|
if (key === 'escape' || key === 'enter') return void stopFind(ui);
|
|
88
|
-
if (key === 'backspace') return void
|
|
89
|
-
|
|
90
|
-
if (
|
|
91
|
-
|
|
70
|
+
if (key === 'backspace' && !ui.nav.find.query) return void stopFind(ui);
|
|
71
|
+
const handled = lineKey(ui.nav.find.editor, key, ui, true);
|
|
72
|
+
if (handled === 'text') {
|
|
73
|
+
ui.nav.find.at = 0;
|
|
74
|
+
showHit(ui, true);
|
|
75
|
+
}
|
|
76
|
+
if (handled) return;
|
|
77
|
+
if (key === 'up') return void moveFind(ui, -1);
|
|
78
|
+
if (key === 'down') moveFind(ui, 1);
|
|
92
79
|
};
|
|
93
80
|
|
|
94
|
-
module.exports = { FIND_PANES, startFind,
|
|
81
|
+
module.exports = { FIND_PANES, startFind, onFindKey };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { remoteKind, selectChangeSource } = require('../source/source.js');
|
|
4
|
+
const { lineKey, lineField } = require('../input/line-edit.js');
|
|
5
|
+
|
|
6
|
+
const changeRepositoryUrl = (change) => {
|
|
7
|
+
if (!change?.url || !change.repository) return '';
|
|
8
|
+
try {
|
|
9
|
+
const url = new URL(change.url);
|
|
10
|
+
return `${url.origin}/${change.repository}`;
|
|
11
|
+
} catch {
|
|
12
|
+
return '';
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const startImport = (ui) => {
|
|
17
|
+
if (ui.mode !== 'review' || ui.pane !== 'tasks') return;
|
|
18
|
+
ui.composer.tasks.closePlanMenu();
|
|
19
|
+
ui.mode = 'import';
|
|
20
|
+
const defaultUrl = ui.repositoryUrl || changeRepositoryUrl(ui.change);
|
|
21
|
+
ui.nav.import = lineField('url', defaultUrl);
|
|
22
|
+
ui.status = '';
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const stopImport = (ui) => {
|
|
26
|
+
ui.mode = 'review';
|
|
27
|
+
ui.nav.import = null;
|
|
28
|
+
ui.status = '';
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const noteImport = (ui, message) => {
|
|
32
|
+
ui.status = message;
|
|
33
|
+
if (ui.uiOpen) ui.paint();
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const finishImport = (ui, store, loaded) => {
|
|
37
|
+
const imported = loaded && loaded.imported;
|
|
38
|
+
if (!imported || ui.review.store !== store) {
|
|
39
|
+
noteImport(ui, 'import failed');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
store.applyImportedNotes(imported);
|
|
43
|
+
ui.flushReview();
|
|
44
|
+
noteImport(ui, 'imported');
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const runImport = (ui, selected) => {
|
|
48
|
+
const kind = remoteKind(selected);
|
|
49
|
+
if (!kind) return Promise.resolve(null);
|
|
50
|
+
const load = ui[kind.option] ?? kind.load;
|
|
51
|
+
const target = kind.target(selected);
|
|
52
|
+
if (!load || !target) return Promise.resolve(null);
|
|
53
|
+
const fetch = ui.fetchImpl ?? globalThis.fetch;
|
|
54
|
+
const options = { cwd: ui.top || ui.cwd, token: kind.token(), fetch };
|
|
55
|
+
return Promise.resolve().then(() => load(target, options));
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const submitImport = (ui) => {
|
|
59
|
+
const state = ui.nav.import;
|
|
60
|
+
const url = state ? state.url.trim() : '';
|
|
61
|
+
const store = ui.review.store;
|
|
62
|
+
stopImport(ui);
|
|
63
|
+
if (!url) return;
|
|
64
|
+
const selected = selectChangeSource([url]);
|
|
65
|
+
if (!remoteKind(selected)) {
|
|
66
|
+
ui.status = 'bad url';
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
ui.status = 'importing';
|
|
70
|
+
const pending = runImport(ui, selected);
|
|
71
|
+
ui.importPromise = pending;
|
|
72
|
+
pending.then(
|
|
73
|
+
(loaded) => finishImport(ui, store, loaded),
|
|
74
|
+
(error) => {
|
|
75
|
+
const message = error instanceof Error ? error.message : '';
|
|
76
|
+
noteImport(ui, message || 'import failed');
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const onImportKey = (ui, key) => {
|
|
82
|
+
const state = ui.nav.import;
|
|
83
|
+
if (!state) {
|
|
84
|
+
ui.mode = 'review';
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (key === 'escape') return void stopImport(ui);
|
|
88
|
+
if (key === 'enter') return void submitImport(ui);
|
|
89
|
+
if (key === 'backspace' && !state.url) return void stopImport(ui);
|
|
90
|
+
lineKey(state.editor, key, ui, true);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
module.exports = { startImport, stopImport, onImportKey };
|
package/lib/session/items.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
const {
|
|
4
|
+
itemPath,
|
|
5
|
+
TASKS_FILE,
|
|
6
|
+
isTaskItem,
|
|
7
|
+
groupByPath,
|
|
8
|
+
} = require('../common/files.js');
|
|
9
|
+
const { feedbackKey } = require('../review/review.js');
|
|
10
|
+
const { refreshIndexPatches } = require('../diff/diff.js');
|
|
9
11
|
|
|
10
12
|
const depChangeKey = (item) => {
|
|
11
13
|
const change = item.dep && item.dep.change;
|
|
@@ -72,17 +74,6 @@ const takeBucket = (map, key, used) => {
|
|
|
72
74
|
return null;
|
|
73
75
|
};
|
|
74
76
|
|
|
75
|
-
const groupByPath = (items) => {
|
|
76
|
-
const groups = new Map();
|
|
77
|
-
for (const item of items) {
|
|
78
|
-
const rel = itemPath(item) || '';
|
|
79
|
-
const list = groups.get(rel) ?? [];
|
|
80
|
-
list.push(item);
|
|
81
|
-
groups.set(rel, list);
|
|
82
|
-
}
|
|
83
|
-
return groups;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
77
|
const alignGroup = (prev, next) => {
|
|
87
78
|
if (!prev.length) return next;
|
|
88
79
|
if (!next.length) return [];
|