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
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Repo reads the screen needs on every frame: loaded ahead and kept here
|
|
4
|
+
class FileReads {
|
|
5
|
+
constructor(ui) {
|
|
6
|
+
this.ui = ui;
|
|
7
|
+
this.reset();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
reset() {
|
|
11
|
+
this.names = [];
|
|
12
|
+
this.textKey = null;
|
|
13
|
+
this.text = '';
|
|
14
|
+
this.stamp = 0;
|
|
15
|
+
this.wanted = null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
keyOf(rel) {
|
|
19
|
+
const ui = this.ui;
|
|
20
|
+
return `${ui.top}\0${ui.rev ?? ''}\0${rel}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async readNames() {
|
|
24
|
+
const ui = this.ui;
|
|
25
|
+
if (!ui.repo.listFiles) return [];
|
|
26
|
+
const options = { commit: ui.rev };
|
|
27
|
+
try {
|
|
28
|
+
return await ui.repo.listFiles(ui.top || ui.cwd, ui.paths ?? [], options);
|
|
29
|
+
} catch {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async readText(rel) {
|
|
35
|
+
const ui = this.ui;
|
|
36
|
+
const key = this.keyOf(rel);
|
|
37
|
+
const repo = ui.repo;
|
|
38
|
+
const readable = rel && repo && typeof repo.fileText === 'function';
|
|
39
|
+
if (!readable) return { key, text: '' };
|
|
40
|
+
try {
|
|
41
|
+
return { key, text: await repo.fileText(ui.top, rel, ui.rev) };
|
|
42
|
+
} catch {
|
|
43
|
+
return { key, text: '' };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// What a reload needs besides the snapshot, applied together with it
|
|
48
|
+
async read() {
|
|
49
|
+
const nav = this.ui.nav;
|
|
50
|
+
const listed = nav.fileScope === 'file';
|
|
51
|
+
const rel = nav.pane === 'unit' ? nav.reviewPath : null;
|
|
52
|
+
const reads = [
|
|
53
|
+
listed ? this.readNames() : null,
|
|
54
|
+
rel ? this.readText(rel) : null,
|
|
55
|
+
];
|
|
56
|
+
const stamp = this.stamp;
|
|
57
|
+
const [names, viewed] = await Promise.all(reads);
|
|
58
|
+
return { names, viewed, stamp };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Text kept since the read began is newer than what the read found
|
|
62
|
+
apply(found) {
|
|
63
|
+
if (found.names) this.names = found.names;
|
|
64
|
+
if (found.viewed && found.stamp === this.stamp) this.keep(found.viewed);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
keep(viewed) {
|
|
68
|
+
this.textKey = viewed.key;
|
|
69
|
+
this.text = viewed.text;
|
|
70
|
+
this.stamp += 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
keepText(rel, text) {
|
|
74
|
+
this.keep({ key: this.keyOf(rel), text });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async loadNames() {
|
|
78
|
+
this.names = await this.readNames();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async loadText(rel) {
|
|
82
|
+
const viewed = await this.readText(rel);
|
|
83
|
+
this.keep(viewed);
|
|
84
|
+
return viewed.text;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
cached(rel) {
|
|
88
|
+
if (!rel || this.textKey !== this.keyOf(rel)) return null;
|
|
89
|
+
return this.text;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// A path nobody loaded ahead is read now and painted when it arrives
|
|
93
|
+
textOf(rel) {
|
|
94
|
+
const text = this.cached(rel);
|
|
95
|
+
if (text !== null || !rel) return text ?? '';
|
|
96
|
+
const key = this.keyOf(rel);
|
|
97
|
+
if (this.wanted === key) return '';
|
|
98
|
+
this.wanted = key;
|
|
99
|
+
const ui = this.ui;
|
|
100
|
+
const done = () => {
|
|
101
|
+
this.wanted = null;
|
|
102
|
+
ui.paint();
|
|
103
|
+
};
|
|
104
|
+
ui.ops.track(this.loadText(rel).then(done, done));
|
|
105
|
+
return '';
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
module.exports = { FileReads };
|
package/lib/session/review.js
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
const { REVIEW_DIR, ISSUE_FILE } = require('../common/files.js');
|
|
7
|
+
const review = require('../review/review.js');
|
|
8
|
+
const { ReviewStore } = review;
|
|
5
9
|
const { listReviewNames, loadTemplates, resolveReviewPath } = review;
|
|
6
10
|
const { loadReview, flushReview } = review;
|
|
7
11
|
|
|
12
|
+
const issueTasks = (imported) => {
|
|
13
|
+
const todos = imported.tasks ?? imported.todos ?? [];
|
|
14
|
+
return todos.filter((todo) => (todo.file || '') === ISSUE_FILE);
|
|
15
|
+
};
|
|
16
|
+
|
|
8
17
|
class ReviewController {
|
|
9
18
|
constructor() {
|
|
10
19
|
this.reset();
|
|
@@ -21,16 +30,17 @@ class ReviewController {
|
|
|
21
30
|
const templates = loadTemplates(dir);
|
|
22
31
|
const resolved = resolveReviewPath(dir, date, names, extra);
|
|
23
32
|
this.didResume = resolved.resume === true;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
33
|
+
const reviewPath = resolved.reviewPath;
|
|
34
|
+
if (this.didResume) this.store = loadReview(reviewPath, templates);
|
|
35
|
+
else this.store = new ReviewStore(reviewPath, templates);
|
|
27
36
|
return this.store;
|
|
28
37
|
}
|
|
29
38
|
|
|
30
39
|
applyImported(imported) {
|
|
31
40
|
if (!imported || !this.store) return false;
|
|
32
|
-
if (this.
|
|
33
|
-
|
|
41
|
+
if (this.importedRemote) return false;
|
|
42
|
+
const notes = this.didResume ? { tasks: issueTasks(imported) } : imported;
|
|
43
|
+
this.store.applyImportedNotes(notes);
|
|
34
44
|
this.importedRemote = true;
|
|
35
45
|
return true;
|
|
36
46
|
}
|
|
@@ -45,9 +55,17 @@ class ReviewController {
|
|
|
45
55
|
}
|
|
46
56
|
}
|
|
47
57
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
58
|
+
usePlan(dir, name) {
|
|
59
|
+
const store = this.store;
|
|
60
|
+
if (!store || !name) return false;
|
|
61
|
+
const next = path.join(dir, REVIEW_DIR, name);
|
|
62
|
+
if (next === store.reviewPath) return false;
|
|
63
|
+
this.flush();
|
|
64
|
+
const templates = store.templates;
|
|
65
|
+
const loaded = fs.existsSync(next);
|
|
66
|
+
if (loaded) this.store = loadReview(next, templates);
|
|
67
|
+
else this.store = new ReviewStore(next, templates);
|
|
68
|
+
return true;
|
|
51
69
|
}
|
|
52
70
|
}
|
|
53
71
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { clamp } = require('../common/utilities.js');
|
|
4
|
+
const { logScrollMax } = require('../render/log.js');
|
|
5
|
+
|
|
6
|
+
class RunPanel {
|
|
7
|
+
constructor(ui) {
|
|
8
|
+
this.ui = ui;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
barMax() {
|
|
12
|
+
const bar = this.ui.lastFrame && this.ui.lastFrame.scrollBar;
|
|
13
|
+
return bar ? Math.max(0, bar.count - bar.rows) : -1;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
setLog(start, max) {
|
|
17
|
+
const next = clamp(start, 0, max);
|
|
18
|
+
this.logScroll = next;
|
|
19
|
+
this.followEnd = next === max;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
placeLog(start) {
|
|
23
|
+
const max = this.barMax();
|
|
24
|
+
if (max >= 0) this.setLog(start, max);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
placeRuns(start) {
|
|
28
|
+
const max = this.barMax();
|
|
29
|
+
if (max >= 0) this.runScroll = clamp(start, 0, max);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
scrollLogBy(delta, text, running) {
|
|
33
|
+
const { lastSize, lastFrame } = this.ui;
|
|
34
|
+
const max = logScrollMax(text, lastSize, lastFrame, running);
|
|
35
|
+
const from = this.followEnd ? max : this.logScroll;
|
|
36
|
+
this.setLog(from + delta, max);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = { RunPanel };
|
|
@@ -1,57 +1,58 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
const
|
|
6
|
-
const {
|
|
7
|
-
const
|
|
8
|
-
const {
|
|
9
|
-
const
|
|
10
|
-
const {
|
|
11
|
-
const
|
|
12
|
-
const {
|
|
13
|
-
const
|
|
14
|
-
const {
|
|
15
|
-
const
|
|
16
|
-
const {
|
|
17
|
-
const
|
|
18
|
-
const {
|
|
19
|
-
const
|
|
20
|
-
const {
|
|
21
|
-
const
|
|
22
|
-
const {
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const progress = require('./session/progress.js');
|
|
28
|
-
const { Progress } = progress;
|
|
29
|
-
const compose = require('./session/compose.js');
|
|
30
|
-
const { Composer } = compose;
|
|
31
|
-
const ops = require('./session/ops.js');
|
|
32
|
-
const { OpsRunner } = ops;
|
|
33
|
-
const commit = require('./session/commit.js');
|
|
34
|
-
const { CommitController } = commit;
|
|
35
|
-
const branches = require('./session/branches.js');
|
|
36
|
-
const { BranchController } = branches;
|
|
37
|
-
const npm = require('./session/npm.js');
|
|
38
|
-
const { NpmController } = npm;
|
|
39
|
-
const packages = require('./session/packages.js');
|
|
40
|
-
const { PackageController } = packages;
|
|
41
|
-
const accessors = require('./session/accessors.js');
|
|
42
|
-
const { bindAccessors, bindGetters } = accessors;
|
|
43
|
-
const view = require('./session/view.js');
|
|
44
|
-
const filesPane = require('./session/files-pane.js');
|
|
45
|
-
const lifecycle = require('./session/lifecycle.js');
|
|
46
|
-
const { Lifecycle } = lifecycle;
|
|
47
|
-
const dispatch = require('./session/dispatch.js');
|
|
3
|
+
const { renderFrame } = require('../render/render.js');
|
|
4
|
+
const { decodeChunk } = require('../input/keys.js');
|
|
5
|
+
const { AUTOSAVE_MS, hasNotes } = require('../review/review.js');
|
|
6
|
+
const { makeTaskItem } = require('../common/files.js');
|
|
7
|
+
const { sessionCapabilities } = require('../source/capabilities.js');
|
|
8
|
+
const { LIST_PANES } = require('../input/actions.js');
|
|
9
|
+
const { Terminal, Progress, LEAVE_TERM } = require('./terminal.js');
|
|
10
|
+
const { LoadCoordinator } = require('./load.js');
|
|
11
|
+
const { ItemCollection } = require('./items.js');
|
|
12
|
+
const { Navigation } = require('./navigation.js');
|
|
13
|
+
const { ReviewController } = require('./review.js');
|
|
14
|
+
const { UpdateCoordinator } = require('./update.js');
|
|
15
|
+
const { Composer } = require('./compose.js');
|
|
16
|
+
const { OpsRunner } = require('./ops.js');
|
|
17
|
+
const { FileReads } = require('./reads.js');
|
|
18
|
+
const { CommitController } = require('./commit.js');
|
|
19
|
+
const { BranchController } = require('./branches.js');
|
|
20
|
+
const { NpmController } = require('./npm/npm.js');
|
|
21
|
+
const { PackageController } = require('./npm/packages.js');
|
|
22
|
+
const { AgentsController } = require('./agents/agents.js');
|
|
23
|
+
const view = require('./view.js');
|
|
24
|
+
const filesPane = require('./files-pane.js');
|
|
25
|
+
const { Lifecycle } = require('./lifecycle.js');
|
|
26
|
+
const dispatch = require('./dispatch.js');
|
|
48
27
|
const { dispatchAction, confirmChoice, handleEvent } = dispatch;
|
|
49
|
-
const
|
|
50
|
-
const {
|
|
51
|
-
|
|
52
|
-
const
|
|
28
|
+
const { Dashboard } = require('./dashboard.js');
|
|
29
|
+
const { Workspace } = require('./workspace.js');
|
|
30
|
+
|
|
31
|
+
const bindAccessors = (target, owner, names) => {
|
|
32
|
+
for (const name of names) {
|
|
33
|
+
Object.defineProperty(target, name, {
|
|
34
|
+
configurable: true,
|
|
35
|
+
enumerable: true,
|
|
36
|
+
get: () => owner[name],
|
|
37
|
+
set: (value) => {
|
|
38
|
+
owner[name] = value;
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const bindGetters = (target, owner, names) => {
|
|
45
|
+
for (const name of names) {
|
|
46
|
+
Object.defineProperty(target, name, {
|
|
47
|
+
configurable: true,
|
|
48
|
+
enumerable: true,
|
|
49
|
+
get: () => owner[name],
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
53
|
|
|
54
54
|
const PROGRESS_MS = 160;
|
|
55
|
+
const QUIT_WAIT_MS = 3000;
|
|
55
56
|
|
|
56
57
|
const NAV_FIELDS = [
|
|
57
58
|
'pane',
|
|
@@ -60,6 +61,8 @@ const NAV_FIELDS = [
|
|
|
60
61
|
'branchCursor',
|
|
61
62
|
'commitCursor',
|
|
62
63
|
'npmCursor',
|
|
64
|
+
'packagesCursor',
|
|
65
|
+
'agentCursor',
|
|
63
66
|
'scroll',
|
|
64
67
|
'listScroll',
|
|
65
68
|
'reviewPath',
|
|
@@ -104,6 +107,11 @@ const assignOptions = (session, options) => {
|
|
|
104
107
|
session.dashboardHome = options.startPane === 'dashboard';
|
|
105
108
|
session.workspaceRoot = options.workspace ? options.workspace.root : '';
|
|
106
109
|
session.workspaceInfo = options.workspace ?? null;
|
|
110
|
+
session.loadPullRequest = options.loadPullRequest ?? null;
|
|
111
|
+
session.loadMergeRequest = options.loadMergeRequest ?? null;
|
|
112
|
+
session.loadGithubIssue = options.loadGithubIssue ?? null;
|
|
113
|
+
session.loadGitlabIssue = options.loadGitlabIssue ?? null;
|
|
114
|
+
session.fetchImpl = options.fetch ?? null;
|
|
107
115
|
};
|
|
108
116
|
|
|
109
117
|
const assignParts = (session, options) => {
|
|
@@ -118,10 +126,12 @@ const assignParts = (session, options) => {
|
|
|
118
126
|
session.updater = new UpdateCoordinator(session);
|
|
119
127
|
session.composer = new Composer(session);
|
|
120
128
|
session.ops = new OpsRunner(session);
|
|
129
|
+
session.reads = new FileReads(session);
|
|
121
130
|
session.commits = new CommitController(session);
|
|
122
131
|
session.gitBranches = new BranchController(session);
|
|
123
132
|
session.npm = new NpmController(session);
|
|
124
133
|
session.packages = new PackageController(session);
|
|
134
|
+
session.agents = new AgentsController(session);
|
|
125
135
|
session.dashboard = new Dashboard(session);
|
|
126
136
|
session.workspace = new Workspace(session);
|
|
127
137
|
session.lifecycle = new Lifecycle(session);
|
|
@@ -164,18 +174,23 @@ class Session {
|
|
|
164
174
|
this.review.reset();
|
|
165
175
|
this.composer.reset();
|
|
166
176
|
this.ops.reset();
|
|
177
|
+
this.reads.reset();
|
|
167
178
|
this.gitBranches.reset();
|
|
168
179
|
this.commits.reset();
|
|
169
180
|
this.npm.reset();
|
|
181
|
+
this.agents.reset();
|
|
170
182
|
this.dashboard.reset();
|
|
171
183
|
this.workspace.reset();
|
|
172
184
|
this.top = this.cwd;
|
|
173
185
|
this.branch = '';
|
|
186
|
+
this.repositoryUrl = '';
|
|
174
187
|
this.status = '';
|
|
175
188
|
this.layout = 'unified';
|
|
189
|
+
this.lineNumbers = false;
|
|
176
190
|
this.done = false;
|
|
177
191
|
this.exitCode = 0;
|
|
178
192
|
this.mode = 'review';
|
|
193
|
+
this.quitWarning = '';
|
|
179
194
|
this.tasksItem = makeTaskItem();
|
|
180
195
|
this.progressFrame = 0;
|
|
181
196
|
this.emptyReview = false;
|
|
@@ -190,13 +205,13 @@ class Session {
|
|
|
190
205
|
this.progress.clear();
|
|
191
206
|
}
|
|
192
207
|
|
|
193
|
-
ensureRepo() {
|
|
208
|
+
async ensureRepo() {
|
|
194
209
|
if (!this.repo.toplevel) return;
|
|
195
|
-
this.top = this.repo.toplevel(this.cwd);
|
|
210
|
+
this.top = await this.repo.toplevel(this.cwd);
|
|
196
211
|
}
|
|
197
212
|
|
|
198
213
|
load() {
|
|
199
|
-
this.lifecycle.load();
|
|
214
|
+
return this.lifecycle.load();
|
|
200
215
|
}
|
|
201
216
|
|
|
202
217
|
loadReady() {
|
|
@@ -234,6 +249,21 @@ class Session {
|
|
|
234
249
|
if (LIST_PANES.includes(this.pane)) {
|
|
235
250
|
this.nav.listScroll = frame.listScroll;
|
|
236
251
|
}
|
|
252
|
+
const menuScroll = frame.menuScroll;
|
|
253
|
+
if (this.agents.pick && typeof menuScroll === 'number') {
|
|
254
|
+
this.agents.pick.scroll = menuScroll;
|
|
255
|
+
}
|
|
256
|
+
const planPick = this.composer.tasks.planPick;
|
|
257
|
+
if (planPick && typeof menuScroll === 'number') {
|
|
258
|
+
planPick.scroll = menuScroll;
|
|
259
|
+
}
|
|
260
|
+
if (typeof frame.runScroll === 'number') {
|
|
261
|
+
const panel = this.pane === 'npm' ? this.npm : this.agents;
|
|
262
|
+
panel.runScroll = frame.runScroll;
|
|
263
|
+
}
|
|
264
|
+
if (typeof frame.gridCols === 'number') {
|
|
265
|
+
this.workspace.cols = frame.gridCols;
|
|
266
|
+
}
|
|
237
267
|
if (this.nav.tasksOpen) this.nav.scroll = frame.scroll;
|
|
238
268
|
const editScroll = frame.cursor && frame.cursor.scroll;
|
|
239
269
|
if (this.editor && typeof editScroll === 'number') {
|
|
@@ -294,7 +324,11 @@ class Session {
|
|
|
294
324
|
}
|
|
295
325
|
|
|
296
326
|
handleEvent(event) {
|
|
297
|
-
handleEvent(this, event);
|
|
327
|
+
if (!this.ops.defer(event)) handleEvent(this, event);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
finishInput() {
|
|
331
|
+
if (this.finishReadLoop) this.finishReadLoop();
|
|
298
332
|
}
|
|
299
333
|
|
|
300
334
|
pushInput(text) {
|
|
@@ -342,28 +376,84 @@ class Session {
|
|
|
342
376
|
this.composer.autosave();
|
|
343
377
|
}
|
|
344
378
|
|
|
379
|
+
retarget({ cwd, top, repoName, pane }) {
|
|
380
|
+
this.lifecycle.stopWatch();
|
|
381
|
+
this.dashboard.stop();
|
|
382
|
+
this.loader.reset();
|
|
383
|
+
this.cwd = cwd;
|
|
384
|
+
if (top) this.top = top;
|
|
385
|
+
this.paths = [];
|
|
386
|
+
this.repoName = repoName;
|
|
387
|
+
this.branch = '';
|
|
388
|
+
this.repositoryUrl = '';
|
|
389
|
+
this.rev = null;
|
|
390
|
+
this.revShort = '';
|
|
391
|
+
this.change = null;
|
|
392
|
+
this.dashboardHome = pane === 'dashboard';
|
|
393
|
+
this.collection.reset();
|
|
394
|
+
this.reads.reset();
|
|
395
|
+
this.review.reset();
|
|
396
|
+
this.nav.pane = pane;
|
|
397
|
+
this.nav.tasksOpen = false;
|
|
398
|
+
this.nav.scroll = 0;
|
|
399
|
+
this.nav.clearSelection();
|
|
400
|
+
this.status = '';
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
childWarning() {
|
|
404
|
+
const tests = this.npm && this.npm.running === true;
|
|
405
|
+
const agents = this.agents && this.agents.runningCount() > 0;
|
|
406
|
+
if (tests && agents) return ' exit will terminate tests and agents';
|
|
407
|
+
if (agents) return ' exit will terminate agents';
|
|
408
|
+
if (tests) return ' exit will terminate tests';
|
|
409
|
+
return '';
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
stopChildren() {
|
|
413
|
+
if (this.npm) this.npm.stopAll();
|
|
414
|
+
if (this.agents) this.agents.killAll();
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// A quick repo write still running lands first, so it is not left half done
|
|
418
|
+
exitNow() {
|
|
419
|
+
if (this.done || !this.ops.unlanded()) return void this.finishExit();
|
|
420
|
+
const exit = () => this.finishExit();
|
|
421
|
+
this.ops.hold(this.ops.landed(QUIT_WAIT_MS).then(exit));
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
finishExit() {
|
|
425
|
+
this.flushReview();
|
|
426
|
+
this.done = true;
|
|
427
|
+
this.exitCode = 0;
|
|
428
|
+
}
|
|
429
|
+
|
|
345
430
|
onQuit() {
|
|
431
|
+
const composer = this.composer;
|
|
432
|
+
if (this.mode === 'compose' && composer.writesDisk()) {
|
|
433
|
+
const quit = () => this.onQuit();
|
|
434
|
+
return void this.ops.hold(composer.writeAndClose().then(quit));
|
|
435
|
+
}
|
|
346
436
|
if (this.mode === 'compose') {
|
|
347
|
-
|
|
348
|
-
|
|
437
|
+
composer.commitCompose();
|
|
438
|
+
composer.closeCompose();
|
|
349
439
|
}
|
|
350
|
-
|
|
440
|
+
const warning = this.childWarning();
|
|
441
|
+
if (warning) {
|
|
442
|
+
this.quitWarning = warning;
|
|
351
443
|
this.mode = 'confirmQuit';
|
|
352
444
|
this.status = '';
|
|
353
445
|
return;
|
|
354
446
|
}
|
|
355
|
-
this.
|
|
356
|
-
this.exitCode = 0;
|
|
447
|
+
this.exitNow();
|
|
357
448
|
}
|
|
358
449
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
this.done = true;
|
|
363
|
-
this.exitCode = 0;
|
|
450
|
+
confirmQuit() {
|
|
451
|
+
this.stopChildren();
|
|
452
|
+
this.exitNow();
|
|
364
453
|
}
|
|
365
454
|
|
|
366
455
|
cancelQuit() {
|
|
456
|
+
this.quitWarning = '';
|
|
367
457
|
this.mode = 'review';
|
|
368
458
|
this.status = '';
|
|
369
459
|
}
|
|
@@ -378,6 +468,7 @@ class Session {
|
|
|
378
468
|
|
|
379
469
|
tickProgress() {
|
|
380
470
|
this.progressFrame += 1;
|
|
471
|
+
if (this.npm.running) this.npm.refreshRecorded();
|
|
381
472
|
this.paint();
|
|
382
473
|
}
|
|
383
474
|
|
|
@@ -398,6 +489,10 @@ class Session {
|
|
|
398
489
|
try {
|
|
399
490
|
if (this.nav.pane === 'repos') this.workspace.start();
|
|
400
491
|
this.openLoad();
|
|
492
|
+
// Populate the agent model cache while the initial screen is loading.
|
|
493
|
+
// Opening the Agents pane can then use the cache instead of being the
|
|
494
|
+
// first place that starts its CLI probes.
|
|
495
|
+
void this.agents.loadModels();
|
|
401
496
|
this.openUpdate();
|
|
402
497
|
this.draw();
|
|
403
498
|
await this.readLoop();
|