@bli-cockpit/cli 0.2.222 → 0.2.236
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/dist/agent-plugins-converge.js +182 -0
- package/dist/agent-plugins.js +116 -0
- package/dist/autostart-darwin-plist.js +2 -2
- package/dist/autostart-windows-scripts.js +2 -2
- package/dist/commands/agent-door.js +35 -0
- package/dist/commands/approvals.js +3 -1
- package/dist/commands/brain.js +23 -0
- package/dist/commands/ci.js +23 -0
- package/dist/commands/docs-export.js +62 -0
- package/dist/commands/docs.js +3 -0
- package/dist/commands/doctor-access.js +2 -2
- package/dist/commands/doctor-agent-plugins.js +82 -0
- package/dist/commands/doctor-pipeline.js +2 -2
- package/dist/commands/doctor-report.js +1 -0
- package/dist/commands/doctor-update.js +2 -2
- package/dist/commands/doctor.js +6 -0
- package/dist/commands/drills-render.js +63 -0
- package/dist/commands/drills.js +152 -0
- package/dist/commands/hits.js +83 -0
- package/dist/commands/intentions.js +49 -0
- package/dist/commands/local-args-docs-export.js +23 -0
- package/dist/commands/local-args-tower-admin.js +8 -0
- package/dist/commands/local-args-tower-brain-ladder.js +90 -0
- package/dist/commands/local-args-tower-brain.js +11 -1
- package/dist/commands/local-args-tower-docs-msg.js +9 -3
- package/dist/commands/local-args-tower-drills.js +87 -0
- package/dist/commands/local-args-tower-hits.js +93 -0
- package/dist/commands/local-args-tower-intentions.js +70 -0
- package/dist/commands/local-args-tower-logs-search.js +51 -0
- package/dist/commands/local-args-tower-logs.js +3 -0
- package/dist/commands/local-args-tower-memory.js +67 -1
- package/dist/commands/local-args-tower-pages.js +3 -1
- package/dist/commands/local-args-tower-people.js +25 -0
- package/dist/commands/local-args-tower-usage.js +4 -4
- package/dist/commands/local-args-tower-who.js +36 -0
- package/dist/commands/local-args-tower.js +8 -1
- package/dist/commands/local-args.js +15 -1
- package/dist/commands/local-auth.js +5 -2
- package/dist/commands/local-command-shapes-auth.js +1 -0
- package/dist/commands/local-command-shapes-drills.js +7 -0
- package/dist/commands/local-command-shapes-hits.js +5 -0
- package/dist/commands/local-help-commands-tower-ops.js +123 -1
- package/dist/commands/local-help-commands-tower.js +19 -7
- package/dist/commands/local-help-commands.js +3 -0
- package/dist/commands/local-help.js +24 -4
- package/dist/commands/local-run-ops.js +11 -0
- package/dist/commands/local.js +16 -8
- package/dist/commands/logs-search.js +45 -0
- package/dist/commands/logs.js +3 -0
- package/dist/commands/memory-exam.js +47 -0
- package/dist/commands/memory-repeats.js +44 -0
- package/dist/commands/memory-search-print.js +95 -0
- package/dist/commands/memory-source.js +39 -0
- package/dist/commands/memory-store.js +18 -30
- package/dist/commands/memory-verb-list.js +7 -2
- package/dist/commands/notes-reads.js +20 -0
- package/dist/commands/notes-writes.js +24 -0
- package/dist/commands/notes.js +4 -2
- package/dist/commands/people.js +29 -0
- package/dist/commands/public-root.js +1 -1
- package/dist/commands/spend.js +79 -0
- package/dist/commands/sync-heal-agent-plugins.js +46 -0
- package/dist/commands/sync-heal.js +6 -0
- package/dist/commands/team.js +35 -0
- package/dist/commands/usage.js +9 -0
- package/dist/commands/who.js +36 -0
- package/dist/evidence-upload-direct.js +44 -0
- package/dist/evidence-upload-object.js +18 -4
- package/dist/evidence-upload-plan.js +1 -0
- package/dist/evidence-upload-transport.js +2 -0
- package/dist/local-state-config.js +21 -1
- package/dist/local-state.js +1 -1
- package/dist/process-runner.js +7 -3
- package/dist/state-dir-audit.js +1 -0
- package/package.json +4 -4
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
* failed install retried hourly
|
|
9
9
|
* sign-in lapsed record the ONE human written when the heartbeat
|
|
10
10
|
* action, stop nagging could not renew, reported daily
|
|
11
|
+
* company plugin missing install it for Claude inspected every tick, a failed
|
|
12
|
+
* (BLI-18200) Code and Codex host retried every six hours,
|
|
13
|
+
* (sync-heal-agent- an installed one refreshed daily
|
|
14
|
+
* plugins.ts)
|
|
11
15
|
*
|
|
12
16
|
* The rest of the table is already on the tick elsewhere: the CLI floor
|
|
13
17
|
* (`sync-followups-self-update.ts`), the scheduler incl. an ABSENT one
|
|
@@ -23,6 +27,7 @@ import path from "node:path";
|
|
|
23
27
|
import { redactedSyncErrorDetail, reportInstallEventsBestEffort, } from "./install-receipts.js";
|
|
24
28
|
import { heartbeatRefusalStatus } from "./heartbeat-token.js";
|
|
25
29
|
import { SIGN_IN_ACTION } from "../sign-in-action.js";
|
|
30
|
+
import { healAgentPlugins } from "./sync-heal-agent-plugins.js";
|
|
26
31
|
import { inspectAgentRules, installAgentRules } from "../agent-rules.js";
|
|
27
32
|
import { getCollectorRuntimePaths, readLocalCollectorConfig, readLocalCollectorSessionFile, toSessionReference, } from "../local-state.js";
|
|
28
33
|
import { normalizeCollectionRoots } from "../root-normalization.js";
|
|
@@ -37,6 +42,7 @@ export async function runMachineHealAfterSync(command, io, dashboardUrl, options
|
|
|
37
42
|
const events = [];
|
|
38
43
|
for (const heal of [
|
|
39
44
|
() => healAgentRules(command, paths, now),
|
|
45
|
+
() => healAgentPlugins(command, io, paths, now),
|
|
40
46
|
() => noteSessionState(paths, heartbeatRefusalStatus(), now),
|
|
41
47
|
]) {
|
|
42
48
|
try {
|
package/dist/commands/team.js
CHANGED
|
@@ -25,6 +25,8 @@ export async function runTeam(command, io) {
|
|
|
25
25
|
const tower = await openTower("team", command, io);
|
|
26
26
|
if (command.action.startsWith("github-login-"))
|
|
27
27
|
return githubLogin(command, tower, io);
|
|
28
|
+
if (command.action.startsWith("timezone-"))
|
|
29
|
+
return timezone(command, tower, io);
|
|
28
30
|
if (command.action === "members")
|
|
29
31
|
return showMembers(command, tower, io);
|
|
30
32
|
if (command.action === "invite")
|
|
@@ -272,6 +274,39 @@ async function githubLogin(command, tower, io) {
|
|
|
272
274
|
`GitHub logins: ${[body.primary_login, ...(Array.isArray(body.extra_logins) ? body.extra_logins : [])].filter(Boolean).join(", ") || "none"}. History is preserved.`);
|
|
273
275
|
return 0;
|
|
274
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* `cockpit team timezone list|set` (BLI-19277). The server owns every rule: who
|
|
279
|
+
* may ask (super admin), how a person is found (the one identity resolver, exact
|
|
280
|
+
* after case folding) and what counts as an IANA zone. This only relays and words
|
|
281
|
+
* the answer, so a stale CLI can be wrong about wording and never about a zone.
|
|
282
|
+
*/
|
|
283
|
+
async function timezone(command, tower, io) {
|
|
284
|
+
const setting = command.action === "timezone-set";
|
|
285
|
+
const result = await callTower(tower, { path: "/api/team/timezones", method: setting ? "PUT" : "GET", label: "team timezone",
|
|
286
|
+
...(setting ? { body: { person: command.personRef, timezone: command.zone } } : {}) });
|
|
287
|
+
writeLine(io.stderr, `[team cli] timezone ${JSON.stringify({ action: setting ? "set" : "list", reason: result.ok ? "answered" : result.reason })}`);
|
|
288
|
+
if (!result.ok)
|
|
289
|
+
return writeCommandFailure(io, command.json, result);
|
|
290
|
+
const body = asRecord(result.body);
|
|
291
|
+
if (command.json) {
|
|
292
|
+
writeLine(io.stdout, JSON.stringify(body));
|
|
293
|
+
return 0;
|
|
294
|
+
}
|
|
295
|
+
if (setting) {
|
|
296
|
+
const name = String(body.display_name ?? command.personRef);
|
|
297
|
+
const before = String(body.before ?? "unknown");
|
|
298
|
+
const after = String(body.after ?? "unknown");
|
|
299
|
+
writeLine(io.stdout, body.changed === false ? `${name} already has ${after}. Nothing changed.` : `${name}: ${before} -> ${after}.`);
|
|
300
|
+
return 0;
|
|
301
|
+
}
|
|
302
|
+
const people = (Array.isArray(body.people) ? body.people : []).map(asRecord);
|
|
303
|
+
const width = Math.max(6, ...people.map(person => String(person.display_name ?? "").length));
|
|
304
|
+
for (const person of people) {
|
|
305
|
+
writeLine(io.stdout, `${String(person.display_name ?? "").padEnd(width)} ${String(person.timezone_label ?? "unknown").padEnd(24)}${person.active === false ? " (inactive)" : ""}`);
|
|
306
|
+
}
|
|
307
|
+
writeLine(io.stdout, `${people.length} people, ${String(body.unknown_count ?? 0)} with an unknown timezone.`);
|
|
308
|
+
return 0;
|
|
309
|
+
}
|
|
275
310
|
async function changeGrant(command, tower, io) {
|
|
276
311
|
const result = await callTower(tower, { path: "/api/team/grants", method: "POST", label: "team section grant",
|
|
277
312
|
body: { person_id: command.targetUserId, section: command.section, level: command.level ?? "see", action: command.action } });
|
package/dist/commands/usage.js
CHANGED
|
@@ -15,6 +15,8 @@ export async function runUsage(command, io) {
|
|
|
15
15
|
query.set("groupBy", "task_type");
|
|
16
16
|
if (command.byRepo)
|
|
17
17
|
query.set("groupBy", "repo");
|
|
18
|
+
if (command.byClient)
|
|
19
|
+
query.set("groupBy", "client");
|
|
18
20
|
if (command.until)
|
|
19
21
|
query.set("until", command.until);
|
|
20
22
|
if (command.includeAutomated)
|
|
@@ -43,6 +45,13 @@ export async function runUsage(command, io) {
|
|
|
43
45
|
if (!answer.ok)
|
|
44
46
|
return failAgentDoor(door, "[usage]", answer.reason, answer.detail);
|
|
45
47
|
const body = answer.body;
|
|
48
|
+
// Ticket 19258: the client app split reads everyone and prints the door's own words (medians always with their N).
|
|
49
|
+
if (command.byClient) {
|
|
50
|
+
if (door.json)
|
|
51
|
+
return emitAgentDoor(door, answer.body);
|
|
52
|
+
writeLine(io.stdout, String(answer.body.text ?? ""));
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
46
55
|
if (command.person) {
|
|
47
56
|
const email = command.person === "me" ? (await loadPairedSession("usage", command.homeDir)).email : command.person;
|
|
48
57
|
if (!email)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { askAgentDoor, emitAgentDoor, failAgentDoor, openAgentDoor } from "./agent-door.js";
|
|
2
|
+
import { writeLine } from "./cli-io.js";
|
|
3
|
+
const TAG = "[who cli]";
|
|
4
|
+
const READ_DEADLINE_MS = 30_000;
|
|
5
|
+
export async function runWho(command, io) {
|
|
6
|
+
let door;
|
|
7
|
+
try {
|
|
8
|
+
door = await openAgentDoor("who", command, io);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
const detail = error instanceof Error ? error.message : "this machine is not paired with Tower";
|
|
12
|
+
writeLine(io.stderr, `${TAG} refused ${JSON.stringify({ reason: "not_paired" })}`);
|
|
13
|
+
if (command.json)
|
|
14
|
+
writeLine(io.stdout, JSON.stringify({ ok: false, error: "not_paired", detail }));
|
|
15
|
+
else
|
|
16
|
+
writeLine(io.stderr, detail);
|
|
17
|
+
return 1;
|
|
18
|
+
}
|
|
19
|
+
const query = new URLSearchParams();
|
|
20
|
+
if (command.topic)
|
|
21
|
+
query.set("topic", command.topic);
|
|
22
|
+
if (command.layer)
|
|
23
|
+
query.set("layer", command.layer);
|
|
24
|
+
if (command.limit)
|
|
25
|
+
query.set("limit", String(command.limit));
|
|
26
|
+
const asked = query.toString();
|
|
27
|
+
const answer = await askAgentDoor(door, { path: asked ? `/api/who?${asked}` : "/api/who", method: "GET", label: "who", timeoutMs: READ_DEADLINE_MS });
|
|
28
|
+
if (!answer.ok)
|
|
29
|
+
return failAgentDoor(door, TAG, answer.reason, answer.detail);
|
|
30
|
+
const body = answer.body;
|
|
31
|
+
writeLine(io.stderr, `${TAG} answered ${JSON.stringify({ resolved_as: body.resolved_as, areas: body.areas.length, as_of: body.as_of })}`);
|
|
32
|
+
if (command.json)
|
|
33
|
+
return emitAgentDoor(door, body);
|
|
34
|
+
writeLine(io.stdout, body.text);
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { encodeEvidenceBytes } from "@bli-cockpit/telemetry-core/evidence-storage-encoding";
|
|
2
|
+
import { noteSyncProgress } from "./sync-lock.js";
|
|
3
|
+
/** The signed capability is the only credential sent to Storage. Never log it,
|
|
4
|
+
* its query string, provider bodies, or thrown errors that might contain it. */
|
|
5
|
+
export async function putSignedChunk(options, signedUrl, bytes, uploadId, index) {
|
|
6
|
+
// Identical manifest + gzip framing to the server chunk route staging write.
|
|
7
|
+
const encoded = encodeEvidenceBytes(bytes);
|
|
8
|
+
console.error("[evidence-upload] chunk encoded for storage", JSON.stringify({
|
|
9
|
+
upload_id: uploadId, chunk_index: index, chunk_encoding: "gzip",
|
|
10
|
+
bytes_before: bytes.length, bytes_after: encoded.length,
|
|
11
|
+
}));
|
|
12
|
+
const attempts = options.maxAttemptsPerRequest ?? 3;
|
|
13
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
14
|
+
let status = 0;
|
|
15
|
+
try {
|
|
16
|
+
const response = await options.fetchImpl(signedUrl, {
|
|
17
|
+
method: "PUT", headers: { "Content-Type": "application/octet-stream", "x-upsert": "false" },
|
|
18
|
+
body: new Uint8Array(encoded), signal: AbortSignal.timeout(60_000), redirect: "error",
|
|
19
|
+
});
|
|
20
|
+
status = response.status;
|
|
21
|
+
await response.body?.cancel();
|
|
22
|
+
if (response.ok) {
|
|
23
|
+
noteSyncProgress();
|
|
24
|
+
log("signed_chunk_uploaded", uploadId, index, attempt, status);
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
log("signed_upload_refused", uploadId, index, attempt, status);
|
|
28
|
+
if (status < 500 && status !== 429)
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
log("signed_upload_network_failure", uploadId, index, attempt, status);
|
|
33
|
+
}
|
|
34
|
+
if (attempt < attempts)
|
|
35
|
+
await (options.sleep ?? sleep)(250 * attempt);
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
function log(reason, uploadId, index, attempt, status) {
|
|
40
|
+
console.error("[evidence-upload] direct chunk", JSON.stringify({
|
|
41
|
+
reason, upload_id: uploadId, chunk_index: index, attempt, http_status: status,
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { putSignedChunk } from "./evidence-upload-direct.js";
|
|
1
2
|
import { gzipSync } from "node:zlib";
|
|
2
3
|
import { COMMIT_CRASHED_PLATFORM, RawEvidenceUploadCommitResponseSchema, isPermanentUploadFailure, } from "@bli-cockpit/telemetry-core";
|
|
3
4
|
import { beginOneObject } from "./evidence-upload-terminal.js";
|
|
@@ -17,10 +18,11 @@ export async function uploadOneObject(options, entry, disposition, chunkSizeByte
|
|
|
17
18
|
if (disposition.disposition === "conflict" || !disposition.upload_id) {
|
|
18
19
|
return failedOutcome(entry.file, disposition.reason ?? "upload_conflict");
|
|
19
20
|
}
|
|
20
|
-
const
|
|
21
|
+
const directChunks = [];
|
|
22
|
+
const chunked = await uploadObjectChunks(options, entry, disposition, chunkSizeBytes, objectKey, directChunks);
|
|
21
23
|
if (!chunked.ok)
|
|
22
24
|
return chunked.outcome;
|
|
23
|
-
const committed = await commitUploadedObject(options, entry, disposition, objectKey, chunked.uploadedChunks);
|
|
25
|
+
const committed = await commitUploadedObject(options, entry, disposition, objectKey, chunked.uploadedChunks, directChunks);
|
|
24
26
|
if (committed.reason !== "commit_failed_http_409_staging_missing_between_passes")
|
|
25
27
|
return committed;
|
|
26
28
|
if (restageAttempted)
|
|
@@ -37,7 +39,7 @@ export async function uploadOneObject(options, entry, disposition, chunkSizeByte
|
|
|
37
39
|
}
|
|
38
40
|
return retried;
|
|
39
41
|
}
|
|
40
|
-
async function uploadObjectChunks(options, entry, disposition, chunkSizeBytes, objectKey) {
|
|
42
|
+
async function uploadObjectChunks(options, entry, disposition, chunkSizeBytes, objectKey, directChunks) {
|
|
41
43
|
const received = new Set(disposition.received_chunk_indexes);
|
|
42
44
|
let uploadedChunks = 0;
|
|
43
45
|
if (disposition.disposition === "already_committed" || disposition.commit_ready) {
|
|
@@ -47,6 +49,17 @@ async function uploadObjectChunks(options, entry, disposition, chunkSizeBytes, o
|
|
|
47
49
|
if (received.has(index))
|
|
48
50
|
continue;
|
|
49
51
|
const chunk = entry.bytes.subarray(index * chunkSizeBytes, Math.min((index + 1) * chunkSizeBytes, entry.bytes.byteLength));
|
|
52
|
+
const offer = disposition.signed_uploads?.find(upload => upload.chunk_index === index);
|
|
53
|
+
if (offer && await putSignedChunk(options, offer.signed_url, chunk, disposition.upload_id, index)) {
|
|
54
|
+
directChunks.push({ chunk_index: index, byte_size: chunk.length,
|
|
55
|
+
chunk_hash_sha256: sha256(chunk) });
|
|
56
|
+
uploadedChunks += 1;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
console.error("[evidence-upload] using chunk route", JSON.stringify({
|
|
60
|
+
reason: offer ? "signed_upload_refused_fallback" : "signed_upload_not_offered",
|
|
61
|
+
upload_id: disposition.upload_id, chunk_index: index,
|
|
62
|
+
}));
|
|
50
63
|
const encodedChunk = gzipSync(chunk);
|
|
51
64
|
console.error("[evidence-upload] chunk encoded", JSON.stringify({
|
|
52
65
|
upload_id: disposition.upload_id, chunk_index: index, chunk_encoding: "gzip",
|
|
@@ -97,13 +110,14 @@ async function uploadObjectChunks(options, entry, disposition, chunkSizeBytes, o
|
|
|
97
110
|
}
|
|
98
111
|
return { ok: true, uploadedChunks };
|
|
99
112
|
}
|
|
100
|
-
async function commitUploadedObject(options, entry, disposition, objectKey, uploadedChunks) {
|
|
113
|
+
async function commitUploadedObject(options, entry, disposition, objectKey, uploadedChunks, directChunks) {
|
|
101
114
|
const commit = await requestJson(options, "/api/ambient/evidence/upload/commit", {
|
|
102
115
|
schema_version: "ambient-raw-evidence-upload-commit.v1",
|
|
103
116
|
generated_at: options.generatedAt,
|
|
104
117
|
provenance: options.provenance,
|
|
105
118
|
upload_id: disposition.upload_id,
|
|
106
119
|
object_key: objectKey,
|
|
120
|
+
...(disposition.signed_uploads ? { direct_chunks: directChunks } : {}),
|
|
107
121
|
});
|
|
108
122
|
if (!commit.ok) {
|
|
109
123
|
// The server can tell us this object will be refused again. Take its reason
|
|
@@ -225,6 +225,7 @@ export function readBeginDispositions(body) {
|
|
|
225
225
|
upload_id: entry.upload_id ?? null,
|
|
226
226
|
received_chunk_indexes: entry.received_chunk_indexes,
|
|
227
227
|
commit_ready: entry.commit_ready === true,
|
|
228
|
+
signed_uploads: entry.signed_uploads,
|
|
228
229
|
reason: entry.reason ?? null,
|
|
229
230
|
raw_evidence_pointer_id: entry.raw_evidence_pointer_id,
|
|
230
231
|
});
|
|
@@ -22,6 +22,8 @@ export async function requestJson(options, routePath, body) {
|
|
|
22
22
|
headers: {
|
|
23
23
|
"Authorization": `Bearer ${options.deviceToken}`,
|
|
24
24
|
"Content-Type": "application/json",
|
|
25
|
+
...(routePath.endsWith("/evidence/upload/begin")
|
|
26
|
+
? { "x-tower-evidence-direct": "staged-gzip-v1" } : {}),
|
|
25
27
|
},
|
|
26
28
|
body: JSON.stringify(body),
|
|
27
29
|
});
|
|
@@ -11,7 +11,27 @@ const localCollectorPackage = JSON.parse(readFileSync(new URL("../package.json",
|
|
|
11
11
|
export const LOCAL_COLLECTOR_VERSION = typeof localCollectorPackage.version === "string"
|
|
12
12
|
? localCollectorPackage.version
|
|
13
13
|
: "0.0.0";
|
|
14
|
-
export const DEFAULT_DASHBOARD_URL = "https://
|
|
14
|
+
export const DEFAULT_DASHBOARD_URL = "https://tower.buildlaunchiterate.ca";
|
|
15
|
+
/**
|
|
16
|
+
* The address every machine paired before 2026-10-14 saved. It stays live as an
|
|
17
|
+
* alias of the same deployment forever, so a saved config naming it keeps
|
|
18
|
+
* working untouched and counts as the default wherever the default is decided.
|
|
19
|
+
*/
|
|
20
|
+
export const LEGACY_DASHBOARD_URL = "https://bli-cockpit-dashboard.vercel.app";
|
|
21
|
+
function dashboardUrlKey(value) {
|
|
22
|
+
return value.trim().replace(/\/+$/, "").toLowerCase();
|
|
23
|
+
}
|
|
24
|
+
/** True for either address of the production Tower; a staging or local URL is false. */
|
|
25
|
+
export function isDefaultDashboardUrl(value) {
|
|
26
|
+
const key = dashboardUrlKey(value);
|
|
27
|
+
return key === dashboardUrlKey(DEFAULT_DASHBOARD_URL) || key === dashboardUrlKey(LEGACY_DASHBOARD_URL);
|
|
28
|
+
}
|
|
29
|
+
/** Same dashboard, the two production addresses counted as one. */
|
|
30
|
+
export function sameDashboardUrl(a, b) {
|
|
31
|
+
if (isDefaultDashboardUrl(a) && isDefaultDashboardUrl(b))
|
|
32
|
+
return true;
|
|
33
|
+
return dashboardUrlKey(a) === dashboardUrlKey(b);
|
|
34
|
+
}
|
|
15
35
|
/**
|
|
16
36
|
* `cockpit install` — the one write that registers collection roots, because
|
|
17
37
|
* widening an operator's boundary is a consent decision and nothing else may
|
package/dist/local-state.js
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
* `runtimeFiles`, or the repo tests stay green while the packed CLI breaks.
|
|
37
37
|
*/
|
|
38
38
|
export { getCollectorRuntimePaths } from "./local-state-paths.js";
|
|
39
|
-
export { DEFAULT_DASHBOARD_URL, ensureLocalCollectorConfig, installLocalCollector, LOCAL_COLLECTOR_VERSION, readLocalCollectorConfig, } from "./local-state-config.js";
|
|
39
|
+
export { DEFAULT_DASHBOARD_URL, ensureLocalCollectorConfig, installLocalCollector, isDefaultDashboardUrl, LEGACY_DASHBOARD_URL, LOCAL_COLLECTOR_VERSION, sameDashboardUrl, readLocalCollectorConfig, } from "./local-state-config.js";
|
|
40
40
|
export { readLocalCollectorSessionFile, readLocalSessionReference, toSessionReference, } from "./local-state-session.js";
|
|
41
41
|
export { logoutLocalCollector, pairLocalCollector, recordDeviceTokenExpiry, } from "./local-state-pairing.js";
|
|
42
42
|
export { PairingCodeError, pairLocalCollectorViaLink, } from "./local-state-pairing-code.js";
|
package/dist/process-runner.js
CHANGED
|
@@ -35,12 +35,16 @@ export function createCapturedExecRunner(options = {}) {
|
|
|
35
35
|
encoding: "utf8",
|
|
36
36
|
env,
|
|
37
37
|
windowsVerbatimArguments: invocation.windowsVerbatimArguments,
|
|
38
|
+
...(runOptions?.timeoutMs ? { timeout: runOptions.timeoutMs } : {}),
|
|
38
39
|
}, (error, stdout, stderr) => {
|
|
40
|
+
// A child ended by `timeoutMs` reports code 124, never a bare 1.
|
|
39
41
|
const code = error == null
|
|
40
42
|
? 0
|
|
41
|
-
:
|
|
42
|
-
?
|
|
43
|
-
:
|
|
43
|
+
: error.killed === true && runOptions?.timeoutMs
|
|
44
|
+
? 124
|
|
45
|
+
: typeof error.code === "number"
|
|
46
|
+
? error.code
|
|
47
|
+
: 1;
|
|
44
48
|
resolve({
|
|
45
49
|
code,
|
|
46
50
|
stdout: stdout ?? "",
|
package/dist/state-dir-audit.js
CHANGED
|
@@ -55,6 +55,7 @@ export const STATE_DIR_RULES = [
|
|
|
55
55
|
// tiny by construction; naming them keeps the unrecognised bucket meaning
|
|
56
56
|
// "something nobody registered", not "something small we forgot".
|
|
57
57
|
{ name: "session-needs-login.json", match: "exact", class: "state", bound: "one small note, overwritten at most daily and removed when the sign-in is valid again (sync-heal.ts)" },
|
|
58
|
+
{ name: "agent-plugins.json", match: "exact", class: "state", bound: "one small file, overwritten: per host the last install attempt, its failure label and the last daily refresh (agent-plugins-converge.ts, BLI-18200)" },
|
|
58
59
|
{ name: "autostart-uninstalled", match: "exact", class: "state", bound: "a zero-byte marker written by `cockpit autostart uninstall` and removed by install or doctor" },
|
|
59
60
|
{ name: "last-turn-trace.json", match: "exact", class: "state", bound: "one file, overwritten" },
|
|
60
61
|
{ name: "sync.lock", match: "exact", class: "state", bound: "lock file, removed when the tick ends" },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bli-cockpit/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.236",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,9 +27,9 @@
|
|
|
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-cli-doctor-json.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.69",
|
|
31
|
+
"@bli-cockpit/mcp": "0.1.141",
|
|
32
|
+
"@bli-cockpit/telemetry-core": "0.1.76"
|
|
33
33
|
},
|
|
34
34
|
"repository": {
|
|
35
35
|
"type": "git",
|