monday-cli 0.6.0 → 0.7.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.
- package/CHANGELOG.md +388 -0
- package/README.md +165 -52
- package/dist/api/column-types.d.ts +61 -28
- package/dist/api/column-types.d.ts.map +1 -1
- package/dist/api/column-types.js +32 -13
- package/dist/api/column-types.js.map +1 -1
- package/dist/api/column-values.d.ts +22 -17
- package/dist/api/column-values.d.ts.map +1 -1
- package/dist/api/column-values.js +50 -34
- package/dist/api/column-values.js.map +1 -1
- package/dist/api/file-column-set.d.ts +164 -58
- package/dist/api/file-column-set.d.ts.map +1 -1
- package/dist/api/file-column-set.js +168 -110
- package/dist/api/file-column-set.js.map +1 -1
- package/dist/api/raw-write.d.ts +29 -18
- package/dist/api/raw-write.d.ts.map +1 -1
- package/dist/api/raw-write.js +48 -26
- package/dist/api/raw-write.js.map +1 -1
- package/dist/commands/board/column-create.d.ts +11 -6
- package/dist/commands/board/column-create.d.ts.map +1 -1
- package/dist/commands/board/column-create.js +23 -12
- package/dist/commands/board/column-create.js.map +1 -1
- package/dist/commands/item/create.d.ts +24 -8
- package/dist/commands/item/create.d.ts.map +1 -1
- package/dist/commands/item/create.js +494 -35
- package/dist/commands/item/create.js.map +1 -1
- package/dist/commands/item/update.d.ts +175 -6
- package/dist/commands/item/update.d.ts.map +1 -1
- package/dist/commands/item/update.js +697 -29
- package/dist/commands/item/update.js.map +1 -1
- package/package.json +1 -1
|
@@ -23,14 +23,30 @@
|
|
|
23
23
|
* v0.3 because the column-resolution path here assumes the
|
|
24
24
|
* classic auto-generated-subitems-board model.
|
|
25
25
|
*
|
|
26
|
-
* **Single round-trip** (cli-design §5.8 —
|
|
27
|
-
* translated `--set` / `--set-raw`
|
|
28
|
-
* `create_item.column_values` (or
|
|
29
|
-
* parameter via `bundleColumnValues`;
|
|
30
|
-
* to `create_item` +
|
|
31
|
-
* failure. Monday's
|
|
32
|
-
*
|
|
33
|
-
* value fixed.
|
|
26
|
+
* **Single round-trip on the JSON-only path** (cli-design §5.8 —
|
|
27
|
+
* hard exit gate). Every translated non-file `--set` / `--set-raw`
|
|
28
|
+
* value bundles into one `create_item.column_values` (or
|
|
29
|
+
* `create_subitem.column_values`) parameter via `bundleColumnValues`;
|
|
30
|
+
* the CLI does **not** fall back to `create_item` +
|
|
31
|
+
* `change_multiple_column_values` on partial failure. Monday's
|
|
32
|
+
* server-side rejection of any value fails the whole mutation, and
|
|
33
|
+
* no item is created — agents retry with the value fixed.
|
|
34
|
+
*
|
|
35
|
+
* **Two-leg dispatch on the create-time file `--set` carve-out
|
|
36
|
+
* (v0.7-M43 D6 fold).** When any `--set <file-col>=<path>` is
|
|
37
|
+
* present, the action body partitions setEntries (non-file →
|
|
38
|
+
* leg-1's `column_values`; file → leg-2) and routes through
|
|
39
|
+
* `runItemCreateFileDispatch`: leg-1 `create_item` (or
|
|
40
|
+
* `create_subitem`) bundles the non-file column_values atomically;
|
|
41
|
+
* leg-2 `add_file_to_column` attaches the file via M31's multipart
|
|
42
|
+
* wire (reused verbatim through M38's `executeFileColumnSet`). The
|
|
43
|
+
* pair is non-atomic by construction; leg-2 failure surfaces
|
|
44
|
+
* `internal_error` with `details.reason:
|
|
45
|
+
* 'create_then_file_upload_partial_failure'` + `details.cause` +
|
|
46
|
+
* `details.created_item_id` echoing the orphan + a hint directing
|
|
47
|
+
* agents to retry leg-2 only OR rollback via `monday item delete`
|
|
48
|
+
* (cli-design §5.8 orphan-warn atomicity envelope, D1 closure). See
|
|
49
|
+
* `runItemCreateFileDispatch` below for the helper signature.
|
|
34
50
|
*
|
|
35
51
|
* **`--position` / `--relative-to` cross-validation.** Both flags
|
|
36
52
|
* are required together (one without the other → `usage_error`).
|
|
@@ -50,23 +66,25 @@
|
|
|
50
66
|
import { z } from 'zod';
|
|
51
67
|
import { ensureSubcommand } from '../types.js';
|
|
52
68
|
import { emitDryRun, emitMutation } from '../emit.js';
|
|
53
|
-
import { resolveClient } from '../../api/resolve-client.js';
|
|
69
|
+
import { resolveClient, } from '../../api/resolve-client.js';
|
|
54
70
|
import { BoardIdSchema, ItemIdSchema } from '../../types/ids.js';
|
|
55
71
|
import { parseArgv } from '../parse-argv.js';
|
|
56
72
|
import { ApiError, MondayCliError, UsageError } from '../../utils/errors.js';
|
|
57
73
|
import { bundleColumnValues, } from '../../api/column-values.js';
|
|
58
74
|
import { parseSetRawExpression, } from '../../api/raw-write.js';
|
|
59
75
|
import { splitSetExpression } from '../../api/set-expression.js';
|
|
60
|
-
import { buildResolutionContexts } from '../../api/resolution-context.js';
|
|
76
|
+
import { buildResolutionContexts, } from '../../api/resolution-context.js';
|
|
61
77
|
import { lookupItemBoard, lookupItemBoardWithHierarchy, } from '../../api/item-board-lookup.js';
|
|
62
78
|
import { SourceAggregator, mergeCacheAge, mergeSourceWithPreflight, } from '../../api/source-aggregator.js';
|
|
63
79
|
import { resolveAndTranslate } from '../../api/resolution-pass.js';
|
|
64
|
-
import { preCheckM38FileDispatch } from '../../api/file-column-set.js';
|
|
80
|
+
import { executeFileColumnSet, preCheckM38FileDispatch, } from '../../api/file-column-set.js';
|
|
65
81
|
import { foldAndRemap, mergeResolverWarningsIntoError, } from '../../api/resolver-error-fold.js';
|
|
66
82
|
import { planCreate } from '../../api/dry-run.js';
|
|
67
83
|
import { loadBoardMetadata } from '../../api/board-metadata.js';
|
|
68
84
|
import { assertResponseFieldPresent } from '../../api/response-root.js';
|
|
69
85
|
import { unwrapOrThrow } from '../../utils/parse-boundary.js';
|
|
86
|
+
import { precheckLocalFile } from '../../utils/file-source.js';
|
|
87
|
+
import { invalidateBoard } from '../../api/cache.js';
|
|
70
88
|
/**
|
|
71
89
|
* Dedupes resolver warnings by `code + message + details.token`.
|
|
72
90
|
* v0.6-M38 IMPL round-2 P3-1 fix: M38 pre-check + downstream
|
|
@@ -442,13 +460,13 @@ const resolveCreateMode = async (inputs) => {
|
|
|
442
460
|
`creation is deferred. Use a classic board ` +
|
|
443
461
|
`(hierarchy_type null/"classic"). v0.3 M28 Decision 11 closure: ` +
|
|
444
462
|
`Monday's sub_items_board carries no subtasks column at API ` +
|
|
445
|
-
`2026-01, so depth-2 subitems have no data-model home — v0.
|
|
463
|
+
`2026-01, so depth-2 subitems have no data-model home — v0.8 ` +
|
|
446
464
|
`picks the feature up if Monday surfaces the capability.`, {
|
|
447
465
|
details: {
|
|
448
466
|
parent_item_id: dispatch.parentItemId,
|
|
449
467
|
parent_board_id: parent.boardId,
|
|
450
468
|
hierarchy_type: parent.hierarchyType,
|
|
451
|
-
deferred_to: 'v0.
|
|
469
|
+
deferred_to: 'v0.8',
|
|
452
470
|
},
|
|
453
471
|
});
|
|
454
472
|
}
|
|
@@ -563,7 +581,7 @@ export const itemCreateCommand = {
|
|
|
563
581
|
const parsed = parseArgv(itemCreateCommand.inputSchema, {
|
|
564
582
|
...opts,
|
|
565
583
|
});
|
|
566
|
-
const { client, globalFlags, apiVersion, toEmit } = resolveClient(ctx, program.opts());
|
|
584
|
+
const { client, globalFlags, apiVersion, multipart, toEmit } = resolveClient(ctx, program.opts());
|
|
567
585
|
const dispatch = validateInputShape(parsed);
|
|
568
586
|
// Argv-parse-time failures fire BEFORE any network call —
|
|
569
587
|
// splits run on pure strings, JSON parse on `--set-raw` runs
|
|
@@ -600,17 +618,31 @@ export const itemCreateCommand = {
|
|
|
600
618
|
? createMode.subitemsBoardId
|
|
601
619
|
: createMode.boardId;
|
|
602
620
|
const { dateResolution, peopleResolution, tagResolution, relationResolution } = buildResolutionContexts({ client, ctx, globalFlags });
|
|
603
|
-
// v0.6-M38 D6 closure — create-time file-set
|
|
604
|
-
// column-resolution boundary
|
|
605
|
-
//
|
|
606
|
-
// create
|
|
607
|
-
//
|
|
608
|
-
//
|
|
609
|
-
//
|
|
610
|
-
//
|
|
621
|
+
// v0.6-M38 / v0.7-M43 D6 closure — create-time file-set
|
|
622
|
+
// dispatch routes through the column-resolution boundary's
|
|
623
|
+
// pre-check. Pre-checks setEntries against the resolved
|
|
624
|
+
// create-mode board (subitems board for subitem create;
|
|
625
|
+
// --board for top-level), then returns one of:
|
|
626
|
+
// - `kind: 'json'` — no file column in `--set` (existing
|
|
627
|
+
// bundled-create path runs below).
|
|
628
|
+
// - `kind: 'file_create'` — clean single-file `--set`
|
|
629
|
+
// entry; branches into the v0.7-M43 two-leg dispatch
|
|
630
|
+
// helper {@link runItemCreateFileDispatch} (carve-out
|
|
631
|
+
// fold from v0.6-M38's permanent rejection).
|
|
632
|
+
// - Throws `usage_error` with
|
|
633
|
+
// `details.reason: 'multi_file_set_unsupported'` on 2+
|
|
634
|
+
// file `--set` entries (universal mutex rule). The
|
|
635
|
+
// `'mixed_file_and_value_sets'` rule is SUPPRESSED on
|
|
636
|
+
// `'item_create'` callShape per the v0.7-M43 D6 mixed-
|
|
637
|
+
// rule asymmetry — `create_item` natively bundles
|
|
638
|
+
// non-file `column_values` atomically into leg-1.
|
|
639
|
+
// `--set-raw <file-col>=<json>` stays at
|
|
640
|
+
// `translateRawColumnValue`'s D3 permanent rejection (the
|
|
641
|
+
// pre-check inspects setEntries only).
|
|
611
642
|
let m38Source;
|
|
612
643
|
let m38CacheAge = null;
|
|
613
644
|
let m38Warnings = [];
|
|
645
|
+
let m38FileCreate;
|
|
614
646
|
if (setEntries.length > 0) {
|
|
615
647
|
const m38 = await preCheckM38FileDispatch({
|
|
616
648
|
client,
|
|
@@ -622,17 +654,51 @@ export const itemCreateCommand = {
|
|
|
622
654
|
env: ctx.env,
|
|
623
655
|
noCache: globalFlags.noCache,
|
|
624
656
|
});
|
|
625
|
-
// `enforceSingleFileColumnSet({callShape: 'item_create'})`
|
|
626
|
-
// throws on any file entry, so reaching this point means
|
|
627
|
-
// `m38.kind === 'json'`. Capture the pre-check's source /
|
|
628
|
-
// cache-age / warnings for downstream aggregation —
|
|
629
|
-
// round-1 P3-1-equivalent (wire-leg surfaces on
|
|
630
|
-
// `meta.source`) + round-2 P3-1 (resolver warnings ride
|
|
631
|
-
// into the envelope even when downstream cache-hits
|
|
632
|
-
// suppress re-emission).
|
|
633
657
|
m38Source = m38.source;
|
|
634
658
|
m38CacheAge = m38.cacheAgeSeconds;
|
|
635
659
|
m38Warnings = m38.warnings;
|
|
660
|
+
if (m38.kind === 'file_create') {
|
|
661
|
+
m38FileCreate = m38;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
// v0.6-M38 → v0.7-M43 D6 fold — branch into the two-leg
|
|
665
|
+
// dispatch helper. {@link runItemCreateFileDispatch} runs
|
|
666
|
+
// the upfront `precheckLocalFile` + partitions setEntries
|
|
667
|
+
// (non-file → leg-1 `column_values`, file → leg-2
|
|
668
|
+
// `add_file_to_column`) + dispatches leg-1 `create_item`
|
|
669
|
+
// / `create_subitem` then leg-2 `add_file_to_column` under
|
|
670
|
+
// the §5.8 orphan-warn atomicity envelope (D1 closure).
|
|
671
|
+
// Reaching this branch means argv parse + shape validation
|
|
672
|
+
// + duplicate-token check + create-mode resolution + M38
|
|
673
|
+
// pre-check all succeeded.
|
|
674
|
+
if (m38FileCreate !== undefined) {
|
|
675
|
+
await runItemCreateFileDispatch({
|
|
676
|
+
parsed,
|
|
677
|
+
client,
|
|
678
|
+
multipart,
|
|
679
|
+
ctx,
|
|
680
|
+
programOpts: program.opts(),
|
|
681
|
+
apiVersion,
|
|
682
|
+
createMode,
|
|
683
|
+
resolveBoardId,
|
|
684
|
+
setEntries,
|
|
685
|
+
rawEntries,
|
|
686
|
+
m38: m38FileCreate,
|
|
687
|
+
preflightSource: createModeResult.preflightSource,
|
|
688
|
+
preflightCacheAgeSeconds: createModeResult.preflightCacheAgeSeconds,
|
|
689
|
+
metaSource: m38Source,
|
|
690
|
+
metaCacheAgeSeconds: m38CacheAge,
|
|
691
|
+
preflightWarnings: m38Warnings,
|
|
692
|
+
dateResolution,
|
|
693
|
+
peopleResolution,
|
|
694
|
+
tagResolution,
|
|
695
|
+
relationResolution,
|
|
696
|
+
isDryRun: globalFlags.dryRun,
|
|
697
|
+
noCache: globalFlags.noCache,
|
|
698
|
+
retries: globalFlags.retry,
|
|
699
|
+
toEmit,
|
|
700
|
+
});
|
|
701
|
+
return;
|
|
636
702
|
}
|
|
637
703
|
if (globalFlags.dryRun) {
|
|
638
704
|
let result;
|
|
@@ -685,11 +751,14 @@ export const itemCreateCommand = {
|
|
|
685
751
|
});
|
|
686
752
|
return;
|
|
687
753
|
}
|
|
688
|
-
// Live create path. Three-pass resolution +
|
|
689
|
-
// through the shared helper (R20 lift), then
|
|
690
|
-
// column_values map and fire the single-
|
|
691
|
-
// per cli-design §5.8.
|
|
692
|
-
//
|
|
754
|
+
// Live create path (JSON-only). Three-pass resolution +
|
|
755
|
+
// translation through the shared helper (R20 lift), then
|
|
756
|
+
// bundle into one column_values map and fire the single-
|
|
757
|
+
// round-trip mutation per cli-design §5.8. Reaching this
|
|
758
|
+
// block means the v0.7-M43 `file_create` dispatch helper
|
|
759
|
+
// did NOT apply (no file `--set` entries present) — the
|
|
760
|
+
// helper returned above; this remaining path is JSON-only
|
|
761
|
+
// single-round-trip.
|
|
693
762
|
let resolutionResult;
|
|
694
763
|
try {
|
|
695
764
|
resolutionResult = await resolveAndTranslate({
|
|
@@ -930,4 +999,394 @@ const executeCreateSubitem = async (client, inputs) => {
|
|
|
930
999
|
response,
|
|
931
1000
|
};
|
|
932
1001
|
};
|
|
1002
|
+
/**
|
|
1003
|
+
* Two-leg create-time file dispatch helper. Runs:
|
|
1004
|
+
*
|
|
1005
|
+
* 1. Single upfront {@link precheckLocalFile} on the file `--set`
|
|
1006
|
+
* raw value. Local-only; failure surfaces `usage_error` with
|
|
1007
|
+
* `details.reason: 'file_not_readable'` / `'file_empty'`
|
|
1008
|
+
* BEFORE either wire leg fires (atomicity-before-wire
|
|
1009
|
+
* discipline per cli-design §5.8).
|
|
1010
|
+
* 2. Partitions `inputs.setEntries` by `token`: the entry whose
|
|
1011
|
+
* `token === inputs.m38.token` routes to leg-2; every other
|
|
1012
|
+
* entry routes to leg-1's `column_values`. `inputs.rawEntries`
|
|
1013
|
+
* route to leg-1 verbatim — `--set-raw <file-col>=<json>` is
|
|
1014
|
+
* rejected upstream at `translateRawColumnValue` per D3
|
|
1015
|
+
* permanent rejection, so by this point no raw entry targets
|
|
1016
|
+
* a file column.
|
|
1017
|
+
* 3. **Dry-run branch.** Invokes {@link planCreate} on the
|
|
1018
|
+
* non-file entries (handles resolution + diff cell build),
|
|
1019
|
+
* then appends a synthetic entry-2
|
|
1020
|
+
* `operation: 'add_file_to_column'` carrying `column_id` +
|
|
1021
|
+
* `file_path` (argv-derived) + `filename` + `file_size_bytes`
|
|
1022
|
+
* from the upfront pre-check. Emits both entries together
|
|
1023
|
+
* via `emitDryRun`; no multipart wire round-trip fires.
|
|
1024
|
+
* Entry-2 omits `item_id` (the item doesn't exist yet at
|
|
1025
|
+
* dry-run time).
|
|
1026
|
+
* 4. **Live branch.** `resolveAndTranslate` on the non-file
|
|
1027
|
+
* entries yields the leg-1 `column_values`; leg-1 invokes
|
|
1028
|
+
* `executeCreateItem` / `executeCreateSubitem` depending on
|
|
1029
|
+
* `inputs.createMode.kind`; leg-2 builds a
|
|
1030
|
+
* {@link FileColumnSetEntry} from the pre-check + leg-1's
|
|
1031
|
+
* new item ID and invokes {@link executeFileColumnSet}.
|
|
1032
|
+
* On full success, a single
|
|
1033
|
+
* {@link invalidateBoard} fires (mirroring M38 single-item
|
|
1034
|
+
* + M42 bulk file-dispatch invalidate timing — leg-2
|
|
1035
|
+
* mutates the file column's asset state wire-side).
|
|
1036
|
+
* 5. **Leg-1 failure.** Routes through {@link foldAndRemap} to
|
|
1037
|
+
* surface `column_archived` on cache-served file-column
|
|
1038
|
+
* resolution against an archived column (mirrors the JSON
|
|
1039
|
+
* path's F4 remap above). No orphan handle because no item
|
|
1040
|
+
* was created.
|
|
1041
|
+
* 6. **Leg-2 failure (orphan-warn per D1).** Catches
|
|
1042
|
+
* `MondayCliError`, applies {@link foldAndRemap} to surface
|
|
1043
|
+
* `column_archived` etc., then wraps the remapped error in
|
|
1044
|
+
* a fresh `ApiError('internal_error', ...)` carrying
|
|
1045
|
+
* `details.reason: 'create_then_file_upload_partial_failure'`
|
|
1046
|
+
* + `details.created_item_id` + `details.column_id` +
|
|
1047
|
+
* `details.cause` (JSON projection of the remapped error) +
|
|
1048
|
+
* `details.hint` (retry-leg-2-only / rollback). The board
|
|
1049
|
+
* cache is NOT invalidated on leg-2 failure — leg-1's
|
|
1050
|
+
* `create_item` doesn't affect cached board metadata
|
|
1051
|
+
* (mirrors the JSON-only create path's no-invalidate), and
|
|
1052
|
+
* leg-2 failure means no file mutation occurred wire-side.
|
|
1053
|
+
*/
|
|
1054
|
+
const runItemCreateFileDispatch = async (inputs) => {
|
|
1055
|
+
// 1) Upfront local file pre-check. Atomicity-before-wire per
|
|
1056
|
+
// cli-design §5.8: pre-checks fire BEFORE any wire round-trip
|
|
1057
|
+
// so a bad path surfaces `usage_error` (exit 1) with
|
|
1058
|
+
// `details.reason: 'file_not_readable'` / `'file_empty'`
|
|
1059
|
+
// without burning either wire leg. R-v0.6-NEW-1 4th-consumer
|
|
1060
|
+
// site (M31 upload + M38 single-item + M42 file-bulk + here);
|
|
1061
|
+
// 5-consumer graduation threshold not yet hit.
|
|
1062
|
+
const precheck = await precheckLocalFile(inputs.m38.rawValue);
|
|
1063
|
+
// 2) Partition setEntries: the file entry's `token` matches
|
|
1064
|
+
// `inputs.m38.token` (the pre-check identified it); every
|
|
1065
|
+
// other token goes to leg-1's column_values.
|
|
1066
|
+
const nonFileSetEntries = inputs.setEntries.filter((e) => e.token !== inputs.m38.token);
|
|
1067
|
+
// 3) Dry-run branch — D2 closure. Two `planned_changes` entries
|
|
1068
|
+
// without burning either wire leg. planCreate handles
|
|
1069
|
+
// non-file column resolution + diff cells; entry-2 is built
|
|
1070
|
+
// locally from the pre-check.
|
|
1071
|
+
if (inputs.isDryRun) {
|
|
1072
|
+
let planResult;
|
|
1073
|
+
try {
|
|
1074
|
+
planResult = await planCreate({
|
|
1075
|
+
client: inputs.client,
|
|
1076
|
+
mode: inputs.createMode,
|
|
1077
|
+
name: inputs.parsed.name,
|
|
1078
|
+
setEntries: nonFileSetEntries,
|
|
1079
|
+
...(inputs.rawEntries.length === 0
|
|
1080
|
+
? {}
|
|
1081
|
+
: { rawEntries: inputs.rawEntries }),
|
|
1082
|
+
dateResolution: inputs.dateResolution,
|
|
1083
|
+
peopleResolution: inputs.peopleResolution,
|
|
1084
|
+
tagResolution: inputs.tagResolution,
|
|
1085
|
+
relationResolution: inputs.relationResolution,
|
|
1086
|
+
env: inputs.ctx.env,
|
|
1087
|
+
noCache: inputs.noCache,
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
catch (err) {
|
|
1091
|
+
// Fold M38 pre-check warnings into the dry-run failure
|
|
1092
|
+
// envelope's `details.resolver_warnings`. `mergeResolverWarningsIntoError`
|
|
1093
|
+
// is a no-op on empty `preflightWarnings`, so no length guard
|
|
1094
|
+
// is needed; the JSON path's analogous catch at
|
|
1095
|
+
// `create.ts:944-951` keeps the guard inline for parity with
|
|
1096
|
+
// its older pattern, but the M43 helper collapses it (smaller
|
|
1097
|
+
// branch surface). Non-`MondayCliError` programmer bugs
|
|
1098
|
+
// re-throw unchanged.
|
|
1099
|
+
if (err instanceof MondayCliError) {
|
|
1100
|
+
throw mergeResolverWarningsIntoError(err, inputs.preflightWarnings);
|
|
1101
|
+
}
|
|
1102
|
+
throw err;
|
|
1103
|
+
}
|
|
1104
|
+
// Source aggregates four legs (planner + M38 pre-check +
|
|
1105
|
+
// pre-planner preflight) — mirrors the JSON-path dry-run
|
|
1106
|
+
// aggregation pattern at lines 959-966 above. planCreate may
|
|
1107
|
+
// return `source: 'none'` when its no-set short-circuit fires
|
|
1108
|
+
// (only relevant here if the call had ONLY the file `--set`),
|
|
1109
|
+
// so the standalone `mergeSourceWithPreflight` helper is used
|
|
1110
|
+
// rather than the SourceAggregator class (which doesn't model
|
|
1111
|
+
// 'none').
|
|
1112
|
+
const dryRunSource = mergeSourceWithPreflight(mergeSourceWithPreflight(planResult.source, inputs.metaSource), inputs.preflightSource);
|
|
1113
|
+
const dryRunCacheAge = mergeCacheAge(mergeCacheAge(inputs.metaCacheAgeSeconds, planResult.cacheAgeSeconds), inputs.preflightCacheAgeSeconds);
|
|
1114
|
+
// Entry-2: `add_file_to_column` planned-change. Mirrors M31's
|
|
1115
|
+
// dry-run shape minus `item_id` (the item doesn't exist yet).
|
|
1116
|
+
// `file_path` is the argv-derived raw value per cli-design §6.4;
|
|
1117
|
+
// resolved absolute path lives in pre-check rejections, not in
|
|
1118
|
+
// the success-shaped dry-run envelope.
|
|
1119
|
+
const fileEntry = {
|
|
1120
|
+
operation: 'add_file_to_column',
|
|
1121
|
+
column_id: inputs.m38.columnId,
|
|
1122
|
+
file_path: inputs.m38.rawValue,
|
|
1123
|
+
filename: precheck.filename,
|
|
1124
|
+
file_size_bytes: precheck.fileSizeBytes,
|
|
1125
|
+
};
|
|
1126
|
+
const plannedChanges = [
|
|
1127
|
+
...planResult.plannedChanges,
|
|
1128
|
+
fileEntry,
|
|
1129
|
+
];
|
|
1130
|
+
emitDryRun({
|
|
1131
|
+
ctx: inputs.ctx,
|
|
1132
|
+
programOpts: inputs.programOpts,
|
|
1133
|
+
plannedChanges,
|
|
1134
|
+
source: dryRunSource,
|
|
1135
|
+
cacheAgeSeconds: dryRunCacheAge,
|
|
1136
|
+
warnings: dedupeCreateWarnings([
|
|
1137
|
+
...inputs.preflightWarnings,
|
|
1138
|
+
...planResult.warnings,
|
|
1139
|
+
]),
|
|
1140
|
+
apiVersion: inputs.apiVersion,
|
|
1141
|
+
});
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
// 4) Live branch — leg-1 (create_item / create_subitem) then
|
|
1145
|
+
// leg-2 (add_file_to_column). resolveAndTranslate on non-file
|
|
1146
|
+
// entries yields leg-1's column_values; the M38 pre-check
|
|
1147
|
+
// already warmed the column-resolution cache so this leg
|
|
1148
|
+
// typically hits cache (source folds to `mixed` once leg-1
|
|
1149
|
+
// + leg-2 record `live`).
|
|
1150
|
+
let resolutionResult;
|
|
1151
|
+
try {
|
|
1152
|
+
resolutionResult = await resolveAndTranslate({
|
|
1153
|
+
client: inputs.client,
|
|
1154
|
+
boardId: inputs.resolveBoardId,
|
|
1155
|
+
setEntries: nonFileSetEntries,
|
|
1156
|
+
rawEntries: inputs.rawEntries,
|
|
1157
|
+
dateResolution: inputs.dateResolution,
|
|
1158
|
+
peopleResolution: inputs.peopleResolution,
|
|
1159
|
+
tagResolution: inputs.tagResolution,
|
|
1160
|
+
relationResolution: inputs.relationResolution,
|
|
1161
|
+
env: inputs.ctx.env,
|
|
1162
|
+
noCache: inputs.noCache,
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
catch (err) {
|
|
1166
|
+
// Same shape as the planCreate catch above — collapse the
|
|
1167
|
+
// `&& length > 0` guard (no-op on empty) for a smaller branch
|
|
1168
|
+
// surface than the JSON path's pattern at
|
|
1169
|
+
// `create.ts:1010-1022`.
|
|
1170
|
+
if (err instanceof MondayCliError) {
|
|
1171
|
+
throw mergeResolverWarningsIntoError(err, inputs.preflightWarnings);
|
|
1172
|
+
}
|
|
1173
|
+
throw err;
|
|
1174
|
+
}
|
|
1175
|
+
// Combined warnings: M38 pre-check + resolveAndTranslate. Deduped
|
|
1176
|
+
// by code+message+token (a stale_cache_refreshed seen at pre-check
|
|
1177
|
+
// AND at resolveAndTranslate for the same token collapses to one
|
|
1178
|
+
// entry). Mirrors the JSON path's dedupeCreateWarnings usage.
|
|
1179
|
+
const collectedWarnings = dedupeCreateWarnings([...inputs.preflightWarnings, ...resolutionResult.warnings]);
|
|
1180
|
+
// Source aggregator across every wire leg that fires (or that
|
|
1181
|
+
// already fired upstream). Records preflight + M38 pre-check +
|
|
1182
|
+
// resolveAndTranslate legs; records `'live'` once at the end of
|
|
1183
|
+
// each successful wire mutation (mergeSource is idempotent for a
|
|
1184
|
+
// constant `'live'` second leg so recording leg-1 + leg-2 separately
|
|
1185
|
+
// is byte-equivalent to recording once).
|
|
1186
|
+
const sourceAgg = new SourceAggregator();
|
|
1187
|
+
// Defensive: the helper is entered only when the action body's
|
|
1188
|
+
// `preCheckM38FileDispatch` returned `kind: 'file_create'`, which
|
|
1189
|
+
// guarantees `metaSource` is defined (the M38 pre-check populates
|
|
1190
|
+
// `source` for every entry it resolves). The `undefined` arm is
|
|
1191
|
+
// unreachable from any callable test surface.
|
|
1192
|
+
/* c8 ignore next 3 */
|
|
1193
|
+
if (inputs.metaSource !== undefined) {
|
|
1194
|
+
sourceAgg.record(inputs.metaSource, inputs.metaCacheAgeSeconds);
|
|
1195
|
+
}
|
|
1196
|
+
if (resolutionResult.source !== undefined) {
|
|
1197
|
+
sourceAgg.record(resolutionResult.source, resolutionResult.cacheAgeSeconds);
|
|
1198
|
+
}
|
|
1199
|
+
if (inputs.preflightSource !== undefined) {
|
|
1200
|
+
sourceAgg.record(inputs.preflightSource, inputs.preflightCacheAgeSeconds);
|
|
1201
|
+
}
|
|
1202
|
+
// resolved_ids — file token + non-file tokens. Mirrors §6.4
|
|
1203
|
+
// mutation-envelope shape: `{ <token>: <resolved_column_id> }`
|
|
1204
|
+
// for every `--set` / `--set-raw` the agent supplied.
|
|
1205
|
+
const resolvedIds = {
|
|
1206
|
+
[inputs.m38.token]: inputs.m38.columnId,
|
|
1207
|
+
...resolutionResult.resolvedIds,
|
|
1208
|
+
};
|
|
1209
|
+
// Bundle non-file translated values into leg-1's column_values
|
|
1210
|
+
// parameter. `null` when zero non-file entries (mirrors the JSON
|
|
1211
|
+
// path's "no `--set` values to bundle" treatment — Monday accepts
|
|
1212
|
+
// `column_values: null` distinctly from an empty map).
|
|
1213
|
+
const translated = resolutionResult.translated;
|
|
1214
|
+
const columnValues = translated.length === 0 ? null : bundleColumnValues(translated);
|
|
1215
|
+
// Leg-1: create_item or create_subitem. F4 remap on failure
|
|
1216
|
+
// mirrors the JSON path's catch arm (cache-served resolution +
|
|
1217
|
+
// Monday rejecting as `validation_failed` → check live archived
|
|
1218
|
+
// state). No orphan handle on leg-1 failure because no item was
|
|
1219
|
+
// created.
|
|
1220
|
+
let leg1Result;
|
|
1221
|
+
try {
|
|
1222
|
+
if (inputs.createMode.kind === 'subitem') {
|
|
1223
|
+
leg1Result = await executeCreateSubitem(inputs.client, {
|
|
1224
|
+
parentItemId: inputs.createMode.parentItemId,
|
|
1225
|
+
itemName: inputs.parsed.name,
|
|
1226
|
+
columnValues,
|
|
1227
|
+
createLabelsIfMissing: inputs.parsed.createLabelsIfMissing,
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
else {
|
|
1231
|
+
leg1Result = await executeCreateItem(inputs.client, {
|
|
1232
|
+
boardId: inputs.createMode.boardId,
|
|
1233
|
+
itemName: inputs.parsed.name,
|
|
1234
|
+
groupId: inputs.createMode.groupId,
|
|
1235
|
+
position: inputs.createMode.position,
|
|
1236
|
+
columnValues,
|
|
1237
|
+
createLabelsIfMissing: inputs.parsed.createLabelsIfMissing,
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
catch (err) {
|
|
1242
|
+
if (err instanceof MondayCliError) {
|
|
1243
|
+
throw await foldAndRemap({
|
|
1244
|
+
err,
|
|
1245
|
+
warnings: collectedWarnings,
|
|
1246
|
+
client: inputs.client,
|
|
1247
|
+
boardId: inputs.resolveBoardId,
|
|
1248
|
+
columnIds: translated.map((t) => t.columnId),
|
|
1249
|
+
env: inputs.ctx.env,
|
|
1250
|
+
noCache: inputs.noCache,
|
|
1251
|
+
resolutionSource: resolutionResult.source ?? 'live',
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
// Defensive: every wire fetcher in `src/api/**` raises typed
|
|
1255
|
+
// errors (ApiError / UsageError) which both extend MondayCliError;
|
|
1256
|
+
// a non-typed throw here indicates a programmer bug in the
|
|
1257
|
+
// wire layer, not a Monday-side failure that needs the F4 remap.
|
|
1258
|
+
/* c8 ignore next */
|
|
1259
|
+
throw err;
|
|
1260
|
+
}
|
|
1261
|
+
// Leg-1 fired live; record into the aggregator.
|
|
1262
|
+
sourceAgg.record('live', null);
|
|
1263
|
+
// Leg-2: add_file_to_column via M31's multipart fetcher. On
|
|
1264
|
+
// success, build the create envelope below; on `MondayCliError`,
|
|
1265
|
+
// surface the D1 orphan-warn envelope with the freshly-created
|
|
1266
|
+
// item ID as the recovery handle.
|
|
1267
|
+
const fileEntry = {
|
|
1268
|
+
columnId: inputs.m38.columnId,
|
|
1269
|
+
columnType: 'file',
|
|
1270
|
+
rawValue: inputs.m38.rawValue,
|
|
1271
|
+
filePath: precheck.filePath,
|
|
1272
|
+
filename: precheck.filename,
|
|
1273
|
+
fileSizeBytes: precheck.fileSizeBytes,
|
|
1274
|
+
};
|
|
1275
|
+
try {
|
|
1276
|
+
await executeFileColumnSet({
|
|
1277
|
+
client: inputs.client,
|
|
1278
|
+
multipart: inputs.multipart,
|
|
1279
|
+
itemId: leg1Result.projected.id,
|
|
1280
|
+
entry: fileEntry,
|
|
1281
|
+
signal: inputs.ctx.signal,
|
|
1282
|
+
retries: inputs.retries,
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
catch (err) {
|
|
1286
|
+
if (err instanceof MondayCliError) {
|
|
1287
|
+
// foldAndRemap surfaces `column_archived` for cache-served
|
|
1288
|
+
// file-column resolution against an archived column (cli-
|
|
1289
|
+
// design §6.5 stable-code rule; mirrors M42's file-bulk
|
|
1290
|
+
// fail-fast pattern). The remapped error's code/message
|
|
1291
|
+
// surface in `details.cause` so agents can branch on
|
|
1292
|
+
// leg-2's underlying outcome from the orphan-warn envelope.
|
|
1293
|
+
const remapped = await foldAndRemap({
|
|
1294
|
+
err,
|
|
1295
|
+
warnings: collectedWarnings,
|
|
1296
|
+
client: inputs.client,
|
|
1297
|
+
boardId: inputs.resolveBoardId,
|
|
1298
|
+
columnIds: [inputs.m38.columnId],
|
|
1299
|
+
env: inputs.ctx.env,
|
|
1300
|
+
noCache: inputs.noCache,
|
|
1301
|
+
resolutionSource: inputs.metaSource ?? 'live',
|
|
1302
|
+
});
|
|
1303
|
+
// D1 orphan-warn envelope. Always-internal-error outer
|
|
1304
|
+
// shape; the remapped error embeds as `details.cause` JSON
|
|
1305
|
+
// projection so the agent sees `{code, message, details?}`
|
|
1306
|
+
// for the underlying failure. Error.cause threads the
|
|
1307
|
+
// remapped error for stack debugging in `--debug` mode.
|
|
1308
|
+
const causeProjection = {
|
|
1309
|
+
code: remapped.code,
|
|
1310
|
+
message: remapped.message,
|
|
1311
|
+
};
|
|
1312
|
+
// Defensive: M31's wire-error rewraps (and foldAndRemap) always
|
|
1313
|
+
// populate `details` on the returned error in practice; the
|
|
1314
|
+
// undefined-arm exists only to satisfy the optional shape on
|
|
1315
|
+
// the `MondayCliError` type.
|
|
1316
|
+
/* c8 ignore next 3 */
|
|
1317
|
+
if (remapped.details !== undefined) {
|
|
1318
|
+
causeProjection.details = remapped.details;
|
|
1319
|
+
}
|
|
1320
|
+
const createdItemId = leg1Result.projected.id;
|
|
1321
|
+
throw new ApiError('internal_error', `Item ${createdItemId} was created on board ${inputs.resolveBoardId} ` +
|
|
1322
|
+
`but the file upload to column ${inputs.m38.columnId} failed ` +
|
|
1323
|
+
`(${remapped.code}: ${remapped.message}). The item persists on ` +
|
|
1324
|
+
`Monday; retry the file upload alone with \`monday item set ` +
|
|
1325
|
+
`${createdItemId} <file-col>=<path>\` against the orphan, or roll ` +
|
|
1326
|
+
`back with \`monday item delete ${createdItemId} --yes\`.`, {
|
|
1327
|
+
cause: remapped,
|
|
1328
|
+
details: {
|
|
1329
|
+
reason: 'create_then_file_upload_partial_failure',
|
|
1330
|
+
created_item_id: createdItemId,
|
|
1331
|
+
column_id: inputs.m38.columnId,
|
|
1332
|
+
cause: causeProjection,
|
|
1333
|
+
hint: `the item was created (id ${createdItemId}) but the file ` +
|
|
1334
|
+
`upload failed. Retry leg-2 alone with \`monday item set ` +
|
|
1335
|
+
`${createdItemId} <file-col>=<path>\`; or rollback the ` +
|
|
1336
|
+
`orphan with \`monday item delete ${createdItemId} --yes\` ` +
|
|
1337
|
+
`and re-run the original \`monday item create\` once the ` +
|
|
1338
|
+
`underlying cause is fixed.`,
|
|
1339
|
+
},
|
|
1340
|
+
});
|
|
1341
|
+
}
|
|
1342
|
+
// Non-CliError programmer bug — re-throw to the runner's catch-
|
|
1343
|
+
// all (surfaces as `internal_error` whole-call). Non-typed
|
|
1344
|
+
// throws indicate broken contract, not a Monday-side failure
|
|
1345
|
+
// that needs the orphan-warn decoration; routing them through
|
|
1346
|
+
// D1's `create_then_file_upload_partial_failure` discriminator
|
|
1347
|
+
// would falsely promise an orphan-recovery path for a programmer
|
|
1348
|
+
// bug.
|
|
1349
|
+
/* c8 ignore next */
|
|
1350
|
+
throw err;
|
|
1351
|
+
}
|
|
1352
|
+
// Leg-2 fired live; record into the aggregator. `'live'` + `'live'`
|
|
1353
|
+
// is idempotent under mergeSource so this is the second authoritative
|
|
1354
|
+
// wire-leg record (leg-1 already recorded).
|
|
1355
|
+
sourceAgg.record('live', null);
|
|
1356
|
+
// Both legs succeeded — single board-cache invalidate before emit
|
|
1357
|
+
// (mirrors M38 single-item + M42 fail-fast file-bulk invalidate
|
|
1358
|
+
// timing; leg-2 mutated the file column's asset state wire-side).
|
|
1359
|
+
// The invalidate fires BEFORE emitMutation so a cache-unlink
|
|
1360
|
+
// failure surfaces through the runner's catch-all rather than
|
|
1361
|
+
// double-emitting after the success envelope already hit stdout.
|
|
1362
|
+
await invalidateBoard(inputs.resolveBoardId, inputs.ctx.env);
|
|
1363
|
+
// Map the resolver warnings into the envelope `warnings` slot.
|
|
1364
|
+
const warnings = collectedWarnings;
|
|
1365
|
+
// Success envelope — `data: ItemCreateOutput` from leg-1's
|
|
1366
|
+
// projection. `toEmit(leg1Result.response)` threads leg-1's
|
|
1367
|
+
// `complexity` + `apiVersion` slots; `sourceAgg.result()`
|
|
1368
|
+
// overrides `source` + `cacheAgeSeconds` so the aggregator's
|
|
1369
|
+
// result (cache + live blended across every leg) is
|
|
1370
|
+
// authoritative. Leg-2's complexity is intentionally NOT folded
|
|
1371
|
+
// — the contract pins leg-1's projection on `data`, and the
|
|
1372
|
+
// envelope's `meta.complexity` is the create mutation's cost
|
|
1373
|
+
// (multipart leg-2 has no GraphQL complexity surface).
|
|
1374
|
+
// The output asset from leg-2 is attached to the item server-
|
|
1375
|
+
// side; agents read it back via `monday item get <iid> --columns
|
|
1376
|
+
// <file-col>` if they need the projection (the file-column
|
|
1377
|
+
// dispatch's `Asset` slot is documented per item upload's
|
|
1378
|
+
// envelope; the v0.7-M43 success envelope keeps the canonical
|
|
1379
|
+
// ItemCreateOutput shape so JSON-path and file-path envelopes
|
|
1380
|
+
// remain byte-equivalent on `data`).
|
|
1381
|
+
emitMutation({
|
|
1382
|
+
ctx: inputs.ctx,
|
|
1383
|
+
data: leg1Result.projected,
|
|
1384
|
+
schema: itemCreateOutputSchema,
|
|
1385
|
+
programOpts: inputs.programOpts,
|
|
1386
|
+
warnings,
|
|
1387
|
+
...inputs.toEmit(leg1Result.response),
|
|
1388
|
+
...sourceAgg.result(),
|
|
1389
|
+
resolvedIds,
|
|
1390
|
+
});
|
|
1391
|
+
};
|
|
933
1392
|
//# sourceMappingURL=create.js.map
|