monday-cli 0.3.0 → 0.4.0

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 (107) hide show
  1. package/CHANGELOG.md +351 -0
  2. package/README.md +130 -36
  3. package/dist/api/assets.d.ts +326 -0
  4. package/dist/api/assets.d.ts.map +1 -0
  5. package/dist/api/assets.js +519 -0
  6. package/dist/api/assets.js.map +1 -0
  7. package/dist/api/column-types.d.ts +11 -7
  8. package/dist/api/column-types.d.ts.map +1 -1
  9. package/dist/api/column-types.js +5 -3
  10. package/dist/api/column-types.js.map +1 -1
  11. package/dist/api/column-values.d.ts +7 -1
  12. package/dist/api/column-values.d.ts.map +1 -1
  13. package/dist/api/column-values.js +15 -6
  14. package/dist/api/column-values.js.map +1 -1
  15. package/dist/api/documents.d.ts +519 -0
  16. package/dist/api/documents.d.ts.map +1 -0
  17. package/dist/api/documents.js +586 -0
  18. package/dist/api/documents.js.map +1 -0
  19. package/dist/api/item-watch.d.ts +263 -0
  20. package/dist/api/item-watch.d.ts.map +1 -0
  21. package/dist/api/item-watch.js +709 -0
  22. package/dist/api/item-watch.js.map +1 -0
  23. package/dist/api/multipart-transport.d.ts +223 -0
  24. package/dist/api/multipart-transport.d.ts.map +1 -0
  25. package/dist/api/multipart-transport.js +274 -0
  26. package/dist/api/multipart-transport.js.map +1 -0
  27. package/dist/api/parallel-dispatch.d.ts +155 -0
  28. package/dist/api/parallel-dispatch.d.ts.map +1 -0
  29. package/dist/api/parallel-dispatch.js +243 -0
  30. package/dist/api/parallel-dispatch.js.map +1 -0
  31. package/dist/api/partial-success-bulk.d.ts +118 -60
  32. package/dist/api/partial-success-bulk.d.ts.map +1 -1
  33. package/dist/api/partial-success-bulk.js +137 -79
  34. package/dist/api/partial-success-bulk.js.map +1 -1
  35. package/dist/api/partial-success-mutation.d.ts +13 -1
  36. package/dist/api/partial-success-mutation.d.ts.map +1 -1
  37. package/dist/api/partial-success-mutation.js +5 -1
  38. package/dist/api/partial-success-mutation.js.map +1 -1
  39. package/dist/api/raw-write.d.ts +12 -4
  40. package/dist/api/raw-write.d.ts.map +1 -1
  41. package/dist/api/raw-write.js +21 -11
  42. package/dist/api/raw-write.js.map +1 -1
  43. package/dist/api/resolve-client.d.ts +11 -0
  44. package/dist/api/resolve-client.d.ts.map +1 -1
  45. package/dist/api/resolve-client.js +9 -1
  46. package/dist/api/resolve-client.js.map +1 -1
  47. package/dist/cli/run.d.ts +20 -0
  48. package/dist/cli/run.d.ts.map +1 -1
  49. package/dist/cli/run.js +1 -0
  50. package/dist/cli/run.js.map +1 -1
  51. package/dist/commands/board/column-create.d.ts +6 -5
  52. package/dist/commands/board/column-create.d.ts.map +1 -1
  53. package/dist/commands/board/column-create.js +9 -6
  54. package/dist/commands/board/column-create.js.map +1 -1
  55. package/dist/commands/completion.d.ts +188 -0
  56. package/dist/commands/completion.d.ts.map +1 -0
  57. package/dist/commands/completion.js +418 -0
  58. package/dist/commands/completion.js.map +1 -0
  59. package/dist/commands/doc/get.d.ts +46 -0
  60. package/dist/commands/doc/get.d.ts.map +1 -0
  61. package/dist/commands/doc/get.js +95 -0
  62. package/dist/commands/doc/get.js.map +1 -0
  63. package/dist/commands/doc/list.d.ts +83 -0
  64. package/dist/commands/doc/list.d.ts.map +1 -0
  65. package/dist/commands/doc/list.js +248 -0
  66. package/dist/commands/doc/list.js.map +1 -0
  67. package/dist/commands/index.d.ts.map +1 -1
  68. package/dist/commands/index.js +46 -0
  69. package/dist/commands/index.js.map +1 -1
  70. package/dist/commands/item/create.js +2 -2
  71. package/dist/commands/item/update.d.ts +1 -0
  72. package/dist/commands/item/update.d.ts.map +1 -1
  73. package/dist/commands/item/update.js +61 -0
  74. package/dist/commands/item/update.js.map +1 -1
  75. package/dist/commands/item/upload.d.ts +108 -0
  76. package/dist/commands/item/upload.d.ts.map +1 -0
  77. package/dist/commands/item/upload.js +370 -0
  78. package/dist/commands/item/upload.js.map +1 -0
  79. package/dist/commands/item/watch.d.ts +90 -0
  80. package/dist/commands/item/watch.d.ts.map +1 -0
  81. package/dist/commands/item/watch.js +342 -0
  82. package/dist/commands/item/watch.js.map +1 -0
  83. package/dist/commands/update/upload.d.ts +69 -0
  84. package/dist/commands/update/upload.d.ts.map +1 -0
  85. package/dist/commands/update/upload.js +235 -0
  86. package/dist/commands/update/upload.js.map +1 -0
  87. package/dist/types/ids.d.ts +2 -0
  88. package/dist/types/ids.d.ts.map +1 -1
  89. package/dist/types/ids.js +9 -2
  90. package/dist/types/ids.js.map +1 -1
  91. package/dist/utils/mime.d.ts +24 -0
  92. package/dist/utils/mime.d.ts.map +1 -0
  93. package/dist/utils/mime.js +64 -0
  94. package/dist/utils/mime.js.map +1 -0
  95. package/dist/utils/output/envelope.d.ts +30 -0
  96. package/dist/utils/output/envelope.d.ts.map +1 -1
  97. package/dist/utils/output/envelope.js +26 -0
  98. package/dist/utils/output/envelope.js.map +1 -1
  99. package/dist/utils/output/ndjson.d.ts +25 -0
  100. package/dist/utils/output/ndjson.d.ts.map +1 -1
  101. package/dist/utils/output/ndjson.js +12 -0
  102. package/dist/utils/output/ndjson.js.map +1 -1
  103. package/dist/utils/signal.d.ts +42 -0
  104. package/dist/utils/signal.d.ts.map +1 -0
  105. package/dist/utils/signal.js +45 -0
  106. package/dist/utils/signal.js.map +1 -0
  107. package/package.json +1 -1
