@bli-cockpit/cli 0.2.148 → 0.2.149
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.
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import os from "node:os";
|
|
2
|
-
import { readRootWorkScan, outsideWorkDirectories,
|
|
3
|
-
import { writeJsonFile } from "../local-state-files.js";
|
|
4
|
-
import { containsPath } from "../root-normalization.js";
|
|
2
|
+
import { readRootWorkScan, outsideWorkDirectories, rootsAddCommand, sessionCoverageLine } from "../root-work.js";
|
|
5
3
|
import { scanWorkDirectories } from "./local-discovery.js";
|
|
6
4
|
import { sendCollectorHeartbeatBestEffort } from "./heartbeat.js";
|
|
7
5
|
import { isInteractiveDoctorFix } from "./doctor-report.js";
|
|
@@ -157,55 +155,36 @@ function shellQuote(value) {
|
|
|
157
155
|
return `'${value.replace(/'/gu, "'\\''")}'`;
|
|
158
156
|
}
|
|
159
157
|
/**
|
|
160
|
-
* The last scan names
|
|
161
|
-
* grants consent
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
158
|
+
* The last scan names where this machine's work happens. Diagnosis never
|
|
159
|
+
* grants consent, and since BLI-10734 there is nothing left to consent TO for
|
|
160
|
+
* the session report itself: every session this scan saw already reached the
|
|
161
|
+
* server (`sessionCoverageLine`), labelled `root_scope: "outside"` when its
|
|
162
|
+
* directory sits outside every approved root. BLI-10740 finishes that ruling
|
|
163
|
+
* on the doctor row itself — approved roots are a LABEL on the upload, never
|
|
164
|
+
* a gate on it, so a session sitting outside one is not a defect doctor found
|
|
165
|
+
* and cannot repair. This row is therefore always informational (`ok`): it
|
|
166
|
+
* reports how many of this scan's sessions were inside vs. outside, never
|
|
167
|
+
* asks for approval, and attempts no fix. Widening the boundary still buys
|
|
168
|
+
* the redacted transcript BYTES for those outside directories (those stay
|
|
169
|
+
* root-gated), so the message still names `cockpit roots add` as something an
|
|
170
|
+
* operator can choose to do, never something doctor is stuck waiting on. The
|
|
171
|
+
* row only turns red the ordinary way every other doctor check does: the scan
|
|
172
|
+
* itself throwing (`work_directory_scan_incomplete` from unreadable session
|
|
173
|
+
* folders), which `runDoctorWithDeps`'s existing `check_threw` handling
|
|
174
|
+
* already turns into a `fail` row — a real collection problem, not a roots
|
|
175
|
+
* problem.
|
|
169
176
|
*/
|
|
170
177
|
export async function readRootsCoverWork(context) {
|
|
171
178
|
const homeDir = context.command.homeDir ?? os.homedir();
|
|
172
179
|
const paths = getCollectorRuntimePaths(homeDir);
|
|
173
180
|
const scan = await readRootWorkScan(paths) ?? await scanWorkDirectories(homeDir, false);
|
|
174
181
|
const outside = outsideWorkDirectories(scan, (await readLocalCollectorConfig(paths))?.default_repo_paths ?? []);
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
// BLI-10734, widening a root no longer rescues a session from oblivion —
|
|
180
|
-
// its metadata already reached the server either way — it buys the
|
|
181
|
-
// redacted transcript content instead, so the "needs fix" branch says so.
|
|
182
|
-
if (!count)
|
|
183
|
-
return ok("roots-cover-work", "work_covered", `${scan.observed} sessions seen; no known working directories outside approved roots. ${sessionCoverageLine(scan, count)}`);
|
|
182
|
+
const outsideCount = outside.reduce((sum, entry) => sum + entry.count, 0);
|
|
183
|
+
const insideCount = scan.observed - outsideCount;
|
|
184
|
+
if (!outsideCount)
|
|
185
|
+
return ok("roots-cover-work", "work_covered", `${scan.observed} sessions seen; no known working directories outside approved roots. ${sessionCoverageLine(scan, outsideCount)}`);
|
|
184
186
|
return {
|
|
185
|
-
...
|
|
187
|
+
...ok("roots-cover-work", "work_outside_roots_labelled", `${insideCount} of ${scan.observed} sessions inside approved roots, ${outsideCount} outside — every one already reached the server, the outside ones carrying an outside label. Their redacted transcript content stays unuploaded until a root widens (scan ${scan.generated_at}):\n${outside.map(entry => `${entry.count}: ${entry.directory}\n ${rootsAddCommand(entry.directory, process.platform, homeDir)}`).join("\n")}\n\n${sessionCoverageLine(scan, outsideCount)}`),
|
|
186
188
|
nextAction: rootsAddCommand(outside[0].directory, process.platform, homeDir),
|
|
187
189
|
};
|
|
188
|
-
}
|
|
189
|
-
export async function fixRootsCoverWork(context) {
|
|
190
|
-
const homeDir = context.command.homeDir ?? os.homedir();
|
|
191
|
-
const paths = getCollectorRuntimePaths(homeDir);
|
|
192
|
-
const config = await readLocalCollectorConfig(paths);
|
|
193
|
-
if (!config)
|
|
194
|
-
return readRootsCoverWork(context);
|
|
195
|
-
const scan = await readRootWorkScan(paths) ?? await scanWorkDirectories(homeDir);
|
|
196
|
-
const approvals = await readRootApprovals(paths);
|
|
197
|
-
const outside = outsideWorkDirectories(scan, config.default_repo_paths);
|
|
198
|
-
const additions = outside.filter(entry => approvals.some(root => containsPath(root, entry.directory, rootPathApi())));
|
|
199
|
-
if (additions.length) {
|
|
200
|
-
// Restore the precise approved directories, preserving every other config option.
|
|
201
|
-
const roots = normalizeCollectionRoots([...config.default_repo_paths, ...additions.map(entry => entry.directory)], rootPathApi());
|
|
202
|
-
await writeJsonFile(paths.config_file, { ...config, default_repo_paths: roots });
|
|
203
|
-
console.error("[doctor] roots-cover-work repaired", JSON.stringify({ added: additions.length }));
|
|
204
|
-
await scanWorkDirectories(homeDir);
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
console.error("[doctor] roots-cover-work needs approval", JSON.stringify({ outside: outside.length, added: 0 }));
|
|
208
|
-
}
|
|
209
|
-
const checked = await readRootsCoverWork(context);
|
|
210
|
-
return { ...checked, fixed: additions.length > 0 && checked.status === "ok" };
|
|
211
190
|
}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -2,7 +2,7 @@ import { LOCAL_COLLECTOR_VERSION } from "../local-state.js";
|
|
|
2
2
|
import { isSemverBelow } from "../scheduled-self-update.js";
|
|
3
3
|
import { describeError } from "../health-detail.js";
|
|
4
4
|
import { withStage } from "../crash-guard.js";
|
|
5
|
-
import { checkSingleInstallState, readRootsCoverWork,
|
|
5
|
+
import { checkSingleInstallState, readRootsCoverWork, fixAuthState, fixRootState, readAuthState, readRootState, } from "./doctor-access.js";
|
|
6
6
|
import { backfillCompletionStepState, backfillFixVerdict, checkBackfillState, checkDiskState, checkGcState, checkSyncState, fixBackfillState, fixDiskState, fixGcState, fixSyncState, syncBacklogDrainingVerdict, syncStandAsideVerdict, } from "./doctor-pipeline.js";
|
|
7
7
|
import { checkMcpAnswersState } from "./doctor-mcp.js";
|
|
8
8
|
import { checkMemoryDaemonState } from "./doctor-memory-daemon.js";
|
|
@@ -119,7 +119,10 @@ function doctorInvariants() {
|
|
|
119
119
|
fix: fixRootState,
|
|
120
120
|
requiresInteractiveFix: true,
|
|
121
121
|
},
|
|
122
|
-
|
|
122
|
+
// BLI-10740: roots are a label on the upload, never a gate — this row has
|
|
123
|
+
// no fix because a session outside an approved root is not a defect
|
|
124
|
+
// doctor can repair; it names the counts and moves on.
|
|
125
|
+
{ id: "roots-cover-work", check: context => context.deps.readRootsCoverWork(context) },
|
|
123
126
|
// Deliberately has NO fix: uninstalling software the operator did not ask
|
|
124
127
|
// to have uninstalled is not a repair (BLI-3218/BLI-3553). Doctor names the
|
|
125
128
|
// other install and the exact command; the person decides.
|
|
@@ -194,7 +197,6 @@ function defaultDoctorDeps(hooks) {
|
|
|
194
197
|
runLogin: (context) => hooks.runLogin(context.command, context.io),
|
|
195
198
|
readRoots: readRootState,
|
|
196
199
|
readRootsCoverWork,
|
|
197
|
-
fixRootsCoverWork,
|
|
198
200
|
resolveAndSaveRoots: (context) => hooks.resolveAndSaveRoots(context.command, context.io),
|
|
199
201
|
checkSingleInstall: checkSingleInstallState,
|
|
200
202
|
checkAutostart: checkAutostartState,
|
|
@@ -91,7 +91,7 @@ export function localSubcommandHelp(command) {
|
|
|
91
91
|
"",
|
|
92
92
|
"Diagnose, repair, and verify this machine.",
|
|
93
93
|
"Repairs CLI, background sync, sign-in, roots, memory and hooks, agent rules, catch-up, uploads, and cleanup.",
|
|
94
|
-
"roots-cover-work names sessions outside saved roots and gives cockpit roots add commands
|
|
94
|
+
"roots-cover-work is informational: it names how many sessions are inside vs. outside saved roots (all already uploaded, outside ones labelled) and gives cockpit roots add commands for widening a root's redacted transcript content. It never needs a fix.",
|
|
95
95
|
"--check or --no-repair diagnoses without repairs. --dry-run previews repairs.",
|
|
96
96
|
"--backfill-budget defaults to 900 seconds; catch-up repeats chunks until complete, with progress every 30 seconds.",
|
|
97
97
|
"--lock-wait defaults to 600 seconds; progress prints every 30 seconds.",
|
|
@@ -21,7 +21,7 @@ export async function runCockpitCli(argv, io) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
if (command === "--version" || command === "-V" || command === "version") {
|
|
24
|
-
writeLine(io?.stdout ?? process.stdout, "0.2.
|
|
24
|
+
writeLine(io?.stdout ?? process.stdout, "0.2.149");
|
|
25
25
|
return 0;
|
|
26
26
|
}
|
|
27
27
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bli-cockpit/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.149",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"test": "node dist/cli.js --help && node ../../scripts/assert-public-cli-routing.mjs && node ../../scripts/assert-public-cli-verb-help.mjs && node ../../scripts/assert-public-cli-surface-doors.mjs && node ../../scripts/assert-public-cli-runtime-files.mjs && node ../../scripts/assert-public-cli-exit-contract.mjs && node ../../scripts/assert-public-cli-no-fleet-posts.mjs && node ../../scripts/assert-public-package-pack.mjs --workspace=@bli-cockpit/cli"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@bli-cockpit/memory-mcp": "0.1.
|
|
31
|
-
"@bli-cockpit/mcp": "0.1.
|
|
32
|
-
"@bli-cockpit/telemetry-core": "0.1.
|
|
30
|
+
"@bli-cockpit/memory-mcp": "0.1.38",
|
|
31
|
+
"@bli-cockpit/mcp": "0.1.72",
|
|
32
|
+
"@bli-cockpit/telemetry-core": "0.1.50"
|
|
33
33
|
}
|
|
34
34
|
}
|