@quickchatai/quickreview 1.2.0 → 1.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/README.md +114 -50
- package/bin/qcr.js +1 -1
- package/config.example.toml +20 -6
- package/deploy/ansible/README.md +20 -12
- package/deploy/ansible/inventory.example.ini +1 -1
- package/deploy/collect-secrets.sh +1 -1
- package/deploy/qcr-update.sh +1 -1
- package/dist/extensions/cli/home.js +14 -0
- package/dist/extensions/cli/home.js.map +1 -0
- package/dist/extensions/cli/selfimprove.js +18 -0
- package/dist/extensions/cli/selfimprove.js.map +1 -0
- package/dist/extensions/home.js +350 -0
- package/dist/extensions/home.js.map +1 -0
- package/dist/extensions/login-route.js +1 -1
- package/dist/extensions/login-route.js.map +1 -1
- package/dist/extensions/onboarding.js +8 -7
- package/dist/extensions/onboarding.js.map +1 -1
- package/dist/extensions/selfimprove.js +49 -0
- package/dist/extensions/selfimprove.js.map +1 -0
- package/dist/extensions/setup-scan.js +23 -592
- package/dist/extensions/setup-scan.js.map +1 -1
- package/dist/extensions/setup.js +2 -47
- package/dist/extensions/setup.js.map +1 -1
- package/dist/src/archive/restore.js +18 -15
- package/dist/src/archive/restore.js.map +1 -1
- package/dist/src/botworker.js +13 -2
- package/dist/src/botworker.js.map +1 -1
- package/dist/src/channelfs.js +3 -26
- package/dist/src/channelfs.js.map +1 -1
- package/dist/src/cli.js +12 -50
- package/dist/src/cli.js.map +1 -1
- package/dist/src/config.js +16 -0
- package/dist/src/config.js.map +1 -1
- package/dist/src/daemon.js +26 -0
- package/dist/src/daemon.js.map +1 -1
- package/dist/src/debuground.js +1 -0
- package/dist/src/debuground.js.map +1 -1
- package/dist/src/debugroundpi.js +1 -0
- package/dist/src/debugroundpi.js.map +1 -1
- package/dist/src/engine/caserunner-sdk.js +15 -251
- package/dist/src/engine/caserunner-sdk.js.map +1 -1
- package/dist/src/home/adapters.js +349 -0
- package/dist/src/home/adapters.js.map +1 -0
- package/dist/src/home/advanced.js +318 -0
- package/dist/src/home/advanced.js.map +1 -0
- package/dist/src/home/advancedtools.js +57 -0
- package/dist/src/home/advancedtools.js.map +1 -0
- package/dist/src/home/autoreview.js +325 -0
- package/dist/src/home/autoreview.js.map +1 -0
- package/dist/src/home/daemonstatus.js +32 -0
- package/dist/src/home/daemonstatus.js.map +1 -0
- package/dist/src/home/devicelogin.js +61 -0
- package/dist/src/home/devicelogin.js.map +1 -0
- package/dist/src/home/launch.js +202 -0
- package/dist/src/home/launch.js.map +1 -0
- package/dist/src/home/loginowner.js +205 -0
- package/dist/src/home/loginowner.js.map +1 -0
- package/dist/src/home/memory.js +122 -0
- package/dist/src/home/memory.js.map +1 -0
- package/dist/src/home/model.js +811 -0
- package/dist/src/home/model.js.map +1 -0
- package/dist/src/home/panel.js +520 -0
- package/dist/src/home/panel.js.map +1 -0
- package/dist/src/home/ports.js +19 -0
- package/dist/src/home/ports.js.map +1 -0
- package/dist/src/home/review.js +163 -0
- package/dist/src/home/review.js.map +1 -0
- package/dist/src/home/reviews.js +478 -0
- package/dist/src/home/reviews.js.map +1 -0
- package/dist/src/home/setup.js +507 -0
- package/dist/src/home/setup.js.map +1 -0
- package/dist/src/home/setupadapters.js +214 -0
- package/dist/src/home/setupadapters.js.map +1 -0
- package/dist/src/home/setupcard.js +199 -0
- package/dist/src/home/setupcard.js.map +1 -0
- package/dist/src/home/setuptools.js +45 -0
- package/dist/src/home/setuptools.js.map +1 -0
- package/dist/src/home/spend.js +160 -0
- package/dist/src/home/spend.js.map +1 -0
- package/dist/src/home/switches.js +209 -0
- package/dist/src/home/switches.js.map +1 -0
- package/dist/src/home/switchon.js +439 -0
- package/dist/src/home/switchon.js.map +1 -0
- package/dist/src/home/toolnames.js +41 -0
- package/dist/src/home/toolnames.js.map +1 -0
- package/dist/src/home/tune.js +341 -0
- package/dist/src/home/tune.js.map +1 -0
- package/dist/src/home/words.js +7 -0
- package/dist/src/home/words.js.map +1 -0
- package/dist/src/homes.js +14 -0
- package/dist/src/homes.js.map +1 -1
- package/dist/src/install.js +1 -1
- package/dist/src/install.js.map +1 -1
- package/dist/src/ipc/workerspec.js +8 -0
- package/dist/src/ipc/workerspec.js.map +1 -1
- package/dist/src/live/publish.js +1 -1
- package/dist/src/live/publish.js.map +1 -1
- package/dist/src/livecli.js +1 -1
- package/dist/src/livecli.js.map +1 -1
- package/dist/src/loginrefresh/handover.js +121 -0
- package/dist/src/loginrefresh/handover.js.map +1 -0
- package/dist/src/loginrefresh/lock.js +54 -3
- package/dist/src/loginrefresh/lock.js.map +1 -1
- package/dist/src/loginrefresh/refresher.js +33 -5
- package/dist/src/loginrefresh/refresher.js.map +1 -1
- package/dist/src/loginrefresh/supervisor.js +18 -1
- package/dist/src/loginrefresh/supervisor.js.map +1 -1
- package/dist/src/npmverbs.js +42 -12
- package/dist/src/npmverbs.js.map +1 -1
- package/dist/src/onboard/choices.js +6 -3
- package/dist/src/onboard/choices.js.map +1 -1
- package/dist/src/onboard/engine.js +33 -292
- package/dist/src/onboard/engine.js.map +1 -1
- package/dist/src/onboard/steps/bringup.js +3 -2
- package/dist/src/onboard/steps/bringup.js.map +1 -1
- package/dist/src/onboard/steps/configfill.js +18 -7
- package/dist/src/onboard/steps/configfill.js.map +1 -1
- package/dist/src/onboard/steps/loginshare.js +213 -0
- package/dist/src/onboard/steps/loginshare.js.map +1 -0
- package/dist/src/onboard/steps/memory.js +14 -2
- package/dist/src/onboard/steps/memory.js.map +1 -1
- package/dist/src/onboard/steps/repoconfig.js +72 -0
- package/dist/src/onboard/steps/repoconfig.js.map +1 -0
- package/dist/src/onboard/toolnames.js +2 -2
- package/dist/src/onboard/toolnames.js.map +1 -1
- package/dist/src/piagentdir.js +13 -0
- package/dist/src/piagentdir.js.map +1 -0
- package/dist/src/pilogin.js +31 -16
- package/dist/src/pilogin.js.map +1 -1
- package/dist/src/qcrbin.js +16 -11
- package/dist/src/qcrbin.js.map +1 -1
- package/dist/src/reviewargs.js +122 -0
- package/dist/src/reviewargs.js.map +1 -0
- package/dist/src/reviewcli.js +7 -161
- package/dist/src/reviewcli.js.map +1 -1
- package/dist/src/reviewdetach.js +76 -11
- package/dist/src/reviewdetach.js.map +1 -1
- package/dist/src/scancli.js +39 -691
- package/dist/src/scancli.js.map +1 -1
- package/dist/src/selfimprove.js +66 -0
- package/dist/src/selfimprove.js.map +1 -0
- package/dist/src/setup/adapters.js +5 -223
- package/dist/src/setup/adapters.js.map +1 -1
- package/dist/src/setup/caserunner.js +15 -249
- package/dist/src/setup/caserunner.js.map +1 -1
- package/dist/src/setup/engine.js +32 -341
- package/dist/src/setup/engine.js.map +1 -1
- package/dist/src/setup/facts.js +3 -592
- package/dist/src/setup/facts.js.map +1 -1
- package/dist/src/setup/findings.js +3 -947
- package/dist/src/setup/findings.js.map +1 -1
- package/dist/src/setup/presentation.js +3 -8
- package/dist/src/setup/presentation.js.map +1 -1
- package/dist/src/setup/scan.js +3 -724
- package/dist/src/setup/scan.js.map +1 -1
- package/dist/src/setup/scanbuild.js +9 -92
- package/dist/src/setup/scanbuild.js.map +1 -1
- package/dist/src/setup/scanlease.js +3 -250
- package/dist/src/setup/scanlease.js.map +1 -1
- package/dist/src/setup/scanreport.js +3 -288
- package/dist/src/setup/scanreport.js.map +1 -1
- package/dist/src/setup/scanrun.js +3 -1732
- package/dist/src/setup/scanrun.js.map +1 -1
- package/dist/src/setup/scantree.js +3 -256
- package/dist/src/setup/scantree.js.map +1 -1
- package/dist/src/setup/stage2request.js +3 -258
- package/dist/src/setup/stage2request.js.map +1 -1
- package/dist/src/setup/unitcut.js +3 -436
- package/dist/src/setup/unitcut.js.map +1 -1
- package/dist/src/state.js +2 -0
- package/dist/src/state.js.map +1 -1
- package/dist/src/takeover.js +1 -0
- package/dist/src/takeover.js.map +1 -1
- package/dist/src/takeoverpi.js +2 -1
- package/dist/src/takeoverpi.js.map +1 -1
- package/dist/src/tui/board.js +1 -1
- package/dist/src/tui/board.js.map +1 -1
- package/dist/src/tui/companion.js +2 -1
- package/dist/src/tui/companion.js.map +1 -1
- package/dist/src/tui/deploytab.js +2 -2
- package/dist/src/tui/deploytab.js.map +1 -1
- package/dist/src/tui/index.js +9 -6
- package/dist/src/tui/index.js.map +1 -1
- package/dist/src/tui/memory.js +3 -16
- package/dist/src/tui/memory.js.map +1 -1
- package/dist/src/tui/memoryurl.js +22 -0
- package/dist/src/tui/memoryurl.js.map +1 -0
- package/dist/src/tui/remote.js +1 -1
- package/dist/src/tui/remote.js.map +1 -1
- package/dist/src/tui/route.js +2 -2
- package/dist/src/tui/route.js.map +1 -1
- package/dist/src/tui/setupstate.js +8 -5
- package/dist/src/tui/setupstate.js.map +1 -1
- package/dist/src/tui/sshtriage.js +1 -1
- package/dist/src/tui/sshtriage.js.map +1 -1
- package/dist/src/wire.js +6 -2
- package/dist/src/wire.js.map +1 -1
- package/dist/src/workerworld.js +4 -0
- package/dist/src/workerworld.js.map +1 -1
- package/docker/README.md +1 -1
- package/docker/entrypoint.sh +40 -6
- package/docker-compose.yml +16 -1
- package/extensions/cli/home.ts +14 -0
- package/extensions/cli/selfimprove.ts +18 -0
- package/extensions/home.ts +484 -0
- package/extensions/login-route.ts +1 -1
- package/extensions/onboarding.ts +8 -7
- package/extensions/selfimprove.ts +65 -0
- package/extensions/setup-scan.ts +79 -766
- package/extensions/setup.ts +14 -70
- package/package.json +6 -4
- package/prompts/onboarding.md +8 -7
- package/schemas/review-result.v1.json +60 -0
- package/scripts/deploy.sh +8 -6
- package/scripts/qcr-host.sh +28 -5
- package/scripts/vm-ghcr-login.sh +7 -4
- package/src/archive/restore.ts +18 -21
- package/src/botworker.ts +13 -2
- package/src/channelfs.ts +3 -26
- package/src/cli.ts +11 -54
- package/src/config.ts +38 -0
- package/src/daemon.ts +26 -0
- package/src/debuground.ts +3 -0
- package/src/debugroundpi.ts +1 -0
- package/src/engine/caserunner-sdk.ts +29 -314
- package/src/home/adapters.ts +418 -0
- package/src/home/advanced.ts +421 -0
- package/src/home/advancedtools.ts +96 -0
- package/src/home/autoreview.ts +385 -0
- package/src/home/daemonstatus.ts +55 -0
- package/src/home/devicelogin.ts +107 -0
- package/src/home/launch.ts +257 -0
- package/src/home/loginowner.ts +248 -0
- package/src/home/memory.ts +176 -0
- package/src/home/model.ts +965 -0
- package/src/home/panel.ts +666 -0
- package/src/home/ports.ts +338 -0
- package/src/home/review.ts +206 -0
- package/src/home/reviews.ts +565 -0
- package/src/home/setup.ts +689 -0
- package/src/home/setupadapters.ts +217 -0
- package/src/home/setupcard.ts +288 -0
- package/src/home/setuptools.ts +57 -0
- package/src/home/spend.ts +194 -0
- package/src/home/switches.ts +293 -0
- package/src/home/switchon.ts +554 -0
- package/src/home/toolnames.ts +46 -0
- package/src/home/tune.ts +405 -0
- package/src/home/words.ts +8 -0
- package/src/homes.ts +17 -0
- package/src/install.ts +1 -1
- package/src/ipc/workerspec.ts +15 -0
- package/src/live/publish.ts +4 -1
- package/src/livecli.ts +6 -1
- package/src/loginrefresh/handover.ts +138 -0
- package/src/loginrefresh/lock.ts +72 -3
- package/src/loginrefresh/refresher.ts +34 -5
- package/src/loginrefresh/supervisor.ts +25 -2
- package/src/npmverbs.ts +51 -11
- package/src/onboard/choices.ts +6 -3
- package/src/onboard/engine.ts +64 -434
- package/src/onboard/steps/bringup.ts +3 -2
- package/src/onboard/steps/configfill.ts +23 -7
- package/src/onboard/steps/loginshare.ts +258 -0
- package/src/onboard/steps/memory.ts +18 -2
- package/src/onboard/steps/repoconfig.ts +85 -0
- package/src/onboard/toolnames.ts +2 -2
- package/src/piagentdir.ts +12 -0
- package/src/pilogin.ts +32 -16
- package/src/qcrbin.ts +16 -11
- package/src/reviewargs.ts +119 -0
- package/src/reviewcli.ts +6 -167
- package/src/reviewdetach.ts +107 -13
- package/src/scancli.ts +75 -826
- package/src/selfimprove.ts +90 -0
- package/src/setup/adapters.ts +13 -221
- package/src/setup/caserunner.ts +34 -273
- package/src/setup/engine.ts +62 -496
- package/src/setup/facts.ts +3 -627
- package/src/setup/findings.ts +3 -1264
- package/src/setup/presentation.ts +3 -18
- package/src/setup/scan.ts +3 -1033
- package/src/setup/scanbuild.ts +20 -114
- package/src/setup/scanlease.ts +3 -297
- package/src/setup/scanreport.ts +3 -373
- package/src/setup/scanrun.ts +3 -2268
- package/src/setup/scantree.ts +3 -259
- package/src/setup/stage2request.ts +3 -347
- package/src/setup/unitcut.ts +3 -523
- package/src/state.ts +25 -0
- package/src/takeover.ts +5 -0
- package/src/takeoverpi.ts +3 -2
- package/src/tui/board.ts +1 -1
- package/src/tui/companion.ts +2 -1
- package/src/tui/deploytab.ts +2 -2
- package/src/tui/index.ts +9 -6
- package/src/tui/memory.ts +3 -15
- package/src/tui/memoryurl.ts +22 -0
- package/src/tui/remote.ts +1 -1
- package/src/tui/route.ts +2 -2
- package/src/tui/setupstate.ts +20 -16
- package/src/tui/sshtriage.ts +1 -1
- package/src/wire.ts +6 -2
- package/src/workerworld.ts +9 -1
- package/dist/src/live/projection.js +0 -450
- package/dist/src/live/projection.js.map +0 -1
- package/dist/src/live/read.js +0 -60
- package/dist/src/live/read.js.map +0 -1
- package/dist/src/onboard/launch.js +0 -75
- package/dist/src/onboard/launch.js.map +0 -1
- package/dist/src/setup/ledger.js +0 -207
- package/dist/src/setup/ledger.js.map +0 -1
- package/dist/src/setup/stage2.js +0 -617
- package/dist/src/setup/stage2.js.map +0 -1
- package/dist/src/setup/textsniff.js +0 -89
- package/dist/src/setup/textsniff.js.map +0 -1
- package/src/live/projection.ts +0 -491
- package/src/live/read.ts +0 -86
- package/src/onboard/launch.ts +0 -103
- package/src/setup/ledger.ts +0 -324
- package/src/setup/stage2.ts +0 -926
- package/src/setup/textsniff.ts +0 -95
package/extensions/setup.ts
CHANGED
|
@@ -57,7 +57,12 @@ import {
|
|
|
57
57
|
} from "@quickchatai/pi-quickreview/extensions/pi-tool.js";
|
|
58
58
|
import { fileURLToPath } from "node:url";
|
|
59
59
|
import { configHome, stateHome } from "../src/install.js";
|
|
60
|
-
import { SetupEngine
|
|
60
|
+
import { SetupEngine } from "../src/setup/engine.js";
|
|
61
|
+
import {
|
|
62
|
+
renderCut,
|
|
63
|
+
renderDraft,
|
|
64
|
+
renderStatus,
|
|
65
|
+
} from "@quickchatai/pi-quickreview/src/scan/cutrender.js";
|
|
61
66
|
import type { HistoryTheme, HistoryThemesFile } from "../src/setup/history.js";
|
|
62
67
|
import {
|
|
63
68
|
HISTORY_SECTIONS,
|
|
@@ -154,75 +159,14 @@ export function renderFacts(facts: RepoFacts, head: string | null): string {
|
|
|
154
159
|
].join("\n\n");
|
|
155
160
|
}
|
|
156
161
|
|
|
157
|
-
export
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const over = u.cases?.some((c) => c.over_budget)
|
|
166
|
-
? " [a file alone exceeds one case — a scan reads it in line ranges]"
|
|
167
|
-
: "";
|
|
168
|
-
return ` - ${u.name} [${u.kind}] ${u.roots.map(displayRoot).join(", ")}: ${u.files ?? "UNKNOWN"} files, ${u.reviewable ?? "UNKNOWN"} reviewable, ${u.lines ?? "UNKNOWN"} lines${split}${over}${u.note ? ` — ${u.note}` : ""}`;
|
|
169
|
-
});
|
|
170
|
-
const lines = [`${title}:`, ...rows];
|
|
171
|
-
if (v.ignored.length > 0)
|
|
172
|
-
lines.push(` ignored: ${v.ignored.join(", ")} (${v.ignored_files ?? "UNKNOWN"} files)`);
|
|
173
|
-
for (const e of v.errors) lines.push(` ✗ ${e}`);
|
|
174
|
-
for (const b of v.blocking_save) lines.push(` ! ${b}`);
|
|
175
|
-
return lines.join("\n");
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/** How a rendering names the save that makes a draft the cut — the tool, or
|
|
179
|
-
* the `qcr scan units` verb. */
|
|
180
|
-
export interface CutVerbs {
|
|
181
|
-
save: string;
|
|
182
|
-
}
|
|
183
|
-
export const CUT_TOOL_VERBS: CutVerbs = { save: "setup_unit_cut_save" };
|
|
184
|
-
export const CUT_CLI_VERBS: CutVerbs = { save: "qcr scan units save" };
|
|
185
|
-
|
|
186
|
-
/** A stored or adjusted draft, and that it is not in use until saved. */
|
|
187
|
-
export function renderDraft(
|
|
188
|
-
title: string,
|
|
189
|
-
draft: CutView,
|
|
190
|
-
verbs: CutVerbs = CUT_TOOL_VERBS,
|
|
191
|
-
): string {
|
|
192
|
-
return `${renderCut(title, draft)}\n\nNot in use until ${verbs.save}.`;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
export function renderStatus(s: CutStatus): string {
|
|
196
|
-
const out: string[] = [];
|
|
197
|
-
for (const p of s.problems) out.push(`✗ ${p}`);
|
|
198
|
-
if (s.saved) {
|
|
199
|
-
const stale =
|
|
200
|
-
s.saved.blocking_save.length > 0 ? " — STALE against the repo now, see the ! lines" : "";
|
|
201
|
-
out.push(
|
|
202
|
-
renderCut(
|
|
203
|
-
`Saved unit cut (saved ${s.saved.saved_at}${s.saved.head ? ` at ${s.saved.head.slice(0, 12)}` : ""})${stale}`,
|
|
204
|
-
s.saved,
|
|
205
|
-
),
|
|
206
|
-
);
|
|
207
|
-
} else if (s.cut_file_unreadable) {
|
|
208
|
-
out.push(
|
|
209
|
-
"Saved unit cut: UNKNOWN — the cut file could not be read (see above); nothing will overwrite it.",
|
|
210
|
-
);
|
|
211
|
-
} else {
|
|
212
|
-
out.push("No saved unit cut yet.");
|
|
213
|
-
}
|
|
214
|
-
if (s.draft)
|
|
215
|
-
out.push(
|
|
216
|
-
renderCut(
|
|
217
|
-
`Draft (${s.draft.source}, updated ${s.draft.updated_at}) — not in use until saved`,
|
|
218
|
-
s.draft,
|
|
219
|
-
),
|
|
220
|
-
);
|
|
221
|
-
if (s.has_previous)
|
|
222
|
-
out.push("The cut before the saved one is kept as `previous` in the state home.");
|
|
223
|
-
return out.join("\n\n");
|
|
224
|
-
}
|
|
225
|
-
|
|
162
|
+
export {
|
|
163
|
+
CUT_CLI_VERBS,
|
|
164
|
+
CUT_TOOL_VERBS,
|
|
165
|
+
renderCut,
|
|
166
|
+
renderDraft,
|
|
167
|
+
renderStatus,
|
|
168
|
+
type CutVerbs,
|
|
169
|
+
} from "@quickchatai/pi-quickreview/src/scan/cutrender.js";
|
|
226
170
|
export function renderThemes(themes: readonly HistoryTheme[]): string {
|
|
227
171
|
return themes.length === 0
|
|
228
172
|
? " (none — an empty history has no themes)"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quickchatai/quickreview",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"//private": "The root is the published `qcr` CLI: the whole app (TUI, daemon, companion, every verb), installed with npm, pnpm or bun. It depends on the pi plugin (packages/pi-plugin) at its exact version and on pi at the exact pins below. Publishing is a release step of its own, never part of a build.",
|
|
6
6
|
"description": "A 24/7 AI code reviewer for GitHub: a deterministic daemon driving pi review sessions, with an operator TUI and a local qcr review",
|
|
@@ -94,11 +94,10 @@
|
|
|
94
94
|
"prepack": "npm run build",
|
|
95
95
|
"watch": "node scripts/tsc-watch.mjs -b --watch --preserveWatchOutput",
|
|
96
96
|
"dev": "bash scripts/dev-tui.sh",
|
|
97
|
-
"onboard": "bash scripts/qcr onboard",
|
|
98
97
|
"test": "vitest run",
|
|
99
98
|
"//canary:pi": "The offline pi canaries (tests/pi-canary/): the real pi SDK at the pinned version on pi-ai's faux provider, so no network and no cost. They also run inside `npm test`; this is the named entry point CI requires whenever the pi dependencies change (a bump is gated by it).",
|
|
100
99
|
"canary:pi": "vitest run tests/pi-canary",
|
|
101
|
-
"//canary:pi:range": "The same canaries on each pi version the plugin's peer range (packages/pi-plugin/package.json) should hold, refusing one outside it: no argument runs the installed pi; `-- --install 1.4.x` fetches another first (the registry
|
|
100
|
+
"//canary:pi:range": "The same canaries on each pi version the plugin's peer range (packages/pi-plugin/package.json) should hold, refusing one outside it: no argument runs the installed pi; `-- --install 1.4.x` fetches another first (the registry). Run it by hand before a version joins the peer range; CI runs only the installed pi's canaries. Needs the build.",
|
|
102
101
|
"canary:pi:range": "node scripts/pi-canary-range.mjs",
|
|
103
102
|
"//lint": "Deliberately NOT chained into `test` or `build`: scripts/dev-tui.sh blocks on the build before the TUI paints (ruling 5), and an ESLint pass there is seconds of blank terminal. CI runs it as its own step.",
|
|
104
103
|
"lint": "node --max-old-space-size=4096 node_modules/eslint/bin/eslint.js .",
|
|
@@ -116,7 +115,7 @@
|
|
|
116
115
|
},
|
|
117
116
|
"dependencies": {
|
|
118
117
|
"@earendil-works/pi-ai": "1.4.0",
|
|
119
|
-
"@quickchatai/pi-quickreview": "1.
|
|
118
|
+
"@quickchatai/pi-quickreview": "1.3.1",
|
|
120
119
|
"@earendil-works/pi-coding-agent": "1.4.0",
|
|
121
120
|
"better-sqlite3": "13.0.3",
|
|
122
121
|
"smol-toml": "1.9.1"
|
|
@@ -132,6 +131,9 @@
|
|
|
132
131
|
"vitest": "5.0.5",
|
|
133
132
|
"yaml": "2.9.1"
|
|
134
133
|
},
|
|
134
|
+
"overrides": {
|
|
135
|
+
"undici": "8.12.2"
|
|
136
|
+
},
|
|
135
137
|
"qcrPi": {
|
|
136
138
|
"//": "Named qcrPi, never `pi`: pi reads a package.json `pi` key as a package manifest, and this root is not a pi package (the plugin is packages/pi-plugin). pi and pi-ai are exact dependencies above (types for the extensions, and the VM boot's plain `npm ci` installs them beside the global CLI the image carries). This block is the mirror a bare checkout without config.toml reads: package and version must equal the dependencies, the lockfile, config.toml [pi], ansible group_vars and every Dockerfile ARG (tests/fences.test.ts [T12], tests/docker-daemon.test.ts). Lens sessions run through our own lens tools (src/engine/lens/), not a pi subagent extension, so no extra extension pin exists.",
|
|
137
139
|
"package": "@earendil-works/pi-coding-agent",
|
package/prompts/onboarding.md
CHANGED
|
@@ -94,20 +94,21 @@ the own-account route: it is skipped there.
|
|
|
94
94
|
`onboard_go_live` are marked "after setup": setup finishes without them. Do
|
|
95
95
|
not run them here unless the person asks. Say plainly that the installation
|
|
96
96
|
stays in dry-run (every intended GitHub write is recorded, nothing is
|
|
97
|
-
posted), and that going live is their decision later
|
|
98
|
-
|
|
97
|
+
posted), and that going live is their decision later, from the home
|
|
98
|
+
(Advanced → "Dry-run or live"), once a review has shown them what it says.
|
|
99
99
|
|
|
100
100
|
## Finishing
|
|
101
101
|
|
|
102
102
|
When every setup step reports done (the "after setup" ones need not be), say
|
|
103
103
|
that `finish_and_exit` will re-verify the whole checklist one last time and,
|
|
104
|
-
only if all green, close this session
|
|
105
|
-
|
|
104
|
+
only if all green, close this session: the home then lists the repository's
|
|
105
|
+
pull requests, and they select one and press `alt+r` to review it now. If it
|
|
106
|
+
returns red checks, that is the answer: explain them, fix
|
|
106
107
|
what can be fixed through the step tools, and try again. Never present
|
|
107
108
|
onboarding as finished while anything is red, and never tell the operator to
|
|
108
109
|
quit around a red check.
|
|
109
110
|
|
|
110
|
-
Before `finish_and_exit`, pass on what comes next: the first review is `
|
|
111
|
-
a pull request
|
|
112
|
-
the
|
|
111
|
+
Before `finish_and_exit`, pass on what comes next: the first review is `alt+r`
|
|
112
|
+
on a pull request in the home; then tune the reviewer to the repository with
|
|
113
|
+
the home's "Tune to this repo" (`t` on the panel). Until then the reviewer knows nothing about this codebase. It is a
|
|
113
114
|
recommendation, once — never start it from here.
|
|
@@ -137,6 +137,10 @@
|
|
|
137
137
|
"post": {
|
|
138
138
|
"$ref": "#/$defs/post"
|
|
139
139
|
},
|
|
140
|
+
"post_ready": {
|
|
141
|
+
"type": "string",
|
|
142
|
+
"description": "A finished PR review that was not posted: the file it is kept in, which a host that asks the person later posts through the gate exactly as `--to pr` would have."
|
|
143
|
+
},
|
|
140
144
|
"run_id": {
|
|
141
145
|
"type": "string",
|
|
142
146
|
"description": "A detached run's id (start, status, stop)."
|
|
@@ -149,6 +153,14 @@
|
|
|
149
153
|
"type": "string",
|
|
150
154
|
"description": "What a detached run reviews."
|
|
151
155
|
},
|
|
156
|
+
"started_at": {
|
|
157
|
+
"type": "number",
|
|
158
|
+
"description": "When a detached run was started, ms since the epoch."
|
|
159
|
+
},
|
|
160
|
+
"ended_at": {
|
|
161
|
+
"type": "number",
|
|
162
|
+
"description": "When a detached run ended (its exit or its stop), ms since the epoch; absent while it runs."
|
|
163
|
+
},
|
|
152
164
|
"elapsed_s": {
|
|
153
165
|
"type": "integer",
|
|
154
166
|
"minimum": 0
|
|
@@ -165,6 +177,50 @@
|
|
|
165
177
|
"items": {
|
|
166
178
|
"type": "string"
|
|
167
179
|
}
|
|
180
|
+
},
|
|
181
|
+
"live": {
|
|
182
|
+
"type": "object",
|
|
183
|
+
"description": "The running round's live log, projected: what the parent and each lens are doing now.",
|
|
184
|
+
"properties": {
|
|
185
|
+
"round": { "type": "integer", "minimum": 1 },
|
|
186
|
+
"parent_status": { "enum": ["active", "settled"] },
|
|
187
|
+
"last_activity": { "type": "string" },
|
|
188
|
+
"updated_at": { "type": "string" },
|
|
189
|
+
"active_tool": { "type": "string" },
|
|
190
|
+
"agents": {
|
|
191
|
+
"type": "array",
|
|
192
|
+
"items": {
|
|
193
|
+
"type": "object",
|
|
194
|
+
"required": ["agent", "status", "duration_ms", "tool_count"],
|
|
195
|
+
"properties": {
|
|
196
|
+
"agent": { "type": "string" },
|
|
197
|
+
"status": { "enum": ["running", "completed", "failed"] },
|
|
198
|
+
"duration_ms": {
|
|
199
|
+
"type": "number",
|
|
200
|
+
"minimum": 0,
|
|
201
|
+
"description": "The lens's time so far; a running lens's counts from its start between updates."
|
|
202
|
+
},
|
|
203
|
+
"tool_count": {
|
|
204
|
+
"type": "number",
|
|
205
|
+
"minimum": 0,
|
|
206
|
+
"description": "Tool calls the lens has started; a finished lens keeps its final count."
|
|
207
|
+
},
|
|
208
|
+
"current_tool": {
|
|
209
|
+
"type": "string",
|
|
210
|
+
"description": "The running (or last) tool, as `<tool>: <args>` or the bare name."
|
|
211
|
+
},
|
|
212
|
+
"current_target": {
|
|
213
|
+
"type": "string",
|
|
214
|
+
"description": "While the lens runs: the path its current tool works on, when it names one."
|
|
215
|
+
},
|
|
216
|
+
"line": {
|
|
217
|
+
"type": "string",
|
|
218
|
+
"description": "The lens as one line a person reads: `security · read src/x.ts · 7 tools · 0:41`."
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
168
224
|
}
|
|
169
225
|
}
|
|
170
226
|
},
|
|
@@ -234,6 +290,10 @@
|
|
|
234
290
|
"kind": {
|
|
235
291
|
"enum": ["pr", "branch", "uncommitted", "diff"],
|
|
236
292
|
"description": "What is reviewed: a pull request, the current branch against its base, the uncommitted working tree, or a unified diff handed in (`--diff`). Only a pr target can be posted."
|
|
293
|
+
},
|
|
294
|
+
"uncommitted": {
|
|
295
|
+
"const": true,
|
|
296
|
+
"description": "A branch target reviewed together with the working tree's uncommitted edits, as one review. Absent otherwise."
|
|
237
297
|
}
|
|
238
298
|
}
|
|
239
299
|
},
|
package/scripts/deploy.sh
CHANGED
|
@@ -46,9 +46,10 @@
|
|
|
46
46
|
# cloudflared when the inventory enables it), the
|
|
47
47
|
# containers, the image stamp, the pi settings and the
|
|
48
48
|
# reviewer stub, and the state/status.json heartbeat the
|
|
49
|
-
# status collector reads. It also warns 14 days before
|
|
50
|
-
#
|
|
51
|
-
# scripts/vm-ghcr-login.sh recorded
|
|
49
|
+
# status collector reads. It also warns 14 days before a
|
|
50
|
+
# private mirror's ghcr pull token expires (the expiry
|
|
51
|
+
# that scripts/vm-ghcr-login.sh recorded; the public
|
|
52
|
+
# release images need no login, so no record).
|
|
52
53
|
#
|
|
53
54
|
# `sync`, `dev` and `rebuild` are gone (the on-VM rsync and build are deleted):
|
|
54
55
|
# they refuse with a pointer to `release`. A pre-release fix is a release.
|
|
@@ -1083,8 +1084,9 @@ release_problem() {
|
|
|
1083
1084
|
fi
|
|
1084
1085
|
}
|
|
1085
1086
|
|
|
1086
|
-
# The
|
|
1087
|
-
#
|
|
1087
|
+
# The release images are public and pull with no login. A private mirror's
|
|
1088
|
+
# ghcr pull token expires (1 year, by ruling), and a lapsed one fails the
|
|
1089
|
+
# updater's pull. scripts/vm-ghcr-login.sh records the expiry on this
|
|
1088
1090
|
# controller; release and verify read it back. Within GHCR_WARN_DAYS of it
|
|
1089
1091
|
# (or past it) the plan line starts with WARNING. Warn only, never a refusal.
|
|
1090
1092
|
GHCR_WARN_DAYS=14
|
|
@@ -1095,7 +1097,7 @@ ghcr_expiry_status() {
|
|
|
1095
1097
|
local file iso epoch now days
|
|
1096
1098
|
file="$(qcr_ghcr_expiry_file 2>/dev/null)" || file=""
|
|
1097
1099
|
if [[ -z "$file" || ! -s "$file" ]]; then
|
|
1098
|
-
GHCR_EXPIRY_LINE="no
|
|
1100
|
+
GHCR_EXPIRY_LINE="no ghcr login recorded: the release images are public and pull without one (a private mirror logs the VM in with scripts/vm-ghcr-login.sh, which records its expiry)"
|
|
1099
1101
|
return 0
|
|
1100
1102
|
fi
|
|
1101
1103
|
iso="$(head -1 "$file" | tr -d '[:space:]')"
|
package/scripts/qcr-host.sh
CHANGED
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
# `stop` find it by label. `stop` sends `docker stop -t
|
|
13
13
|
# <grace>`, then `docker kill`: the container is the
|
|
14
14
|
# hard-kill backstop for a driver whose loop is frozen.
|
|
15
|
-
# qcr a bare qcr opens the
|
|
15
|
+
# qcr a bare qcr (or `qcr home`) opens the home: the image's
|
|
16
|
+
# pi with the plugin and its panel (home mode)
|
|
17
|
+
# qcr tui the operator TUI (tui mode), the one verb that starts
|
|
18
|
+
# the companion
|
|
16
19
|
# qcr login [provider] pi's own /login, stored in the qcr-login volume
|
|
17
20
|
# qcr update [version] pull a newer image and repin this file
|
|
18
21
|
#
|
|
@@ -21,8 +24,8 @@
|
|
|
21
24
|
# a worktree's common git dir at its own path read-only
|
|
22
25
|
# the qcr-state volume /opt/qcr/state read-write
|
|
23
26
|
# the qcr-login volume /qcr-login read-only
|
|
24
|
-
# (only `login`
|
|
25
|
-
# at pi's agent dir; its files are in
|
|
27
|
+
# (only `login` and the home mount it
|
|
28
|
+
# read-write, at pi's agent dir; its files are in
|
|
26
29
|
# group 4747, which every call joins,
|
|
27
30
|
# so a uid change never loses the login)
|
|
28
31
|
# ~/.config/qcr/profiles /qcr-config/profiles read-only
|
|
@@ -219,11 +222,20 @@ split=1
|
|
|
219
222
|
drop=0
|
|
220
223
|
gh=1
|
|
221
224
|
case "$verb" in
|
|
225
|
+
# The home is the person's own pi, as `qcr` from npm opens it: pi's agent
|
|
226
|
+
# dir on the login volume, read-write (its device login lands there), its
|
|
227
|
+
# config and sessions on the state volume, and the GitHub token for its `gh`.
|
|
222
228
|
'')
|
|
223
|
-
mode=
|
|
229
|
+
mode=home
|
|
224
230
|
tty=1
|
|
225
231
|
split=0
|
|
226
232
|
;;
|
|
233
|
+
home)
|
|
234
|
+
mode=home
|
|
235
|
+
tty=1
|
|
236
|
+
split=0
|
|
237
|
+
drop=1
|
|
238
|
+
;;
|
|
227
239
|
tui)
|
|
228
240
|
mode=tui
|
|
229
241
|
tty=1
|
|
@@ -555,7 +567,8 @@ fi
|
|
|
555
567
|
# ---- the GitHub token (GITHUB_TOKEN, GH_TOKEN, gh; no App on a laptop) -----
|
|
556
568
|
|
|
557
569
|
# The claim call only reads git: it needs no token, and a token file is read once.
|
|
558
|
-
|
|
570
|
+
# The home is handed it too: its `gh` lists and opens the pull requests.
|
|
571
|
+
if { [ "$split" = 1 ] || [ "$mode" = home ]; } && [ "$gh" = 1 ] && [ "$phase" != claim ]; then
|
|
559
572
|
token="${GITHUB_TOKEN:-}"
|
|
560
573
|
[ -n "$token" ] || token="${GH_TOKEN:-}"
|
|
561
574
|
if [ -z "$token" ] && command -v gh >/dev/null 2>&1; then
|
|
@@ -603,6 +616,16 @@ if [ "$mode" = login ]; then
|
|
|
603
616
|
# pi's own /login, written to the login volume: the only read-write mount of
|
|
604
617
|
# it. A login needs no repo, no state and no profiles.
|
|
605
618
|
set -- "$@" --mount "type=volume,src=qcr-login,dst=/home/qcr/.pi/agent"
|
|
619
|
+
elif [ "$mode" = home ]; then
|
|
620
|
+
# The home works on a GitHub repository, not on the directory you stand in:
|
|
621
|
+
# no repo mount. pi's agent dir is the login volume, read-write, as login's
|
|
622
|
+
# is. Its state home, sessions and config.toml (the repository it picks,
|
|
623
|
+
# which it writes) live on the state volume, so they persist and stay
|
|
624
|
+
# writable; the install home is never mounted.
|
|
625
|
+
set -- "$@" --mount "type=volume,src=qcr-login,dst=/home/qcr/.pi/agent"
|
|
626
|
+
set -- "$@" --mount "type=volume,src=qcr-state,dst=/opt/qcr/state"
|
|
627
|
+
set -- "$@" -e QCR_STATE_HOME=/opt/qcr/state/home
|
|
628
|
+
set -- "$@" -e QCR_CONFIG=/opt/qcr/state/home/config.toml
|
|
606
629
|
else
|
|
607
630
|
# The repo, read-only; a worktree's common git dir at its own path.
|
|
608
631
|
set -- "$@" --mount "type=bind,src=$root,dst=/repo,readonly" -w "/repo$rel"
|
package/scripts/vm-ghcr-login.sh
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# vm-ghcr-login.sh — log the review VM in to ghcr.io, so it can pull
|
|
3
|
-
#
|
|
4
|
-
#
|
|
2
|
+
# vm-ghcr-login.sh — log the review VM in to ghcr.io, so it can pull images
|
|
3
|
+
# that are not public: a private mirror named by QC_RELEASE_IMAGE and
|
|
4
|
+
# QC_RELEASE_MEMORY_IMAGE. The release images are public and pull with no
|
|
5
|
+
# login, so a VM on them needs none of this. Run by the owner, on the
|
|
6
|
+
# controller. Idempotent: running it again replaces the login and the recorded
|
|
7
|
+
# expiry.
|
|
5
8
|
#
|
|
6
9
|
# The credential is a CLASSIC personal access token, scoped read:packages and
|
|
7
10
|
# nothing else (the one carve-out from the App-only credential rule, for the
|
|
@@ -26,7 +29,7 @@
|
|
|
26
29
|
# scripts/vm-ghcr-login.sh --version X.Y.Z [--vm HOST] [--login USER] [--token-file FILE]
|
|
27
30
|
# pbpaste | scripts/vm-ghcr-login.sh --version X.Y.Z # token on stdin
|
|
28
31
|
#
|
|
29
|
-
# --version a published
|
|
32
|
+
# --version a published version; both images must exist at it
|
|
30
33
|
# --vm ssh target (default: $QC_VM_HOST, else the inventory's first host)
|
|
31
34
|
# --login the GitHub login to store (default: the token's own; if given
|
|
32
35
|
# it must be the token's)
|
package/src/archive/restore.ts
CHANGED
|
@@ -32,13 +32,7 @@ import { readdir } from "node:fs/promises";
|
|
|
32
32
|
import { join, relative } from "node:path";
|
|
33
33
|
import type { StateStore } from "../state.js";
|
|
34
34
|
import { yieldToLoop } from "@quickchatai/pi-quickreview/src/yieldloop.js";
|
|
35
|
-
import {
|
|
36
|
-
archiveStamp,
|
|
37
|
-
bundlePassOf,
|
|
38
|
-
freshPassId,
|
|
39
|
-
identityFields,
|
|
40
|
-
sameRecorded,
|
|
41
|
-
} from "./archivewrite.js";
|
|
35
|
+
import { archiveStamp, bundlePassOf, freshPassId, identityFields } from "./archivewrite.js";
|
|
42
36
|
import { readBundleRecords } from "./bundle.js";
|
|
43
37
|
import { sameIdentity } from "./fsutil.js";
|
|
44
38
|
import {
|
|
@@ -182,20 +176,23 @@ export async function restorePr(
|
|
|
182
176
|
const steady = sameIdentity(live, after);
|
|
183
177
|
if (steady && d.bytes === r.bytes && d.sha256 === r.sha256) {
|
|
184
178
|
out.present += 1;
|
|
185
|
-
// Its identity is recorded
|
|
186
|
-
//
|
|
187
|
-
//
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
179
|
+
// Its identity is recorded, always. A file an earlier restore pass
|
|
180
|
+
// put back — one that died before its entry was written — is
|
|
181
|
+
// unknown to the manifest otherwise, and a re-archive after a
|
|
182
|
+
// re-close would compress the same bytes again under `.v2` instead
|
|
183
|
+
// of reusing the archived copy. Its identity is no sign of whether
|
|
184
|
+
// it was ever unlinked: the filesystem hands a freed inode number
|
|
185
|
+
// back, and the restore gave the file its original size and mtime,
|
|
186
|
+
// so a file put back can carry exactly the identity the archive
|
|
187
|
+
// record holds. Recording a source that was never unlinked costs
|
|
188
|
+
// one `reused` entry at the re-archive, nothing more.
|
|
189
|
+
restored.push({
|
|
190
|
+
source: r.source,
|
|
191
|
+
archive: r.archive,
|
|
192
|
+
sha256: r.sha256,
|
|
193
|
+
...identityFields(live),
|
|
194
|
+
present: true,
|
|
195
|
+
});
|
|
199
196
|
} else out.liveDiffers.push(r.source);
|
|
200
197
|
continue;
|
|
201
198
|
}
|
package/src/botworker.ts
CHANGED
|
@@ -439,7 +439,14 @@ export async function runBotWorker(args: WorkerArgs, deps: WorkerDeps): Promise<
|
|
|
439
439
|
// The login: borrowed, blanked, and checked against this worker's own cap.
|
|
440
440
|
let auth: EngineAuth;
|
|
441
441
|
try {
|
|
442
|
-
auth = engineCredentials({
|
|
442
|
+
auth = engineCredentials({
|
|
443
|
+
srcDir: spec.login_dir ?? spec.agent_dir,
|
|
444
|
+
needMs: spec.wall_clock_ms,
|
|
445
|
+
now,
|
|
446
|
+
// a shared pi home holds the person's other logins too: only the
|
|
447
|
+
// review's providers are admitted
|
|
448
|
+
...(spec.providers !== undefined ? { providers: spec.providers } : {}),
|
|
449
|
+
});
|
|
443
450
|
} catch (e) {
|
|
444
451
|
if (e instanceof AuthError) throw new Stop(EXIT.auth, e.message);
|
|
445
452
|
throw e;
|
|
@@ -461,7 +468,11 @@ export async function runBotWorker(args: WorkerArgs, deps: WorkerDeps): Promise<
|
|
|
461
468
|
ownsProcess: true,
|
|
462
469
|
homeDir: homedir(),
|
|
463
470
|
...(ids !== null && !("refused" in ids) ? { toolUid: ids } : {}),
|
|
464
|
-
fenceDirs: [
|
|
471
|
+
fenceDirs: [
|
|
472
|
+
...loginSourceDirs(env),
|
|
473
|
+
...(spec.login_dir ? [spec.login_dir] : []),
|
|
474
|
+
...credentialPaths(env, spec.env),
|
|
475
|
+
],
|
|
465
476
|
credentials: auth.credentials,
|
|
466
477
|
settings: agentDirSettings(spec.agent_dir),
|
|
467
478
|
});
|
package/src/channelfs.ts
CHANGED
|
@@ -1,26 +1,3 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
// imports (scanreport.ts, stage2request.ts) share it without reaching each
|
|
5
|
-
// other at runtime.
|
|
6
|
-
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
7
|
-
import { dirname } from "node:path";
|
|
8
|
-
|
|
9
|
-
/** A file's text, or null when it is ABSENT — any other failure throws, so a
|
|
10
|
-
* reader can tell "not written yet" from "cannot be read". */
|
|
11
|
-
export function readTextIfPresent(path: string): string | null {
|
|
12
|
-
try {
|
|
13
|
-
return readFileSync(path, "utf8");
|
|
14
|
-
} catch (err) {
|
|
15
|
-
if ((err as NodeJS.ErrnoException).code === "ENOENT") return null;
|
|
16
|
-
throw err;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/** tmp+rename: a reader never sees a half-written file. */
|
|
21
|
-
export function writeAtomic(path: string, text: string): void {
|
|
22
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
23
|
-
const tmp = `${path}.${process.pid}.tmp`;
|
|
24
|
-
writeFileSync(tmp, text);
|
|
25
|
-
renameSync(tmp, path);
|
|
26
|
-
}
|
|
1
|
+
// Moved to the plugin (packages/pi-plugin/src/scan/channelfs.ts): this name
|
|
2
|
+
// stays for the app's importers.
|
|
3
|
+
export * from "@quickchatai/pi-quickreview/src/scan/channelfs.js";
|
package/src/cli.ts
CHANGED
|
@@ -1857,55 +1857,6 @@ export async function cmdSetup(rest: string[]): Promise<number> {
|
|
|
1857
1857
|
return 0;
|
|
1858
1858
|
}
|
|
1859
1859
|
|
|
1860
|
-
/** `qcr onboard` — the guided setup wizard: pi at the pinned
|
|
1861
|
-
* version via npx (works from a bare clone; pi stays a non-dependency), the
|
|
1862
|
-
* onboarding prompt + extension + a restricted tool set, then the TUI handoff
|
|
1863
|
-
* when the checklist verifies complete. Resumable: run it again after a crash
|
|
1864
|
-
* and completed steps are re-verified, not repeated. */
|
|
1865
|
-
export async function cmdOnboard(): Promise<number> {
|
|
1866
|
-
const { piPinFromPackageJson, onboardingSessionDir, runOnboard } =
|
|
1867
|
-
await import("./onboard/launch.js");
|
|
1868
|
-
const { checklistComplete } = await import("./onboard/engine.js");
|
|
1869
|
-
const { spawn } = await import("node:child_process");
|
|
1870
|
-
const root = sandboxRoot();
|
|
1871
|
-
// Pin source: config.toml [pi] when it loads; package.json's "qcrPi" block on a
|
|
1872
|
-
// bare clone (config.toml is written later, BY onboarding). Same pinned
|
|
1873
|
-
// version by the rule-7 mirror discipline.
|
|
1874
|
-
let pin: { package: string; version: string } | null = null;
|
|
1875
|
-
try {
|
|
1876
|
-
const { package: pkg, version } = loadConfig().pi;
|
|
1877
|
-
pin = { package: pkg, version };
|
|
1878
|
-
} catch {
|
|
1879
|
-
pin = piPinFromPackageJson(root);
|
|
1880
|
-
}
|
|
1881
|
-
if (!pin)
|
|
1882
|
-
throw new Error(
|
|
1883
|
-
'onboard: pi pin not found (need config.toml [pi] or the package.json "qcrPi" block)',
|
|
1884
|
-
);
|
|
1885
|
-
mkdirSync(onboardingSessionDir(root), { recursive: true });
|
|
1886
|
-
const run = (cmd: string, args: string[]): Promise<number> =>
|
|
1887
|
-
new Promise((resolvePromise) => {
|
|
1888
|
-
const child = spawn(cmd, args, {
|
|
1889
|
-
stdio: "inherit",
|
|
1890
|
-
cwd: root,
|
|
1891
|
-
env: { ...process.env, QCR_ROOT: root },
|
|
1892
|
-
});
|
|
1893
|
-
child.on("error", (err) => {
|
|
1894
|
-
console.error(`onboard: ${cmd} failed to start: ${err.message}`);
|
|
1895
|
-
resolvePromise(1);
|
|
1896
|
-
});
|
|
1897
|
-
child.on("close", (code) => resolvePromise(code ?? 1));
|
|
1898
|
-
});
|
|
1899
|
-
return runOnboard({
|
|
1900
|
-
pin,
|
|
1901
|
-
root,
|
|
1902
|
-
spawn: run,
|
|
1903
|
-
isComplete: () => checklistComplete(join(root, "state")),
|
|
1904
|
-
log: (line) => console.log(line),
|
|
1905
|
-
cliPath: join(root, "dist", "src", "cli.js"),
|
|
1906
|
-
});
|
|
1907
|
-
}
|
|
1908
|
-
|
|
1909
1860
|
export const ARCHIVE_USAGE =
|
|
1910
1861
|
"usage: qcr archive status [--plan] [--json] | qcr archive run | qcr archive restore <pr> | " +
|
|
1911
1862
|
"qcr archive extract <pr> --to <dir>";
|
|
@@ -2154,6 +2105,16 @@ export async function main(rawArgv: string[]): Promise<void> {
|
|
|
2154
2105
|
const { runTui } = await import("./tui/index.js");
|
|
2155
2106
|
return runTui(rest);
|
|
2156
2107
|
}
|
|
2108
|
+
case "home": {
|
|
2109
|
+
// the home (src/home/launch.ts): the bin routes a bare `qcr` here too
|
|
2110
|
+
// (src/qcrbin.ts); the image's home mode reaches it through this verb
|
|
2111
|
+
if (rest.length > 0) throw new Error("usage: qcr home");
|
|
2112
|
+
const { homeRunDeps, runHome } = await import("./home/launch.js");
|
|
2113
|
+
// the token taken at startup, when the wrapper handed one over
|
|
2114
|
+
const githubToken = takeHandoffToken();
|
|
2115
|
+
process.exitCode = runHome({ ...homeRunDeps(sandboxRoot()), githubToken: () => githubToken });
|
|
2116
|
+
return;
|
|
2117
|
+
}
|
|
2157
2118
|
case "companion":
|
|
2158
2119
|
if (rest.length !== 1) throw new Error("usage: qcr companion <up|down|status|rebuild|plan>");
|
|
2159
2120
|
return cmdCompanion(rest[0]);
|
|
@@ -2161,10 +2122,6 @@ export async function main(rawArgv: string[]): Promise<void> {
|
|
|
2161
2122
|
process.exitCode = await cmdMemory(rest);
|
|
2162
2123
|
return;
|
|
2163
2124
|
}
|
|
2164
|
-
case "onboard": {
|
|
2165
|
-
process.exitCode = await cmdOnboard();
|
|
2166
|
-
return;
|
|
2167
|
-
}
|
|
2168
2125
|
case "setup": {
|
|
2169
2126
|
process.exitCode = await cmdSetup(rest);
|
|
2170
2127
|
return;
|
|
@@ -2273,7 +2230,7 @@ export async function main(rawArgv: string[]): Promise<void> {
|
|
|
2273
2230
|
}
|
|
2274
2231
|
default:
|
|
2275
2232
|
console.log(
|
|
2276
|
-
"usage: qcr <version|config check [--config-home <dir>]|
|
|
2233
|
+
"usage: qcr <version|config check [--config-home <dir>]|home|setup [validate [<profile>]|commit]|status|spend|today|why <n>|metrics [--pr <n>]|events|takeover <n>|debug-round <n>|release <n>|tui [pr|overseer]|drain <on [--hold]|off>|pause-pr <pr> [--reason <text>]|resume-pr <pr>|review-now <pr>|github-token sync [--gh <path>] [--secrets-dir <dir>]|message <pr> [--may-post] <text...>|archive <status [--plan]|run|restore <pr>|extract <pr> --to <dir>>|install <where|migrate>|" +
|
|
2277
2234
|
"companion <up|down|status|rebuild>|review [start|status|stop|branch|--uncommitted|--diff FILE|-|<PR number|URL>] [--repo OWNER/NAME] [--base REF] [--preview] [--key K] [--limit USD] [--json]|live [RUN_ID|DIR] [--lens ID] [--round N] [--follow] [--json]|open [RUN_ID|DIR|FILE.jsonl|scan[:RUN]|pr N [--round R]] [--lens ID] [--write] [--print]|scan <preview|start|status|stop|findings|matches|match|suggestions|stage2 propose|stage2 start|dismiss|units show|units propose|units adjust|units save|login|doctor|rebuild>|memory reembed [--user <name>]|memory relayout [--plan|--apply]|backfill [--dry-run] [--limit <n>]|history <digest|pull>|outcomes [--days <n>] [--capture [--read-github]]|lessons [mine|shadow-report [--days <n>]|off|on|suppress <id>|unsuppress <id>]|checklist|compare <pr...>|" +
|
|
2278
2235
|
"regression [--set <path>] [--clone <path>] [--change <name>] [--limit <n>] [--out <path>]>",
|
|
2279
2236
|
);
|