@bli-cockpit/cli 0.2.53 → 0.2.55
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/attribution-core-fallbacks.js +247 -0
- package/dist/adapters/attribution-core-paths.js +182 -0
- package/dist/adapters/attribution-core-score.js +159 -0
- package/dist/adapters/attribution-core-types.js +13 -0
- package/dist/adapters/attribution-core.js +13 -565
- package/dist/adapters/claude-attribution-discovery.js +186 -0
- package/dist/adapters/claude-attribution-score.js +204 -0
- package/dist/adapters/claude-attribution-signals.js +180 -0
- package/dist/adapters/claude-attribution-types.js +25 -0
- package/dist/adapters/claude-attribution.js +14 -569
- package/dist/commands/doctor-access.js +129 -0
- package/dist/commands/doctor-pipeline.js +326 -0
- package/dist/commands/doctor-registration.js +105 -0
- package/dist/commands/doctor-report.js +111 -0
- package/dist/commands/doctor-update.js +120 -0
- package/dist/commands/doctor.js +8 -753
- package/dist/commands/heartbeat.js +8 -0
- package/dist/commands/jarvis-contracts.js +8 -0
- package/dist/commands/jarvis-render.js +413 -0
- package/dist/commands/jarvis-turn.js +305 -0
- package/dist/commands/jarvis.js +23 -698
- package/dist/commands/local-args-collector-setup.js +250 -0
- package/dist/commands/local-args-collector-status.js +227 -0
- package/dist/commands/local-args-collector-work.js +175 -0
- package/dist/commands/local-args-collector.js +19 -624
- package/dist/commands/local-args-tower-admin.js +456 -0
- package/dist/commands/local-args-tower-chat.js +194 -0
- package/dist/commands/local-args-tower-pages.js +314 -0
- package/dist/commands/local-args-tower.js +13 -880
- package/dist/commands/local-help.js +10 -2
- package/dist/commands/onboard-completion.js +136 -0
- package/dist/commands/onboard-flows.js +165 -0
- package/dist/commands/onboard-setup.js +102 -0
- package/dist/commands/onboard.js +5 -392
- package/dist/commands/public-root.js +1 -1
- package/dist/commands/session-sync-counters.js +55 -0
- package/dist/commands/session-sync-health.js +8 -1
- package/dist/commands/session-sync-plan.js +47 -7
- package/dist/commands/session-sync-scan.js +4 -4
- package/dist/commands/session-sync.js +6 -0
- package/dist/commands/settings-render.js +27 -0
- package/dist/commands/sync-followups.js +5 -1
- package/dist/commands/sync.js +5 -1
- package/dist/commands/team-device-reasons.js +16 -0
- package/dist/commands/team.js +87 -7
- package/dist/evidence-upload-client.js +14 -763
- package/dist/evidence-upload-object.js +181 -0
- package/dist/evidence-upload-plan.js +233 -0
- package/dist/evidence-upload-terminal.js +309 -0
- package/dist/evidence-upload-transport.js +104 -0
- package/dist/spool/local-spool-io.js +122 -0
- package/dist/spool/local-spool-mutations.js +174 -0
- package/dist/spool/local-spool-parse.js +143 -0
- package/dist/spool/local-spool-types.js +22 -0
- package/dist/spool/local-spool.js +20 -426
- package/dist/upload-evidence-delivery-offer.js +144 -0
- package/dist/upload-evidence-delivery-reconcile.js +134 -0
- package/dist/upload-evidence-delivery-summary.js +205 -0
- package/dist/upload-evidence-delivery.js +12 -482
- package/package.json +3 -3
|
@@ -98,6 +98,33 @@ export function renderTeamMembers(body) {
|
|
|
98
98
|
}
|
|
99
99
|
return lines;
|
|
100
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* BLI-3559: `cockpit team device list` — the same rows and the same summary
|
|
103
|
+
* sentence (`revoked_reason` / "Approved <date>" / "Waiting for approval")
|
|
104
|
+
* `GET /api/team/devices` computes, printed the way the web ambient page's
|
|
105
|
+
* device table shows them.
|
|
106
|
+
*/
|
|
107
|
+
export function renderDeviceList(body) {
|
|
108
|
+
const devices = list(body.devices);
|
|
109
|
+
if (devices.length === 0)
|
|
110
|
+
return [`${INDENT}no collector devices`];
|
|
111
|
+
return devices.map((device) => {
|
|
112
|
+
const name = text(device.device_name, text(device.device_id));
|
|
113
|
+
const state = text(device.trust_state, "unknown");
|
|
114
|
+
const owner = text(device.owner_label, "—");
|
|
115
|
+
const summary = text(device.summary, "");
|
|
116
|
+
return `${INDENT}${padEndDisplay(name, 24)} ${padEndDisplay(state, 10)} ${padEndDisplay(owner, 26)} ${summary} [${text(device.device_id)}]`;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/** `cockpit team device revoke <id|name>` — one line naming what happened. */
|
|
120
|
+
export function renderDeviceRevoked(body) {
|
|
121
|
+
const device = record(body.device);
|
|
122
|
+
const name = text(device.device_name, text(device.device_id, "device"));
|
|
123
|
+
const reason = text(device.revoked_reason, "");
|
|
124
|
+
return reason
|
|
125
|
+
? `${INDENT}Revoked ${name}. Reason: ${reason}`
|
|
126
|
+
: `${INDENT}Revoked ${name}.`;
|
|
127
|
+
}
|
|
101
128
|
export function renderSwitches(body) {
|
|
102
129
|
const switches = list(body.switches);
|
|
103
130
|
if (switches.length === 0)
|
|
@@ -135,7 +135,11 @@ export async function runMemoryInstallAfterSync(command, io, dashboardUrl, optio
|
|
|
135
135
|
dashboardUrl,
|
|
136
136
|
dryRun: false,
|
|
137
137
|
json: command.json,
|
|
138
|
-
}, io
|
|
138
|
+
}, io,
|
|
139
|
+
// Undefined on the real CLI (no io literal sets it); a test io can
|
|
140
|
+
// override the bin lookup so `bin_missing` is a fixture rather than a
|
|
141
|
+
// property of the machine the suite runs on (BLI-3630).
|
|
142
|
+
io.memoryInstallDeps);
|
|
139
143
|
event = memoryInstallEvent(outcome);
|
|
140
144
|
}
|
|
141
145
|
catch (error) {
|
package/dist/commands/sync.js
CHANGED
|
@@ -168,10 +168,12 @@ async function runSyncWithHealthReceipt(command, io) {
|
|
|
168
168
|
};
|
|
169
169
|
}
|
|
170
170
|
try {
|
|
171
|
-
const { exitCode, failureReasons, failureRecords, notice, sessionsObserved, sessionsOutsideRoot, } = await runSyncLocked(command, io);
|
|
171
|
+
const { exitCode, failureReasons, failureRecords, notice, sessionsObserved, sessionsOutsideRoot, sessionsNewThisTick, sessionsPendingUpload, } = await runSyncLocked(command, io);
|
|
172
172
|
const counts = {
|
|
173
173
|
sessionsObserved,
|
|
174
174
|
sessionsOutsideRoot,
|
|
175
|
+
sessionsNewThisTick,
|
|
176
|
+
sessionsPendingUpload,
|
|
175
177
|
};
|
|
176
178
|
if (exitCode === 0) {
|
|
177
179
|
// BLI-3551: an `ok` tick can still have something to say. `nothing_in_root`
|
|
@@ -226,6 +228,8 @@ function syncResult(run) {
|
|
|
226
228
|
notice: run.notice,
|
|
227
229
|
sessionsObserved: run.sessions_observed,
|
|
228
230
|
sessionsOutsideRoot: run.sessions_outside_root,
|
|
231
|
+
sessionsNewThisTick: run.sessions_new_this_tick,
|
|
232
|
+
sessionsPendingUpload: run.sessions_pending_upload,
|
|
229
233
|
};
|
|
230
234
|
}
|
|
231
235
|
/**
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BLI-3559: the same closed reason vocabulary the dashboard's
|
|
3
|
+
* `lib/settings/device-revoke-reasons.ts` publishes, kept in this package
|
|
4
|
+
* because a CLI workspace cannot import the dashboard's app code. Five
|
|
5
|
+
* entries; keep the two lists in sync by eye if either changes.
|
|
6
|
+
*/
|
|
7
|
+
export const TEAM_DEVICE_REVOKE_REASON_LABELS = [
|
|
8
|
+
"stale_test_pairing",
|
|
9
|
+
"machine_retired",
|
|
10
|
+
"person_left",
|
|
11
|
+
"re_pairing",
|
|
12
|
+
"other",
|
|
13
|
+
];
|
|
14
|
+
export function isTeamDeviceRevokeReasonLabel(value) {
|
|
15
|
+
return TEAM_DEVICE_REVOKE_REASON_LABELS.includes(value);
|
|
16
|
+
}
|
package/dist/commands/team.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `cockpit team` — who is on the team, and the
|
|
3
|
-
* (BLI-3461, decision D3: invite and role change ship in the PUBLIC build
|
|
2
|
+
* `cockpit team` — who is on the team, and the things an admin does to it
|
|
3
|
+
* (BLI-3461, decision D3: invite and role change ship in the PUBLIC build;
|
|
4
|
+
* BLI-3559 adds `device list` / `device revoke`).
|
|
4
5
|
*
|
|
5
6
|
* Same shape as the rest of the CLI-parity surface: this file owns terminal
|
|
6
7
|
* input and output, the dashboard owns every decision. The roster union, the
|
|
@@ -8,12 +9,16 @@
|
|
|
8
9
|
* server-side, so a stale CLI can be wrong about wording and never about
|
|
9
10
|
* permission.
|
|
10
11
|
*
|
|
11
|
-
* `team invite` and `team
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* `team invite`, `team role` and `team device revoke` change what a person
|
|
13
|
+
* can do (or end a machine's session outright), so all three are deliberate:
|
|
14
|
+
* each asks before it acts unless `--yes` is passed, and a headless run
|
|
15
|
+
* without `--yes` is refused by name rather than assumed. `device revoke`
|
|
16
|
+
* additionally names the device it is about to revoke BEFORE asking — the
|
|
17
|
+
* same "name it, then confirm" shape `dispatchCodingTask` uses (BLI-2981) —
|
|
18
|
+
* because a revoke is irreversible for that token.
|
|
14
19
|
*/
|
|
15
20
|
import { writeLine } from "./cli-io.js";
|
|
16
|
-
import { renderTeamMembers } from "./settings-render.js";
|
|
21
|
+
import { renderDeviceList, renderDeviceRevoked, renderTeamMembers } from "./settings-render.js";
|
|
17
22
|
import { confirmDestructive } from "./settings.js";
|
|
18
23
|
import { asRecord, callTower, openTower, writeCommandFailure, } from "./tower-command.js";
|
|
19
24
|
export async function runTeam(command, io) {
|
|
@@ -22,7 +27,11 @@ export async function runTeam(command, io) {
|
|
|
22
27
|
return showMembers(command, tower, io);
|
|
23
28
|
if (command.action === "invite")
|
|
24
29
|
return invite(command, tower, io);
|
|
25
|
-
|
|
30
|
+
if (command.action === "role")
|
|
31
|
+
return changeRole(command, tower, io);
|
|
32
|
+
if (command.action === "device-list")
|
|
33
|
+
return deviceList(command, tower, io);
|
|
34
|
+
return deviceRevoke(command, tower, io);
|
|
26
35
|
}
|
|
27
36
|
async function showMembers(command, tower, io) {
|
|
28
37
|
const result = await callTower(tower, { path: "/api/team/members", label: "team members" });
|
|
@@ -108,4 +117,75 @@ async function changeRole(command, tower, io) {
|
|
|
108
117
|
}
|
|
109
118
|
writeLine(io.stdout, `${String(body.user_id ?? command.targetUserId)} is now ${String(body.role)}.`);
|
|
110
119
|
return 0;
|
|
120
|
+
}
|
|
121
|
+
function devicesOf(body) {
|
|
122
|
+
return Array.isArray(body.devices) ? body.devices : [];
|
|
123
|
+
}
|
|
124
|
+
/** Exact device_id, or an unambiguous case-insensitive device_name match. */
|
|
125
|
+
function findDevice(devices, ref) {
|
|
126
|
+
const needle = ref.trim();
|
|
127
|
+
if (!needle)
|
|
128
|
+
return null;
|
|
129
|
+
const byId = devices.find((d) => d.device_id === needle);
|
|
130
|
+
if (byId)
|
|
131
|
+
return byId;
|
|
132
|
+
const lowerNeedle = needle.toLowerCase();
|
|
133
|
+
const byName = devices.filter((d) => String(d.device_name ?? "").toLowerCase() === lowerNeedle);
|
|
134
|
+
return byName.length === 1 ? (byName[0] ?? null) : null;
|
|
135
|
+
}
|
|
136
|
+
async function deviceList(command, tower, io) {
|
|
137
|
+
const result = await callTower(tower, { path: "/api/team/devices", label: "team device list" });
|
|
138
|
+
if (!result.ok)
|
|
139
|
+
return writeCommandFailure(io, command.json, result);
|
|
140
|
+
const body = asRecord(result.body);
|
|
141
|
+
if (command.json) {
|
|
142
|
+
writeLine(io.stdout, JSON.stringify({ ok: true, ...body }));
|
|
143
|
+
return 0;
|
|
144
|
+
}
|
|
145
|
+
for (const line of renderDeviceList(body))
|
|
146
|
+
writeLine(io.stdout, line);
|
|
147
|
+
return 0;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* `cockpit team device revoke <id|name> --reason <label> [--note "<text>"]`
|
|
151
|
+
*
|
|
152
|
+
* Names the device it is about to revoke BEFORE asking for confirmation — the
|
|
153
|
+
* same order `dispatchCodingTask`'s approval uses — and only then sends the
|
|
154
|
+
* revoke. A revoke is irreversible for that token, so the confirmation is
|
|
155
|
+
* real: `--yes` or a person at a keyboard, nothing else (`confirmDestructive`).
|
|
156
|
+
*/
|
|
157
|
+
async function deviceRevoke(command, tower, io) {
|
|
158
|
+
const listed = await callTower(tower, { path: "/api/team/devices", label: "team device revoke lookup" });
|
|
159
|
+
if (!listed.ok)
|
|
160
|
+
return writeCommandFailure(io, command.json, listed);
|
|
161
|
+
const devices = devicesOf(asRecord(listed.body));
|
|
162
|
+
const device = findDevice(devices, command.deviceRef ?? "");
|
|
163
|
+
if (!device) {
|
|
164
|
+
return writeCommandFailure(io, command.json, {
|
|
165
|
+
reason: "device_not_found",
|
|
166
|
+
detail: `No device matches "${String(command.deviceRef)}". Run "cockpit team device list" to see ids and names.`,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
const confirmed = await confirmDestructive(command, io, `Revoke ${String(device.device_name ?? device.device_id)} (${device.device_id})? This cannot be undone. [Y/n] `, "team device revoke");
|
|
170
|
+
if (!confirmed.ok)
|
|
171
|
+
return writeCommandFailure(io, command.json, confirmed);
|
|
172
|
+
const result = await callTower(tower, {
|
|
173
|
+
path: `/api/ambient/devices/${encodeURIComponent(device.device_id)}/revoke`,
|
|
174
|
+
method: "POST",
|
|
175
|
+
label: "team device revoke",
|
|
176
|
+
body: { reason_label: command.reasonLabel, reason_note: command.reasonNote },
|
|
177
|
+
});
|
|
178
|
+
writeLine(io.stderr, `[team cli] device revoke ${JSON.stringify({
|
|
179
|
+
reason_label: command.reasonLabel,
|
|
180
|
+
outcome: result.ok ? "revoked" : result.reason,
|
|
181
|
+
})}`);
|
|
182
|
+
if (!result.ok)
|
|
183
|
+
return writeCommandFailure(io, command.json, result);
|
|
184
|
+
const body = asRecord(result.body);
|
|
185
|
+
if (command.json) {
|
|
186
|
+
writeLine(io.stdout, JSON.stringify({ ok: true, ...body }));
|
|
187
|
+
return 0;
|
|
188
|
+
}
|
|
189
|
+
writeLine(io.stdout, renderDeviceRevoked(body));
|
|
190
|
+
return 0;
|
|
111
191
|
}
|