@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
@@ -0,0 +1,314 @@
1
+ /**
2
+ * The three commands that read a page instead of asking a question: the daily
3
+ * page (`cockpit brief`), meeting notes (`cockpit notes`), and the document
4
+ * library (`cockpit workbook`). Split out of local-args-tower.ts (BLI-3636).
5
+ *
6
+ * Every parser moved verbatim: same flags, same defaults, same refusal
7
+ * sentences. The three names `local-args.ts` re-exports from this family
8
+ * (`WORKBOOK_MIN_WIDTH` and `NotesAction`) are re-exported from
9
+ * `./local-args-tower.js`, the address they have always had.
10
+ */
11
+ import { optionalNonEmpty, optionalPositiveInteger, optionalUrl, parseNamedArgs, } from "./local-arg-values.js";
12
+ /**
13
+ * `cockpit brief` (BLI-3458) — the TODAY page, in the terminal.
14
+ *
15
+ * `--for` is the terminal's `?p=`, and it follows the same rule the website
16
+ * does: the dashboard resolves it against the roster and the database (or the
17
+ * route's own mirror of the database's rule) decides whether the page opens.
18
+ * Nothing is decided here.
19
+ *
20
+ * `--date` (BLI-3484) is the terminal's `?d=`, and the same sentence applies to
21
+ * it twice over: what counts as a date, where that person's day starts, and
22
+ * whether anything was compiled for it are all the dashboard's answer. A local
23
+ * copy of "when does Tuesday begin" would be a second answer to a question this
24
+ * product already answers per person, per zone.
25
+ */
26
+ export function parseBriefArgs(args) {
27
+ const values = parseNamedArgs(args, {
28
+ allowedFlags: [
29
+ "--home",
30
+ "--dashboard-url",
31
+ "--for",
32
+ "--as",
33
+ "--who",
34
+ "--version",
35
+ "--date",
36
+ "--delta",
37
+ "--against",
38
+ "--days",
39
+ "--tldr",
40
+ "--full",
41
+ "--versions",
42
+ "--claims",
43
+ "--render",
44
+ "--reason",
45
+ "--wait",
46
+ "--no-wait",
47
+ "--json",
48
+ ],
49
+ valueFlags: [
50
+ "--home",
51
+ "--dashboard-url",
52
+ "--for",
53
+ "--as",
54
+ "--who",
55
+ "--version",
56
+ "--date",
57
+ "--against",
58
+ "--days",
59
+ "--reason",
60
+ ],
61
+ });
62
+ // Bare `cockpit brief` reads the page, which is what somebody typing it almost
63
+ // always wants — the same shape `cockpit notes` and `cockpit scout` have.
64
+ // `status` (BLI-3462) answers why a brief was or was not delivered.
65
+ const first = values.positionals[0];
66
+ const action = (first === undefined ? "read" : first);
67
+ if (!["read", "edit", "rewrite", "history", "status"].includes(action)) {
68
+ throw new Error(`Unknown brief command: ${first}. Try edit, rewrite, history or status, or nothing to read it.`);
69
+ }
70
+ if (values.positionals.length > (first === undefined ? 0 : 1)) {
71
+ throw new Error(`brief ${action} does not take "${values.positionals[1]}".`);
72
+ }
73
+ const tldr = values.booleans.has("--tldr");
74
+ const full = values.booleans.has("--full");
75
+ if (tldr && full) {
76
+ throw new Error("brief accepts either --tldr or --full, not both.");
77
+ }
78
+ const wait = values.booleans.has("--wait");
79
+ const noWait = values.booleans.has("--no-wait");
80
+ if (wait && noWait) {
81
+ throw new Error("brief rewrite accepts either --wait or --no-wait, not both.");
82
+ }
83
+ const reason = optionalNonEmpty(values.flags.get("--reason"));
84
+ if (reason && reason.length > 280) {
85
+ // The server's own ceiling (`REASON_MAX`). Said here so the person is told
86
+ // before the page is opened rather than after they have finished editing.
87
+ throw new Error("A reason is limited to 280 characters.");
88
+ }
89
+ if (action !== "edit" && reason) {
90
+ throw new Error("--reason belongs to `cockpit brief edit`.");
91
+ }
92
+ if (action !== "rewrite" && (wait || noWait)) {
93
+ throw new Error("--wait and --no-wait belong to `cockpit brief rewrite`.");
94
+ }
95
+ // ── Reading a past day (BLI-3484) ────────────────────────────────────────
96
+ const date = optionalNonEmpty(values.flags.get("--date"));
97
+ const against = optionalNonEmpty(values.flags.get("--against"));
98
+ const delta = values.booleans.has("--delta");
99
+ const days = optionalPositiveInteger(values.flags.get("--days"), "--days");
100
+ if (date && action !== "read") {
101
+ throw new Error("--date belongs to `cockpit brief` on its own — it reads one day's page.");
102
+ }
103
+ if (delta && action !== "read") {
104
+ throw new Error("--delta belongs to `cockpit brief` on its own.");
105
+ }
106
+ if (against && !delta) {
107
+ // Said rather than silently ignored: somebody who typed `--against` asked
108
+ // for a comparison, and running the plain read would answer a different
109
+ // question without saying so.
110
+ throw new Error("--against needs --delta: it names the day to compare against.");
111
+ }
112
+ if (days !== undefined && action !== "history") {
113
+ throw new Error("--days belongs to `cockpit brief history`.");
114
+ }
115
+ if (action === "history" && (values.booleans.has("--tldr") || values.booleans.has("--claims"))) {
116
+ throw new Error("brief history lists days; --tldr and --claims belong to reading a page.");
117
+ }
118
+ // `--as` is accepted as an alias so the two conversational commands read the
119
+ // same way; `cockpit jarvis --as <person>` has meant this since BLI-3380.
120
+ // `--who` is the third spelling, and it exists because `cockpit brief status
121
+ // --who <person>` is the terminal echo of `jarvis:dm --who`.
122
+ const forPerson = optionalNonEmpty(values.flags.get("--for"));
123
+ const asPerson = optionalNonEmpty(values.flags.get("--as"));
124
+ const whoPerson = optionalNonEmpty(values.flags.get("--who"));
125
+ const named = [forPerson, asPerson, whoPerson].filter(Boolean);
126
+ if (new Set(named).size > 1) {
127
+ throw new Error("brief --for, --as and --who must name the same person.");
128
+ }
129
+ const render = values.booleans.has("--render");
130
+ if (render && action !== "status") {
131
+ throw new Error("brief --render belongs to `cockpit brief status`; the page is printed by default.");
132
+ }
133
+ return {
134
+ kind: "brief",
135
+ action,
136
+ render,
137
+ homeDir: optionalNonEmpty(values.flags.get("--home")),
138
+ dashboardUrl: optionalUrl(values.flags.get("--dashboard-url")),
139
+ subject: forPerson ?? asPerson ?? whoPerson,
140
+ version: optionalNonEmpty(values.flags.get("--version")),
141
+ ...(date ? { date } : {}),
142
+ ...(delta ? { delta: true } : {}),
143
+ ...(against ? { against } : {}),
144
+ ...(days !== undefined ? { days } : {}),
145
+ tldr,
146
+ versions: values.booleans.has("--versions"),
147
+ claims: values.booleans.has("--claims"),
148
+ ...(reason ? { reason } : {}),
149
+ // Waiting is the default; only an explicit `--no-wait` turns it off. A
150
+ // person who typed `rewrite` wants the page, not a receipt.
151
+ ...(noWait ? { wait: false } : {}),
152
+ json: values.booleans.has("--json"),
153
+ };
154
+ }
155
+ const NOTES_ACTIONS = new Set([
156
+ "list",
157
+ "show",
158
+ "shelf",
159
+ "shelves",
160
+ "upload",
161
+ "paste",
162
+ "share",
163
+ "unshare",
164
+ "move",
165
+ ]);
166
+ /** Actions whose first positional is the note it acts on. */
167
+ const NOTES_ACTIONS_NEEDING_A_NOTE = new Set([
168
+ "show",
169
+ "share",
170
+ "unshare",
171
+ "move",
172
+ ]);
173
+ export function parseNotesArgs(args) {
174
+ const values = parseNamedArgs(args, {
175
+ allowedFlags: [
176
+ "--home",
177
+ "--dashboard-url",
178
+ "--file",
179
+ "--name",
180
+ "--exclude",
181
+ "--to",
182
+ "--clear-shelf",
183
+ "--series",
184
+ "--kind",
185
+ "--since",
186
+ "--until",
187
+ "--limit",
188
+ "--yes",
189
+ "--json",
190
+ ],
191
+ valueFlags: [
192
+ "--home",
193
+ "--dashboard-url",
194
+ "--file",
195
+ "--name",
196
+ "--exclude",
197
+ "--to",
198
+ "--series",
199
+ "--kind",
200
+ "--since",
201
+ "--until",
202
+ "--limit",
203
+ ],
204
+ });
205
+ // Bare `cockpit notes` is the list, which is the thing a person typing it
206
+ // almost always wants — same reasoning as bare `cockpit` running convergence.
207
+ const first = values.positionals[0];
208
+ const action = (first === undefined ? "list" : first);
209
+ if (!NOTES_ACTIONS.has(action)) {
210
+ throw new Error(`Unknown notes command: ${first}. Try list, show, shelf, shelves, upload, paste, share, unshare, or move.`);
211
+ }
212
+ const rest = values.positionals.slice(first === undefined ? 0 : 1);
213
+ const json = values.booleans.has("--json");
214
+ // `--json` implies `--yes`: a machine-readable run has nobody to prompt, and
215
+ // failing it for want of a confirmation flag it cannot see is a worse
216
+ // surprise than an explicit share it already asked for by name.
217
+ const yes = values.booleans.has("--yes") || json;
218
+ let noteId;
219
+ if (NOTES_ACTIONS_NEEDING_A_NOTE.has(action)) {
220
+ noteId = optionalNonEmpty(rest[0]);
221
+ if (!noteId)
222
+ throw new Error(`notes ${action} needs a note id.`);
223
+ if (rest.length > 1) {
224
+ throw new Error(`notes ${action} takes one note id, not ${rest.length}.`);
225
+ }
226
+ }
227
+ let paths;
228
+ if (action === "upload") {
229
+ // Explicit paths only. No globbing happens here — a shell that expands
230
+ // `*.md` hands us the names it found, and a shell that does not would have
231
+ // this command silently uploading a file literally called `*.md`.
232
+ paths = rest.filter((value) => value.trim() !== "");
233
+ if (paths.length === 0)
234
+ throw new Error("notes upload needs at least one file path.");
235
+ }
236
+ else if (action !== "paste" && !NOTES_ACTIONS_NEEDING_A_NOTE.has(action) && rest.length > 0) {
237
+ throw new Error(`notes ${action} does not take "${rest[0]}".`);
238
+ }
239
+ const to = optionalNonEmpty(values.flags.get("--to"));
240
+ const clearShelf = values.booleans.has("--clear-shelf");
241
+ if (action === "move") {
242
+ if (to && clearShelf) {
243
+ throw new Error("notes move accepts either --to or --clear-shelf, not both.");
244
+ }
245
+ if (!to && !clearShelf) {
246
+ throw new Error('notes move needs --to "<shelf>" or --clear-shelf.');
247
+ }
248
+ }
249
+ const limit = optionalPositiveInteger(values.flags.get("--limit"), "--limit");
250
+ return {
251
+ kind: "notes",
252
+ action,
253
+ homeDir: optionalNonEmpty(values.flags.get("--home")),
254
+ dashboardUrl: optionalUrl(values.flags.get("--dashboard-url")),
255
+ ...(noteId ? { noteId } : {}),
256
+ ...(paths ? { paths } : {}),
257
+ filePath: optionalNonEmpty(values.flags.get("--file")),
258
+ name: optionalNonEmpty(values.flags.get("--name")),
259
+ exclude: optionalNonEmpty(values.flags.get("--exclude")),
260
+ ...(to ? { to } : {}),
261
+ ...(clearShelf ? { clearShelf } : {}),
262
+ series: optionalNonEmpty(values.flags.get("--series")),
263
+ meetingKind: optionalNonEmpty(values.flags.get("--kind")),
264
+ since: optionalNonEmpty(values.flags.get("--since")),
265
+ until: optionalNonEmpty(values.flags.get("--until")),
266
+ ...(limit === undefined ? {} : { limit }),
267
+ yes,
268
+ json,
269
+ };
270
+ }
271
+ /** The narrowest width worth wrapping to; below it every line is one word. */
272
+ export const WORKBOOK_MIN_WIDTH = 20;
273
+ /**
274
+ * `cockpit workbook` with nothing lists the library, one positional lists a
275
+ * project's shelf, two read a document.
276
+ */
277
+ export function parseWorkbookArgs(args) {
278
+ const values = parseNamedArgs(args, {
279
+ allowedFlags: [
280
+ "--home",
281
+ "--dashboard-url",
282
+ "--section",
283
+ "--width",
284
+ "--markdown",
285
+ "--json",
286
+ ],
287
+ valueFlags: ["--home", "--dashboard-url", "--section", "--width"],
288
+ });
289
+ if (values.positionals.length > 2) {
290
+ throw new Error("workbook accepts at most a project and a document.");
291
+ }
292
+ const project = optionalNonEmpty(values.positionals[0]);
293
+ const doc = optionalNonEmpty(values.positionals[1]);
294
+ const section = optionalNonEmpty(values.flags.get("--section"));
295
+ const markdown = values.booleans.has("--markdown");
296
+ if (!doc && (section || markdown)) {
297
+ throw new Error("workbook --section and --markdown need a project and a document, e.g. `cockpit workbook tower workbook`.");
298
+ }
299
+ const width = optionalPositiveInteger(values.flags.get("--width"), "--width");
300
+ if (width !== undefined && width < WORKBOOK_MIN_WIDTH) {
301
+ throw new Error(`workbook --width must be at least ${WORKBOOK_MIN_WIDTH}.`);
302
+ }
303
+ return {
304
+ kind: "workbook",
305
+ project,
306
+ doc,
307
+ section,
308
+ markdown,
309
+ width,
310
+ homeDir: optionalNonEmpty(values.flags.get("--home")),
311
+ dashboardUrl: optionalUrl(values.flags.get("--dashboard-url")),
312
+ json: values.booleans.has("--json"),
313
+ };
314
+ }