@quickchatai/quickreview 1.2.0 → 1.3.2
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 +116 -53
- package/bin/qcr.js +1 -1
- package/config.example.toml +25 -7
- 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/extensions/vendor/openviking-pi/index.js +4 -0
- package/dist/extensions/vendor/openviking-pi/index.js.map +1 -1
- package/dist/extensions/vendor/openviking-pi/qcr-hooks.js +3 -1
- package/dist/extensions/vendor/openviking-pi/qcr-hooks.js.map +1 -1
- package/dist/extensions/vendor/openviking-pi/sync.js +81 -0
- package/dist/extensions/vendor/openviking-pi/sync.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 +14 -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 +33 -4
- 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/ledgercheck.js +39 -10
- package/dist/src/ledgercheck.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/session-command-supervisor.js +38 -9
- package/dist/src/session-command-supervisor.js.map +1 -1
- 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 +75 -9
- 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/alerts.js +4 -1
- package/dist/src/tui/alerts.js.map +1 -1
- package/dist/src/tui/board.js +2 -2
- 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/verdicts.js +12 -0
- package/dist/src/verdicts.js.map +1 -1
- package/dist/src/wire.js +9 -4
- package/dist/src/wire.js.map +1 -1
- package/dist/src/workerbreaker.js +32 -5
- package/dist/src/workerbreaker.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/extensions/vendor/openviking-pi/NOTICE +5 -0
- package/extensions/vendor/openviking-pi/README.md +39 -5
- package/extensions/vendor/openviking-pi/index.ts +4 -0
- package/extensions/vendor/openviking-pi/patches/0014-one-turn-sync-in-flight.patch +239 -0
- package/extensions/vendor/openviking-pi/qcr-hooks.ts +3 -1
- package/extensions/vendor/openviking-pi/sync.ts +80 -0
- package/extensions/vendor/openviking-pi/upstream.json +2 -1
- 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 +13 -54
- package/src/config.ts +38 -0
- package/src/daemon.ts +34 -4
- 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/ledgercheck.ts +45 -9
- 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/session-command-supervisor.ts +41 -8
- 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 +126 -11
- package/src/takeover.ts +5 -0
- package/src/takeoverpi.ts +3 -2
- package/src/tui/alerts.ts +9 -2
- package/src/tui/board.ts +2 -2
- 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/verdicts.ts +13 -0
- package/src/wire.ts +9 -4
- package/src/workerbreaker.ts +41 -5
- 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
|
@@ -1,289 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
// it reaches its siblings by type only, so the TUI (which never imports the
|
|
5
|
-
// setup engine — tests/single-shepherd.test.ts) can read the run record and
|
|
6
|
-
// the findings store without carrying the case runner along.
|
|
7
|
-
//
|
|
8
|
-
// Two record files, both the engine's (this module owns their names and
|
|
9
|
-
// their parsers, so the engine and the TUI can never read them differently):
|
|
10
|
-
// `scan/run.json` (scanrun.ts — the current run and a short history) and
|
|
11
|
-
// `scan/findings.json` (findings.ts — every finding with its state). Each is
|
|
12
|
-
// read totally and is one of three facts: absent (no scan has written it),
|
|
13
|
-
// read, or unreadable with the reason — never an empty list standing in for
|
|
14
|
-
// a file that could not be read (the honest-unknown rule).
|
|
15
|
-
//
|
|
16
|
-
// The stop channel mirrors the stage-2 start channel: the TUI writes
|
|
17
|
-
// `SCAN_STOP_FILE` naming the run it showed running; the companion's scan
|
|
18
|
-
// belt picks it up within seconds, stops exactly that run (in-flight cases
|
|
19
|
-
// aborted, the ledger resumes the rest) and answers in
|
|
20
|
-
// `SCAN_STOP_RESULT_FILE`, naming the request it answered — so a stop is
|
|
21
|
-
// answered once and never replayed onto a later run.
|
|
22
|
-
import { join } from "node:path";
|
|
23
|
-
import { readTextIfPresent, writeAtomic } from "../channelfs.js";
|
|
24
|
-
export const FINDING_STATES = ["new", "promoted", "dismissed", "fixed"];
|
|
25
|
-
export const RUN_FILE = "scan/run.json";
|
|
26
|
-
export const RUN_VERSION = 1;
|
|
27
|
-
export const FINDINGS_FILE = "scan/findings.json";
|
|
28
|
-
export const FINDINGS_VERSION = 1;
|
|
29
|
-
export const SCAN_STOP_FILE = "scan/stop.json";
|
|
30
|
-
export const SCAN_STOP_RESULT_FILE = "scan/stop-result.json";
|
|
31
|
-
export const VALIDITIES = ["confirmed", "likely", "doubtful"];
|
|
32
|
-
/** Display order: confirmed first, unknown last. */
|
|
33
|
-
export const VALIDITY_ORDER = [...VALIDITIES, "unknown"];
|
|
34
|
-
/** The longest dismissal reason triage takes. The TUI checks it before
|
|
35
|
-
* asking, so an over-long reason is refused where it is typed. */
|
|
36
|
-
export const DISMISS_REASON_MAX = 500;
|
|
37
|
-
/** A dismissed finding a re-scan settled as no longer reported (findings.ts
|
|
38
|
-
* `unreported`): out of play, as a fixed one is, until a scan reports it again. */
|
|
39
|
-
export const goneDismissal = (f) => f.state === "dismissed" && f.unreported != null;
|
|
40
|
-
/** A finding's tier as stored — `unknown` when it carries none. */
|
|
41
|
-
export function validityOf(f) {
|
|
42
|
-
return f.validity !== undefined &&
|
|
43
|
-
f.validity !== null &&
|
|
44
|
-
VALIDITIES.includes(f.validity)
|
|
45
|
-
? f.validity
|
|
46
|
-
: "unknown";
|
|
47
|
-
}
|
|
48
|
-
const clean = (err) => (err instanceof Error ? err.message : String(err));
|
|
49
|
-
// ---- the two records ---------------------------------------------------------------
|
|
50
|
-
/** Is a finding still standing — new, or promoted and not yet fixed? The
|
|
51
|
-
* portrait's counts and the scan tab's weights read open the same way. */
|
|
52
|
-
export const isOpenFinding = (f) => f.state === "new" || f.state === "promoted";
|
|
53
|
-
/** A finding's resemblance to a DISMISSED one (findings.ts sets it when it
|
|
54
|
-
* stores the finding), as a reader shows it: only on a finding still
|
|
55
|
-
* untriaged (`new`) — once the operator promotes or dismisses it, the
|
|
56
|
-
* resemblance is answered. */
|
|
57
|
-
export function dismissedLookalike(f) {
|
|
58
|
-
return f.state === "new" ? (f.resembles_dismissed ?? null) : null;
|
|
59
|
-
}
|
|
60
|
-
/** 1 for a finding flagged as resembling a dismissed one, else 0 — the sort
|
|
61
|
-
* key that puts it below the unflagged findings of its tier. */
|
|
62
|
-
export const lookalikeRank = (f) => dismissedLookalike(f) ? 1 : 0;
|
|
63
|
-
/** Parse the run record; throws on anything this version does not read. */
|
|
64
|
-
export function parseRunFile(text) {
|
|
65
|
-
const raw = JSON.parse(text);
|
|
66
|
-
if (typeof raw !== "object" || raw === null || raw.version !== RUN_VERSION)
|
|
67
|
-
throw new Error("unknown version");
|
|
68
|
-
const current = raw.current ?? null;
|
|
69
|
-
if (current !== null && (typeof current !== "object" || !Array.isArray(current.cases))) {
|
|
70
|
-
throw new Error("`current` is not a scan run");
|
|
71
|
-
}
|
|
72
|
-
return { version: RUN_VERSION, current, history: Array.isArray(raw.history) ? raw.history : [] };
|
|
73
|
-
}
|
|
74
|
-
/** Parse the findings store; throws on anything this version does not read. */
|
|
75
|
-
export function parseFindingsFile(text) {
|
|
76
|
-
const raw = JSON.parse(text);
|
|
77
|
-
if (typeof raw !== "object" ||
|
|
78
|
-
raw === null ||
|
|
79
|
-
raw.version !== FINDINGS_VERSION ||
|
|
80
|
-
!Array.isArray(raw.findings)) {
|
|
81
|
-
throw new Error("not a version-1 findings store");
|
|
82
|
-
}
|
|
83
|
-
for (const f of raw.findings) {
|
|
84
|
-
if (typeof f?.fingerprint !== "string" ||
|
|
85
|
-
typeof f.path !== "string" ||
|
|
86
|
-
typeof f.state !== "string") {
|
|
87
|
-
throw new Error("a finding has no fingerprint, path or state");
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
const q = raw.question ?? null;
|
|
91
|
-
if (q !== null &&
|
|
92
|
-
(typeof q.key !== "string" || !Array.isArray(q.unreported) || !Array.isArray(q.fresh))) {
|
|
93
|
-
throw new Error("the pending match question is malformed");
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
version: FINDINGS_VERSION,
|
|
97
|
-
findings: currentLookalikes(raw.findings.map(stickyDismissal)),
|
|
98
|
-
question: q,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
/** A `resembles_dismissed` flag is written when a finding is stored; the
|
|
102
|
-
* dismissal it names can change after that — re-dismissed with another
|
|
103
|
-
* reason, promoted (the operator changed their mind), or folded into a fresh
|
|
104
|
-
* finding by a match answer. Every reader goes through this parse, so the
|
|
105
|
-
* flag is re-read against the store here: it names the finding that now
|
|
106
|
-
* carries that fingerprint (itself, or the one it became an alias of) and
|
|
107
|
-
* that finding's current reason while it is still dismissed, and it is
|
|
108
|
-
* dropped otherwise — a stale "looks like a finding you dismissed" never
|
|
109
|
-
* reaches the operator. */
|
|
110
|
-
function currentLookalikes(findings) {
|
|
111
|
-
if (!findings.some((f) => f.resembles_dismissed))
|
|
112
|
-
return findings;
|
|
113
|
-
const owner = new Map();
|
|
114
|
-
for (const f of findings)
|
|
115
|
-
for (const a of f.aliases ?? [])
|
|
116
|
-
owner.set(a, f);
|
|
117
|
-
for (const f of findings)
|
|
118
|
-
owner.set(f.fingerprint, f);
|
|
119
|
-
return findings.map((f) => {
|
|
120
|
-
if (!f.resembles_dismissed)
|
|
121
|
-
return f;
|
|
122
|
-
const { resembles_dismissed: flag, ...rest } = f;
|
|
123
|
-
const d = owner.get(flag.fingerprint);
|
|
124
|
-
if (!d || d.state !== "dismissed" || d.fingerprint === f.fingerprint)
|
|
125
|
-
return rest;
|
|
126
|
-
return {
|
|
127
|
-
...rest,
|
|
128
|
-
resembles_dismissed: {
|
|
129
|
-
fingerprint: d.fingerprint,
|
|
130
|
-
reason: d.dismissal?.reason ?? flag.reason,
|
|
131
|
-
},
|
|
132
|
-
};
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
/** A legacy store may hold a dismissed finding recorded as `fixed` with
|
|
136
|
-
* `fixed.from = "dismissed"`: it reads back as the dismissal it is, its fix
|
|
137
|
-
* kept as the `unreported` audit stamp (findings.ts). Every other finding is
|
|
138
|
-
* returned as it is. */
|
|
139
|
-
function stickyDismissal(f) {
|
|
140
|
-
if (f.state !== "fixed" || f.fixed?.from !== "dismissed")
|
|
141
|
-
return f;
|
|
142
|
-
const { run, sha, at } = f.fixed;
|
|
143
|
-
return { ...f, state: "dismissed", fixed: null, unreported: { run, sha, at } };
|
|
144
|
-
}
|
|
145
|
-
function readRecord(home, rel, parse) {
|
|
146
|
-
let text;
|
|
147
|
-
try {
|
|
148
|
-
text = readTextIfPresent(join(home, rel));
|
|
149
|
-
}
|
|
150
|
-
catch (err) {
|
|
151
|
-
return { kind: "unreadable", why: `${rel} cannot be read: ${clean(err)}` };
|
|
152
|
-
}
|
|
153
|
-
if (text === null)
|
|
154
|
-
return { kind: "absent" };
|
|
155
|
-
try {
|
|
156
|
-
return { kind: "read", value: parse(text) };
|
|
157
|
-
}
|
|
158
|
-
catch (err) {
|
|
159
|
-
return { kind: "unreadable", why: `${rel} is not a record this version reads (${clean(err)})` };
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
/** The scan run record in the state home at `home`. */
|
|
163
|
-
export function readScanRuns(home) {
|
|
164
|
-
return readRecord(home, RUN_FILE, (t) => {
|
|
165
|
-
const f = parseRunFile(t);
|
|
166
|
-
return { current: f.current, history: f.history };
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
/** The findings store in the state home at `home`. */
|
|
170
|
-
export function readScanFindings(home) {
|
|
171
|
-
return readRecord(home, FINDINGS_FILE, (t) => {
|
|
172
|
-
const f = parseFindingsFile(t);
|
|
173
|
-
return { findings: f.findings, question: f.question ?? null };
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
/** Parse a stop request, or null when it is not one. */
|
|
177
|
-
export function parseStopRequest(text) {
|
|
178
|
-
try {
|
|
179
|
-
const r = JSON.parse(text);
|
|
180
|
-
if (typeof r !== "object" ||
|
|
181
|
-
r === null ||
|
|
182
|
-
typeof r.id !== "string" ||
|
|
183
|
-
r.id === "" ||
|
|
184
|
-
typeof r.run !== "string" ||
|
|
185
|
-
r.run === "")
|
|
186
|
-
return null;
|
|
187
|
-
return {
|
|
188
|
-
id: r.id,
|
|
189
|
-
run: r.run,
|
|
190
|
-
at: typeof r.at === "string" ? r.at : "",
|
|
191
|
-
by: r.by === "cli" || r.by === "companion" ? r.by : "tui",
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
catch {
|
|
195
|
-
return null;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
/** Parse a stop result, or null when it is not one. */
|
|
199
|
-
export function parseStopResult(text) {
|
|
200
|
-
try {
|
|
201
|
-
const r = JSON.parse(text);
|
|
202
|
-
if (typeof r !== "object" ||
|
|
203
|
-
r === null ||
|
|
204
|
-
typeof r.request !== "string" ||
|
|
205
|
-
typeof r.ok !== "boolean")
|
|
206
|
-
return null;
|
|
207
|
-
return {
|
|
208
|
-
request: r.request,
|
|
209
|
-
run: typeof r.run === "string" ? r.run : "",
|
|
210
|
-
at: typeof r.at === "string" ? r.at : "",
|
|
211
|
-
ok: r.ok,
|
|
212
|
-
errors: Array.isArray(r.errors)
|
|
213
|
-
? r.errors.filter((e) => typeof e === "string")
|
|
214
|
-
: [],
|
|
215
|
-
...(typeof r.in_flight === "string" || r.in_flight === null
|
|
216
|
-
? { in_flight: r.in_flight }
|
|
217
|
-
: {}),
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
catch {
|
|
221
|
-
return null;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* The TUI's stop: ask the companion to stop the run `run`, which the TUI
|
|
226
|
-
* showed running. Refused when the record cannot be read or no longer shows
|
|
227
|
-
* that run running — a stop is never aimed at a run the operator did not see.
|
|
228
|
-
* The notice line says what was asked, or why nothing was.
|
|
229
|
-
*/
|
|
230
|
-
export function clickStopScan(home, run, now = new Date(), by = "tui") {
|
|
231
|
-
const read = readScanRuns(home);
|
|
232
|
-
if (read.kind === "unreadable")
|
|
233
|
-
return { ok: false, line: `scan not stopped: ${read.why}` };
|
|
234
|
-
const cur = read.kind === "read" ? read.value.current : null;
|
|
235
|
-
if (cur === null || cur.id !== run || cur.state !== "running") {
|
|
236
|
-
return {
|
|
237
|
-
ok: false,
|
|
238
|
-
line: `scan not stopped: ${run} is no longer running — look at the report again`,
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
const request = {
|
|
242
|
-
id: `${now.toISOString()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
243
|
-
run,
|
|
244
|
-
at: now.toISOString(),
|
|
245
|
-
by,
|
|
246
|
-
};
|
|
247
|
-
try {
|
|
248
|
-
writeAtomic(join(home, SCAN_STOP_FILE), `${JSON.stringify(request)}\n`);
|
|
249
|
-
}
|
|
250
|
-
catch (err) {
|
|
251
|
-
return {
|
|
252
|
-
ok: false,
|
|
253
|
-
line: `scan not stopped: the stop request could not be written: ${clean(err)}`,
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
return {
|
|
257
|
-
ok: true,
|
|
258
|
-
request: request.id,
|
|
259
|
-
line: `stop asked for ${run} — the companion stops it within seconds; the ledger resumes the rest`,
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
export function readStopResult(home) {
|
|
263
|
-
let text;
|
|
264
|
-
try {
|
|
265
|
-
text = readTextIfPresent(join(home, SCAN_STOP_RESULT_FILE));
|
|
266
|
-
}
|
|
267
|
-
catch (err) {
|
|
268
|
-
return { kind: "unreadable", why: `${SCAN_STOP_RESULT_FILE}: ${clean(err)}` };
|
|
269
|
-
}
|
|
270
|
-
const r = text === null ? null : parseStopResult(text);
|
|
271
|
-
return r === null ? { kind: "absent" } : { kind: "read", result: r };
|
|
272
|
-
}
|
|
273
|
-
/** What became of the stop `request`: the companion's answer, or null while
|
|
274
|
-
* it has not answered (a companion that is down stops nothing — and runs
|
|
275
|
-
* nothing either). */
|
|
276
|
-
export function scanStopOutcome(home, request) {
|
|
277
|
-
const read = readStopResult(home);
|
|
278
|
-
// Not "no answer yet": the answer may be there, unreadable — said once,
|
|
279
|
-
// never polled for silently.
|
|
280
|
-
if (read.kind === "unreadable")
|
|
281
|
-
return `the scan stop's answer cannot be read (${read.why}) — check scan_status`;
|
|
282
|
-
if (read.kind === "absent" || read.result.request !== request)
|
|
283
|
-
return null;
|
|
284
|
-
const r = read.result;
|
|
285
|
-
return r.ok
|
|
286
|
-
? `scan ${r.run} stopped — what finished is in the ledger`
|
|
287
|
-
: `scan stop refused: ${r.errors.join("; ")}`;
|
|
288
|
-
}
|
|
1
|
+
// Moved to the plugin (packages/pi-plugin/src/scan/scanreport.ts), the scan engine's
|
|
2
|
+
// home: this name stays for the app's importers.
|
|
3
|
+
export * from "@quickchatai/pi-quickreview/src/scan/scanreport.js";
|
|
289
4
|
//# sourceMappingURL=scanreport.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanreport.js","sourceRoot":"","sources":["../../../src/setup/scanreport.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"scanreport.js","sourceRoot":"","sources":["../../../src/setup/scanreport.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,iDAAiD;AACjD,cAAc,oDAAoD,CAAC"}
|