@bli-cockpit/cli 0.2.54 → 0.2.56

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 (60) hide show
  1. package/dist/adapters/attribution-core-fallbacks.js +247 -0
  2. package/dist/adapters/attribution-core-paths.js +182 -0
  3. package/dist/adapters/attribution-core-score.js +159 -0
  4. package/dist/adapters/attribution-core-types.js +13 -0
  5. package/dist/adapters/attribution-core.js +13 -565
  6. package/dist/adapters/claude-attribution-discovery.js +186 -0
  7. package/dist/adapters/claude-attribution-score.js +204 -0
  8. package/dist/adapters/claude-attribution-signals.js +180 -0
  9. package/dist/adapters/claude-attribution-types.js +25 -0
  10. package/dist/adapters/claude-attribution.js +14 -569
  11. package/dist/commands/doctor-access.js +129 -0
  12. package/dist/commands/doctor-pipeline.js +326 -0
  13. package/dist/commands/doctor-registration.js +105 -0
  14. package/dist/commands/doctor-report.js +111 -0
  15. package/dist/commands/doctor-update.js +120 -0
  16. package/dist/commands/doctor.js +8 -753
  17. package/dist/commands/heartbeat.js +8 -0
  18. package/dist/commands/jarvis-contracts.js +8 -0
  19. package/dist/commands/jarvis-render.js +413 -0
  20. package/dist/commands/jarvis-turn.js +305 -0
  21. package/dist/commands/jarvis.js +23 -698
  22. package/dist/commands/local-args-collector-setup.js +250 -0
  23. package/dist/commands/local-args-collector-status.js +227 -0
  24. package/dist/commands/local-args-collector-work.js +175 -0
  25. package/dist/commands/local-args-collector.js +19 -624
  26. package/dist/commands/local-args-tower-admin.js +456 -0
  27. package/dist/commands/local-args-tower-chat.js +194 -0
  28. package/dist/commands/local-args-tower-pages.js +314 -0
  29. package/dist/commands/local-args-tower.js +13 -880
  30. package/dist/commands/local-help.js +10 -2
  31. package/dist/commands/onboard-completion.js +136 -0
  32. package/dist/commands/onboard-flows.js +165 -0
  33. package/dist/commands/onboard-setup.js +102 -0
  34. package/dist/commands/onboard.js +5 -392
  35. package/dist/commands/public-root.js +1 -1
  36. package/dist/commands/session-sync-counters.js +55 -0
  37. package/dist/commands/session-sync-health.js +8 -1
  38. package/dist/commands/session-sync-plan.js +47 -7
  39. package/dist/commands/session-sync-scan.js +4 -4
  40. package/dist/commands/session-sync.js +6 -0
  41. package/dist/commands/settings-render.js +27 -0
  42. package/dist/commands/sync-followups.js +5 -1
  43. package/dist/commands/sync.js +5 -1
  44. package/dist/commands/team-device-reasons.js +16 -0
  45. package/dist/commands/team.js +87 -7
  46. package/dist/evidence-upload-client.js +14 -763
  47. package/dist/evidence-upload-object.js +181 -0
  48. package/dist/evidence-upload-plan.js +233 -0
  49. package/dist/evidence-upload-terminal.js +309 -0
  50. package/dist/evidence-upload-transport.js +104 -0
  51. package/dist/spool/local-spool-io.js +122 -0
  52. package/dist/spool/local-spool-mutations.js +174 -0
  53. package/dist/spool/local-spool-parse.js +143 -0
  54. package/dist/spool/local-spool-types.js +22 -0
  55. package/dist/spool/local-spool.js +20 -426
  56. package/dist/upload-evidence-delivery-offer.js +144 -0
  57. package/dist/upload-evidence-delivery-reconcile.js +134 -0
  58. package/dist/upload-evidence-delivery-summary.js +205 -0
  59. package/dist/upload-evidence-delivery.js +12 -482
  60. package/package.json +3 -3
@@ -6,629 +6,24 @@
6
6
  * maintainer's `release`.
