@wave-ai-os/wave-cli 0.1.77 → 0.1.80

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 (3) hide show
  1. package/dist/index.cjs +509 -42
  2. package/dist/index.js +509 -42
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -328,6 +328,9 @@ function buildAtlasActionLedgerRequest(params) {
328
328
  }
329
329
 
330
330
  // src/client/graphqlClient.ts
331
+ var MAX_QUERY_ATTEMPTS = 3;
332
+ var MAX_RETRY_DELAY_MS = 2e3;
333
+ var TRANSIENT_QUERY_STATUSES = /* @__PURE__ */ new Set([429, 502, 503, 504]);
331
334
  function buildEnvelope(params) {
332
335
  return {
333
336
  ok: params.ok,
@@ -358,6 +361,47 @@ function debugLog(config, message) {
358
361
  process.stderr.write(`[wave:debug] ${message}
359
362
  `);
360
363
  }
364
+ function retryAfterDelayMs(value, nowMs = Date.now()) {
365
+ if (value === null) {
366
+ return null;
367
+ }
368
+ const trimmed = value.trim();
369
+ if (/^\d+$/.test(trimmed)) {
370
+ return Math.min(Number(trimmed) * 1e3, MAX_RETRY_DELAY_MS);
371
+ }
372
+ const retryAtMs = Date.parse(trimmed);
373
+ if (Number.isNaN(retryAtMs)) {
374
+ return null;
375
+ }
376
+ return Math.min(Math.max(retryAtMs - nowMs, 0), MAX_RETRY_DELAY_MS);
377
+ }
378
+ function retryDelayMs(attempt, retryAfter) {
379
+ const serverDelay = retryAfterDelayMs(retryAfter);
380
+ if (serverDelay !== null) {
381
+ return serverDelay;
382
+ }
383
+ const exponentialCeiling = Math.min(100 * 2 ** (attempt - 1), MAX_RETRY_DELAY_MS);
384
+ return Math.floor(Math.random() * exponentialCeiling);
385
+ }
386
+ function waitForRetry(delayMs, signal) {
387
+ if (signal.aborted) {
388
+ return Promise.reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
389
+ }
390
+ if (delayMs <= 0) {
391
+ return Promise.resolve();
392
+ }
393
+ return new Promise((resolve, reject) => {
394
+ const timeoutId = setTimeout(() => {
395
+ signal.removeEventListener("abort", handleAbort);
396
+ resolve();
397
+ }, delayMs);
398
+ const handleAbort = () => {
399
+ clearTimeout(timeoutId);
400
+ reject(signal.reason ?? new DOMException("Aborted", "AbortError"));
401
+ };
402
+ signal.addEventListener("abort", handleAbort, { once: true });
403
+ });
404
+ }
361
405
  function graphqlOperationName(command) {
362
406
  return command.split(/[^a-zA-Z0-9]/).filter(Boolean).map((part) => part[0].toUpperCase() + part.slice(1)).join("");
363
407
  }
@@ -675,10 +719,41 @@ async function requestGraphqlHttp(params) {
675
719
  return {
676
720
  status: response.status,
677
721
  requestId: responseRequestId,
722
+ retryAfter: response.headers.get("retry-after"),
678
723
  body,
679
724
  graph
680
725
  };
681
726
  }
727
+ async function requestGraphqlHttpWithRetry(params) {
728
+ const maxAttempts = params.input.operationType === "query" ? MAX_QUERY_ATTEMPTS : 1;
729
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
730
+ try {
731
+ const response = await requestGraphqlHttp(params);
732
+ const shouldRetry = attempt < maxAttempts && TRANSIENT_QUERY_STATUSES.has(response.status);
733
+ if (!shouldRetry) {
734
+ return response;
735
+ }
736
+ const delayMs = retryDelayMs(attempt, response.retryAfter);
737
+ debugLog(
738
+ params.input.config,
739
+ `graphql retry command=${params.input.command} attempt=${attempt + 1}/${maxAttempts} status=${response.status} delayMs=${delayMs}`
740
+ );
741
+ await waitForRetry(delayMs, params.controller.signal);
742
+ } catch (error) {
743
+ if (attempt >= maxAttempts || params.controller.signal.aborted) {
744
+ throw error;
745
+ }
746
+ const delayMs = retryDelayMs(attempt, null);
747
+ const message = error instanceof Error ? error.message : "Network error.";
748
+ debugLog(
749
+ params.input.config,
750
+ `graphql retry command=${params.input.command} attempt=${attempt + 1}/${maxAttempts} error=${message} delayMs=${delayMs}`
751
+ );
752
+ await waitForRetry(delayMs, params.controller.signal);
753
+ }
754
+ }
755
+ throw new Error("GraphQL query retry attempts exhausted.");
756
+ }
682
757
  async function reportAtlasLedgerForResult(input, url, result) {
683
758
  const ledgerInput = buildAtlasActionLedgerRequest({
684
759
  config: input.config,
@@ -859,7 +934,7 @@ async function graphqlRequest(input) {
859
934
  }
860
935
  }
861
936
  }
862
- const http = await requestGraphqlHttp({
937
+ const http = await requestGraphqlHttpWithRetry({
863
938
  input,
864
939
  url,
865
940
  requestId,
@@ -3037,18 +3112,24 @@ var dtoHelpCatalog = {
3037
3112
  create: [
3038
3113
  ["rank", "number"],
3039
3114
  ["organization_id", "string"],
3040
- ["list_id", "string"],
3041
- ["summary", "string"],
3115
+ ["list_id*", "string"],
3116
+ ["summary*", "string"],
3042
3117
  ["member_id", "string"],
3043
- ["status", "ListItemStatus"],
3118
+ ["status", "enum(open|completed)"],
3044
3119
  ["due_date", "string"],
3045
- ["priority", "Priority"],
3120
+ ["priority", "enum(no_priority|urgent|high|medium|low)"],
3046
3121
  ["description", "string"],
3047
3122
  ["notes", "string | null"],
3048
3123
  ["label_ids", "number[]"],
3049
3124
  ["estimate_ids", "number[]"],
3050
3125
  ["resources_attributes", "ResourceDTO[]"],
3051
- ["subitems_attributes", "SubitemAttributes[]"]
3126
+ ["subitems_attributes", "object[]"],
3127
+ ["subitems_attributes[].name", "string"],
3128
+ ["subitems_attributes[].member_id", "string"],
3129
+ ["subitems_attributes[].status", "enum(active|completed)"],
3130
+ ["subitems_attributes[].priority", "enum(no_priority|urgent|high|medium|low)"],
3131
+ ["subitems_attributes[].description", "string"],
3132
+ ["subitems_attributes[].notes", "string | null"]
3052
3133
  ],
3053
3134
  update: [
3054
3135
  ["rank", "number"],
@@ -3056,18 +3137,50 @@ var dtoHelpCatalog = {
3056
3137
  ["list_id", "string"],
3057
3138
  ["summary", "string"],
3058
3139
  ["member_id", "string"],
3059
- ["status", "ListItemStatus"],
3140
+ ["status", "enum(open|completed)"],
3060
3141
  ["due_date", "string"],
3061
- ["priority", "Priority"],
3142
+ ["priority", "enum(no_priority|urgent|high|medium|low)"],
3062
3143
  ["description", "string"],
3063
3144
  ["notes", "string | null"],
3064
3145
  ["label_ids", "number[]"],
3065
3146
  ["estimate_ids", "number[]"],
3066
3147
  ["resources_attributes", "ResourceDTO[]"],
3067
- ["subitems_attributes", "SubitemAttributes[]"],
3148
+ ["subitems_attributes", "object[]"],
3149
+ ["subitems_attributes[].name", "string"],
3150
+ ["subitems_attributes[].member_id", "string"],
3151
+ ["subitems_attributes[].status", "enum(active|completed)"],
3152
+ ["subitems_attributes[].priority", "enum(no_priority|urgent|high|medium|low)"],
3153
+ ["subitems_attributes[].description", "string"],
3154
+ ["subitems_attributes[].notes", "string | null"],
3068
3155
  ["archived_at", "string | null"]
3069
3156
  ]
3070
3157
  },
3158
+ subitem: {
3159
+ source: "wave-api-rb/config/initializers/constants/subitem.rb + wave-api-rb/app/models/subitem.rb",
3160
+ create: [
3161
+ ["list_item_id*", "string"],
3162
+ ["name*", "string"],
3163
+ ["member_id", "string"],
3164
+ ["status", "enum(active|completed)"],
3165
+ ["priority", "enum(no_priority|urgent|high|medium|low)"],
3166
+ ["description", "string"],
3167
+ ["notes", "string | null"],
3168
+ ["rank", "number"],
3169
+ ["due_date", "string"],
3170
+ ["estimate_ids", "number[]"]
3171
+ ],
3172
+ update: [
3173
+ ["name", "string"],
3174
+ ["member_id", "string"],
3175
+ ["status", "enum(active|completed)"],
3176
+ ["priority", "enum(no_priority|urgent|high|medium|low)"],
3177
+ ["description", "string"],
3178
+ ["notes", "string | null"],
3179
+ ["rank", "number"],
3180
+ ["due_date", "string"],
3181
+ ["estimate_ids", "number[]"]
3182
+ ]
3183
+ },
3071
3184
  issue_group: {
3072
3185
  source: "wave-ui/src/types/issueGroup.ts + wave-api-rb/config/initializers/constants/issue_group.rb + wave-api-rb/app/models/issue_group.rb",
3073
3186
  create: [
@@ -3442,6 +3555,24 @@ function toRows(fields, mode) {
3442
3555
  return `${field} | required:${requiredForMode} | type:${type} | ${humanize(field)}`;
3443
3556
  });
3444
3557
  }
3558
+ function exampleValue(type) {
3559
+ if (type === "number") return 1;
3560
+ if (type === "boolean") return true;
3561
+ if (type.endsWith("[]")) return [];
3562
+ const enumValues = /^enum\(([^)]+)\)$/u.exec(type)?.[1]?.split("|");
3563
+ return enumValues?.[0] ?? "value";
3564
+ }
3565
+ function examplePayload(rootKey, fields, mode) {
3566
+ const requiredFields = mode === "create" ? fields.filter(([field]) => field.endsWith("*")) : [];
3567
+ const exampleFields = requiredFields.length > 0 ? requiredFields : fields.slice(0, 1);
3568
+ const entity = Object.fromEntries(
3569
+ exampleFields.map(([rawField, type]) => [
3570
+ rawField.replace(/\*$/u, ""),
3571
+ exampleValue(type)
3572
+ ])
3573
+ );
3574
+ return JSON.stringify({ [rootKey]: entity });
3575
+ }
3445
3576
  function buildDataJsonHelp(rootKey, mode) {
3446
3577
  const config = dtoHelpCatalog[rootKey];
3447
3578
  if (!config) return null;
@@ -3454,10 +3585,205 @@ function buildDataJsonHelp(rootKey, mode) {
3454
3585
  `note: fields containing "preference" are intentionally omitted.`,
3455
3586
  "field | required | type | description",
3456
3587
  ...toRows(fields, mode),
3457
- `example: {"${rootKey}":{"${fields[0][0].replace(/\*$/, "")}":"value"}}`
3588
+ `example: ${examplePayload(rootKey, fields, mode)}`
3458
3589
  ].join("\n");
3459
3590
  }
3460
3591
 
3592
+ // src/entityPayloadContracts.ts
3593
+ var PRIORITIES = ["no_priority", "urgent", "high", "medium", "low"];
3594
+ var SUBITEM_STATUSES = ["active", "completed"];
3595
+ var LIST_ITEM_STATUSES = ["open", "completed"];
3596
+ var subitemFields = {
3597
+ list_item_id: { type: "string" },
3598
+ name: { type: "string" },
3599
+ status: { type: "string", enum: SUBITEM_STATUSES },
3600
+ priority: { type: "string", enum: PRIORITIES }
3601
+ };
3602
+ var listItemFields = {
3603
+ list_id: { type: "string" },
3604
+ summary: { type: "string" },
3605
+ status: { type: "string", enum: LIST_ITEM_STATUSES },
3606
+ priority: { type: "string", enum: PRIORITIES },
3607
+ subitems_attributes: {
3608
+ type: "array",
3609
+ items: {
3610
+ type: "object",
3611
+ fields: subitemFields,
3612
+ required: ["name"]
3613
+ }
3614
+ }
3615
+ };
3616
+ var listItemCreateContract = {
3617
+ rootKey: "list_item",
3618
+ fields: listItemFields,
3619
+ required: ["list_id", "summary"]
3620
+ };
3621
+ var listItemUpdateContract = {
3622
+ rootKey: "list_item",
3623
+ fields: listItemFields
3624
+ };
3625
+ var subitemCreateContract = {
3626
+ rootKey: "subitem",
3627
+ fields: subitemFields,
3628
+ required: ["list_item_id", "name"]
3629
+ };
3630
+ var subitemUpdateContract = {
3631
+ rootKey: "subitem",
3632
+ fields: subitemFields
3633
+ };
3634
+ var CONTRACTS = {
3635
+ "list-items.create": listItemCreateContract,
3636
+ "list-items.update": listItemUpdateContract,
3637
+ "subitems.create": subitemCreateContract,
3638
+ "subitems.update": subitemUpdateContract
3639
+ };
3640
+ function isPlainObject(value) {
3641
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3642
+ }
3643
+ function parsePayload(value) {
3644
+ if (typeof value !== "string") return value;
3645
+ try {
3646
+ return JSON.parse(value);
3647
+ } catch {
3648
+ return /* @__PURE__ */ Symbol.for("invalid-json");
3649
+ }
3650
+ }
3651
+ function typeMatches(value, type) {
3652
+ if (!type) return true;
3653
+ if (type === "array") return Array.isArray(value);
3654
+ if (type === "object") return isPlainObject(value);
3655
+ return typeof value === type;
3656
+ }
3657
+ function validateField(contract, value, path) {
3658
+ if (!typeMatches(value, contract.type)) {
3659
+ return [`${path.join(".")} must be ${contract.type}.`];
3660
+ }
3661
+ if (contract.enum && !contract.enum.includes(value)) {
3662
+ return [`${path.join(".")} must be one of ${contract.enum.join(", ")}.`];
3663
+ }
3664
+ if (contract.type === "object" && contract.fields && isPlainObject(value)) {
3665
+ const missing = (contract.required ?? []).filter(
3666
+ (field) => value[field] === void 0 || value[field] === null || value[field] === ""
3667
+ );
3668
+ return [
3669
+ ...missing.map((field) => `${[...path, field].join(".")} is required.`),
3670
+ ...validateFields(contract.fields, value, path)
3671
+ ];
3672
+ }
3673
+ if (contract.type === "array" && contract.items && Array.isArray(value)) {
3674
+ return value.flatMap(
3675
+ (item, index) => validateField(contract.items, item, [...path, index])
3676
+ );
3677
+ }
3678
+ return [];
3679
+ }
3680
+ function validateFields(fields, value, path) {
3681
+ return Object.entries(fields).flatMap(([field, contract]) => {
3682
+ const fieldValue = value[field];
3683
+ return fieldValue === void 0 ? [] : validateField(contract, fieldValue, [...path, field]);
3684
+ });
3685
+ }
3686
+ function contractEntity(contract, payload) {
3687
+ if (!isPlainObject(payload)) return null;
3688
+ if (!(contract.rootKey in payload)) return payload;
3689
+ const rooted = payload[contract.rootKey];
3690
+ return isPlainObject(rooted) ? rooted : null;
3691
+ }
3692
+ function validateOperationDataJson(operationId2, value) {
3693
+ const contract = CONTRACTS[operationId2];
3694
+ if (!contract) return [];
3695
+ const payload = parsePayload(value);
3696
+ if (payload === /* @__PURE__ */ Symbol.for("invalid-json")) {
3697
+ return ["Invalid input value for dataJson: must be valid JSON."];
3698
+ }
3699
+ const entity = contractEntity(contract, payload);
3700
+ if (!entity) {
3701
+ return [
3702
+ `Invalid input value for dataJson: ${contract.rootKey} payload must be a JSON object.`
3703
+ ];
3704
+ }
3705
+ const missing = (contract.required ?? []).filter(
3706
+ (field) => entity[field] === void 0 || entity[field] === null || entity[field] === ""
3707
+ );
3708
+ return [
3709
+ ...missing.map((field) => `${contract.rootKey}.${field} is required.`),
3710
+ ...validateFields(contract.fields, entity, [contract.rootKey])
3711
+ ].map(
3712
+ (error) => `Invalid input value for dataJson: ${error}`
3713
+ );
3714
+ }
3715
+ function assertOperationPayload(operationId2, body) {
3716
+ const errors = validateOperationDataJson(operationId2, body);
3717
+ if (errors.length === 0) return;
3718
+ throw new CliError({
3719
+ message: errors.join(" "),
3720
+ kind: "invalid_args",
3721
+ status: 400,
3722
+ exitCode: EXIT_CODES.invalidArgs
3723
+ });
3724
+ }
3725
+ function fieldSchema(contract) {
3726
+ const type = contract.type ?? "object";
3727
+ return {
3728
+ type,
3729
+ ...contract.enum ? { enum: [...contract.enum] } : {},
3730
+ ...contract.fields ? {
3731
+ properties: Object.fromEntries(
3732
+ Object.entries(contract.fields).map(([field, nested]) => [
3733
+ field,
3734
+ fieldSchema(nested)
3735
+ ])
3736
+ ),
3737
+ ...contract.required ? { required: [...contract.required] } : {},
3738
+ additionalProperties: true
3739
+ } : {},
3740
+ ...contract.items ? { items: fieldSchema(contract.items) } : {}
3741
+ };
3742
+ }
3743
+ function entitySchema(contract) {
3744
+ return {
3745
+ type: "object",
3746
+ properties: Object.fromEntries(
3747
+ Object.entries(contract.fields).map(([field, nested]) => [
3748
+ field,
3749
+ fieldSchema(nested)
3750
+ ])
3751
+ ),
3752
+ ...contract.required ? { required: [...contract.required] } : {},
3753
+ additionalProperties: true
3754
+ };
3755
+ }
3756
+ function exampleDataJsonForOperation(operationId2) {
3757
+ const contract = CONTRACTS[operationId2];
3758
+ if (!contract) return null;
3759
+ const entity = Object.fromEntries(
3760
+ (contract.required ?? []).map((field) => [field, "example"])
3761
+ );
3762
+ return { [contract.rootKey]: entity };
3763
+ }
3764
+ function dataJsonSchemaPropertyForOperation(operationId2, description) {
3765
+ const contract = CONTRACTS[operationId2];
3766
+ if (!contract) return null;
3767
+ const entity = entitySchema(contract);
3768
+ return {
3769
+ type: ["object", "string"],
3770
+ ...description ? { description } : {},
3771
+ anyOf: [
3772
+ {
3773
+ type: "string",
3774
+ description: "A JSON-serialized payload matching one of the object forms."
3775
+ },
3776
+ entity,
3777
+ {
3778
+ type: "object",
3779
+ properties: { [contract.rootKey]: entity },
3780
+ required: [contract.rootKey],
3781
+ additionalProperties: false
3782
+ }
3783
+ ]
3784
+ };
3785
+ }
3786
+
3461
3787
  // src/commands/entityCrud.ts
3462
3788
  var idSchema2 = import_zod4.z.string().min(1);
3463
3789
  function toSingularResourceName(resourcePath) {
@@ -3631,6 +3957,7 @@ function registerEntityCrudCommands(program, config) {
3631
3957
  if (config.normalizeCreateBody) {
3632
3958
  body = config.normalizeCreateBody(body);
3633
3959
  }
3960
+ assertOperationPayload(`${config.command}.create`, body);
3634
3961
  assertRequiredCreateFields(body, config.rootKey, config.requiredCreateFields);
3635
3962
  const defaultCommand = `${config.command}.create`;
3636
3963
  const defaultField = `create_${toSingularResourceName(config.resourcePath)}`;
@@ -3663,6 +3990,7 @@ function registerEntityCrudCommands(program, config) {
3663
3990
  if (config.normalizeUpdateBody) {
3664
3991
  body = config.normalizeUpdateBody(body);
3665
3992
  }
3993
+ assertOperationPayload(`${config.command}.update`, body);
3666
3994
  const singular = toSingularResourceName(config.resourcePath);
3667
3995
  await runGraphqlMutationCommand({
3668
3996
  command: `${config.command}.update`,
@@ -4421,10 +4749,17 @@ var nameSchema = import_zod10.z.string().min(1);
4421
4749
  var issueTypeSchema = import_zod10.z.string().min(1).refine((value) => value === "short_term" || value === "long_term", {
4422
4750
  message: "Invalid issue type. Use one of: short_term, long_term."
4423
4751
  });
4752
+ var issueStatusSchema = import_zod10.z.string().min(1).refine((value) => value === "open" || value === "completed", {
4753
+ message: "Invalid issue status. Use one of: open, completed."
4754
+ });
4424
4755
  var updateHelp4 = buildDataJsonHelp("issue", "update") ?? 'JSON object for issue or {"issue": {...}}';
4756
+ function parseIssueIndexEnum(value, schema) {
4757
+ if (value === void 0) return void 0;
4758
+ return schema.parse(String(value)).toUpperCase();
4759
+ }
4425
4760
  function registerIssueCommands(program) {
4426
4761
  const issues = program.command("issues").description("Issue operations");
4427
- issues.command("list").option("--page <page>").option("--per <per>").option("--issue-group-id <issueGroupId>").option("--start-date <startDate>").option("--issue-type <issueType>").option("--team-id <teamId>").option("--member-id <memberId>").option("--meeting-id <meetingId>").action(async (opts, cmd) => {
4762
+ issues.command("list").option("--page <page>").option("--per <per>").option("--issue-group-id <issueGroupId>").option("--start-date <startDate>").option("--issue-type <issueType>").option("--status <status>", "Issue status: open | completed").option("--team-id <teamId>").option("--member-id <memberId>").option("--meeting-id <meetingId>").action(async (opts, cmd) => {
4428
4763
  const context = await resolveCommandContext(cmd.optsWithGlobals());
4429
4764
  const organizationId = resolveOrganizationId(context.organizationId);
4430
4765
  await runGraphqlQueryCommand({
@@ -4437,11 +4772,24 @@ function registerIssueCommands(program) {
4437
4772
  per: opts.per,
4438
4773
  issue_group_id: opts.issueGroupId,
4439
4774
  start_date: opts.startDate,
4440
- issue_type: opts.issueType,
4775
+ issue_type: parseIssueIndexEnum(opts.issueType, issueTypeSchema),
4776
+ status: parseIssueIndexEnum(opts.status, issueStatusSchema),
4441
4777
  team_id: opts.teamId,
4442
4778
  member_id: opts.memberId,
4443
4779
  meeting_id: opts.meetingId
4444
4780
  }),
4781
+ variableTypes: {
4782
+ organization_id: "ID!",
4783
+ page: "Int",
4784
+ per: "Int",
4785
+ issue_group_id: "ID",
4786
+ start_date: "String",
4787
+ issue_type: "IssueType",
4788
+ status: "IssueStatus",
4789
+ team_id: "ID",
4790
+ member_id: "ID",
4791
+ meeting_id: "ID"
4792
+ },
4445
4793
  isList: true
4446
4794
  });
4447
4795
  });
@@ -6175,13 +6523,17 @@ function registerChildCommands(program, config) {
6175
6523
  ...config.searchRequiredOptions ? { requiredOptions: config.searchRequiredOptions } : {}
6176
6524
  };
6177
6525
  registerGraphqlSearchCommand(command, searchConfig);
6178
- command.command("create").requiredOption("--data-json <dataJson>").action(async (opts, cmd) => {
6526
+ command.command("create").requiredOption(
6527
+ "--data-json <dataJson>",
6528
+ buildDataJsonHelp(config.rootKey, "create") ?? void 0
6529
+ ).action(async (opts, cmd) => {
6179
6530
  const context = await resolveCommandContext(cmd.optsWithGlobals());
6180
6531
  const organizationId = resolveOrganizationId(context.organizationId);
6181
6532
  let body = normalizeBody2(String(opts.dataJson), config.rootKey);
6182
6533
  if (config.normalizeCreateBody) {
6183
6534
  body = config.normalizeCreateBody(body);
6184
6535
  }
6536
+ assertOperationPayload(`${config.command}.create`, body);
6185
6537
  assertRequiredParent(body, config.rootKey, config.parentFlag.replace(/-/g, "_"));
6186
6538
  await runGraphqlMutationCommand({
6187
6539
  command: `${config.command}.create`,
@@ -6194,11 +6546,15 @@ function registerChildCommands(program, config) {
6194
6546
  }
6195
6547
  });
6196
6548
  });
6197
- command.command("update").requiredOption("--id <id>").requiredOption("--data-json <dataJson>").action(async (opts, cmd) => {
6549
+ command.command("update").requiredOption("--id <id>").requiredOption(
6550
+ "--data-json <dataJson>",
6551
+ buildDataJsonHelp(config.rootKey, "update") ?? void 0
6552
+ ).action(async (opts, cmd) => {
6198
6553
  const context = await resolveCommandContext(cmd.optsWithGlobals());
6199
6554
  const organizationId = resolveOrganizationId(context.organizationId);
6200
6555
  const id = idSchema12.parse(opts.id);
6201
6556
  const body = normalizeBody2(String(opts.dataJson), config.rootKey);
6557
+ assertOperationPayload(`${config.command}.update`, body);
6202
6558
  await runGraphqlMutationCommand({
6203
6559
  command: `${config.command}.update`,
6204
6560
  operationName: config.updateOperationName,
@@ -14812,6 +15168,11 @@ var AUTOMATION_SELECTION = `{
14812
15168
  organizationId
14813
15169
  memberId
14814
15170
  agentId
15171
+ agentTriggerId
15172
+ scheduleStatus
15173
+ triggerEnabled
15174
+ cronExpression
15175
+ timezone
14815
15176
  createdAt
14816
15177
  updatedAt
14817
15178
  updateVersion
@@ -14838,6 +15199,29 @@ var AUTOMATION_RUN_SELECTION = `{
14838
15199
  targetId
14839
15200
  }
14840
15201
  }`;
15202
+ var AUTOMATION_RUN_STATUS_SELECTION = `{
15203
+ status
15204
+ automationTaskId
15205
+ automationTaskSlug
15206
+ agentId
15207
+ agentSlug
15208
+ agentTriggerId
15209
+ chatId
15210
+ chatSlug
15211
+ chatLane
15212
+ messageId
15213
+ runId
15214
+ executionId
15215
+ executionSlug
15216
+ traceId
15217
+ correlationId
15218
+ outputContentId
15219
+ outputContentSlug
15220
+ terminalReason
15221
+ error
15222
+ queuedAt
15223
+ completedAt
15224
+ }`;
14841
15225
  function asRecord7(value) {
14842
15226
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
14843
15227
  }
@@ -14968,15 +15352,58 @@ function normalizeAutomationRunPayload(payload) {
14968
15352
  const automationTaskId = asRequiredString(data?.automation_task_id);
14969
15353
  const automationTaskSlug = asRequiredString(data?.automation_task_slug);
14970
15354
  const agentId = asRequiredString(data?.agent_id);
14971
- const agentSlug = asRequiredString(data?.agent_slug);
14972
- const agentTriggerId = asRequiredString(data?.agent_trigger_id);
14973
- const executionId = asRequiredString(data?.execution_id);
14974
- const executionSlug = asRequiredString(data?.execution_slug);
14975
15355
  const executionStatus = asRequiredString(data?.execution_status);
14976
- const traceId = asRequiredString(data?.trace_id);
14977
- if (!data || !automationTaskId || !automationTaskSlug || !agentId || !agentSlug || !agentTriggerId || !executionId || !executionSlug || !executionStatus || !traceId) {
15356
+ if (!data || !automationTaskId || !automationTaskSlug || !agentId || !executionStatus) {
15357
+ throw new CliError({
15358
+ message: "Automation run response did not include automation identity and status.",
15359
+ kind: "malformed_response",
15360
+ status: 502,
15361
+ exitCode: EXIT_CODES.networkOrUpstream
15362
+ });
15363
+ }
15364
+ if (executionStatus === "queued") {
15365
+ const chatId = asRequiredString(data.chat_id);
15366
+ const chatSlug = asRequiredString(data.chat_slug);
15367
+ const chatLane = asRequiredString(data.chat_lane);
15368
+ const messageId = asRequiredString(data.message_id);
15369
+ const runId = asRequiredString(data.run_id);
15370
+ const memberId = asRequiredString(data.member_id);
15371
+ if (!chatId || !chatSlug || !chatLane || !messageId || !runId || !memberId) {
15372
+ throw new CliError({
15373
+ message: "Queued Automation response did not include chat, message, run, and member identity.",
15374
+ kind: "malformed_response",
15375
+ status: 502,
15376
+ exitCode: EXIT_CODES.networkOrUpstream
15377
+ });
15378
+ }
15379
+ return {
15380
+ ok: mutation.ok,
15381
+ status: mutation.status,
15382
+ errorCode: mutation.errorCode ?? null,
15383
+ errors: mutation.errors ?? null,
15384
+ run: {
15385
+ executed: data.executed === true,
15386
+ status: executionStatus,
15387
+ automation: { id: automationTaskId, slug: automationTaskSlug },
15388
+ agent: { id: agentId },
15389
+ trigger: { id: asRequiredString(data.agent_trigger_id) },
15390
+ queue: {
15391
+ chat: { id: chatId, slug: chatSlug, lane: chatLane },
15392
+ message_id: messageId,
15393
+ run_id: runId,
15394
+ member_id: memberId
15395
+ },
15396
+ readback_command: `wave automations run-status --id ${automationTaskSlug} --message-id ${messageId} --run-id ${runId}`
15397
+ }
15398
+ };
15399
+ }
15400
+ const agentSlug = asRequiredString(data.agent_slug);
15401
+ const executionId = asRequiredString(data.execution_id);
15402
+ const executionSlug = asRequiredString(data.execution_slug);
15403
+ const traceId = asRequiredString(data.trace_id);
15404
+ if (!agentSlug || !executionId || !executionSlug || !traceId) {
14978
15405
  throw new CliError({
14979
- message: "Automation run response did not include automation, execution, and trace evidence.",
15406
+ message: "Terminal Automation response did not include execution and trace evidence.",
14980
15407
  kind: "malformed_response",
14981
15408
  status: 502,
14982
15409
  exitCode: EXIT_CODES.networkOrUpstream
@@ -14999,7 +15426,7 @@ function normalizeAutomationRunPayload(payload) {
14999
15426
  slug: agentSlug
15000
15427
  },
15001
15428
  trigger: {
15002
- id: agentTriggerId,
15429
+ id: asRequiredString(data.agent_trigger_id),
15003
15430
  type: asRequiredString(data.trigger_type)
15004
15431
  },
15005
15432
  execution: {
@@ -15296,7 +15723,7 @@ function registerAtlasAuthoringCommands(program) {
15296
15723
  isShow: true
15297
15724
  });
15298
15725
  });
15299
- automations.command("run").description("Run one scheduled Automation by id or slug and return execution trace evidence").requiredOption("--id <idOrSlug>", "Automation id or slug").action(async (opts, cmd) => {
15726
+ automations.command("run").description("Queue one Automation by id or slug and return exact status readback identifiers").requiredOption("--id <idOrSlug>", "Automation id or slug").action(async (opts, cmd) => {
15300
15727
  const automationId = idSchema14.parse(opts.id);
15301
15728
  const context = await resolveCommandContext(cmd.optsWithGlobals());
15302
15729
  const organizationId = resolveOrganizationId(context.organizationId);
@@ -15310,6 +15737,33 @@ function registerAtlasAuthoringCommands(program) {
15310
15737
  transformMutationPayload: normalizeAutomationRunPayload
15311
15738
  });
15312
15739
  });
15740
+ automations.command("run-status").description("Read one queued or terminal Automation execution by its run identity").requiredOption("--id <idOrSlug>", "Automation id or slug returned by automations run").requiredOption("--message-id <messageId>", "Message id returned by automations run").requiredOption("--run-id <runId>", "Run id returned by automations run").action(async (opts, cmd) => {
15741
+ const automationId = idSchema14.parse(opts.id);
15742
+ const messageId = idSchema14.parse(opts.messageId);
15743
+ const runId = idSchema14.parse(opts.runId);
15744
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
15745
+ const organizationId = resolveOrganizationId(context.organizationId);
15746
+ await runGraphqlQueryCommand({
15747
+ command: "automations.run-status",
15748
+ operationName: "AutomationsRunStatus",
15749
+ runtimeOptions: context.runtimeOptions,
15750
+ field: "automation_run_status",
15751
+ variables: {
15752
+ organization_id: organizationId,
15753
+ automation_id: automationId,
15754
+ message_id: messageId,
15755
+ run_id: runId
15756
+ },
15757
+ variableTypes: {
15758
+ organization_id: "ID!",
15759
+ automation_id: "ID!",
15760
+ message_id: "ID!",
15761
+ run_id: "ID!"
15762
+ },
15763
+ selectionSet: AUTOMATION_RUN_STATUS_SELECTION,
15764
+ isShow: true
15765
+ });
15766
+ });
15313
15767
  automations.command("run-show").description("Read one Automation run artifact by Agent id and execution slug").requiredOption("--agent-id <agentIdOrSlug>", "Agent id or slug").requiredOption("--execution-slug <executionSlug>", "Execution slug returned by automations run").action(async (opts, cmd) => {
15314
15768
  const agentId = idSchema14.parse(opts.agentId);
15315
15769
  const executionSlug = idSchema14.parse(opts.executionSlug);
@@ -15472,7 +15926,7 @@ var import_node_path4 = require("path");
15472
15926
  var import_node_crypto3 = require("crypto");
15473
15927
 
15474
15928
  // src/version.ts
15475
- var CLI_VERSION = "0.1.77";
15929
+ var CLI_VERSION = "0.1.80";
15476
15930
 
15477
15931
  // src/operationMetadata.ts
15478
15932
  var DISCOVERY_OPERATION_IDS = [
@@ -15595,6 +16049,7 @@ var READ_OPERATION_IDS = [
15595
16049
  "agents.show",
15596
16050
  "auth.status",
15597
16051
  "automations.run-show",
16052
+ "automations.run-status",
15598
16053
  "automations.show",
15599
16054
  "broadcast.community",
15600
16055
  "broadcast.list",
@@ -16009,7 +16464,7 @@ function operationId(path) {
16009
16464
  function inputKeyForArgument(argument) {
16010
16465
  return argument.name().replace(/<|>|\[|\]|\.\.\./g, "");
16011
16466
  }
16012
- function inputSchemaFor(command) {
16467
+ function inputSchemaFor(command, id) {
16013
16468
  const properties = {};
16014
16469
  const required = [];
16015
16470
  for (const argument of command.registeredArguments) {
@@ -16023,7 +16478,8 @@ function inputSchemaFor(command) {
16023
16478
  for (const option of command.options) {
16024
16479
  const key = option.attributeName();
16025
16480
  if (MACHINE_PRESENTATION_OPTIONS.has(key)) continue;
16026
- properties[key] = {
16481
+ const payloadSchema = key === "dataJson" ? dataJsonSchemaPropertyForOperation(id, option.description) : null;
16482
+ properties[key] = payloadSchema ?? {
16027
16483
  type: option.required ? "string" : option.optional ? ["boolean", "string"] : "boolean",
16028
16484
  ...option.description ? { description: option.description } : {}
16029
16485
  };
@@ -16036,12 +16492,17 @@ function inputSchemaFor(command) {
16036
16492
  required: required.sort()
16037
16493
  };
16038
16494
  }
16039
- function exampleFor(inputSchema) {
16495
+ function exampleFor(inputSchema, id) {
16040
16496
  const input = {};
16041
16497
  for (const key of inputSchema.required) {
16498
+ const payloadExample = key === "dataJson" ? exampleDataJsonForOperation(id) : null;
16499
+ if (payloadExample) {
16500
+ input[key] = payloadExample;
16501
+ continue;
16502
+ }
16042
16503
  const propertyType = inputSchema.properties[key]?.type;
16043
16504
  const types = Array.isArray(propertyType) ? propertyType : [propertyType];
16044
- input[key] = types.includes("array") ? ["example"] : types.includes("boolean") ? true : "example";
16505
+ input[key] = types.includes("object") ? {} : types.includes("array") ? ["example"] : types.includes("boolean") ? true : "example";
16045
16506
  }
16046
16507
  return [{ name: "minimal valid input", input }];
16047
16508
  }
@@ -16072,7 +16533,8 @@ function listInvocableCommands(program) {
16072
16533
  }
16073
16534
  function entryFor(command, metadata) {
16074
16535
  const path = commandPath(command);
16075
- const inputSchema = inputSchemaFor(command);
16536
+ const id = operationId(path);
16537
+ const inputSchema = inputSchemaFor(command, id);
16076
16538
  const summary = command.description() || `Run ${path.join(" ")}.`;
16077
16539
  return {
16078
16540
  id: operationId(path),
@@ -16085,7 +16547,7 @@ function entryFor(command, metadata) {
16085
16547
  atlasSafetyClass: metadata.atlasSafetyClass,
16086
16548
  inputSchema,
16087
16549
  outputSchema: outputSchema(),
16088
- examples: exampleFor(inputSchema),
16550
+ examples: exampleFor(inputSchema, id),
16089
16551
  machine: metadata.machine
16090
16552
  };
16091
16553
  }
@@ -16303,6 +16765,7 @@ var NAMESPACE_DOCS = {
16303
16765
  `wave automations create --summary "Weekly review" --agent-id 123 --ai-task-config '{"cycle":"repeat","repeatSchedule":{"interval":1,"frequency":"week","weekdays":[1,3],"at":"2:30 PM","starting":"2026-07-20T00:00:00.000Z","ending":"never","endingRuns":1,"endingDate":null,"timezone":"America/Phoenix"}}' --idempotency-key automation-create-001`,
16304
16766
  "wave automations show --id ATK-01",
16305
16767
  "wave automations run --id ATK-01",
16768
+ "wave automations run-status --id ATK-01 --message-id 123 --run-id run_123",
16306
16769
  "wave automations run-show --agent-id AGT-01 --execution-slug ART-1234567890",
16307
16770
  'wave automations update --id ATK-01 --expected-update-version 2026-07-17T12:00:00.123456Z --summary "Weekly project review"'
16308
16771
  ],
@@ -16315,11 +16778,12 @@ var NAMESPACE_DOCS = {
16315
16778
  "Only the API-defined ai_task_config field accepts validated JSON.",
16316
16779
  "Optional executor Agent linkage is sent only through the API-defined top-level agentId input.",
16317
16780
  "Update calls only updateTask with an exact opaque updateVersion token; it cannot change status, task type, ownership, or project linkage.",
16318
- "Run calls only runAutomationNow for an existing scheduled Automation and returns execution/trace evidence.",
16781
+ "Run calls only runAutomationNow and returns the exact queued chat, message, and run identity.",
16782
+ "Run-status reads queued or terminal execution and trace evidence using that exact identity.",
16319
16783
  "Run-show reads the persisted Automation run artifact through agentAutomationRun by Agent id and execution slug.",
16320
16784
  "Show uses the API-owned automation query by id; no slug fallback is implemented."
16321
16785
  ],
16322
- commands: ["create", "show", "run", "run-show", "update"]
16786
+ commands: ["create", "show", "run", "run-status", "run-show", "update"]
16323
16787
  }
16324
16788
  },
16325
16789
  broadcast: {
@@ -17210,7 +17674,7 @@ function machineEnvelope(params) {
17210
17674
  meta: { requestId: "machine" }
17211
17675
  };
17212
17676
  }
17213
- function isPlainObject(value) {
17677
+ function isPlainObject2(value) {
17214
17678
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
17215
17679
  }
17216
17680
  function hasAction2(command) {
@@ -17284,7 +17748,7 @@ async function readMachineInput(location) {
17284
17748
  }
17285
17749
  if (!raw.trim()) throw new Error("Machine input JSON is required.");
17286
17750
  const parsed = JSON.parse(raw);
17287
- if (!isPlainObject(parsed)) throw new Error("Machine input must be a JSON object.");
17751
+ if (!isPlainObject2(parsed)) throw new Error("Machine input must be a JSON object.");
17288
17752
  return parsed;
17289
17753
  }
17290
17754
  function inputDigest(input) {
@@ -17292,7 +17756,7 @@ function inputDigest(input) {
17292
17756
  }
17293
17757
  function canonicalJson(value) {
17294
17758
  if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
17295
- if (isPlainObject(value)) {
17759
+ if (isPlainObject2(value)) {
17296
17760
  return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(",")}}`;
17297
17761
  }
17298
17762
  return JSON.stringify(value);
@@ -17322,18 +17786,18 @@ function parseTrustedJsonFromFd(fd, predicate) {
17322
17786
  }
17323
17787
  }
17324
17788
  function isTrustedAuth(value) {
17325
- return isPlainObject(value) && typeof value.token === "string" && value.token.trim() !== "" && typeof value.baseUrl === "string" && value.baseUrl.trim() !== "" && typeof value.organizationId === "string" && value.organizationId.trim() !== "" && typeof value.actorId === "string" && value.actorId.trim() !== "";
17789
+ return isPlainObject2(value) && typeof value.token === "string" && value.token.trim() !== "" && typeof value.baseUrl === "string" && value.baseUrl.trim() !== "" && typeof value.organizationId === "string" && value.organizationId.trim() !== "" && typeof value.actorId === "string" && value.actorId.trim() !== "";
17326
17790
  }
17327
17791
  function isTrustedApproval(value) {
17328
- return isPlainObject(value) && typeof value.operation === "string" && typeof value.inputDigest === "string" && typeof value.cliVersion === "string" && typeof value.registryDigest === "string" && typeof value.organizationId === "string" && value.organizationId.trim() !== "" && typeof value.actorId === "string" && value.actorId.trim() !== "";
17792
+ return isPlainObject2(value) && typeof value.operation === "string" && typeof value.inputDigest === "string" && typeof value.cliVersion === "string" && typeof value.registryDigest === "string" && typeof value.organizationId === "string" && value.organizationId.trim() !== "" && typeof value.actorId === "string" && value.actorId.trim() !== "";
17329
17793
  }
17330
17794
  function operationCommand(program, id) {
17331
17795
  return listInvocableCommands(program).find((command) => commandId(command) === id);
17332
17796
  }
17333
- function typeMatches(value, type) {
17797
+ function typeMatches2(value, type) {
17334
17798
  if (type === "array") return Array.isArray(value);
17335
17799
  if (type === "null") return value === null;
17336
- if (type === "object") return isPlainObject(value);
17800
+ if (type === "object") return isPlainObject2(value);
17337
17801
  return typeof value === type;
17338
17802
  }
17339
17803
  function validateInput(operation, input) {
@@ -17342,16 +17806,19 @@ function validateInput(operation, input) {
17342
17806
  const missing = operation.inputSchema.required.filter(
17343
17807
  (key) => input[key] === void 0 || input[key] === null || input[key] === ""
17344
17808
  );
17345
- const typeErrors = Object.entries(input).flatMap(([key, value]) => {
17809
+ const valueErrors = Object.entries(input).flatMap(([key, value]) => {
17346
17810
  const property = operation.inputSchema.properties[key];
17347
17811
  if (!property) return [];
17348
17812
  const types = Array.isArray(property.type) ? property.type : [property.type];
17349
- return types.some((type) => typeMatches(value, type)) ? [] : [`Invalid input type for ${key}: expected ${types.join(" or ")}.`];
17813
+ if (!types.some((type) => typeMatches2(value, type))) {
17814
+ return [`Invalid input type for ${key}: expected ${types.join(" or ")}.`];
17815
+ }
17816
+ return key === "dataJson" ? validateOperationDataJson(operation.id, value) : [];
17350
17817
  });
17351
17818
  return [
17352
17819
  ...unknown.map((key) => `Unknown input property: ${key}`),
17353
17820
  ...missing.map((key) => `Missing required input property: ${key}`),
17354
- ...typeErrors
17821
+ ...valueErrors
17355
17822
  ];
17356
17823
  }
17357
17824
  function optionValue(value) {