@bli-cockpit/cli 0.2.149 → 0.2.154
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/adapters/local-sources.js +1 -0
- package/dist/adapters/raw-evidence-collection-state.js +1 -0
- package/dist/adapters/raw-evidence-facts.js +1 -0
- package/dist/adapters/raw-evidence-manifest.js +5 -0
- package/dist/adapters/raw-evidence-sanitize.js +82 -20
- package/dist/adapters/raw-evidence-snapshot-supersede.js +82 -0
- package/dist/adapters/raw-evidence-transcript-file.js +10 -0
- package/dist/agent-rules.js +3 -3
- package/dist/commands/agent-door.js +3 -0
- package/dist/commands/backfill-lock-wait.js +49 -0
- package/dist/commands/backfill-outside-roots.js +97 -0
- package/dist/commands/backfill-reasons.js +17 -0
- package/dist/commands/backfill-scan.js +8 -3
- package/dist/commands/backfill-scope.js +14 -1
- package/dist/commands/backfill-session-report.js +3 -0
- package/dist/commands/backfill-upload.js +6 -0
- package/dist/commands/backfill.js +11 -5
- package/dist/commands/cal-calendars-write.js +107 -0
- package/dist/commands/cal.js +29 -110
- package/dist/commands/docs.js +20 -4
- package/dist/commands/doctor-budget.js +69 -0
- package/dist/commands/doctor-lock-wait.js +12 -3
- package/dist/commands/doctor-pipeline-verdicts.js +2 -0
- package/dist/commands/doctor-pipeline.js +5 -2
- package/dist/commands/doctor.js +26 -4
- package/dist/commands/issue-directory.js +7 -0
- package/dist/commands/issue.js +23 -4
- package/dist/commands/local-arg-values.js +9 -0
- package/dist/commands/local-args-collector-setup.js +4 -2
- package/dist/commands/local-args-collector-work.js +9 -1
- package/dist/commands/local-help-commands.js +4 -1
- package/dist/commands/local-help.js +1 -1
- package/dist/commands/local.js +14 -0
- package/dist/commands/mail.js +20 -4
- package/dist/commands/memory-store.js +27 -10
- package/dist/commands/msg.js +25 -5
- package/dist/commands/public-root.js +1 -1
- package/dist/commands/read-cache.js +115 -0
- package/dist/commands/settings.js +17 -2
- package/dist/commands/tower-command.js +4 -0
- package/dist/cursors/raw-evidence-cursor.js +14 -0
- package/dist/tower-client.js +31 -3
- package/dist/upload-envelope-build.js +9 -0
- package/dist/upload-sync.js +10 -22
- package/dist/warm-tower-fetch.js +83 -0
- package/package.json +5 -5
package/dist/upload-sync.js
CHANGED
|
@@ -1,23 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `syncLocalAmbientEnvelope`: one ambient sync, end to end.
|
|
3
|
-
*
|
|
4
|
-
* 1. Assemble the envelope — or record why this machine cannot upload at all
|
|
5
|
-
* and rethrow, so `cockpit status` names the blocker.
|
|
6
|
-
* 2. Deliver the raw evidence objects, skipping anything inside its delivery
|
|
7
|
-
* backoff window (`upload-evidence-delivery.ts`).
|
|
8
|
-
* 3. Reconcile the envelope with what actually became durable, POST it to
|
|
9
|
-
* ingest, and refuse to believe a receipt we cannot read
|
|
10
|
-
* (`upload-ingest-receipt.ts`).
|
|
11
|
-
* 4. Advance the content cursor, report any agent images, and write the ledger
|
|
12
|
-
* row — a retry when a later sync could still rescue the gap, a named
|
|
13
|
-
* blocker when it never can, nothing extra when the sync was clean.
|
|
14
|
-
* 5. On any failure, spool a retry that carries its own reason.
|
|
15
|
-
*
|
|
16
|
-
* The whole file is built around one rule from the fleet contract: a sync that
|
|
17
|
-
* did not collect everything must never read green. Objects held by backoff are
|
|
18
|
-
* reported as named failures, permanent rejections are logged and blocked
|
|
19
|
-
* rather than silently retried forever, and the ledger row always says why.
|
|
20
|
-
*/
|
|
21
1
|
import { getCollectorRuntimePaths } from "./local-state.js";
|
|
22
2
|
import { uploadRawEvidenceFilesChunked, } from "./evidence-upload-client.js";
|
|
23
3
|
import { markObjectCommitted, readRawEvidenceCursor, writeRawEvidenceCursor, } from "./cursors/raw-evidence-cursor.js";
|
|
@@ -80,7 +60,7 @@ export async function syncLocalAmbientEnvelope(options = {}) {
|
|
|
80
60
|
built,
|
|
81
61
|
envelope: applyRawEvidenceUploadOutcomes(built.envelope, uploadOutcomes),
|
|
82
62
|
});
|
|
83
|
-
advanceRawEvidenceCursor(cursor, uploadOutcomes, attemptedAt);
|
|
63
|
+
advanceRawEvidenceCursor(cursor, uploadOutcomes, attemptedAt, built.raw_evidence_upload_files);
|
|
84
64
|
await writeRawEvidenceCursor(paths, cursor);
|
|
85
65
|
await reportAgentImageArtifacts({
|
|
86
66
|
fetchImpl,
|
|
@@ -221,17 +201,25 @@ async function buildEnvelopeOrRecordBlocker(paths, options, cursorObjects, attem
|
|
|
221
201
|
* bytes instead of re-uploading them. A failed upload is deliberately absent:
|
|
222
202
|
* recording it would make the next sync skip a file that never landed.
|
|
223
203
|
*/
|
|
224
|
-
function advanceRawEvidenceCursor(cursor, outcomes, attemptedAt) {
|
|
204
|
+
function advanceRawEvidenceCursor(cursor, outcomes, attemptedAt, files = []) {
|
|
205
|
+
// BLI-11088: a transcript's source key and snapshot facts ride into the
|
|
206
|
+
// cursor, so the next sync can prove its snapshot rebuilds this one.
|
|
207
|
+
const snapshotByHash = new Map(files.filter((file) => file.snapshot && file.source_key && file.pointer.content_hash_sha256)
|
|
208
|
+
.map((file) => [file.pointer.content_hash_sha256, file]));
|
|
225
209
|
for (const outcome of outcomes) {
|
|
226
210
|
if (outcome.upload_state === "upload_failed")
|
|
227
211
|
continue;
|
|
228
212
|
const contentHash = outcome.pointer.content_hash_sha256;
|
|
229
213
|
if (!contentHash)
|
|
230
214
|
continue;
|
|
215
|
+
const source = snapshotByHash.get(contentHash);
|
|
231
216
|
markObjectCommitted(cursor, contentHash, {
|
|
232
217
|
object_key: outcome.object_key,
|
|
233
218
|
byte_size: outcome.pointer.byte_size ?? 0,
|
|
234
219
|
committed_at: attemptedAt,
|
|
220
|
+
...(source
|
|
221
|
+
? { source_key: source.source_key, checkpoints: source.snapshot.checkpoints }
|
|
222
|
+
: {}),
|
|
235
223
|
});
|
|
236
224
|
}
|
|
237
225
|
cursor.updated_at = attemptedAt;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A CLI READ, ROUTED THROUGH THE RESIDENT MEMORY DAEMON'S WARM CONNECTION
|
|
3
|
+
* (BLI-10746).
|
|
4
|
+
*
|
|
5
|
+
* Every `cockpit` process today opens its own TCP+TLS connection to Tower —
|
|
6
|
+
* measured from Vietnam, about 420 ms of the ~1,700 ms `work list` takes is
|
|
7
|
+
* exactly that setup, paid fresh on every single command. `@bli-cockpit/
|
|
8
|
+
* memory-mcp`'s resident daemon already holds one connection open across
|
|
9
|
+
* turns for recall (BLI-10741); this module is "reuse that for every other
|
|
10
|
+
* read too" — a GET (or the one POST read this repo has, `memory search`)
|
|
11
|
+
* asks the daemon to replay it on its own dispatcher instead of opening a new
|
|
12
|
+
* socket.
|
|
13
|
+
*
|
|
14
|
+
* **Fallback is the whole safety argument.** A daemon that is absent, wedged,
|
|
15
|
+
* refuses, times out, or answers something this cannot parse means exactly
|
|
16
|
+
* one thing here: go the way this command always went. `isWarmRoutableRead`
|
|
17
|
+
* decides which requests are even eligible — writes NEVER take this path, so
|
|
18
|
+
* there is no daemon-retry-of-a-write hazard to reason about.
|
|
19
|
+
*
|
|
20
|
+
* **Auth never changes hands.** The caller's own `authorization` header
|
|
21
|
+
* travels inside `init.headers` exactly as `towerRequest` already built it;
|
|
22
|
+
* the daemon forwards it unread (see `@bli-cockpit/memory-mcp`'s
|
|
23
|
+
* `daemon/http-proxy.ts`). This module never reads the device token either.
|
|
24
|
+
*/
|
|
25
|
+
import os from "node:os";
|
|
26
|
+
import { memoryDaemonEndpoint } from "@bli-cockpit/telemetry-core";
|
|
27
|
+
import { askMemoryDaemonHttp, } from "@bli-cockpit/telemetry-core/node-daemon-http-client";
|
|
28
|
+
/**
|
|
29
|
+
* The only POST this repo treats as a read for warm-routing purposes
|
|
30
|
+
* (`cockpit memory search`, `POST /api/memory/search`). Every other read is a
|
|
31
|
+
* GET; a caller names itself with the same `label` it already logs under.
|
|
32
|
+
*/
|
|
33
|
+
const WARM_ROUTABLE_POST_LABELS = new Set(["memory search"]);
|
|
34
|
+
/** GET is always eligible; a small named allowlist covers the one read that is not. */
|
|
35
|
+
export function isWarmRoutableRead(method, label) {
|
|
36
|
+
return method === "GET" || WARM_ROUTABLE_POST_LABELS.has(label);
|
|
37
|
+
}
|
|
38
|
+
/** The whole local-socket-plus-daemon's-own-fetch budget. Comfortably under any `READ_DEADLINE_MS` a command sets. */
|
|
39
|
+
export const WARM_FETCH_DEADLINE_MS = 10_000;
|
|
40
|
+
/**
|
|
41
|
+
* Tries the daemon; returns `null` on ANY reason it could not, so the caller
|
|
42
|
+
* falls back to a direct request. Never throws.
|
|
43
|
+
*/
|
|
44
|
+
export async function tryWarmTowerFetch(url, init, log, deps = {}) {
|
|
45
|
+
const endpoint = memoryDaemonEndpoint({
|
|
46
|
+
homeDir: deps.homeDir ?? os.homedir(),
|
|
47
|
+
...(deps.platform ? { platform: deps.platform } : {}),
|
|
48
|
+
username: deps.username ?? safeUsername(),
|
|
49
|
+
});
|
|
50
|
+
if (endpoint.kind === "unix" && endpoint.addressTooLong) {
|
|
51
|
+
log(`[tower client] warm route skipped ${JSON.stringify({ reason: "socket_path_too_long" })}`);
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
const result = await askMemoryDaemonHttp({
|
|
55
|
+
address: endpoint.address,
|
|
56
|
+
deadlineMs: deps.deadlineMs ?? WARM_FETCH_DEADLINE_MS,
|
|
57
|
+
...(deps.connectImpl ? { connectImpl: deps.connectImpl } : {}),
|
|
58
|
+
...(deps.now ? { now: deps.now } : {}),
|
|
59
|
+
request: {
|
|
60
|
+
method: init.method,
|
|
61
|
+
url,
|
|
62
|
+
headers: init.headers,
|
|
63
|
+
...(init.body === undefined ? {} : { body: init.body }),
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
if (!result.ok) {
|
|
67
|
+
log(`[tower client] warm route missed ${JSON.stringify({ reason: result.reason, elapsed_ms: result.elapsedMs })}`);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
log(`[tower client] warm route used ${JSON.stringify({ elapsed_ms: result.elapsedMs })}`);
|
|
71
|
+
return new Response(result.answer.body, {
|
|
72
|
+
status: result.answer.status,
|
|
73
|
+
headers: result.answer.headers,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function safeUsername() {
|
|
77
|
+
try {
|
|
78
|
+
return os.userInfo().username;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bli-cockpit/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.154",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
"pretypecheck": "node ../../scripts/build-workspace-dep.mjs @bli-cockpit/cli",
|
|
25
25
|
"typecheck": "node -e \"await import('./dist/commands/public-root.js')\"",
|
|
26
26
|
"pretest": "node ../../scripts/build-workspace-dep.mjs @bli-cockpit/cli",
|
|
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"
|
|
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.41",
|
|
31
|
+
"@bli-cockpit/mcp": "0.1.75",
|
|
32
|
+
"@bli-cockpit/telemetry-core": "0.1.53"
|
|
33
33
|
}
|
|
34
34
|
}
|