7
7
  *
8
8
  * Split out of commands/local-args.ts (BLI-3578) alongside its sibling
9
- * local-args-tower.ts, which parses the commands that talk to Tower. Every
10
- * parser moved verbatim: same allowed flags, same value flags, same defaults,
11
- * same refusal sentences.
9
+ * local-args-tower.ts, which parses the commands that talk to Tower. This file
10
+ * itself became a table of contents in BLI-3636, split by COMMAND FAMILY into
11
+ * three siblings, each moved verbatim (same allowed flags, same value flags,
12
+ * same defaults, same refusal sentences):
12
13
  *
13
- * `OnboardLikeOptions` — the flag set the setup doors share moved with the
14
- * parser that produces it and is imported back by `local-args.ts` for the
15
- * `LocalCommand` union. It has never been part of that module's export surface
16
- * and still is not.
17
- */
18
- import { DEFAULT_DASHBOARD_URL } from "../local-state.js";
19
- import { DEFAULT_AUTOSTART_INTERVAL_SECONDS } from "../autostart.js";
20
- import { IntentSourceSchema, WorkIntentSchema, WorkPhaseSchema, } from "@bli-cockpit/telemetry-core";
21
- import { assertNoPositionals, normalizeUrl, optionalConfidence, optionalEmail, optionalNonEmpty, optionalNonEmptyList, optionalPositiveInteger, optionalSchemaValue, optionalUrl, parseNamedArgs, workRootFlagValue, workRootFlagValues, } from "./local-arg-values.js";
22
- function parseOnboardLikeArgs(args, command) {
23
- const values = parseNamedArgs(args, {
24
- allowedFlags: [
25
- "--home",
26
- "--repo",
27
- "--workspace",
28
- "--dashboard-url",
29
- "--email",
30
- "--device-name",
31
- "--ticket",
32
- "--branch",
33
- "--json",
34
- "--no-auth",
35
- "--poll-interval-ms",
36
- "--timeout-ms",
37
- "--max-depth",
38
- "--max-repos",
39
- "--allow-home-root",
40
- ],
41
- valueFlags: [
42
- "--home",
43
- "--repo",
44
- "--workspace",
45
- "--dashboard-url",
46
- "--email",
47
- "--device-name",
48
- "--ticket",
49
- "--branch",
50
- "--poll-interval-ms",
51
- "--timeout-ms",
52
- "--max-depth",
53
- "--max-repos",
54
- ],
55
- });
56
- assertNoPositionals(values.positionals, command);
57
- return {
58
- homeDir: optionalNonEmpty(values.flags.get("--home")),
59
- repoRoot: optionalNonEmpty(workRootFlagValue(values)),
60
- collectionRoots: optionalNonEmptyList(workRootFlagValues(values)),
61
- dashboardUrl: normalizeUrl(values.flags.get("--dashboard-url") ?? DEFAULT_DASHBOARD_URL),
62
- dashboardUrlExplicit: values.flags.has("--dashboard-url"),
63
- claimedOwnerEmail: optionalEmail(values.flags.get("--email")),
64
- deviceName: optionalNonEmpty(values.flags.get("--device-name")),
65
- activeTicketId: optionalNonEmpty(values.flags.get("--ticket")),
66
- branch: optionalNonEmpty(values.flags.get("--branch")),
67
- noAuth: values.booleans.has("--no-auth"),
68
- json: values.booleans.has("--json"),
69
- pollIntervalMs: optionalPositiveInteger(values.flags.get("--poll-interval-ms"), "--poll-interval-ms"),
70
- timeoutMs: optionalPositiveInteger(values.flags.get("--timeout-ms"), "--timeout-ms"),
71
- maxDepth: optionalPositiveInteger(values.flags.get("--max-depth"), "--max-depth"),
72
- maxRepos: optionalPositiveInteger(values.flags.get("--max-repos"), "--max-repos"),
73
- allowHomeRoot: values.booleans.has("--allow-home-root"),
74
- };
75
- }
76
- export function parseOnboardArgs(args) {
77
- return { kind: "onboard", ...parseOnboardLikeArgs(args, "onboard") };
78
- }
79
- export function parseUpdateArgs(alias, args) {
80
- return {
81
- kind: "update",
82
- alias,
83
- ...parseOnboardLikeArgs(args, alias),
84
- };
85
- }
86
- export function parseDoctorArgs(alias, args) {
87
- // The allowed set is the UNION of what the six setup doors used to accept.
88
- // An alias that silently rejected a flag its own docs told people to pass
89
- // would be a worse dead end than the one we are removing.
90
- const values = parseNamedArgs(args, {
91
- allowedFlags: [
92
- "--home",
93
- "--repo",
94
- "--workspace",
95
- "--dashboard-url",
96
- "--update-tag",
97
- "--dry-run",
98
- "--json",
99
- "--allow-home-root",
100
- "--max-depth",
101
- "--max-repos",
102
- // Accepted and ignored: the convergence run works these out itself.
103
- // Rejecting them would break existing DMs and runbooks for no gain.
104
- "--email",
105
- "--device-name",
106
- "--ticket",
107
- "--branch",
108
- "--no-auth",
109
- "--poll-interval-ms",
110
- "--timeout-ms",
111
- ],
112
- valueFlags: [
113
- "--home",
114
- "--repo",
115
- "--workspace",
116
- "--dashboard-url",
117
- "--update-tag",
118
- "--max-depth",
119
- "--max-repos",
120
- "--email",
121
- "--device-name",
122
- "--ticket",
123
- "--branch",
124
- "--poll-interval-ms",
125
- "--timeout-ms",
126
- ],
127
- });
128
- assertNoPositionals(values.positionals, alias);
129
- const updateTag = optionalNonEmpty(values.flags.get("--update-tag"));
130
- if (updateTag && !/^[a-z0-9][a-z0-9._-]*$/u.test(updateTag)) {
131
- throw new Error("--update-tag must be a lowercase npm dist-tag such as 'next' or 'latest'.");
132
- }
133
- return {
134
- kind: "doctor",
135
- alias,
136
- homeDir: optionalNonEmpty(values.flags.get("--home")),
137
- repoRoot: optionalNonEmpty(workRootFlagValue(values)),
138
- collectionRoots: optionalNonEmptyList(workRootFlagValues(values)),
139
- dashboardUrl: normalizeUrl(values.flags.get("--dashboard-url") ?? DEFAULT_DASHBOARD_URL),
140
- updateTag,
141
- dryRun: values.booleans.has("--dry-run"),
142
- json: values.booleans.has("--json"),
143
- allowHomeRoot: values.booleans.has("--allow-home-root"),
144
- maxDepth: optionalPositiveInteger(values.flags.get("--max-depth"), "--max-depth"),
145
- maxRepos: optionalPositiveInteger(values.flags.get("--max-repos"), "--max-repos"),
146
- };
147
- }
148
- export function parseInstallArgs(args) {
149
- const values = parseNamedArgs(args, {
150
- allowedFlags: [
151
- "--home",
152
- "--repo",
153
- "--workspace",
154
- "--dashboard-url",
155
- "--supabase-url",
156
- "--json",
157
- "--allow-home-root",
158
- ],
159
- valueFlags: [
160
- "--home",
161
- "--repo",
162
- "--workspace",
163
- "--dashboard-url",
164
- "--supabase-url",
165
- ],
166
- });
167
- assertNoPositionals(values.positionals, "install");
168
- return {
169
- kind: "install",
170
- homeDir: optionalNonEmpty(values.flags.get("--home")),
171
- repoRoot: optionalNonEmpty(workRootFlagValue(values)),
172
- dashboardUrl: normalizeUrl(values.flags.get("--dashboard-url") ?? DEFAULT_DASHBOARD_URL),
173
- supabaseUrl: optionalNonEmpty(values.flags.get("--supabase-url")),
174
- json: values.booleans.has("--json"),
175
- allowHomeRoot: values.booleans.has("--allow-home-root"),
176
- };
177
- }
178
- export function parseReleaseArgs(args) {
179
- const values = parseNamedArgs(args, {
180
- allowedFlags: [
181
- "--dry-run",
182
- "--tag",
183
- "--access",
184
- "--otp",
185
- "--skip-checks",
186
- // BLI-3557: publish without raising the fleet forced-update floor. The
187
- // maintainer path must be able to say that, or the staged rollout only
188
- // exists for whoever runs the npm script directly.
189
- "--no-floor",
190
- ],
191
- valueFlags: ["--tag", "--access", "--otp"],
192
- });
193
- assertNoPositionals(values.positionals, "release");
194
- const releaseArgs = [];
195
- if (values.booleans.has("--dry-run"))
196
- releaseArgs.push("--dry-run");
197
- if (values.booleans.has("--skip-checks"))
198
- releaseArgs.push("--skip-checks");
199
- if (values.booleans.has("--no-floor"))
200
- releaseArgs.push("--no-floor");
201
- for (const flag of ["--tag", "--access", "--otp"]) {
202
- const value = values.flags.get(flag);
203
- if (value !== undefined)
204
- releaseArgs.push(flag, value);
205
- }
206
- return { kind: "release", args: releaseArgs };
207
- }
208
- export function parseLoginArgs(args) {
209
- const values = parseNamedArgs(args, {
210
- allowedFlags: [
211
- "--home",
212
- "--dashboard-url",
213
- "--email",
214
- "--device-name",
215
- "--json",
216
- "--no-auth",
217
- "--poll-interval-ms",
218
- "--timeout-ms",
219
- ],
220
- valueFlags: [
221
- "--home",
222
- "--dashboard-url",
223
- "--email",
224
- "--device-name",
225
- "--poll-interval-ms",
226
- "--timeout-ms",
227
- ],
228
- });
229
- assertNoPositionals(values.positionals, "login");
230
- return {
231
- kind: "login",
232
- homeDir: optionalNonEmpty(values.flags.get("--home")),
233
- dashboardUrl: optionalUrl(values.flags.get("--dashboard-url")),
234
- claimedOwnerEmail: optionalEmail(values.flags.get("--email")),
235
- deviceName: optionalNonEmpty(values.flags.get("--device-name")),
236
- json: values.booleans.has("--json"),
237
- noAuth: values.booleans.has("--no-auth"),
238
- pollIntervalMs: optionalPositiveInteger(values.flags.get("--poll-interval-ms"), "--poll-interval-ms"),
239
- timeoutMs: optionalPositiveInteger(values.flags.get("--timeout-ms"), "--timeout-ms"),
240
- };
241
- }
242
- export function parseLogoutArgs(args) {
243
- const values = parseNamedArgs(args, {
244
- allowedFlags: ["--home", "--json", "--revoke", "--dashboard-url", "--yes"],
245
- valueFlags: ["--home", "--dashboard-url"],
246
- });
247
- assertNoPositionals(values.positionals, "logout");
248
- return {
249
- kind: "logout",
250
- homeDir: optionalNonEmpty(values.flags.get("--home")),
251
- json: values.booleans.has("--json"),
252
- revoke: values.booleans.has("--revoke"),
253
- dashboardUrl: optionalUrl(values.flags.get("--dashboard-url")),
254
- yes: values.booleans.has("--yes"),
255
- };
256
- }
257
- export function parseStartArgs(args) {
258
- const values = parseNamedArgs(args, {
259
- allowedFlags: [
260
- "--home",
261
- "--repo",
262
- "--workspace",
263
- "--branch",
264
- "--ticket",
265
- "--clear-ticket",
266
- "--topic",
267
- "--topic-summary",
268
- "--intent",
269
- "--phase",
270
- "--intent-source",
271
- "--intent-confidence",
272
- "--operator-id",
273
- "--session-id",
274
- "--json",
275
- "--max-depth",
276
- "--max-repos",
277
- ],
278
- valueFlags: [
279
- "--home",
280
- "--repo",
281
- "--workspace",
282
- "--branch",
283
- "--ticket",
284
- "--topic",
285
- "--topic-summary",
286
- "--intent",
287
- "--phase",
288
- "--intent-source",
289
- "--intent-confidence",
290
- "--operator-id",
291
- "--session-id",
292
- "--max-depth",
293
- "--max-repos",
294
- ],
295
- });
296
- assertNoPositionals(values.positionals, "start");
297
- const activeTicketId = optionalNonEmpty(values.flags.get("--ticket"));
298
- const clearTicket = values.booleans.has("--clear-ticket");
299
- if (activeTicketId && clearTicket) {
300
- throw new Error("--ticket and --clear-ticket cannot be combined.");
301
- }
302
- const topicLabel = optionalNonEmpty(values.flags.get("--topic"));
303
- const topicSummaryRedacted = optionalNonEmpty(values.flags.get("--topic-summary"));
304
- const workIntent = optionalSchemaValue(WorkIntentSchema, values.flags.get("--intent"), "--intent");
305
- const workPhase = optionalSchemaValue(WorkPhaseSchema, values.flags.get("--phase"), "--phase");
306
- const intentConfidence = optionalConfidence(values.flags.get("--intent-confidence"), "--intent-confidence");
307
- const explicitIntentMetadata = Boolean(topicLabel ||
308
- topicSummaryRedacted ||
309
- workIntent ||
310
- workPhase ||
311
- intentConfidence !== undefined);
312
- return {
313
- kind: "start",
314
- homeDir: optionalNonEmpty(values.flags.get("--home")),
315
- repoRoot: optionalNonEmpty(workRootFlagValue(values)),
316
- branch: optionalNonEmpty(values.flags.get("--branch")),
317
- activeTicketId,
318
- clearTicket,
319
- topicLabel,
320
- topicSummaryRedacted,
321
- workIntent,
322
- workPhase,
323
- intentSource: optionalSchemaValue(IntentSourceSchema, values.flags.get("--intent-source"), "--intent-source") ?? (explicitIntentMetadata ? "explicit_user" : undefined),
324
- intentConfidence,
325
- operatorId: optionalNonEmpty(values.flags.get("--operator-id")),
326
- sessionId: optionalNonEmpty(values.flags.get("--session-id")),
327
- json: values.booleans.has("--json"),
328
- maxDepth: optionalPositiveInteger(values.flags.get("--max-depth"), "--max-depth"),
329
- maxRepos: optionalPositiveInteger(values.flags.get("--max-repos"), "--max-repos"),
330
- };
331
- }
332
- export function parseSyncArgs(args) {
333
- return parseSyncLikeArgs(args, "sync");
334
- }
335
- export function parseAnalyzeArgs(args) {
336
- return parseSyncLikeArgs(args, "analyze");
337
- }
338
- function parseSyncLikeArgs(args, command) {
339
- const values = parseNamedArgs(args, {
340
- allowedFlags: [
341
- "--home",
342
- "--repo",
343
- "--workspace",
344
- "--dashboard-url",
345
- "--json",
346
- "--max-depth",
347
- "--max-repos",
348
- ],
349
- valueFlags: [
350
- "--home",
351
- "--repo",
352
- "--workspace",
353
- "--dashboard-url",
354
- "--max-depth",
355
- "--max-repos",
356
- ],
357
- });
358
- assertNoPositionals(values.positionals, command);
359
- return {
360
- kind: command,
361
- homeDir: optionalNonEmpty(values.flags.get("--home")),
362
- repoRoot: optionalNonEmpty(workRootFlagValue(values)),
363
- dashboardUrl: optionalUrl(values.flags.get("--dashboard-url")),
364
- json: values.booleans.has("--json"),
365
- maxDepth: optionalPositiveInteger(values.flags.get("--max-depth"), "--max-depth"),
366
- maxRepos: optionalPositiveInteger(values.flags.get("--max-repos"), "--max-repos"),
367
- };
368
- }
369
- export function parseBackfillArgs(args) {
370
- const values = parseNamedArgs(args, {
371
- allowedFlags: [
372
- "--home",
373
- "--repo",
374
- "--workspace",
375
- "--since-days",
376
- "--all",
377
- "--source",
378
- "--dry-run",
379
- "--max-files",
380
- "--max-depth",
381
- "--max-repos",
382
- "--yes",
383
- "--json",
384
- ],
385
- valueFlags: [
386
- "--home",
387
- "--repo",
388
- "--workspace",
389
- "--since-days",
390
- "--source",
391
- "--max-files",
392
- "--max-depth",
393
- "--max-repos",
394
- ],
395
- });
396
- assertNoPositionals(values.positionals, "backfill");
397
- const source = values.flags.get("--source");
398
- if (source !== undefined && source !== "codex" && source !== "claude") {
399
- throw new Error("--source must be 'codex' or 'claude'. Omit it to scan both.");
400
- }
401
- const sinceDays = optionalPositiveInteger(values.flags.get("--since-days"), "--since-days");
402
- const all = values.booleans.has("--all");
403
- if (all && sinceDays !== undefined) {
404
- throw new Error("--since-days and --all cannot be combined.");
405
- }
406
- return {
407
- kind: "backfill",
408
- homeDir: optionalNonEmpty(values.flags.get("--home")),
409
- repoRoot: optionalNonEmpty(workRootFlagValue(values)),
410
- source,
411
- sinceDays,
412
- all,
413
- dryRun: values.booleans.has("--dry-run"),
414
- maxFiles: optionalPositiveInteger(values.flags.get("--max-files"), "--max-files"),
415
- maxDepth: optionalPositiveInteger(values.flags.get("--max-depth"), "--max-depth"),
416
- maxRepos: optionalPositiveInteger(values.flags.get("--max-repos"), "--max-repos"),
417
- yes: values.booleans.has("--yes"),
418
- json: values.booleans.has("--json"),
419
- };
420
- }
421
- export function parseStatusArgs(args) {
422
- const values = parseNamedArgs(args, {
423
- allowedFlags: [
424
- "--home",
425
- "--repo",
426
- "--workspace",
427
- "--json",
428
- "--max-depth",
429
- "--max-repos",
430
- ],
431
- valueFlags: [
432
- "--home",
433
- "--repo",
434
- "--workspace",
435
- "--max-depth",
436
- "--max-repos",
437
- ],
438
- });
439
- assertNoPositionals(values.positionals, "status");
440
- return {
441
- kind: "status",
442
- homeDir: optionalNonEmpty(values.flags.get("--home")),
443
- repoRoot: optionalNonEmpty(workRootFlagValue(values)),
444
- json: values.booleans.has("--json"),
445
- maxDepth: optionalPositiveInteger(values.flags.get("--max-depth"), "--max-depth"),
446
- maxRepos: optionalPositiveInteger(values.flags.get("--max-repos"), "--max-repos"),
447
- };
448
- }
449
- export function parseSessionsArgs(args) {
450
- const values = parseNamedArgs(args, {
451
- allowedFlags: [
452
- "--home",
453
- "--repo",
454
- "--workspace",
455
- "--source",
456
- "--since-days",
457
- "--all",
458
- "--json",
459
- "--max-depth",
460
- "--max-repos",
461
- ],
462
- valueFlags: [
463
- "--home",
464
- "--repo",
465
- "--workspace",
466
- "--source",
467
- "--since-days",
468
- "--max-depth",
469
- "--max-repos",
470
- ],
471
- });
472
- assertNoPositionals(values.positionals, "sessions");
473
- const source = values.flags.get("--source");
474
- if (source !== undefined && source !== "codex" && source !== "claude") {
475
- throw new Error("--source must be 'codex' or 'claude'. Omit it to scan both.");
476
- }
477
- const sinceDays = optionalPositiveInteger(values.flags.get("--since-days"), "--since-days");
478
- const all = values.booleans.has("--all");
479
- if (all && sinceDays !== undefined) {
480
- throw new Error("--since-days and --all cannot be combined.");
481
- }
482
- return {
483
- kind: "sessions",
484
- homeDir: optionalNonEmpty(values.flags.get("--home")),
485
- repoRoot: optionalNonEmpty(workRootFlagValue(values)),
486
- source,
487
- sinceDays,
488
- all,
489
- json: values.booleans.has("--json"),
490
- maxDepth: optionalPositiveInteger(values.flags.get("--max-depth"), "--max-depth"),
491
- maxRepos: optionalPositiveInteger(values.flags.get("--max-repos"), "--max-repos"),
492
- };
493
- }
494
- export function parseServeArgs(args) {
495
- const values = parseNamedArgs(args, {
496
- allowedFlags: ["--home", "--repo", "--workspace", "--port"],
497
- valueFlags: ["--home", "--repo", "--workspace", "--port"],
498
- });
499
- assertNoPositionals(values.positionals, "serve");
500
- const port = Number(values.flags.get("--port") ?? "4174");
501
- if (!Number.isInteger(port) || port < 1 || port > 65535) {
502
- throw new Error("--port must be a TCP port between 1 and 65535.");
503
- }
504
- return {
505
- kind: "serve",
506
- homeDir: optionalNonEmpty(values.flags.get("--home")),
507
- repoRoot: optionalNonEmpty(workRootFlagValue(values)),
508
- port,
509
- };
510
- }
511
- export function parseAutostartArgs(args) {
512
- const values = parseNamedArgs(args, {
513
- allowedFlags: [
514
- "--home",
515
- "--repo",
516
- "--workspace",
517
- "--dashboard-url",
518
- "--interval-seconds",
519
- "--parent-pid",
520
- "--json",
521
- ],
522
- valueFlags: [
523
- "--home",
524
- "--repo",
525
- "--workspace",
526
- "--dashboard-url",
527
- "--interval-seconds",
528
- "--parent-pid",
529
- ],
530
- });
531
- if (values.positionals.length > 1) {
532
- throw new Error("autostart accepts at most one action (install|uninstall|status).");
533
- }
534
- const action = values.positionals[0] ?? "install";
535
- if (action !== "install" &&
536
- action !== "uninstall" &&
537
- action !== "status" &&
538
- action !== "heal-detached") {
539
- throw new Error("autostart action must be install, uninstall, or status.");
540
- }
541
- return {
542
- kind: "autostart",
543
- action,
544
- homeDir: optionalNonEmpty(values.flags.get("--home")),
545
- repoRoot: optionalNonEmpty(workRootFlagValue(values)),
546
- dashboardUrl: normalizeUrl(values.flags.get("--dashboard-url") ?? DEFAULT_DASHBOARD_URL),
547
- intervalSeconds: optionalPositiveInteger(values.flags.get("--interval-seconds"), "--interval-seconds") ?? DEFAULT_AUTOSTART_INTERVAL_SECONDS,
548
- parentPid: optionalPositiveInteger(values.flags.get("--parent-pid"), "--parent-pid"),
549
- json: values.booleans.has("--json"),
550
- };
551
- }
552
- export function parseAgentRulesArgs(args) {
553
- const values = parseNamedArgs(args, {
554
- allowedFlags: ["--home", "--host", "--repo", "--workspace", "--json"],
555
- valueFlags: ["--home", "--host", "--repo", "--workspace"],
556
- });
557
- if (values.positionals.length > 1) {
558
- throw new Error("agent-rules accepts at most one action (install|uninstall|status).");
559
- }
560
- const action = values.positionals[0] ?? "install";
561
- if (action !== "install" && action !== "uninstall" && action !== "status") {
562
- throw new Error("agent-rules action must be install, uninstall, or status.");
563
- }
564
- return {
565
- kind: "agent-rules",
566
- action,
567
- host: parseAgentRulesHost(values.flags.get("--host")),
568
- homeDir: optionalNonEmpty(values.flags.get("--home")),
569
- repoRoot: optionalNonEmpty(workRootFlagValue(values)),
570
- json: values.booleans.has("--json"),
571
- };
572
- }
573
- /**
574
- * BLI-3580. `install` is the default action on purpose: this command exists to
575
- * be run unasked (by `do-everything` and by the sync tick), and a bare
576
- * `cockpit memory` should do the thing rather than print usage.
577
- */
578
- export function parseMemoryArgs(args) {
579
- const values = parseNamedArgs(args, {
580
- allowedFlags: ["--home", "--dashboard-url", "--dry-run", "--json"],
581
- valueFlags: ["--home", "--dashboard-url"],
582
- });
583
- if (values.positionals.length > 1) {
584
- throw new Error("memory accepts at most one action (install|status).");
585
- }
586
- const action = values.positionals[0] ?? "install";
587
- if (action !== "install" && action !== "status") {
588
- throw new Error("memory action must be install or status.");
589
- }
590
- return {
591
- kind: "memory",
592
- action,
593
- homeDir: optionalNonEmpty(values.flags.get("--home")),
594
- dashboardUrl: optionalUrl(values.flags.get("--dashboard-url")),
595
- dryRun: values.booleans.has("--dry-run"),
596
- json: values.booleans.has("--json"),
597
- };
598
- }
599
- /**
600
- * BLI-3619. Deliberately takes no positional: `clean` is one verb, and the two
601
- * flags say how far it goes. A path is never accepted — the only directory this
602
- * command may touch is the collector's own state directory.
14
+ * local-args-collector-setup.ts install, onboard, login, pair, update,
15
+ * upgrade, do-everything, fix, logout,
16
+ * release — getting a machine collecting
17
+ * local-args-collector-work.ts start, sync, analyze, backfill — the
18
+ * ongoing collection work an already-set-up
19
+ * machine does
20
+ * local-args-collector-status.ts status, sessions, serve, autostart,
21
+ * agent-rules, memory, clean reading or
22
+ * maintaining a machine that already
23
+ * collects
24
+ *
25
+ * Every name this module has ever exported is still importable from here.
603
26
  */
