@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.
Files changed (83) hide show
  1. package/dist/adapters/raw-evidence-attribution-gaps.js +133 -0
  2. package/dist/adapters/raw-evidence-claude-reader.js +108 -0
  3. package/dist/adapters/raw-evidence-codex-reader.js +147 -0
  4. package/dist/adapters/raw-evidence-collection-state.js +199 -0
  5. package/dist/adapters/raw-evidence-facts.js +338 -0
  6. package/dist/adapters/raw-evidence-git-diff-reader.js +187 -0
  7. package/dist/adapters/raw-evidence-image-reader.js +107 -0
  8. package/dist/adapters/raw-evidence-sanitize.js +56 -0
  9. package/dist/adapters/raw-evidence-transcript-file.js +182 -0
  10. package/dist/adapters/raw-evidence.js +94 -1203
  11. package/dist/autostart-contract.js +79 -0
  12. package/dist/autostart-darwin-plist.js +265 -0
  13. package/dist/autostart-darwin.js +171 -0
  14. package/dist/autostart-windows-scripts.js +310 -0
  15. package/dist/autostart-windows-task-xml.js +260 -0
  16. package/dist/autostart-windows.js +237 -0
  17. package/dist/autostart-xml.js +23 -0
  18. package/dist/autostart.js +35 -1148
  19. package/dist/commands/agent-rules-command.js +55 -0
  20. package/dist/commands/agent-session-report.js +290 -0
  21. package/dist/commands/analyze.js +131 -0
  22. package/dist/commands/autostart-command.js +105 -0
  23. package/dist/commands/backfill-batches.js +34 -0
  24. package/dist/commands/backfill-candidates.js +54 -0
  25. package/dist/commands/backfill-checkpoint.js +101 -0
  26. package/dist/commands/backfill-command-line.js +70 -0
  27. package/dist/commands/backfill-evidence-outcomes.js +104 -0
  28. package/dist/commands/backfill-issues.js +265 -0
  29. package/dist/commands/backfill-output.js +75 -0
  30. package/dist/commands/backfill-plan.js +71 -0
  31. package/dist/commands/backfill-reasons.js +107 -0
  32. package/dist/commands/backfill-report.js +298 -0
  33. package/dist/commands/backfill-result.js +150 -0
  34. package/dist/commands/backfill-scan.js +274 -0
  35. package/dist/commands/backfill-scope.js +114 -0
  36. package/dist/commands/backfill-session-report.js +145 -0
  37. package/dist/commands/backfill-types.js +1 -0
  38. package/dist/commands/backfill-upload.js +212 -0
  39. package/dist/commands/backfill.js +58 -1705
  40. package/dist/commands/cli-io.js +13 -0
  41. package/dist/commands/doctor.js +57 -0
  42. package/dist/commands/jarvis-trace.js +184 -0
  43. package/dist/commands/jarvis.js +323 -7
  44. package/dist/commands/local-arg-values.js +169 -0
  45. package/dist/commands/local-args-collector.js +604 -0
  46. package/dist/commands/local-args-tower.js +891 -0
  47. package/dist/commands/local-args.js +10 -1549
  48. package/dist/commands/local-help.js +30 -5
  49. package/dist/commands/local.js +21 -1786
  50. package/dist/commands/login.js +53 -0
  51. package/dist/commands/logout.js +66 -0
  52. package/dist/commands/memory-install-claude.js +294 -0
  53. package/dist/commands/memory-install-codex.js +205 -0
  54. package/dist/commands/memory-install-contract.js +231 -0
  55. package/dist/commands/memory-install-files.js +63 -0
  56. package/dist/commands/memory-install-skills.js +121 -0
  57. package/dist/commands/memory-install-toml.js +265 -0
  58. package/dist/commands/memory-install.js +378 -0
  59. package/dist/commands/onboard-receipts.js +66 -0
  60. package/dist/commands/onboard-report.js +274 -0
  61. package/dist/commands/onboard.js +449 -0
  62. package/dist/commands/ops-render.js +36 -0
  63. package/dist/commands/public-root.js +1 -1
  64. package/dist/commands/serve.js +13 -0
  65. package/dist/commands/session-sync.js +513 -534
  66. package/dist/commands/settings-render.js +28 -0
  67. package/dist/commands/settings.js +66 -2
  68. package/dist/commands/start.js +47 -0
  69. package/dist/commands/sync-followups.js +308 -0
  70. package/dist/commands/sync.js +387 -0
  71. package/dist/local-state-attributed-target.js +75 -0
  72. package/dist/local-state-config.js +147 -0
  73. package/dist/local-state-files.js +59 -0
  74. package/dist/local-state-identity.js +73 -0
  75. package/dist/local-state-pairing.js +263 -0
  76. package/dist/local-state-paths.js +61 -0
  77. package/dist/local-state-session.js +68 -0
  78. package/dist/local-state-status.js +163 -0
  79. package/dist/local-state-work-context.js +190 -0
  80. package/dist/local-state.js +34 -848
  81. package/dist/tower-client.js +3 -2
  82. package/dist/tower-stream.js +76 -6
  83. 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
+ }