@bli-cockpit/cli 0.2.48 → 0.2.50
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/raw-evidence-attribution-gaps.js +133 -0
- package/dist/adapters/raw-evidence-claude-reader.js +108 -0
- package/dist/adapters/raw-evidence-codex-reader.js +147 -0
- package/dist/adapters/raw-evidence-collection-state.js +199 -0
- package/dist/adapters/raw-evidence-facts.js +338 -0
- package/dist/adapters/raw-evidence-git-diff-reader.js +187 -0
- package/dist/adapters/raw-evidence-image-reader.js +107 -0
- package/dist/adapters/raw-evidence-sanitize.js +56 -0
- package/dist/adapters/raw-evidence-transcript-file.js +182 -0
- package/dist/adapters/raw-evidence.js +94 -1203
- package/dist/autostart-contract.js +79 -0
- package/dist/autostart-darwin-plist.js +265 -0
- package/dist/autostart-darwin.js +171 -0
- package/dist/autostart-windows-scripts.js +310 -0
- package/dist/autostart-windows-task-xml.js +260 -0
- package/dist/autostart-windows.js +237 -0
- package/dist/autostart-xml.js +23 -0
- package/dist/autostart.js +35 -1148
- package/dist/commands/agent-rules-command.js +55 -0
- package/dist/commands/agent-session-report.js +290 -0
- package/dist/commands/analyze.js +131 -0
- package/dist/commands/autostart-command.js +105 -0
- package/dist/commands/backfill-batches.js +34 -0
- package/dist/commands/backfill-candidates.js +54 -0
- package/dist/commands/backfill-checkpoint.js +101 -0
- package/dist/commands/backfill-command-line.js +70 -0
- package/dist/commands/backfill-evidence-outcomes.js +104 -0
- package/dist/commands/backfill-issues.js +265 -0
- package/dist/commands/backfill-output.js +75 -0
- package/dist/commands/backfill-plan.js +71 -0
- package/dist/commands/backfill-reasons.js +107 -0
- package/dist/commands/backfill-report.js +298 -0
- package/dist/commands/backfill-result.js +150 -0
- package/dist/commands/backfill-scan.js +274 -0
- package/dist/commands/backfill-scope.js +114 -0
- package/dist/commands/backfill-session-report.js +145 -0
- package/dist/commands/backfill-types.js +1 -0
- package/dist/commands/backfill-upload.js +212 -0
- package/dist/commands/backfill.js +58 -1705
- package/dist/commands/cli-io.js +13 -0
- package/dist/commands/doctor.js +57 -0
- package/dist/commands/jarvis-trace.js +184 -0
- package/dist/commands/jarvis.js +323 -7
- package/dist/commands/local-arg-values.js +169 -0
- package/dist/commands/local-args-collector.js +604 -0
- package/dist/commands/local-args-tower.js +891 -0
- package/dist/commands/local-args.js +10 -1549
- package/dist/commands/local-help.js +30 -5
- package/dist/commands/local.js +21 -1786
- package/dist/commands/login.js +53 -0
- package/dist/commands/logout.js +66 -0
- package/dist/commands/memory-install-claude.js +294 -0
- package/dist/commands/memory-install-codex.js +205 -0
- package/dist/commands/memory-install-contract.js +231 -0
- package/dist/commands/memory-install-files.js +63 -0
- package/dist/commands/memory-install-skills.js +121 -0
- package/dist/commands/memory-install-toml.js +265 -0
- package/dist/commands/memory-install.js +378 -0
- package/dist/commands/onboard-receipts.js +66 -0
- package/dist/commands/onboard-report.js +274 -0
- package/dist/commands/onboard.js +449 -0
- package/dist/commands/ops-render.js +36 -0
- package/dist/commands/public-root.js +1 -1
- package/dist/commands/serve.js +13 -0
- package/dist/commands/session-sync.js +513 -534
- package/dist/commands/settings-render.js +28 -0
- package/dist/commands/settings.js +66 -2
- package/dist/commands/start.js +47 -0
- package/dist/commands/sync-followups.js +308 -0
- package/dist/commands/sync.js +387 -0
- package/dist/local-state-attributed-target.js +75 -0
- package/dist/local-state-config.js +147 -0
- package/dist/local-state-files.js +59 -0
- package/dist/local-state-identity.js +73 -0
- package/dist/local-state-pairing.js +263 -0
- package/dist/local-state-paths.js +61 -0
- package/dist/local-state-session.js +68 -0
- package/dist/local-state-status.js +163 -0
- package/dist/local-state-work-context.js +190 -0
- package/dist/local-state.js +34 -848
- package/dist/tower-client.js +3 -2
- package/dist/tower-stream.js +76 -6
- package/package.json +2 -1
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { writeLine } from "./cli-io.js";
|
|
2
|
+
import { attributedSyncRunStatus, displayTicketId, rawEvidenceSyncLine, writeAgentSessionSummary, } from "./collection-report.js";
|
|
3
|
+
import { COLLECTION_ROOT_REQUIRED, missingCollectionRootMessage, } from "../onboarding-roots.js";
|
|
4
|
+
export function writeOnboardBanner(command, io) {
|
|
5
|
+
writeLine(io.stdout, "Setting up Tower");
|
|
6
|
+
writeLine(io.stdout, `Dashboard: ${command.dashboardUrl}`);
|
|
7
|
+
writeLine(io.stdout, `Ticket: ${displayTicketId(command.activeTicketId)}`);
|
|
8
|
+
}
|
|
9
|
+
export function writePairingInstructions(io, request) {
|
|
10
|
+
writeLine(io.stdout, "2/5 Device pairing started.");
|
|
11
|
+
writeLine(io.stdout, `Open: ${request.approve_url}`);
|
|
12
|
+
writeLine(io.stdout, `Code: ${request.user_code}`);
|
|
13
|
+
writeLine(io.stdout, "Waiting for dashboard approval...");
|
|
14
|
+
}
|
|
15
|
+
export function writeOnboardLiveStatus(io, command, roots, options) {
|
|
16
|
+
writeLine(io.stdout, "You're live.");
|
|
17
|
+
writeLine(io.stdout, "Collecting from:");
|
|
18
|
+
for (const root of roots)
|
|
19
|
+
writeLine(io.stdout, `- ${root}`);
|
|
20
|
+
writeLine(io.stdout, `Paired user: ${options.pair?.session.email ??
|
|
21
|
+
options.pair?.session.auth_subject_id ??
|
|
22
|
+
(options.status?.session_state === "valid" ? "existing valid session" : "pending")}`);
|
|
23
|
+
writeLine(io.stdout, `Background sync: ${backgroundSyncLine(options.autostart)}`);
|
|
24
|
+
writeLine(io.stdout, `Initial sync: ${options.initialSyncOk ? options.sync?.status ?? "uploaded" : "blocked"}`);
|
|
25
|
+
writeLine(io.stdout, `Historical backfill: complete (${options.backfill.counts.backfilled} uploaded, ${options.backfill.counts.skipped} explicit skip(s))`);
|
|
26
|
+
writeLine(io.stdout, `Agent rules: ${options.agentRules ? onboardAgentRulesInstallLine(options.agentRules) : "not refreshed"}`);
|
|
27
|
+
writeLine(io.stdout, `Dashboard: ${command.dashboardUrl}/my-work`);
|
|
28
|
+
writeLine(io.stdout, "Next: cockpit status");
|
|
29
|
+
}
|
|
30
|
+
function backgroundSyncLine(result) {
|
|
31
|
+
if (!result)
|
|
32
|
+
return "not refreshed (autostart runner unavailable)";
|
|
33
|
+
if (result.status === "unsupported")
|
|
34
|
+
return `unsupported (${result.message})`;
|
|
35
|
+
if (result.status === "installed" && result.loaded)
|
|
36
|
+
return "installed";
|
|
37
|
+
if (result.status === "installed") {
|
|
38
|
+
return `installed with warning (${result.message ?? "operating-system scheduler load failed"})`;
|
|
39
|
+
}
|
|
40
|
+
return result.status;
|
|
41
|
+
}
|
|
42
|
+
export function onboardAgentRulesInstallLine(result) {
|
|
43
|
+
if (result.targets.some((target) => target.stale_block_replaced)) {
|
|
44
|
+
return "updated; replaced stale Tower ticket-binding guidance.";
|
|
45
|
+
}
|
|
46
|
+
switch (result.status) {
|
|
47
|
+
case "created":
|
|
48
|
+
return "installed.";
|
|
49
|
+
case "updated":
|
|
50
|
+
return "updated.";
|
|
51
|
+
case "unchanged":
|
|
52
|
+
return "already current.";
|
|
53
|
+
case "missing":
|
|
54
|
+
return "not installed.";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export function writeOnboardAutostartBlocker(io, result) {
|
|
58
|
+
writeLine(io.stderr, "BLOCKED: initial collection succeeded, but recurring background collection is not running.");
|
|
59
|
+
if (result?.message)
|
|
60
|
+
writeLine(io.stderr, `Failure: ${result.message}`);
|
|
61
|
+
writeLine(io.stderr, "Next: run `cockpit autostart install`, then require `cockpit autostart status --json` to exit 0.");
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The blocked-backfill result, identical in both onboarding arms. `extra`
|
|
65
|
+
* carries the arm-specific keys and is spread where those keys appeared before,
|
|
66
|
+
* so the `--json` key order is unchanged.
|
|
67
|
+
*/
|
|
68
|
+
export function writeOnboardBackfillBlockedResult(io, options) {
|
|
69
|
+
if (!options.json) {
|
|
70
|
+
writeOnboardBackfillBlocker(io, options.backfill);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
writeLine(io.stdout, JSON.stringify({
|
|
74
|
+
...options.base,
|
|
75
|
+
...options.extra,
|
|
76
|
+
backfill: onboardBackfillPayload(options.backfill),
|
|
77
|
+
blocker: "backfill_incomplete",
|
|
78
|
+
backfill_failure_reason: options.backfill.failureReason,
|
|
79
|
+
next_step: options.backfill.retryCommand,
|
|
80
|
+
}, null, 2));
|
|
81
|
+
}
|
|
82
|
+
function writeOnboardBackfillBlocker(io, outcome) {
|
|
83
|
+
writeLine(io.stderr, "BLOCKED: all-history Codex and Claude backfill is incomplete for the approved collection roots.");
|
|
84
|
+
writeLine(io.stderr, `Failure: ${outcome.failureReason ?? `backfill_${outcome.status}`}`);
|
|
85
|
+
writeLine(io.stderr, `Retry: ${outcome.retryCommand}`);
|
|
86
|
+
}
|
|
87
|
+
function onboardBackfillPayload(outcome) {
|
|
88
|
+
return (outcome.result ?? {
|
|
89
|
+
status: "blocked",
|
|
90
|
+
failure_reason: outcome.failureReason,
|
|
91
|
+
retry_command: outcome.retryCommand,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Every onboard `--json` payload is `onboardResult` plus the roots this pass
|
|
96
|
+
* resolved plus whatever extra keys that arm of onboarding adds. Assembling it
|
|
97
|
+
* here means the call sites below cannot drift on key order or forget a field
|
|
98
|
+
* a sibling call site remembers.
|
|
99
|
+
*/
|
|
100
|
+
export function onboardJsonPayload(resultStatus, command, install, pair, sync, status, rootsResult, extra = {}) {
|
|
101
|
+
return {
|
|
102
|
+
...onboardResult(resultStatus, command, install, pair, sync, status),
|
|
103
|
+
collection_roots: rootsResult?.roots ?? [],
|
|
104
|
+
root_resolution: rootsResult,
|
|
105
|
+
...extra,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
export function writeOnboardJson(io, payload) {
|
|
109
|
+
writeLine(io.stdout, JSON.stringify(payload, null, 2));
|
|
110
|
+
}
|
|
111
|
+
function onboardResult(resultStatus, command, install, pair, sync, status) {
|
|
112
|
+
return {
|
|
113
|
+
status: resultStatus,
|
|
114
|
+
dashboard_url: command.dashboardUrl,
|
|
115
|
+
ticket_id: sync?.ticket_id ?? command.activeTicketId ?? null,
|
|
116
|
+
work_context_id: sync?.work_context_id ?? status?.work_context_id ?? null,
|
|
117
|
+
config_file: install?.paths.config_file ?? status?.config_file ?? null,
|
|
118
|
+
session_file: install?.paths.session_file ?? status?.session_file ?? null,
|
|
119
|
+
collection_roots: command.collectionRoots ?? (command.repoRoot ? [command.repoRoot] : []),
|
|
120
|
+
paired_user: pair?.session.email ?? pair?.session.auth_subject_id ?? null,
|
|
121
|
+
paired_device: pair?.session.device_name ?? pair?.session.device_id ?? null,
|
|
122
|
+
upload_status: sync?.status ?? null,
|
|
123
|
+
upload_state: status?.upload_state ?? null,
|
|
124
|
+
event_count: sync?.event_count ?? null,
|
|
125
|
+
source_scan_count: sync?.source_scan_count ?? null,
|
|
126
|
+
risk_flag_count: sync?.risk_flag_count ?? null,
|
|
127
|
+
pending_upload_count: status?.pending_upload_count ?? null,
|
|
128
|
+
last_upload_success_at: status?.last_upload_success_at ?? null,
|
|
129
|
+
next_dashboard_path: `${command.dashboardUrl}/my-work`,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export function nextStepForOnboardBlocker(blocker, options = {}) {
|
|
133
|
+
switch (blocker) {
|
|
134
|
+
case COLLECTION_ROOT_REQUIRED:
|
|
135
|
+
return missingCollectionRootMessage(options);
|
|
136
|
+
case "ticket":
|
|
137
|
+
case "ticket_binding":
|
|
138
|
+
return "Run `cockpit start --ticket <id>` when actual ticket work begins, then run `cockpit sync`.";
|
|
139
|
+
case "device_pairing":
|
|
140
|
+
return "Ask Edward to approve this machine in the dashboard under Ambient -> Collector approvals, then run `cockpit onboard` again.";
|
|
141
|
+
case "network_or_ingest":
|
|
142
|
+
return "Check dashboard URL/network, then run `cockpit sync --json` or rerun `cockpit onboard`.";
|
|
143
|
+
case "install":
|
|
144
|
+
return "Rerun `cockpit onboard` from the repo root; it will reinstall local config.";
|
|
145
|
+
case "work_context":
|
|
146
|
+
return "Run `cockpit start --ticket <id> --workspace \"$PWD\"`, then retry `cockpit sync`.";
|
|
147
|
+
default:
|
|
148
|
+
return "Run `cockpit status --json` and report the blocker label plus last failure reason.";
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/** Step 3 of a single-repo onboard: the work context this machine just bound. */
|
|
152
|
+
export function writeOnboardWorkContextStarted(io, context) {
|
|
153
|
+
writeLine(io.stdout, "3/5 Work context active.");
|
|
154
|
+
writeLine(io.stdout, `Repo: ${context.repo}`);
|
|
155
|
+
writeLine(io.stdout, `Branch: ${context.branch}`);
|
|
156
|
+
writeLine(io.stdout, `Ticket: ${displayTicketId(context.active_ticket_id)}`);
|
|
157
|
+
writeLine(io.stdout, `Context: ${context.work_context_id}`);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* The single-repo arm's blocked-collection result. The retry command is the
|
|
161
|
+
* spooled run's own when there is one, because that one names the pack to send.
|
|
162
|
+
*/
|
|
163
|
+
export function reportOnboardSyncBlocked(ctx, outcome) {
|
|
164
|
+
const { command, resolvedCommand, install, pair, rootsResult, io } = ctx;
|
|
165
|
+
const { run, sync, status, worktreeRoot } = outcome;
|
|
166
|
+
const collectionRunStatus = attributedSyncRunStatus(run);
|
|
167
|
+
if (command.json) {
|
|
168
|
+
writeOnboardJson(io, onboardJsonPayload("blocked", resolvedCommand, install, pair, sync, status, rootsResult, {
|
|
169
|
+
codex_sessions: run.summary,
|
|
170
|
+
collection_status: collectionRunStatus,
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
const syncFailureReason = sync.status === "spooled" ? sync.failure_reason : null;
|
|
175
|
+
const retryCommand = sync.status === "spooled"
|
|
176
|
+
? sync.retry_command
|
|
177
|
+
: `cockpit sync --workspace ${JSON.stringify(worktreeRoot)}`;
|
|
178
|
+
writeLine(io.stderr, "BLOCKED: initial collection is incomplete; retry until every eligible session has a durable receipt or explicit terminal reason.");
|
|
179
|
+
writeLine(io.stderr, `Failure: ${syncFailureReason ?? (run.summary.report_posted ? collectionRunStatus : run.summary.report_reason)}`);
|
|
180
|
+
writeAgentSessionSummary(io, run.summary);
|
|
181
|
+
writeLine(io.stderr, `Retry: ${retryCommand}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/** Steps 4 and 5 of a single-repo onboard: what was uploaded, and where to read it. */
|
|
185
|
+
export function writeOnboardUploadNarrative(io, uploaded) {
|
|
186
|
+
const { command, run, sync, status } = uploaded;
|
|
187
|
+
writeLine(io.stdout, "4/5 Uploaded what you worked on.");
|
|
188
|
+
writeLine(io.stdout, `HTTP: ${sync.http_status}`);
|
|
189
|
+
writeLine(io.stdout, `Things recorded: ${sync.event_count}`);
|
|
190
|
+
writeLine(io.stdout, `Sources: ${sync.source_scan_count}`);
|
|
191
|
+
writeLine(io.stdout, `Risk flags: ${sync.risk_flag_count}`);
|
|
192
|
+
writeLine(io.stdout, `Raw evidence files: ${sync.raw_evidence_file_count}`);
|
|
193
|
+
writeLine(io.stdout, rawEvidenceSyncLine(sync));
|
|
194
|
+
writeAgentSessionSummary(io, run.summary);
|
|
195
|
+
writeLine(io.stdout, "5/5 Status ready.");
|
|
196
|
+
writeLine(io.stdout, `Upload state: ${status.upload_state}`);
|
|
197
|
+
writeLine(io.stdout, `Open: ${command.dashboardUrl}/my-work`);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* The single-repo arm's `--json` result. A scheduler that could not load
|
|
201
|
+
* recurring collection is the one thing that turns a finished setup into a
|
|
202
|
+
* blocked one, and it says so by name.
|
|
203
|
+
*/
|
|
204
|
+
export function writeOnboardSingleRepoResultJson(ctx, finished) {
|
|
205
|
+
const { resolvedCommand, install, pair, rootsResult, io } = ctx;
|
|
206
|
+
const { run, sync, status, backfill, setup } = finished;
|
|
207
|
+
const { agentRules, autostart } = setup;
|
|
208
|
+
const onboardOk = setup.ok;
|
|
209
|
+
writeOnboardJson(io, onboardJsonPayload(onboardOk ? "pass" : "blocked", resolvedCommand, install, pair, sync, status, rootsResult, {
|
|
210
|
+
agent_rules: agentRules,
|
|
211
|
+
autostart,
|
|
212
|
+
backfill,
|
|
213
|
+
codex_sessions: run.summary,
|
|
214
|
+
...(!onboardOk
|
|
215
|
+
? {
|
|
216
|
+
blocker: "autostart_load_failed",
|
|
217
|
+
next_step: "Run `cockpit autostart install`, then require `cockpit autostart status --json` to exit 0.",
|
|
218
|
+
}
|
|
219
|
+
: {}),
|
|
220
|
+
}));
|
|
221
|
+
}
|
|
222
|
+
/** The parent-folder arm's blocked-collection result; `--json` only, as it always was. */
|
|
223
|
+
export function writeOnboardMultiRepoSyncBlocked(ctx, multi) {
|
|
224
|
+
const { resolvedCommand, install, pair, rootsResult, io } = ctx;
|
|
225
|
+
writeOnboardJson(io, onboardJsonPayload("blocked", resolvedCommand, install, pair, null, null, rootsResult, {
|
|
226
|
+
mode: "multi_repo",
|
|
227
|
+
repos: multi.results,
|
|
228
|
+
codex_sessions: multi.codex_sessions,
|
|
229
|
+
blocker: "sync_blocked",
|
|
230
|
+
next_step: "Run `cockpit sync --json` until every root returns an uploaded receipt.",
|
|
231
|
+
}));
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* The parent-folder arm's finished result, in whichever of the three shapes
|
|
235
|
+
* applies: the `--json` payload, the live-status page, or the autostart blocker
|
|
236
|
+
* when a supported scheduler refused the registration.
|
|
237
|
+
*/
|
|
238
|
+
export function reportOnboardMultiRepoResult(ctx, finished) {
|
|
239
|
+
const { command, resolvedCommand, collectionRoots, install, pair, rootsResult, io } = ctx;
|
|
240
|
+
const { multi, backfill, setup } = finished;
|
|
241
|
+
const { agentRules, autostart } = setup;
|
|
242
|
+
const onboardOk = setup.ok;
|
|
243
|
+
if (command.json) {
|
|
244
|
+
writeOnboardJson(io, onboardJsonPayload(onboardOk ? "pass" : "blocked", resolvedCommand, install, pair, null, null, rootsResult, {
|
|
245
|
+
agent_rules: agentRules,
|
|
246
|
+
autostart,
|
|
247
|
+
backfill,
|
|
248
|
+
mode: "multi_repo",
|
|
249
|
+
repos: multi.results,
|
|
250
|
+
codex_sessions: multi.codex_sessions,
|
|
251
|
+
...(!onboardOk && multi.ok
|
|
252
|
+
? {
|
|
253
|
+
blocker: "autostart_load_failed",
|
|
254
|
+
next_step: "Run `cockpit autostart install`, then require `cockpit autostart status --json` to exit 0.",
|
|
255
|
+
}
|
|
256
|
+
: {}),
|
|
257
|
+
}));
|
|
258
|
+
}
|
|
259
|
+
if (onboardOk && !command.json) {
|
|
260
|
+
writeLine(io.stdout, "PASS: Tower is set up and collecting.");
|
|
261
|
+
writeOnboardLiveStatus(io, resolvedCommand, collectionRoots, {
|
|
262
|
+
pair,
|
|
263
|
+
status: null,
|
|
264
|
+
sync: null,
|
|
265
|
+
agentRules,
|
|
266
|
+
autostart,
|
|
267
|
+
initialSyncOk: true,
|
|
268
|
+
backfill,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
else if (multi.ok && !command.json) {
|
|
272
|
+
writeOnboardAutostartBlocker(io, autostart);
|
|
273
|
+
}
|
|
274
|
+
}
|