604
- export function parseCleanArgs(args) {
605
- const values = parseNamedArgs(args, {
606
- allowedFlags: [
607
- "--home",
608
- "--dashboard-url",
609
- "--dry-run",
610
- "--all-committed",
611
- "--reconcile",
612
- "--json",
613
- ],
614
- valueFlags: ["--home", "--dashboard-url"],
615
- });
616
- if (values.positionals.length > 0) {
617
- throw new Error("clean takes no arguments; use --dry-run, --all-committed, or --reconcile.");
618
- }
619
- return {
620
- kind: "clean",
621
- homeDir: optionalNonEmpty(values.flags.get("--home")),
622
- dashboardUrl: optionalUrl(values.flags.get("--dashboard-url")),
623
- dryRun: values.booleans.has("--dry-run"),
624
- allCommitted: values.booleans.has("--all-committed"),
625
- reconcile: values.booleans.has("--reconcile"),
626
- json: values.booleans.has("--json"),
627
- };
628
- }
629
- function parseAgentRulesHost(value) {
630
- const host = value?.trim().toLowerCase() || "all";
631
- if (host === "codex" || host === "claude" || host === "all")
632
- return host;
633
- throw new Error("agent-rules --host must be codex, claude, or all.");
634
- }
27
+ export { parseOnboardArgs, parseUpdateArgs, parseDoctorArgs, parseInstallArgs, parseReleaseArgs, parseLoginArgs, parseLogoutArgs, } from "./local-args-collector-setup.js";
28
+ export { parseStartArgs, parseSyncArgs, parseAnalyzeArgs, parseBackfillArgs, } from "./local-args-collector-work.js";
29
+ export { parseStatusArgs, parseSessionsArgs, parseServeArgs, parseAutostartArgs, parseAgentRulesArgs, parseMemoryArgs, parseCleanArgs, } from "./local-args-collector-status.js";