@@ -0,0 +1,342 @@
1
+ /**
2
+ * `monday item watch <iid>` — polling-based event stream over the
3
+ * v0.3-M24 `item-history-projection.ts` projector. Runtime body
4
+ * shipped at v0.4-M29 IMPL (`7b83a3a` + round-1 fix-ups). Pinned
5
+ * per cli-design §13 v0.4 entry + §14.4 closure (`31713fb`) +
6
+ * v0.4-plan §3 M29.
7
+ *
8
+ * **What this verb answers:** "wait for changes on this item + emit
9
+ * them as they arrive". Single CLI invocation polls Monday's
10
+ * `boards(ids:){ activity_logs(item_ids:, from:, limit:) }` surface
11
+ * each tick, projects new rows through the M24 projector, emits one
12
+ * NDJSON record per new event plus a session-summary trailer on exit.
13
+ *
14
+ * **GraphQL operation:** `ItemWatchPoll` (one per poll tick;
15
+ * R-NEW-37 W2 audit-point — operationName pinned in
16
+ * `WATCH_POLL_QUERY` literal at `src/api/item-watch.ts`).
17
+ *
18
+ * **Action shape (M29 IMPL).** Item-board lookup via
19
+ * `lookupItemBoard` → `watchItem` polling loop with NDJSON
20
+ * `onEvent` streaming hook + per-event projection via M24's
21
+ * `projectActivityLogRow` → trailer-meta emit on graceful exit.
22
+ * SIGINT graceful drain via `ctx.signal` (the same AbortSignal seam
23
+ * M22 status uses). The polling loop owns:
24
+ *
25
+ * - Cadence (default 30s; range 1s–1h; `--interval <ms>`).
26
+ * - Watermark advance (last-seen-event-id; `--since <event-id>`
27
+ * bootstraps).
28
+ * - Circuit breaker (reactive on Monday wire errors; trip after 5
29
+ * consecutive failures; per-failure warnings accumulate on
30
+ * `WatchItemResult.warnings` and fold into the trailer's
31
+ * `_meta.warnings` slot at session end per cli-design §6.3 —
32
+ * NOT interleaved with event lines).
33
+ * - Limit enforcement (`--max-events <n>` / `--max-duration
34
+ * <seconds>`).
35
+ * - `--once` short-circuit (drain backlog and exit; do NOT poll).
36
+ *
37
+ * **Output:** NDJSON only at v0.4-M29 — `--json` / `--table` /
38
+ * `--output` global flags ignored (this is a streaming verb).
39
+ * Trailer-meta carries seven M29-specific slots:
40
+ * `events_emitted` + `polls_made` + `failed_polls` +
41
+ * `watch_duration_seconds` + `last_seen_event_id` +
42
+ * `circuit_broken_at` + `exit_reason`. Plus the standard §6.3
43
+ * `_meta.warnings[]` slot collects any `WatchSessionWarning`
44
+ * records the polling loop accumulated (poll_failed,
45
+ * circuit_breaker_armed, unknown_event_kind) — warnings are NOT
46
+ * interleaved with event lines.
47
+ *
48
+ * Idempotent: yes (pure read; re-running with the same `--since` is
49
+ * safe).
50
+ */
51
+ import { z } from 'zod';
52
+ import { ensureSubcommand } from '../types.js';
53
+ import { parseArgv } from '../parse-argv.js';
54
+ import { resolveClient } from '../../api/resolve-client.js';
55
+ import { lookupItemBoard } from '../../api/item-board-lookup.js';
56
+ import { SourceAggregator } from '../../api/source-aggregator.js';
57
+ import { buildStreamingTrailerMeta, startNdjsonStream, } from '../../utils/output/ndjson.js';
58
+ import { collectSecrets } from '../../cli/envelope-out.js';
59
+ import { ApiError } from '../../utils/errors.js';
60
+ import { ItemIdSchema } from '../../types/ids.js';
61
+ import { CIRCUIT_BREAKER_CONSECUTIVE_FAILS, DEFAULT_WATCH_INTERVAL_MS, MAX_WATCH_INTERVAL_MS, MIN_WATCH_INTERVAL_MS, watchItem, } from '../../api/item-watch.js';
62
+ import { historyEventSchema, } from '../../api/item-history-projection.js';
63
+ /**
64
+ * The `--include` flag accepts a comma-separated list of literal kind
65
+ * values from the M24 closed event-kind taxonomy (9 kinds). Mirrors
66
+ * `item history`'s `--kinds` enum verbatim — forward-compat at the
67
+ * argv boundary even though v0.4-M29 only emits activity-log-sourced
68
+ * kinds (the projector's `update_posted` / `update_replied` variants
69
+ * are from the updates source, which v0.4-M29 doesn't poll; agents
70
+ * passing those kinds get no events at v0.4 but the argv accepts them
71
+ * for v0.5+ comment-polling compatibility).
72
+ */
73
+ const WATCH_KIND_LITERALS = [
74
+ 'update_column_value',
75
+ 'create_column',
76
+ 'create_group',
77
+ 'update_board_name',
78
+ 'update_board_nickname',
79
+ 'board_workspace_id_changed',
80
+ 'update_posted',
81
+ 'update_replied',
82
+ 'unknown',
83
+ ];
84
+ const watchKindSchema = z.enum(WATCH_KIND_LITERALS);
85
+ /**
86
+ * Parses `--include <list>` (comma-separated; commander hands it over
87
+ * as a raw string). Empty entries filtered before validation so
88
+ * `--include update_column_value,` doesn't raise `usage_error`. Empty
89
+ * arrays after the filter raise `usage_error` rather than silently
90
+ * meaning "include everything" — an agent passing `--include ,,` is
91
+ * almost certainly bug, not intent.
92
+ */
93
+ const includeListSchema = z
94
+ .string()
95
+ .transform((raw) => raw.split(',').map((s) => s.trim()).filter((s) => s.length > 0))
96
+ .pipe(z.array(watchKindSchema).min(1));
97
+ /**
98
+ * Event-ID validator for `--since <event-id>`. Numeric string per
99
+ * Monday's `ActivityLogType.id` shape (NON_NULL String at the wire
100
+ * level but always digits in practice per the M24 probe). Open shape
101
+ * (no length cap) — Monday's event IDs are typically 13+ digits.
102
+ */
103
+ const eventIdSchema = z
104
+ .string()
105
+ .min(1)
106
+ .regex(/^\d+$/u, { message: 'must be a numeric event ID (digits only)' });
107
+ /**
108
+ * Argv input schema for `monday item watch <iid>`. Validates at the
109
+ * parse boundary; the action body consumes the validated shape
110
+ * directly (no defensive re-checks).
111
+ *
112
+ * Mutual-exclusion rules (superRefine):
113
+ *
114
+ * - `--once` is incompatible with `--max-events` / `--max-duration`.
115
+ * `--once` already pins the exit (drain then return); a max-event
116
+ * ceiling would be redundant and a max-duration ceiling could
117
+ * race the backlog drain.
118
+ * - `--interval <ms>` requires the bare-integer ms form; the closure
119
+ * pins ms semantics (not bare seconds) to disambiguate 30 vs
120
+ * 30000 unambiguously. Range 1000–3600000 (1s–1h).
121
+ */
122
+ const inputSchema = z
123
+ .object({
124
+ iid: ItemIdSchema,
125
+ /**
126
+ * Polling cadence in milliseconds. Default
127
+ * {@link DEFAULT_WATCH_INTERVAL_MS} (30000ms / 30s) per cli-design
128
+ * §14.4 closure. Range {@link MIN_WATCH_INTERVAL_MS} (1000ms /
129
+ * 1s; faster trips Monday's request-rate concerns + the
130
+ * propagation-lag floor) to {@link MAX_WATCH_INTERVAL_MS}
131
+ * (3600000ms / 1h; slower crosses the "no longer a watch" line —
132
+ * use `cron + monday item history` for hourly cadences).
133
+ */
134
+ interval: z.coerce
135
+ .number()
136
+ .int()
137
+ .min(MIN_WATCH_INTERVAL_MS)
138
+ .max(MAX_WATCH_INTERVAL_MS)
139
+ .optional(),
140
+ /**
141
+ * Last-seen-event-id watermark for session restart. One-shot
142
+ * bootstrap — the runtime looks up the event's `created_at`
143
+ * once, sets the initial poll-from timestamp, emits any backlog
144
+ * past the watermark, then enters the polling loop. Distinct
145
+ * from a full `--resume <token>` mechanism (still open per
146
+ * cli-design §14.6).
147
+ */
148
+ since: eventIdSchema.optional(),
149
+ /**
150
+ * Drain backlog from `--since` (or recent N if no `--since`) and
151
+ * exit without polling. Distinct from `--max-events 1` which
152
+ * waits for the NEXT event.
153
+ */
154
+ once: z.boolean().optional(),
155
+ /**
156
+ * Cap on emitted events. Session exits with
157
+ * `exit_reason: 'max_events'` once the count is reached
158
+ * (success envelope).
159
+ */
160
+ maxEvents: z.coerce.number().int().positive().optional(),
161
+ /**
162
+ * Wall-clock ceiling in seconds. Session exits with
163
+ * `exit_reason: 'max_duration'` once the duration is reached
164
+ * (current in-flight poll completes first).
165
+ */
166
+ maxDuration: z.coerce.number().int().positive().optional(),
167
+ /**
168
+ * Comma-separated list of event kinds to retain. Filter applied
169
+ * at projection time (Monday doesn't expose a server-side filter
170
+ * on `activity_logs.event`). Accepts all 9 M24 kinds for
171
+ * forward-compat; v0.4-M29 only emits activity-log-sourced
172
+ * kinds.
173
+ */
174
+ include: includeListSchema.optional(),
175
+ })
176
+ .strict()
177
+ .superRefine((value, ctx) => {
178
+ if (value.once === true && value.maxEvents !== undefined) {
179
+ ctx.addIssue({
180
+ code: 'custom',
181
+ message: '--once is incompatible with --max-events (pick one)',
182
+ path: ['once'],
183
+ });
184
+ }
185
+ if (value.once === true && value.maxDuration !== undefined) {
186
+ ctx.addIssue({
187
+ code: 'custom',
188
+ message: '--once is incompatible with --max-duration (pick one)',
189
+ path: ['once'],
190
+ });
191
+ }
192
+ });
193
+ export const itemWatchCommand = {
194
+ name: 'item.watch',
195
+ summary: 'Poll Monday for activity-log events on an item; stream NDJSON as they arrive',
196
+ examples: [
197
+ 'monday item watch 1234567890',
198
+ 'monday item watch 1234567890 --interval 60000 # 60s cadence',
199
+ 'monday item watch 1234567890 --since 999999 # resume from event-id',
200
+ 'monday item watch 1234567890 --once # drain backlog + exit',
201
+ 'monday item watch 1234567890 --max-events 10',
202
+ 'monday item watch 1234567890 --max-duration 3600 # 1h ceiling',
203
+ 'monday item watch 1234567890 --include update_column_value,update_posted',
204
+ ],
205
+ idempotent: true,
206
+ inputSchema,
207
+ // Mirrors M24 `item history`: the output schema describes the
208
+ // per-event record shape an agent sees on the NDJSON stream — NOT
209
+ // the session-summary trailer (the trailer-meta shape is documented
210
+ // in output-shapes.md + cli-design §4.3, but a streaming verb has no
211
+ // buffered `data` payload). `monday schema item.watch` reflects
212
+ // the event-record shape so agents pin their per-line parsers
213
+ // against the same discriminated-union taxonomy `item history`
214
+ // uses.
215
+ outputSchema: historyEventSchema,
216
+ attach: (program, ctx) => {
217
+ const noun = ensureSubcommand(program, 'item', 'Item commands');
218
+ noun
219
+ .command('watch <iid>')
220
+ .description(itemWatchCommand.summary)
221
+ .option('--interval <ms>', `polling cadence in milliseconds (${String(MIN_WATCH_INTERVAL_MS)}–${String(MAX_WATCH_INTERVAL_MS)}, default ${String(DEFAULT_WATCH_INTERVAL_MS)})`)
222
+ .option('--since <event-id>', 'resume from a previous session\'s last-seen-event-id (numeric ID from trailer-meta)')
223
+ .option('--once', 'drain backlog from --since (or recent events) and exit without polling')
224
+ .option('--max-events <n>', 'exit cleanly after emitting N events')
225
+ .option('--max-duration <seconds>', 'exit cleanly after N wall-clock seconds')
226
+ .option('--include <list>', 'comma-separated event kinds to retain (e.g. update_column_value,update_posted)')
227
+ .addHelpText('after', [
228
+ '',
229
+ 'Examples:',
230
+ ...itemWatchCommand.examples.map((e) => ` ${e}`),
231
+ '',
232
+ `NOTE: emits NDJSON only (one event per line + trailing meta).`,
233
+ `Default cadence ${String(DEFAULT_WATCH_INTERVAL_MS)}ms (${String(DEFAULT_WATCH_INTERVAL_MS / 1000)}s); circuit-breaker trips after`,
234
+ `${String(CIRCUIT_BREAKER_CONSECUTIVE_FAILS)} consecutive failed polls. Resume across sessions via`,
235
+ '--since <event-id> from the prior trailer-meta\'s last_seen_event_id.',
236
+ 'SIGINT triggers a graceful drain + trailer emit + exit 130.',
237
+ '',
238
+ 'Monday\'s activity_logs has an empirically-measured propagation lag',
239
+ '>30s on freshly-edited boards (M24 pre-flight finding 2026-05-11);',
240
+ 'cadence faster than 30s would generate polls against unpropagated data.',
241
+ '',
242
+ ].join('\n'))
243
+ .action(async (iid, rawOpts) => {
244
+ const merged = { ...rawOpts, iid };
245
+ const parsed = parseArgv(itemWatchCommand.inputSchema, merged);
246
+ const { client, apiVersion } = resolveClient(ctx, program.opts());
247
+ // Item-board lookup short-circuits a missing-item watch with
248
+ // `not_found` before the polling loop spins up. The lookup is
249
+ // a single wire call; SourceAggregator records it as `'live'`
250
+ // so the trailer's `meta.source` stays correct if a future
251
+ // cache layer lifts in here.
252
+ const { boardId } = await lookupItemBoard({
253
+ client,
254
+ itemId: parsed.iid,
255
+ });
256
+ const aggregator = new SourceAggregator();
257
+ aggregator.record('live', null);
258
+ const stream = startNdjsonStream({
259
+ stream: ctx.stdout,
260
+ secrets: collectSecrets(ctx.env, ctx.runtimeSecrets),
261
+ project: (event) => event,
262
+ });
263
+ const result = await watchItem({
264
+ client,
265
+ itemId: parsed.iid,
266
+ boardId,
267
+ intervalMs: parsed.interval ?? DEFAULT_WATCH_INTERVAL_MS,
268
+ ...(parsed.since === undefined ? {} : { since: parsed.since }),
269
+ ...(parsed.once === undefined ? {} : { once: parsed.once }),
270
+ ...(parsed.maxEvents === undefined ? {} : { maxEvents: parsed.maxEvents }),
271
+ ...(parsed.maxDuration === undefined ? {} : { maxDurationSeconds: parsed.maxDuration }),
272
+ ...(parsed.include === undefined ? {} : { includeKinds: parsed.include }),
273
+ signal: ctx.signal,
274
+ onEvent: stream.onItem,
275
+ });
276
+ aggregator.record(result.source, null);
277
+ const aggregated = aggregator.result('live');
278
+ // `WatchSessionWarning` already structurally satisfies the
279
+ // §6.1 `Warning` shape (code + message + details); the
280
+ // trailer slot accepts the superset directly.
281
+ const trailerWarnings = result.warnings;
282
+ stream.writeTrailer(buildStreamingTrailerMeta({
283
+ ctx: {
284
+ cliVersion: ctx.cliVersion,
285
+ requestId: ctx.requestId,
286
+ clock: ctx.clock,
287
+ },
288
+ apiVersion,
289
+ source: aggregated.source,
290
+ cacheAgeSeconds: aggregated.cacheAgeSeconds,
291
+ result: {
292
+ // `has_more` reflects "the source still has events past
293
+ // this session's exit point" — true for ceiling-driven
294
+ // exits (max_events / max_duration / signal) where the
295
+ // agent might re-invoke with --since; false for
296
+ // once_complete (the backlog was the whole window) and
297
+ // circuit_broken (the session failed, not the source
298
+ // running out).
299
+ hasMore: result.exit_reason === 'max_events' ||
300
+ result.exit_reason === 'max_duration' ||
301
+ result.exit_reason === 'signal',
302
+ totalReturned: result.events_emitted,
303
+ complexity: null,
304
+ },
305
+ session: {
306
+ eventsEmitted: result.events_emitted,
307
+ pollsMade: result.polls_made,
308
+ failedPolls: result.failed_polls,
309
+ watchDurationSeconds: result.watch_duration_seconds,
310
+ lastSeenEventId: result.last_seen_event_id,
311
+ circuitBrokenAt: result.circuit_broken_at,
312
+ exitReason: result.exit_reason,
313
+ },
314
+ warnings: trailerWarnings,
315
+ }));
316
+ // Circuit-broken exit surfaces as a §6.5 failure envelope on
317
+ // stderr AFTER the trailer emitted on stdout. The Monday code
318
+ // that tripped the breaker lives on the last `poll_failed`
319
+ // warning's `details.monday_code` slot (no other source: the
320
+ // ApiError thrown by `client.raw` was caught + converted to a
321
+ // warning inside `watchItem`).
322
+ if (result.exit_reason === 'circuit_broken') {
323
+ const lastPollFailed = [...result.warnings]
324
+ .reverse()
325
+ .find((w) => w.code === 'poll_failed');
326
+ /* c8 ignore next 2 — defensive: circuit_broken always
327
+ trips off a poll_failed accumulation; the find always
328
+ succeeds in production. */
329
+ const mondayCode = lastPollFailed?.details.monday_code ??
330
+ 'complexity_exceeded';
331
+ throw new ApiError(mondayCode, `watch session tripped the circuit breaker after ${String(result.failed_polls)} failed polls (${String(CIRCUIT_BREAKER_CONSECUTIVE_FAILS)} consecutive)`, {
332
+ details: {
333
+ failed_polls: result.failed_polls,
334
+ circuit_broken_at: result.circuit_broken_at,
335
+ events_emitted: result.events_emitted,
336
+ },
337
+ });
338
+ }
339
+ });
340
+ },
341
+ };
342
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../../src/commands/item/watch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * `monday update upload <uid> <file>` — attach a file to an Update
3
+ * (comment) via Monday's `add_file_to_update` mutation
4
+ * (cli-design.md §4.3 + §6.4 asset-upload sub-section + §13 v0.4
5
+ * entry; v0.4-plan.md §3 M31).
6
+ *
7
+ * **Wire shape.** Single multipart/form-data round-trip via
8
+ * {@link addFileToUpdate} against `mutation AddFileToUpdate` with
9
+ * `operationName: 'AddFileToUpdate'` (R-NEW-37 W2 audit-point).
10
+ * Same `MultipartTransport` seam as `item upload`; no column-id
11
+ * involved (Updates carry attachments via `Update.assets` directly,
12
+ * not via column values).
13
+ *
14
+ * **Argv shape.** Two positional args:
15
+ *
16
+ * - `<uid>` — numeric update ID; brand-validated via
17
+ * {@link UpdateIdSchema}.
18
+ * - `<file>` — local file path (same constraints as
19
+ * `monday item upload`: regular readable file; stdin not
20
+ * supported at v0.4-M31).
21
+ *
22
+ * **No column-type validation needed.** Updates accept any file
23
+ * type Monday supports — no column-shape gating like
24
+ * `item upload`'s `file`-only check. Server-side validation handles
25
+ * the rest (size cap, filename sanity, virus scan).
26
+ *
27
+ * **Local file failures + size handling — same `details.reason`
28
+ * discrimination as `item upload`.** Three values:
29
+ * - `'file_not_readable'` — ENOENT / EACCES / path is a
30
+ * directory; fires at IMPL via `fs.stat()` pre-check.
31
+ * - `'file_empty'` — zero-byte file; fires via `fs.stat()`.
32
+ * - `'file_too_large'` — Monday's server-side size-cap
33
+ * rejection rewrap; carries `details.file_size_bytes`
34
+ * from the local `fs.stat()` measurement at upload
35
+ * time (NOT a Monday error-payload field — Monday's
36
+ * wire rejection may not surface a size; the CLI
37
+ * threads the locally-measured size into the details
38
+ * slot for a stable agent-keyed envelope).
39
+ * No CLI-side hardcoded size pre-check; Monday's per-file cap
40
+ * is plan-tier-dependent and not exposed via the schema.
41
+ *
42
+ * **`--dry-run` shape** per §6.4 asset-upload variant — emits
43
+ * `{operation: 'add_file_to_update', update_id, file_path,
44
+ * filename, file_size_bytes}` with `meta.source: 'none'`. No wire
45
+ * call fires.
46
+ *
47
+ * **Idempotency: NO** — re-running uploads a second copy. Agents
48
+ * needing register-once dedupe on `Update.assets` reads.
49
+ *
50
+ * **Cache invalidation.** N/A — Updates aren't part of the §8
51
+ * cache scope (board-metadata-only); the upload changes the
52
+ * Update's asset collection but nothing the cache tracks.
53
+ *
54
+ * **Status: runtime body shipped at v0.4-M31 IMPL** — mirrors
55
+ * `item upload` minus the column-resolution + cache-invalidation
56
+ * legs (Updates aren't part of the §8 cache scope; no per-column
57
+ * type check needed because Updates accept any file type Monday
58
+ * supports).
59
+ */
60
+ import { z } from 'zod';
61
+ import { type CommandModule } from '../types.js';
62
+ import { type UpdateUploadOutput } from '../../api/assets.js';
63
+ declare const inputSchema: z.ZodObject<{
64
+ updateId: z.core.$ZodBranded<z.ZodString, "UpdateId", "out">;
65
+ file: z.ZodString;
66
+ }, z.core.$strict>;
67
+ export declare const updateUploadCommand: CommandModule<z.infer<typeof inputSchema>, UpdateUploadOutput>;
68
+ export {};
69
+ //# sourceMappingURL=upload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../../src/commands/update/upload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAGnE,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,qBAAqB,CAAC;AAM7B,QAAA,MAAM,WAAW;;;kBAcN,CAAC;AAEZ,eAAO,MAAM,mBAAmB,EAAE,aAAa,CAC7C,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,EAC3B,kBAAkB,CAuLnB,CAAC"}
@@ -0,0 +1,235 @@
1
+ /**
2
+ * `monday update upload <uid> <file>` — attach a file to an Update
3
+ * (comment) via Monday's `add_file_to_update` mutation
4
+ * (cli-design.md §4.3 + §6.4 asset-upload sub-section + §13 v0.4
5
+ * entry; v0.4-plan.md §3 M31).
6
+ *
7
+ * **Wire shape.** Single multipart/form-data round-trip via
8
+ * {@link addFileToUpdate} against `mutation AddFileToUpdate` with
9
+ * `operationName: 'AddFileToUpdate'` (R-NEW-37 W2 audit-point).
10
+ * Same `MultipartTransport` seam as `item upload`; no column-id
11
+ * involved (Updates carry attachments via `Update.assets` directly,
12
+ * not via column values).
13
+ *
14
+ * **Argv shape.** Two positional args:
15
+ *
16
+ * - `<uid>` — numeric update ID; brand-validated via
17
+ * {@link UpdateIdSchema}.
18
+ * - `<file>` — local file path (same constraints as
19
+ * `monday item upload`: regular readable file; stdin not
20
+ * supported at v0.4-M31).
21
+ *
22
+ * **No column-type validation needed.** Updates accept any file
23
+ * type Monday supports — no column-shape gating like
24
+ * `item upload`'s `file`-only check. Server-side validation handles
25
+ * the rest (size cap, filename sanity, virus scan).
26
+ *
27
+ * **Local file failures + size handling — same `details.reason`
28
+ * discrimination as `item upload`.** Three values:
29
+ * - `'file_not_readable'` — ENOENT / EACCES / path is a
30
+ * directory; fires at IMPL via `fs.stat()` pre-check.
31
+ * - `'file_empty'` — zero-byte file; fires via `fs.stat()`.
32
+ * - `'file_too_large'` — Monday's server-side size-cap
33
+ * rejection rewrap; carries `details.file_size_bytes`
34
+ * from the local `fs.stat()` measurement at upload
35
+ * time (NOT a Monday error-payload field — Monday's
36
+ * wire rejection may not surface a size; the CLI
37
+ * threads the locally-measured size into the details
38
+ * slot for a stable agent-keyed envelope).
39
+ * No CLI-side hardcoded size pre-check; Monday's per-file cap
40
+ * is plan-tier-dependent and not exposed via the schema.
41
+ *
42
+ * **`--dry-run` shape** per §6.4 asset-upload variant — emits
43
+ * `{operation: 'add_file_to_update', update_id, file_path,
44
+ * filename, file_size_bytes}` with `meta.source: 'none'`. No wire
45
+ * call fires.
46
+ *
47
+ * **Idempotency: NO** — re-running uploads a second copy. Agents
48
+ * needing register-once dedupe on `Update.assets` reads.
49
+ *
50
+ * **Cache invalidation.** N/A — Updates aren't part of the §8
51
+ * cache scope (board-metadata-only); the upload changes the
52
+ * Update's asset collection but nothing the cache tracks.
53
+ *
54
+ * **Status: runtime body shipped at v0.4-M31 IMPL** — mirrors
55
+ * `item upload` minus the column-resolution + cache-invalidation
56
+ * legs (Updates aren't part of the §8 cache scope; no per-column
57
+ * type check needed because Updates accept any file type Monday
58
+ * supports).
59
+ */
60
+ import { z } from 'zod';
61
+ import { stat as fsStat, access as fsAccess, readFile } from 'node:fs/promises';
62
+ import { constants as fsConstants } from 'node:fs';
63
+ import { resolve as resolvePath, basename } from 'node:path';
64
+ import { ensureSubcommand } from '../types.js';
65
+ import { parseArgv } from '../parse-argv.js';
66
+ import { UpdateIdSchema } from '../../types/ids.js';
67
+ import { updateUploadOutputSchema, addFileToUpdate, } from '../../api/assets.js';
68
+ import { resolveClient } from '../../api/resolve-client.js';
69
+ import { UsageError, asError, errorCode } from '../../utils/errors.js';
70
+ import { sniffContentType } from '../../utils/mime.js';
71
+ import { emitMutation, emitDryRun } from '../emit.js';
72
+ const inputSchema = z
73
+ .object({
74
+ updateId: UpdateIdSchema,
75
+ file: z
76
+ .string()
77
+ .min(1, {
78
+ message: '<file> must be a non-empty local file path; stdin (`-`) is not supported in v0.4-M31 (a future contract extension may add stdin support once a `--filename <name>` companion flag is pinned).',
79
+ })
80
+ .refine((p) => p !== '-', {
81
+ message: '<file> cannot be `-` — stdin upload is not supported in v0.4-M31. Pass a local file path resolved relative to cwd. A future contract extension may add stdin support once a `--filename <name>` companion flag is pinned.',
82
+ }),
83
+ })
84
+ .strict();
85
+ export const updateUploadCommand = {
86
+ name: 'update.upload',
87
+ summary: 'Attach a file to an Update (comment) via add_file_to_update',
88
+ examples: [
89
+ 'monday update upload 98765 ./screenshot.png',
90
+ 'monday update upload 98765 ./report.pdf --dry-run',
91
+ ],
92
+ idempotent: false,
93
+ inputSchema,
94
+ outputSchema: updateUploadOutputSchema,
95
+ attach: (program, ctx) => {
96
+ const noun = ensureSubcommand(program, 'update', 'Update (comment) commands (cli-design §4.3 UPDATE)');
97
+ noun
98
+ .command('upload <updateId> <file>')
99
+ .description(updateUploadCommand.summary)
100
+ .addHelpText('after', [
101
+ '',
102
+ 'Examples:',
103
+ ...updateUploadCommand.examples.map((e) => ` ${e}`),
104
+ '',
105
+ 'Notes:',
106
+ ' - Uploads cross the wire as multipart/form-data (different transport from JSON-only verbs).',
107
+ ' - File path is resolved relative to the cwd; stdin (`-`) is not supported in this release.',
108
+ ' - Re-running with the same args creates a second Asset; `add_file_to_update` is not idempotent.',
109
+ '',
110
+ ].join('\n'))
111
+ .action(async (updateIdArg, fileArg) => {
112
+ const parsed = parseArgv(updateUploadCommand.inputSchema, {
113
+ updateId: updateIdArg,
114
+ file: fileArg,
115
+ });
116
+ // Same fs.stat() + fs.access(R_OK) pre-check shape as
117
+ // `item upload` (round-1 P2-2 fix). Pre-resolveClient so a
118
+ // missing/unreadable-file error surfaces as usage_error
119
+ // (exit 1) before any token check.
120
+ const filePath = resolvePath(process.cwd(), parsed.file);
121
+ const filename = basename(filePath);
122
+ let fileSizeBytes;
123
+ try {
124
+ const stats = await fsStat(filePath);
125
+ if (!stats.isFile()) {
126
+ throw new UsageError(`<file> ${JSON.stringify(parsed.file)} is not a regular file ` +
127
+ `(resolved to ${JSON.stringify(filePath)}).`, {
128
+ details: {
129
+ reason: 'file_not_readable',
130
+ file_path: filePath,
131
+ hint: 'pass a path to a regular readable file; directories ' +
132
+ 'and special files (sockets, devices) are rejected.',
133
+ },
134
+ });
135
+ }
136
+ await fsAccess(filePath, fsConstants.R_OK);
137
+ fileSizeBytes = stats.size;
138
+ }
139
+ catch (err) {
140
+ if (err instanceof UsageError) {
141
+ throw err;
142
+ }
143
+ const code = errorCode(err);
144
+ throw new UsageError(`<file> ${JSON.stringify(parsed.file)} cannot be read ` +
145
+ `(resolved to ${JSON.stringify(filePath)}): ` +
146
+ `${asError(err).message}.`, {
147
+ cause: err,
148
+ details: {
149
+ reason: 'file_not_readable',
150
+ file_path: filePath,
151
+ ...(code === undefined ? {} : { errno_code: code }),
152
+ hint: 'check that the path exists, is readable by the current ' +
153
+ 'user, and isn\'t a directory.',
154
+ },
155
+ });
156
+ }
157
+ if (fileSizeBytes === 0) {
158
+ throw new UsageError(`<file> ${JSON.stringify(parsed.file)} is empty (0 bytes); ` +
159
+ `Monday rejects empty uploads server-side.`, {
160
+ details: {
161
+ reason: 'file_empty',
162
+ file_path: filePath,
163
+ filename,
164
+ file_size_bytes: 0,
165
+ hint: 'Monday returns FILE_SIZE_LIMIT_EXCEEDED on empty ' +
166
+ 'uploads. Provide a non-empty file or remove the upload ' +
167
+ 'call.',
168
+ },
169
+ });
170
+ }
171
+ const { client, globalFlags, apiVersion, multipart, toEmit } = resolveClient(ctx, program.opts());
172
+ if (globalFlags.dryRun) {
173
+ // D5 closure mirror — dry-run is fs.stat()-backed; no
174
+ // wire mutation; no file bytes loaded. `update upload`
175
+ // dry-run carries `update_id` instead of `item_id` +
176
+ // `column_id`; otherwise structurally identical to the
177
+ // `item upload` dry-run shape. `file_path` is the
178
+ // argv-derived path per cli-design §6.4 sample (round-2
179
+ // P3-2 fix; mirrors `item upload`).
180
+ emitDryRun({
181
+ ctx,
182
+ programOpts: program.opts(),
183
+ plannedChanges: [
184
+ {
185
+ operation: 'add_file_to_update',
186
+ update_id: parsed.updateId,
187
+ file_path: parsed.file,
188
+ filename,
189
+ file_size_bytes: fileSizeBytes,
190
+ },
191
+ ],
192
+ source: 'none',
193
+ cacheAgeSeconds: null,
194
+ apiVersion,
195
+ });
196
+ return;
197
+ }
198
+ const bytes = await readFile(filePath);
199
+ const file = new Blob([bytes], { type: sniffContentType(filename) });
200
+ const result = await addFileToUpdate({
201
+ client,
202
+ multipart,
203
+ updateId: parsed.updateId,
204
+ file,
205
+ filename,
206
+ signal: ctx.signal,
207
+ retries: globalFlags.retry,
208
+ });
209
+ // No cache invalidation per D6 — Updates aren't part of the
210
+ // §8 cache scope (which covers board metadata only).
211
+ const data = {
212
+ operation: 'add_file_to_update',
213
+ update_id: parsed.updateId,
214
+ filename,
215
+ file_size_bytes: fileSizeBytes,
216
+ asset: result.asset,
217
+ };
218
+ emitMutation({
219
+ ctx,
220
+ data,
221
+ schema: updateUploadCommand.outputSchema,
222
+ programOpts: program.opts(),
223
+ ...toEmit({
224
+ data: result.asset,
225
+ complexity: result.complexity,
226
+ stats: { attempts: 1, totalBackoffMs: 0 },
227
+ }),
228
+ source: 'live',
229
+ cacheAgeSeconds: null,
230
+ complexity: result.complexity,
231
+ });
232
+ });
233
+ },
234
+ };
235
+ //# sourceMappingURL=upload.js.map