@wave-ai-os/wave-cli 0.1.60 → 0.1.62

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 +583 -222
  2. package/dist/index.js +580 -219
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1758,6 +1758,21 @@ async function runGraphqlMutationCommand(input) {
1758
1758
  variableTypes: input.variableTypes,
1759
1759
  selectionSet: input.selectionSet ?? "{ ok status errorCode data errors }"
1760
1760
  });
1761
+ if (result.envelope.ok && input.transformMutationPayload) {
1762
+ const envelopeData = result.envelope.data;
1763
+ if (!isRecord(envelopeData) || !Object.prototype.hasOwnProperty.call(envelopeData, input.field)) {
1764
+ throw new CliError({
1765
+ message: "Mutation response was missing its expected payload.",
1766
+ kind: "malformed_response",
1767
+ status: 502,
1768
+ exitCode: EXIT_CODES.networkOrUpstream
1769
+ });
1770
+ }
1771
+ result.envelope.data = {
1772
+ ...envelopeData,
1773
+ [input.field]: input.transformMutationPayload(envelopeData[input.field])
1774
+ };
1775
+ }
1761
1776
  printEnvelopeAndExit(result);
1762
1777
  } catch (error) {
1763
1778
  if (isEnvelopeEmittedSignal(error)) {
@@ -2136,13 +2151,18 @@ function resolveFromSources(options, stdin, config, env) {
2136
2151
  normalize3(env.WAVE_API_URL),
2137
2152
  normalize3(config.baseUrl)
2138
2153
  );
2139
- const organizationId = firstDefined(
2140
- normalize3(options.organizationId),
2141
- normalize3(stdin.organizationId),
2142
- normalize3(env.WAVE_ORGANIZATION_ID),
2143
- normalize3(env.WAVE_ORG_ID),
2144
- normalize3(config.organizationId)
2145
- );
2154
+ const organizationCandidates = [
2155
+ { organizationId: normalize3(options.organizationId), source: "flag" },
2156
+ { organizationId: normalize3(stdin.organizationId), source: "stdin" },
2157
+ { organizationId: normalize3(env.WAVE_ORGANIZATION_ID), source: "env" },
2158
+ { organizationId: normalize3(env.WAVE_ORG_ID), source: "env" },
2159
+ { organizationId: normalize3(config.organizationId), source: "config" }
2160
+ ];
2161
+ const resolvedOrganization = organizationCandidates.find((candidate) => candidate.organizationId) ?? {
2162
+ organizationId: void 0,
2163
+ source: "none"
2164
+ };
2165
+ const organizationId = resolvedOrganization.organizationId;
2146
2166
  const timeoutMs = firstDefined(options.timeoutMs, stdin.timeoutMs, env.WAVE_TIMEOUT_MS, config.timeoutMs);
2147
2167
  const debug = firstDefined(
2148
2168
  options.debug,
@@ -2231,6 +2251,7 @@ function resolveFromSources(options, stdin, config, env) {
2231
2251
  const resolvedAuth = resolveAuthToken(options, stdin, config, env);
2232
2252
  return {
2233
2253
  organizationId,
2254
+ organizationIdSource: resolvedOrganization.source,
2234
2255
  runtimeOptions: {
2235
2256
  token: resolvedAuth.token,
2236
2257
  tokenSource: resolvedAuth.token ? resolvedAuth.source : "none",
@@ -2440,6 +2461,140 @@ function registerGraphqlSearchCommand(command, config) {
2440
2461
  });
2441
2462
  }
2442
2463
 
2464
+ // src/authClient.ts
2465
+ import { randomUUID as randomUUID2 } from "crypto";
2466
+
2467
+ // src/redaction.ts
2468
+ var TOKENISH_PATTERNS = [
2469
+ /\b(?:cli|wave|token|secret|bearer)[A-Za-z0-9._~+/=-]{8,}\b/gi,
2470
+ /\b[A-Za-z0-9._~+/=-]{24,}\b/g
2471
+ ];
2472
+ function redactOne(value) {
2473
+ if (value.length <= 8) {
2474
+ return "[redacted]";
2475
+ }
2476
+ return `${value.slice(0, 4)}...[redacted]...${value.slice(-4)}`;
2477
+ }
2478
+ function redactSecrets(input, knownSecrets = []) {
2479
+ let output = input;
2480
+ for (const secret of knownSecrets) {
2481
+ if (!secret) continue;
2482
+ output = output.split(secret).join(redactOne(secret));
2483
+ }
2484
+ for (const pattern of TOKENISH_PATTERNS) {
2485
+ output = output.replace(pattern, (match) => redactOne(match));
2486
+ }
2487
+ return output;
2488
+ }
2489
+ function redactUnknown(input, knownSecrets = []) {
2490
+ if (typeof input === "string") {
2491
+ return redactSecrets(input, knownSecrets);
2492
+ }
2493
+ if (Array.isArray(input)) {
2494
+ return input.map((entry2) => redactUnknown(entry2, knownSecrets));
2495
+ }
2496
+ if (!input || typeof input !== "object") {
2497
+ return input;
2498
+ }
2499
+ const output = {};
2500
+ for (const [key, value] of Object.entries(input)) {
2501
+ if (/token|secret|authorization|bearer/i.test(key)) {
2502
+ output[key] = typeof value === "string" ? redactSecrets(value, knownSecrets) : "[redacted]";
2503
+ continue;
2504
+ }
2505
+ output[key] = redactUnknown(value, knownSecrets);
2506
+ }
2507
+ return output;
2508
+ }
2509
+
2510
+ // src/authClient.ts
2511
+ function parseJsonSafely2(input) {
2512
+ try {
2513
+ return JSON.parse(input);
2514
+ } catch {
2515
+ return null;
2516
+ }
2517
+ }
2518
+ function graphqlErrors(payload, knownSecrets) {
2519
+ const errors = payload.errors;
2520
+ if (!Array.isArray(errors) || errors.length === 0) return null;
2521
+ return {
2522
+ code: "upstream_error",
2523
+ message: "GraphQL request failed.",
2524
+ status: 400,
2525
+ details: {
2526
+ errors: redactUnknown(errors, knownSecrets)
2527
+ }
2528
+ };
2529
+ }
2530
+ async function authGraphqlRequest(params) {
2531
+ const requestId = randomUUID2();
2532
+ const controller = new AbortController();
2533
+ const timeoutId = setTimeout(() => controller.abort(), params.timeoutMs);
2534
+ const knownSecrets = [params.token, ...params.knownSecrets ?? []].filter(
2535
+ (secret) => typeof secret === "string" && secret.length > 0
2536
+ );
2537
+ try {
2538
+ const url = new URL("/graphql", params.baseUrl);
2539
+ const response = await fetch(url, {
2540
+ method: "POST",
2541
+ headers: {
2542
+ Accept: "application/json",
2543
+ "Content-Type": "application/json",
2544
+ "X-Origin": "wave-cli",
2545
+ "X-Request-Id": requestId,
2546
+ ...params.token ? { Authorization: `Bearer ${params.token}` } : {}
2547
+ },
2548
+ body: JSON.stringify({ query: params.query, variables: params.variables ?? {} }),
2549
+ signal: controller.signal
2550
+ });
2551
+ const responseRequestId = response.headers.get("x-request-id") ?? requestId;
2552
+ const text = await response.text();
2553
+ const payload = text ? parseJsonSafely2(text) : null;
2554
+ const graph = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
2555
+ const gqlError = graphqlErrors(graph, knownSecrets);
2556
+ if (gqlError) {
2557
+ return { ok: false, error: gqlError, requestId: responseRequestId };
2558
+ }
2559
+ if (!response.ok) {
2560
+ return {
2561
+ ok: false,
2562
+ requestId: responseRequestId,
2563
+ error: {
2564
+ code: `http_${response.status}`,
2565
+ message: "Auth request failed.",
2566
+ status: response.status,
2567
+ details: { body: redactUnknown(graph, knownSecrets) }
2568
+ }
2569
+ };
2570
+ }
2571
+ const data = graph.data && typeof graph.data === "object" && !Array.isArray(graph.data) ? graph.data : {};
2572
+ return {
2573
+ ok: true,
2574
+ result: {
2575
+ status: response.status,
2576
+ requestId: responseRequestId,
2577
+ data
2578
+ }
2579
+ };
2580
+ } catch (error) {
2581
+ const message = error instanceof Error ? error.message : "Network error.";
2582
+ const timedOut = error instanceof Error && error.name === "AbortError";
2583
+ return {
2584
+ ok: false,
2585
+ requestId,
2586
+ error: {
2587
+ code: timedOut ? "timeout" : "network_error",
2588
+ message: redactSecrets(timedOut ? "Auth request timed out." : message, knownSecrets),
2589
+ status: timedOut ? 408 : 503,
2590
+ details: {}
2591
+ }
2592
+ };
2593
+ } finally {
2594
+ clearTimeout(timeoutId);
2595
+ }
2596
+ }
2597
+
2443
2598
  // src/commands/tasks.ts
2444
2599
  var projectIdSchema = z2.string().min(1);
2445
2600
  var idSchema = z2.string().min(1);
@@ -2468,6 +2623,44 @@ function parseTaskUpdateJson(raw) {
2468
2623
  function parseLabelIds(raw) {
2469
2624
  return raw.split(",").map((labelId) => labelId.trim()).filter((labelId) => labelId.length > 0);
2470
2625
  }
2626
+ function asRecord3(value) {
2627
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
2628
+ return null;
2629
+ }
2630
+ return value;
2631
+ }
2632
+ function asNonEmptyString2(value) {
2633
+ if (typeof value !== "string") {
2634
+ return void 0;
2635
+ }
2636
+ const trimmed = value.trim();
2637
+ return trimmed.length > 0 ? trimmed : void 0;
2638
+ }
2639
+ async function resolveTaskReadOrganizationId(params) {
2640
+ const resolvedOrganizationId = asNonEmptyString2(params.organizationId);
2641
+ if (params.organizationIdSource === "flag" && resolvedOrganizationId) {
2642
+ return resolvedOrganizationId;
2643
+ }
2644
+ const baseUrl = asNonEmptyString2(params.runtimeOptions.baseUrl);
2645
+ const token = asNonEmptyString2(params.runtimeOptions.token);
2646
+ if (baseUrl && token) {
2647
+ const result = await authGraphqlRequest({
2648
+ baseUrl,
2649
+ token,
2650
+ timeoutMs: typeof params.runtimeOptions.timeoutMs === "number" ? params.runtimeOptions.timeoutMs : 1e4,
2651
+ query: "query WaveCliTaskReadOrganization { cliAuthStatus { authenticated baseAuthStatus organization { id slug } } }"
2652
+ });
2653
+ if (result.ok) {
2654
+ const status = asRecord3(result.result.data.cliAuthStatus);
2655
+ const organization = status ? asRecord3(status.organization) : null;
2656
+ const organizationId = organization ? asNonEmptyString2(organization.id) : void 0;
2657
+ if (organizationId) {
2658
+ return organizationId;
2659
+ }
2660
+ }
2661
+ }
2662
+ return resolveOrganizationId(resolvedOrganizationId);
2663
+ }
2471
2664
  function registerTaskCommands(program) {
2472
2665
  const tasks = program.command("tasks").description("Task operations");
2473
2666
  tasks.command("list").option("--project-id <projectId>").option("--page <page>").option("--per <per>").option("--team-id <teamId>").option("--team-ids <teamIds>").option("--member-id <memberId>").option("--meeting-id <meetingId>").option("--field-name <fieldName>").option("--field-value <fieldValue>").option("--field-blank <fieldBlank>").option("--open <open>").option("--rank-direction <rankDirection>").option("--include-archived <includeArchived>").action(async (opts, cmd) => {
@@ -2504,7 +2697,11 @@ function registerTaskCommands(program) {
2504
2697
  tasks.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
2505
2698
  const parsed = idSchema.parse(opts.id);
2506
2699
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2507
- const organizationId = resolveOrganizationId(context.organizationId);
2700
+ const organizationId = await resolveTaskReadOrganizationId({
2701
+ organizationId: context.organizationId,
2702
+ organizationIdSource: context.organizationIdSource,
2703
+ runtimeOptions: context.runtimeOptions
2704
+ });
2508
2705
  await runGraphqlQueryCommand({
2509
2706
  command: "tasks.show",
2510
2707
  runtimeOptions: context.runtimeOptions,
@@ -3406,16 +3603,16 @@ var displayPreferenceAttributesSelectionSet = "attributes { id viewType favorite
3406
3603
  var filterPreferenceAttributesSelectionSet = "attributes { id filterType filter memberId focusMemberId focusTeamId filterableId filterableType preferenceType agendaItemId }";
3407
3604
  var healthUpdateSummarySelectionSet = "id type value memberId status createdAt updatedAt updatableType updatableId parentUpdateId emojis { id name memberId } resources { ...ResourceSummaryFull }";
3408
3605
  var projectShowFullSelectionSet = `{ id type name slug description status priority createdAt updatedAt startDate targetDate archivedAt memberId organizationId teamIds emoji { id name memberId } backgroundImage { backgroundType gradientStart gradientEnd gradientDegrees color imageUrl image { url lowUrl } } favorites { id memberId } resources { ...ResourceSummaryFull } displayPreference { id type ${displayPreferenceAttributesSelectionSet} viewType favorite groupingField groupToggleState memberId focusMemberId focusTeamId displayableId displayableType preferenceType agendaItemId } filterPreferences { id type ${filterPreferenceAttributesSelectionSet} filterType filter memberId focusMemberId focusTeamId filterableId filterableType preferenceType agendaItemId } healthUpdates { ${healthUpdateSummarySelectionSet} replies { ${healthUpdateSummarySelectionSet} replies { id type } } } } fragment ResourceSummaryFull on ResourceSummary { id resourceType slug url skillId skill { id name slug emoji scope description } metadata { urlName imageUrl siteName providerName mediaType skillId skillName skillSlug skillScope skillEmoji skillDescription } attachment { id fileKey filename url } content { id name slug type firstChildSlug childCount } }`;
3409
- function asRecord3(value) {
3606
+ function asRecord4(value) {
3410
3607
  return value && typeof value === "object" ? value : null;
3411
3608
  }
3412
3609
  function toNonEmptyString(value) {
3413
3610
  return typeof value === "string" && value.trim() !== "" ? value : void 0;
3414
3611
  }
3415
3612
  function normalizeProjectRowForDisplay(row) {
3416
- const record = asRecord3(row);
3613
+ const record = asRecord4(row);
3417
3614
  if (!record) return row;
3418
- const attributes = asRecord3(record.attributes);
3615
+ const attributes = asRecord4(record.attributes);
3419
3616
  const topLevelName = toNonEmptyString(record.name);
3420
3617
  const topLevelTitle = toNonEmptyString(record.title);
3421
3618
  const attributeName = toNonEmptyString(attributes?.name);
@@ -3430,7 +3627,7 @@ function normalizeProjectRowForDisplay(row) {
3430
3627
  };
3431
3628
  }
3432
3629
  function normalizeProjectsListForDisplay(payload) {
3433
- const record = asRecord3(payload);
3630
+ const record = asRecord4(payload);
3434
3631
  if (!record || !Array.isArray(record.data)) return payload;
3435
3632
  return {
3436
3633
  ...record,
@@ -3638,7 +3835,7 @@ var MEETING_STATUSES = /* @__PURE__ */ new Set(["upcoming", "active", "completed
3638
3835
  var MEETING_REPEATS = /* @__PURE__ */ new Set(["never", "weekly", "biweekly", "monthly", "quarterly"]);
3639
3836
  var createHelp2 = buildDataJsonHelp("meeting", "create") ?? 'JSON object for meeting or {"meeting": {...}}';
3640
3837
  var updateHelp2 = buildDataJsonHelp("meeting", "update") ?? 'JSON object for meeting or {"meeting": {...}}';
3641
- function asNonEmptyString2(value) {
3838
+ function asNonEmptyString3(value) {
3642
3839
  if (typeof value !== "string") {
3643
3840
  return void 0;
3644
3841
  }
@@ -3696,7 +3893,7 @@ function normalizeMeetingCreateBody(body) {
3696
3893
  });
3697
3894
  }
3698
3895
  const meeting = { ...entity };
3699
- const type = asNonEmptyString2(meeting.type);
3896
+ const type = asNonEmptyString3(meeting.type);
3700
3897
  if (!type || !MEETING_TYPES.has(type)) {
3701
3898
  throw new CliError({
3702
3899
  message: "Invalid meeting.type. Use one of: TeamMeeting, OneOnOneMeeting.",
@@ -3706,8 +3903,8 @@ function normalizeMeetingCreateBody(body) {
3706
3903
  details: { field: "meeting.type", allowed: Array.from(MEETING_TYPES) }
3707
3904
  });
3708
3905
  }
3709
- const memberId = asNonEmptyString2(meeting.member_id);
3710
- const date = asNonEmptyString2(meeting.date);
3906
+ const memberId = asNonEmptyString3(meeting.member_id);
3907
+ const date = asNonEmptyString3(meeting.date);
3711
3908
  const startTime = toFiniteNumber(meeting.start_time, "meeting.start_time");
3712
3909
  const missingRequired = [];
3713
3910
  if (!memberId) missingRequired.push("member_id");
@@ -3722,7 +3919,7 @@ function normalizeMeetingCreateBody(body) {
3722
3919
  details: { requiredFields: ["member_id", "date", "start_time"], rootKey: "meeting" }
3723
3920
  });
3724
3921
  }
3725
- const status = asNonEmptyString2(meeting.status);
3922
+ const status = asNonEmptyString3(meeting.status);
3726
3923
  if (status && !MEETING_STATUSES.has(status)) {
3727
3924
  throw new CliError({
3728
3925
  message: "Invalid meeting.status. Use one of: upcoming, active, completed.",
@@ -3732,7 +3929,7 @@ function normalizeMeetingCreateBody(body) {
3732
3929
  details: { field: "meeting.status", allowed: Array.from(MEETING_STATUSES) }
3733
3930
  });
3734
3931
  }
3735
- const repeats = asNonEmptyString2(meeting.repeats) ?? "never";
3932
+ const repeats = asNonEmptyString3(meeting.repeats) ?? "never";
3736
3933
  if (!MEETING_REPEATS.has(repeats)) {
3737
3934
  throw new CliError({
3738
3935
  message: "Invalid meeting.repeats. Use one of: never, weekly, biweekly, monthly, quarterly.",
@@ -4021,7 +4218,7 @@ var SKILL_SELECTION = `{
4021
4218
  createdAt
4022
4219
  updatedAt
4023
4220
  }`;
4024
- function asRecord4(value) {
4221
+ function asRecord5(value) {
4025
4222
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
4026
4223
  }
4027
4224
  function findSkillById(id) {
@@ -4029,11 +4226,11 @@ function findSkillById(id) {
4029
4226
  if (!Array.isArray(payload)) {
4030
4227
  return null;
4031
4228
  }
4032
- return payload.find((entry2) => String(asRecord4(entry2)?.id ?? "") === id) ?? null;
4229
+ return payload.find((entry2) => String(asRecord5(entry2)?.id ?? "") === id) ?? null;
4033
4230
  };
4034
4231
  }
4035
4232
  function registerSkillCommands(program) {
4036
- const skills = program.command("skills").description("Read Skill records");
4233
+ const skills = program.command("skills").description("Skill record operations");
4037
4234
  skills.command("list").description("List Skill records").option("--scope <scope>", "Filter skills by scope").option("--query <query>", "Filter skills by search query").option("--limit <limit>", "Limit skills returned").requiredOption("--json", "Emit the stable JSON envelope").action(async (opts, cmd) => {
4038
4235
  const context = await resolveCommandContext(cmd.optsWithGlobals());
4039
4236
  const organizationId = resolveOrganizationId(context.organizationId);
@@ -4059,7 +4256,7 @@ function registerSkillCommands(program) {
4059
4256
  isList: true
4060
4257
  });
4061
4258
  });
4062
- skills.command("show").description("Read one Skill record by id").requiredOption("--id <id>", "Skill id").requiredOption("--json", "Emit the stable JSON envelope").action(async (opts, cmd) => {
4259
+ skills.command("show").description("Read one persisted Skill record by id").requiredOption("--id <id>", "Skill id").requiredOption("--json", "Emit the stable JSON envelope").action(async (opts, cmd) => {
4063
4260
  const id = idSchema7.parse(opts.id);
4064
4261
  const context = await resolveCommandContext(cmd.optsWithGlobals());
4065
4262
  const organizationId = resolveOrganizationId(context.organizationId);
@@ -4421,7 +4618,7 @@ function normalizeTodosCreateBody(body) {
4421
4618
  }
4422
4619
  return { ...body, todo };
4423
4620
  }
4424
- function asNonEmptyString3(value) {
4621
+ function asNonEmptyString4(value) {
4425
4622
  if (typeof value !== "string") {
4426
4623
  return void 0;
4427
4624
  }
@@ -4429,7 +4626,7 @@ function asNonEmptyString3(value) {
4429
4626
  return trimmed.length > 0 ? trimmed : void 0;
4430
4627
  }
4431
4628
  function validateEnumField(params) {
4432
- const value = asNonEmptyString3(params.rawValue);
4629
+ const value = asNonEmptyString4(params.rawValue);
4433
4630
  if (!value) {
4434
4631
  return void 0;
4435
4632
  }
@@ -4463,7 +4660,7 @@ function normalizeKnowledgeCreateBody(body) {
4463
4660
  message: "Invalid content.status. Use one of: draft, published."
4464
4661
  });
4465
4662
  content.status = status ?? "draft";
4466
- const memberId = asNonEmptyString3(content.member_id);
4663
+ const memberId = asNonEmptyString4(content.member_id);
4467
4664
  if (!memberId) {
4468
4665
  throwMissingRequiredCreateFields("content", ["member_id"]);
4469
4666
  }
@@ -4472,7 +4669,7 @@ function normalizeKnowledgeCreateBody(body) {
4472
4669
  }
4473
4670
  function normalizeNewsCreateBody(body) {
4474
4671
  const headline = ensureEntityObject(body, "headline");
4475
- const memberId = asNonEmptyString3(headline.member_id);
4672
+ const memberId = asNonEmptyString4(headline.member_id);
4476
4673
  if (!memberId) {
4477
4674
  throwMissingRequiredCreateFields("headline", ["member_id"]);
4478
4675
  }
@@ -4501,14 +4698,14 @@ function normalizeNewsCreateBody(body) {
4501
4698
  }
4502
4699
  function normalizeQuestionsCreateBody(body) {
4503
4700
  const question = ensureEntityObject(body, "question");
4504
- const summary = asNonEmptyString3(question.summary);
4505
- const currentName = asNonEmptyString3(question.name);
4701
+ const summary = asNonEmptyString4(question.summary);
4702
+ const currentName = asNonEmptyString4(question.name);
4506
4703
  if (!currentName && summary) {
4507
4704
  question.name = summary;
4508
4705
  }
4509
4706
  delete question.summary;
4510
- const name = asNonEmptyString3(question.name);
4511
- const memberId = asNonEmptyString3(question.member_id);
4707
+ const name = asNonEmptyString4(question.name);
4708
+ const memberId = asNonEmptyString4(question.member_id);
4512
4709
  const missing = [];
4513
4710
  if (!name) missing.push("name");
4514
4711
  if (!memberId) missing.push("member_id");
@@ -4530,13 +4727,13 @@ function normalizeQuestionsCreateBody(body) {
4530
4727
  }
4531
4728
  function normalizeQuestionsUpdateBody(body) {
4532
4729
  const question = ensureEntityObject(body, "question");
4533
- const summary = asNonEmptyString3(question.summary);
4534
- const currentName = asNonEmptyString3(question.name);
4730
+ const summary = asNonEmptyString4(question.summary);
4731
+ const currentName = asNonEmptyString4(question.name);
4535
4732
  if (!currentName && summary) {
4536
4733
  question.name = summary;
4537
4734
  }
4538
4735
  delete question.summary;
4539
- const name = asNonEmptyString3(question.name);
4736
+ const name = asNonEmptyString4(question.name);
4540
4737
  if (name) {
4541
4738
  question.name = name;
4542
4739
  }
@@ -4553,9 +4750,9 @@ function normalizeQuestionsUpdateBody(body) {
4553
4750
  }
4554
4751
  function normalizePulseCreateBody(body) {
4555
4752
  const healthUpdate = ensureEntityObject(body, "health_update");
4556
- const healthUpdatableId = asNonEmptyString3(healthUpdate.health_updatable_id) ?? asNonEmptyString3(healthUpdate.updatable_id);
4557
- const healthUpdatableType = asNonEmptyString3(healthUpdate.health_updatable_type) ?? asNonEmptyString3(healthUpdate.updatable_type);
4558
- const memberId = asNonEmptyString3(healthUpdate.member_id);
4753
+ const healthUpdatableId = asNonEmptyString4(healthUpdate.health_updatable_id) ?? asNonEmptyString4(healthUpdate.updatable_id);
4754
+ const healthUpdatableType = asNonEmptyString4(healthUpdate.health_updatable_type) ?? asNonEmptyString4(healthUpdate.updatable_type);
4755
+ const memberId = asNonEmptyString4(healthUpdate.member_id);
4559
4756
  const status = validateEnumField({
4560
4757
  rawValue: healthUpdate.status,
4561
4758
  field: "health_update.status",
@@ -4580,8 +4777,8 @@ function normalizePulseCreateBody(body) {
4580
4777
  }
4581
4778
  function normalizeSurveysCreateBody(body) {
4582
4779
  const survey = ensureEntityObject(body, "survey");
4583
- const title = asNonEmptyString3(survey.title);
4584
- const currentName = asNonEmptyString3(survey.name);
4780
+ const title = asNonEmptyString4(survey.title);
4781
+ const currentName = asNonEmptyString4(survey.name);
4585
4782
  if (!currentName && title) {
4586
4783
  survey.name = title;
4587
4784
  }
@@ -4610,8 +4807,8 @@ function normalizeSurveysCreateBody(body) {
4610
4807
  }
4611
4808
  function normalizeSurveysUpdateBody(body) {
4612
4809
  const survey = ensureEntityObject(body, "survey");
4613
- const title = asNonEmptyString3(survey.title);
4614
- const currentName = asNonEmptyString3(survey.name);
4810
+ const title = asNonEmptyString4(survey.title);
4811
+ const currentName = asNonEmptyString4(survey.name);
4615
4812
  if (!currentName && title) {
4616
4813
  survey.name = title;
4617
4814
  }
@@ -4638,8 +4835,8 @@ function normalizeSurveysUpdateBody(body) {
4638
4835
  }
4639
4836
  function normalizeFeedbacksCreateBody(body) {
4640
4837
  const feedback = ensureEntityObject(body, "feedback");
4641
- const title = asNonEmptyString3(feedback.title);
4642
- const currentName = asNonEmptyString3(feedback.name);
4838
+ const title = asNonEmptyString4(feedback.title);
4839
+ const currentName = asNonEmptyString4(feedback.name);
4643
4840
  if (!currentName && title) {
4644
4841
  feedback.name = title;
4645
4842
  }
@@ -4656,7 +4853,7 @@ function normalizeFeedbacksCreateBody(body) {
4656
4853
  allowed: FEEDBACK_QUARTERS,
4657
4854
  message: "Invalid feedback.quarter. Use one of: q1, q2, q3, q4."
4658
4855
  });
4659
- const year = asNonEmptyString3(feedback.year);
4856
+ const year = asNonEmptyString4(feedback.year);
4660
4857
  const missing = [];
4661
4858
  if (!name) missing.push("name");
4662
4859
  if (!quarter) missing.push("quarter");
@@ -4671,8 +4868,8 @@ function normalizeFeedbacksCreateBody(body) {
4671
4868
  }
4672
4869
  function normalizeFeedbacksUpdateBody(body) {
4673
4870
  const feedback = ensureEntityObject(body, "feedback");
4674
- const title = asNonEmptyString3(feedback.title);
4675
- const currentName = asNonEmptyString3(feedback.name);
4871
+ const title = asNonEmptyString4(feedback.title);
4872
+ const currentName = asNonEmptyString4(feedback.name);
4676
4873
  if (!currentName && title) {
4677
4874
  feedback.name = title;
4678
4875
  }
@@ -4699,14 +4896,14 @@ function normalizeFeedbacksUpdateBody(body) {
4699
4896
  }
4700
4897
  function normalizeAccountabilityCreateBody(body) {
4701
4898
  const responsibility = ensureEntityObject(body, "responsibility");
4702
- const summary = asNonEmptyString3(responsibility.summary);
4703
- const currentName = asNonEmptyString3(responsibility.name);
4899
+ const summary = asNonEmptyString4(responsibility.summary);
4900
+ const currentName = asNonEmptyString4(responsibility.name);
4704
4901
  if (!currentName && summary) {
4705
4902
  responsibility.name = summary;
4706
4903
  }
4707
4904
  delete responsibility.summary;
4708
- const name = asNonEmptyString3(responsibility.name);
4709
- const memberId = asNonEmptyString3(responsibility.member_id);
4905
+ const name = asNonEmptyString4(responsibility.name);
4906
+ const memberId = asNonEmptyString4(responsibility.member_id);
4710
4907
  const missing = [];
4711
4908
  if (!name) missing.push("name");
4712
4909
  if (!memberId) missing.push("member_id");
@@ -4721,8 +4918,8 @@ function normalizeAccountabilityCreateBody(body) {
4721
4918
  }
4722
4919
  function normalizeAccountabilityUpdateBody(body) {
4723
4920
  const responsibility = ensureEntityObject(body, "responsibility");
4724
- const summary = asNonEmptyString3(responsibility.summary);
4725
- const currentName = asNonEmptyString3(responsibility.name);
4921
+ const summary = asNonEmptyString4(responsibility.summary);
4922
+ const currentName = asNonEmptyString4(responsibility.name);
4726
4923
  if (!currentName && summary) {
4727
4924
  responsibility.name = summary;
4728
4925
  }
@@ -4754,7 +4951,7 @@ function parseSmartKpiViewCreateBody(raw) {
4754
4951
  }
4755
4952
  function normalizeSmartKpiViewCreateBody(body) {
4756
4953
  const smartKpiView = ensureEntityObject(body, "smart_kpi_view");
4757
- const name = asNonEmptyString3(smartKpiView.name);
4954
+ const name = asNonEmptyString4(smartKpiView.name);
4758
4955
  if (!name) {
4759
4956
  throwMissingRequiredCreateFields("smart_kpi_view", ["name"]);
4760
4957
  }
@@ -4792,9 +4989,9 @@ function buildKpisCreateMutation(params) {
4792
4989
  });
4793
4990
  }
4794
4991
  const smartKpi = { ...entity };
4795
- const name = asNonEmptyString3(smartKpi.name);
4796
- const smartKpiViewId = asNonEmptyString3(smartKpi.smart_kpi_view_id);
4797
- const measurableGroupId = asNonEmptyString3(smartKpi.measurable_group_id);
4992
+ const name = asNonEmptyString4(smartKpi.name);
4993
+ const smartKpiViewId = asNonEmptyString4(smartKpi.smart_kpi_view_id);
4994
+ const measurableGroupId = asNonEmptyString4(smartKpi.measurable_group_id);
4798
4995
  const hasAllowedName = typeof name === "string" && SMART_KPI_NAME_SET.has(name);
4799
4996
  if (!name) {
4800
4997
  throw new CliError({
@@ -4814,7 +5011,7 @@ function buildKpisCreateMutation(params) {
4814
5011
  measurable_type: "number",
4815
5012
  condition: "greater_than_or_equal_to"
4816
5013
  };
4817
- const notes = asNonEmptyString3(smartKpi.notes);
5014
+ const notes = asNonEmptyString4(smartKpi.notes);
4818
5015
  if (notes) {
4819
5016
  measurable.notes = notes;
4820
5017
  }
@@ -5217,7 +5414,7 @@ function ensureRootObject(body, rootKey) {
5217
5414
  }
5218
5415
  return { ...root };
5219
5416
  }
5220
- function asNonEmptyString4(value) {
5417
+ function asNonEmptyString5(value) {
5221
5418
  if (typeof value !== "string") {
5222
5419
  return void 0;
5223
5420
  }
@@ -5227,7 +5424,7 @@ function asNonEmptyString4(value) {
5227
5424
  function normalizeOrganizationUpdateBody(body) {
5228
5425
  const organization = ensureRootObject(body, "organization");
5229
5426
  const detail = isRecord3(organization.organization_detail_attributes) ? { ...organization.organization_detail_attributes } : {};
5230
- const workspaceName = asNonEmptyString4(organization.workspace_name);
5427
+ const workspaceName = asNonEmptyString5(organization.workspace_name);
5231
5428
  if (workspaceName) {
5232
5429
  detail.workspace_name = workspaceName;
5233
5430
  }
@@ -5240,7 +5437,7 @@ function normalizeOrganizationUpdateBody(body) {
5240
5437
  function normalizeOrganizationMetaProfileUpdateBody(body) {
5241
5438
  const root = ensureRootObject(body, "organization_meta_profile");
5242
5439
  const profile = isRecord3(root.profile) ? { ...root.profile } : {};
5243
- const title = asNonEmptyString4(root.title);
5440
+ const title = asNonEmptyString5(root.title);
5244
5441
  if (title) {
5245
5442
  const companyIdentity = isRecord3(profile.company_identity) ? { ...profile.company_identity } : {};
5246
5443
  companyIdentity.one_sentence_summary = title;
@@ -5270,7 +5467,7 @@ function normalizeOrganizationMetaProfileUpdateBody(body) {
5270
5467
  function normalizeKeyMetricMetaProfileUpdateBody(body) {
5271
5468
  const root = ensureRootObject(body, "key_metric_meta_profile");
5272
5469
  const profile = isRecord3(root.profile) ? { ...root.profile } : {};
5273
- const annualRevenue = asNonEmptyString4(root.annual_revenue);
5470
+ const annualRevenue = asNonEmptyString5(root.annual_revenue);
5274
5471
  if (annualRevenue) {
5275
5472
  const financial = isRecord3(profile.financial) ? { ...profile.financial } : {};
5276
5473
  financial.revenue = annualRevenue;
@@ -5441,7 +5638,7 @@ function ensureRootObject2(body, rootKey) {
5441
5638
  }
5442
5639
  return { ...root };
5443
5640
  }
5444
- function asNonEmptyString5(value) {
5641
+ function asNonEmptyString6(value) {
5445
5642
  if (typeof value !== "string") {
5446
5643
  return void 0;
5447
5644
  }
@@ -5469,8 +5666,8 @@ function normalizeStrategicPlanUpdateBody(body) {
5469
5666
  }
5470
5667
  function normalizeStrategicObjectiveUpdateBody(body) {
5471
5668
  const strategicObjective = ensureRootObject2(body, "strategic_objective");
5472
- const title = asNonEmptyString5(strategicObjective.title);
5473
- if (!asNonEmptyString5(strategicObjective.summary) && title) {
5669
+ const title = asNonEmptyString6(strategicObjective.title);
5670
+ if (!asNonEmptyString6(strategicObjective.summary) && title) {
5474
5671
  strategicObjective.summary = title;
5475
5672
  }
5476
5673
  delete strategicObjective.title;
@@ -5493,8 +5690,8 @@ function normalizeStrategicObjectiveUpdateBody(body) {
5493
5690
  }
5494
5691
  function normalizeAnnualObjectiveCreateBody(body) {
5495
5692
  const annualObjective = ensureRootObject2(body, "annual_objective");
5496
- const title = asNonEmptyString5(annualObjective.title);
5497
- if (!asNonEmptyString5(annualObjective.name) && title) {
5693
+ const title = asNonEmptyString6(annualObjective.title);
5694
+ if (!asNonEmptyString6(annualObjective.name) && title) {
5498
5695
  annualObjective.name = title;
5499
5696
  }
5500
5697
  delete annualObjective.title;
@@ -5502,8 +5699,8 @@ function normalizeAnnualObjectiveCreateBody(body) {
5502
5699
  }
5503
5700
  function normalizeQuarterlyObjectiveCreateBody(body) {
5504
5701
  const quarterlyObjective = ensureRootObject2(body, "quarterly_objective");
5505
- const title = asNonEmptyString5(quarterlyObjective.title);
5506
- if (!asNonEmptyString5(quarterlyObjective.name) && title) {
5702
+ const title = asNonEmptyString6(quarterlyObjective.title);
5703
+ if (!asNonEmptyString6(quarterlyObjective.name) && title) {
5507
5704
  quarterlyObjective.name = title;
5508
5705
  }
5509
5706
  delete quarterlyObjective.title;
@@ -6304,7 +6501,7 @@ import { z as z16 } from "zod";
6304
6501
 
6305
6502
  // src/internalOptions.ts
6306
6503
  var INTERNAL_OPTIONS_KEY = "__waveInternalOptions";
6307
- function asRecord5(value) {
6504
+ function asRecord6(value) {
6308
6505
  if (!value || typeof value !== "object" || Array.isArray(value)) {
6309
6506
  return null;
6310
6507
  }
@@ -6318,7 +6515,7 @@ function setInternalCliOptions(program, options) {
6318
6515
  function getInternalCliOptions(command) {
6319
6516
  let current = command;
6320
6517
  while (current) {
6321
- const record = asRecord5(current[INTERNAL_OPTIONS_KEY]);
6518
+ const record = asRecord6(current[INTERNAL_OPTIONS_KEY]);
6322
6519
  if (record) {
6323
6520
  return {
6324
6521
  enableRetryOnEmptyPhrase: record.enableRetryOnEmptyPhrase === true
@@ -9963,142 +10160,6 @@ function registerOsmdCommands(program) {
9963
10160
 
9964
10161
  // src/commands/auth.ts
9965
10162
  import { spawn } from "child_process";
9966
-
9967
- // src/authClient.ts
9968
- import { randomUUID as randomUUID2 } from "crypto";
9969
-
9970
- // src/redaction.ts
9971
- var TOKENISH_PATTERNS = [
9972
- /\b(?:cli|wave|token|secret|bearer)[A-Za-z0-9._~+/=-]{8,}\b/gi,
9973
- /\b[A-Za-z0-9._~+/=-]{24,}\b/g
9974
- ];
9975
- function redactOne(value) {
9976
- if (value.length <= 8) {
9977
- return "[redacted]";
9978
- }
9979
- return `${value.slice(0, 4)}...[redacted]...${value.slice(-4)}`;
9980
- }
9981
- function redactSecrets(input, knownSecrets = []) {
9982
- let output = input;
9983
- for (const secret of knownSecrets) {
9984
- if (!secret) continue;
9985
- output = output.split(secret).join(redactOne(secret));
9986
- }
9987
- for (const pattern of TOKENISH_PATTERNS) {
9988
- output = output.replace(pattern, (match) => redactOne(match));
9989
- }
9990
- return output;
9991
- }
9992
- function redactUnknown(input, knownSecrets = []) {
9993
- if (typeof input === "string") {
9994
- return redactSecrets(input, knownSecrets);
9995
- }
9996
- if (Array.isArray(input)) {
9997
- return input.map((entry2) => redactUnknown(entry2, knownSecrets));
9998
- }
9999
- if (!input || typeof input !== "object") {
10000
- return input;
10001
- }
10002
- const output = {};
10003
- for (const [key, value] of Object.entries(input)) {
10004
- if (/token|secret|authorization|bearer/i.test(key)) {
10005
- output[key] = typeof value === "string" ? redactSecrets(value, knownSecrets) : "[redacted]";
10006
- continue;
10007
- }
10008
- output[key] = redactUnknown(value, knownSecrets);
10009
- }
10010
- return output;
10011
- }
10012
-
10013
- // src/authClient.ts
10014
- function parseJsonSafely2(input) {
10015
- try {
10016
- return JSON.parse(input);
10017
- } catch {
10018
- return null;
10019
- }
10020
- }
10021
- function graphqlErrors(payload, knownSecrets) {
10022
- const errors = payload.errors;
10023
- if (!Array.isArray(errors) || errors.length === 0) return null;
10024
- return {
10025
- code: "upstream_error",
10026
- message: "GraphQL request failed.",
10027
- status: 400,
10028
- details: {
10029
- errors: redactUnknown(errors, knownSecrets)
10030
- }
10031
- };
10032
- }
10033
- async function authGraphqlRequest(params) {
10034
- const requestId = randomUUID2();
10035
- const controller = new AbortController();
10036
- const timeoutId = setTimeout(() => controller.abort(), params.timeoutMs);
10037
- const knownSecrets = [params.token, ...params.knownSecrets ?? []].filter(
10038
- (secret) => typeof secret === "string" && secret.length > 0
10039
- );
10040
- try {
10041
- const url = new URL("/graphql", params.baseUrl);
10042
- const response = await fetch(url, {
10043
- method: "POST",
10044
- headers: {
10045
- Accept: "application/json",
10046
- "Content-Type": "application/json",
10047
- "X-Origin": "wave-cli",
10048
- "X-Request-Id": requestId,
10049
- ...params.token ? { Authorization: `Bearer ${params.token}` } : {}
10050
- },
10051
- body: JSON.stringify({ query: params.query, variables: params.variables ?? {} }),
10052
- signal: controller.signal
10053
- });
10054
- const responseRequestId = response.headers.get("x-request-id") ?? requestId;
10055
- const text = await response.text();
10056
- const payload = text ? parseJsonSafely2(text) : null;
10057
- const graph = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
10058
- const gqlError = graphqlErrors(graph, knownSecrets);
10059
- if (gqlError) {
10060
- return { ok: false, error: gqlError, requestId: responseRequestId };
10061
- }
10062
- if (!response.ok) {
10063
- return {
10064
- ok: false,
10065
- requestId: responseRequestId,
10066
- error: {
10067
- code: `http_${response.status}`,
10068
- message: "Auth request failed.",
10069
- status: response.status,
10070
- details: { body: redactUnknown(graph, knownSecrets) }
10071
- }
10072
- };
10073
- }
10074
- const data = graph.data && typeof graph.data === "object" && !Array.isArray(graph.data) ? graph.data : {};
10075
- return {
10076
- ok: true,
10077
- result: {
10078
- status: response.status,
10079
- requestId: responseRequestId,
10080
- data
10081
- }
10082
- };
10083
- } catch (error) {
10084
- const message = error instanceof Error ? error.message : "Network error.";
10085
- const timedOut = error instanceof Error && error.name === "AbortError";
10086
- return {
10087
- ok: false,
10088
- requestId,
10089
- error: {
10090
- code: timedOut ? "timeout" : "network_error",
10091
- message: redactSecrets(timedOut ? "Auth request timed out." : message, knownSecrets),
10092
- status: timedOut ? 408 : 503,
10093
- details: {}
10094
- }
10095
- };
10096
- } finally {
10097
- clearTimeout(timeoutId);
10098
- }
10099
- }
10100
-
10101
- // src/commands/auth.ts
10102
10163
  var DEFAULT_LOGIN_TIMEOUT_MS = 12e4;
10103
10164
  var DEFAULT_POLL_INTERVAL_MS = 2e3;
10104
10165
  function envelope(params) {
@@ -10126,7 +10187,7 @@ function positiveInt2(raw, fallback) {
10126
10187
  function requestTimeoutMs(totalTimeoutMs) {
10127
10188
  return Math.max(1e3, Math.min(totalTimeoutMs, 1e4));
10128
10189
  }
10129
- function asRecord6(value) {
10190
+ function asRecord7(value) {
10130
10191
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
10131
10192
  }
10132
10193
  function asString(value) {
@@ -10173,9 +10234,9 @@ function cliTokenFromPoll(payload) {
10173
10234
  return asString(payload.cliToken) ?? asString(payload.cli_token) ?? asString(payload.token);
10174
10235
  }
10175
10236
  function unwrapMutationResult(value) {
10176
- const record = asRecord6(value);
10237
+ const record = asRecord7(value);
10177
10238
  if (!record) return null;
10178
- const data = asRecord6(record.data);
10239
+ const data = asRecord7(record.data);
10179
10240
  if (data && (Object.prototype.hasOwnProperty.call(record, "ok") || Object.prototype.hasOwnProperty.call(record, "errors") || Object.prototype.hasOwnProperty.call(record, "errorCode") || Object.prototype.hasOwnProperty.call(record, "error_code"))) {
10180
10241
  return data;
10181
10242
  }
@@ -10239,7 +10300,7 @@ async function runTokenLogin(cmd, opts) {
10239
10300
  exitCode: mapStatusToExitCode(status.error.status)
10240
10301
  });
10241
10302
  }
10242
- const statusData = asRecord6(status.result.data.cliAuthStatus) ?? {};
10303
+ const statusData = asRecord7(status.result.data.cliAuthStatus) ?? {};
10243
10304
  const storage = await writeStoredToken(token, baseUrl);
10244
10305
  const configPath2 = opts.saveBaseUrl ? await persistBaseUrl(baseUrl) : void 0;
10245
10306
  return printEnvelopeAndExit({
@@ -10456,7 +10517,7 @@ async function runLogout(cmd) {
10456
10517
  });
10457
10518
  if (result.ok) {
10458
10519
  requestId = result.result.requestId;
10459
- const payload = asRecord6(result.result.data.revokeCliToken) ?? {};
10520
+ const payload = asRecord7(result.result.data.revokeCliToken) ?? {};
10460
10521
  revokedRemote = payload.ok !== false;
10461
10522
  } else {
10462
10523
  requestId = result.requestId;
@@ -10519,7 +10580,8 @@ async function runAuthStatus(cmd) {
10519
10580
  exitCode: mapStatusToExitCode(result.error.status)
10520
10581
  });
10521
10582
  }
10522
- const status = asRecord6(result.result.data.cliAuthStatus) ?? {};
10583
+ const status = asRecord7(result.result.data.cliAuthStatus) ?? {};
10584
+ const baseAuthStatus = status.baseAuthStatus;
10523
10585
  return printEnvelopeAndExit({
10524
10586
  envelope: envelope({
10525
10587
  ok: true,
@@ -10528,6 +10590,7 @@ async function runAuthStatus(cmd) {
10528
10590
  requestId: result.result.requestId,
10529
10591
  data: {
10530
10592
  authenticated: Boolean(status.authenticated),
10593
+ baseAuthStatus: typeof baseAuthStatus === "string" ? baseAuthStatus : null,
10531
10594
  baseUrl,
10532
10595
  tokenSource,
10533
10596
  member: redactUnknown(status.member, [token]) ?? null,
@@ -12168,11 +12231,11 @@ function sanitizePlannerJson(value) {
12168
12231
  }
12169
12232
  return output;
12170
12233
  }
12171
- function asRecord7(value) {
12234
+ function asRecord8(value) {
12172
12235
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
12173
12236
  }
12174
12237
  function readPlannerStateKey(value, keys) {
12175
- const record = asRecord7(value);
12238
+ const record = asRecord8(value);
12176
12239
  if (!record) {
12177
12240
  return null;
12178
12241
  }
@@ -14837,6 +14900,259 @@ function registerAiNotesCommands(program) {
14837
14900
  });
14838
14901
  }
14839
14902
 
14903
+ // src/commands/atlasAuthoring.ts
14904
+ import { z as z19 } from "zod";
14905
+ var idSchema14 = z19.string().trim().min(1);
14906
+ var idempotencyKeySchema = z19.string().min(1).refine((value) => value.trim() === value, "Idempotency key must not have leading or trailing whitespace.");
14907
+ var skillScopeSchema = z19.enum(["ADMIN_GLOBAL", "MEMBER_PERSONAL"]);
14908
+ var isoDateSchema = z19.iso.date();
14909
+ var AGENT_SELECTION = `{
14910
+ id
14911
+ type
14912
+ name
14913
+ slug
14914
+ description
14915
+ notes
14916
+ status
14917
+ visibility
14918
+ model
14919
+ runWhenMentioned
14920
+ webAccessEnabled
14921
+ organizationId
14922
+ memberId
14923
+ createdAt
14924
+ updatedAt
14925
+ }`;
14926
+ var AUTOMATION_SELECTION = `{
14927
+ id
14928
+ type
14929
+ summary
14930
+ slug
14931
+ description
14932
+ notes
14933
+ status
14934
+ priority
14935
+ taskType
14936
+ aiTaskConfig
14937
+ organizationId
14938
+ memberId
14939
+ createdAt
14940
+ updatedAt
14941
+ }`;
14942
+ function asRecord9(value) {
14943
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
14944
+ }
14945
+ function asRequiredString(value) {
14946
+ if (typeof value !== "string") return null;
14947
+ const trimmed = value.trim();
14948
+ return trimmed.length > 0 ? trimmed : null;
14949
+ }
14950
+ function parseBooleanOption(value, optionName) {
14951
+ if (value === void 0) return void 0;
14952
+ if (value === "true") return true;
14953
+ if (value === "false") return false;
14954
+ throw new CliError({
14955
+ message: `Invalid ${optionName}: expected true or false.`,
14956
+ kind: "invalid_args",
14957
+ status: 400,
14958
+ exitCode: EXIT_CODES.invalidArgs
14959
+ });
14960
+ }
14961
+ function parseCommaSeparatedStrings(value) {
14962
+ if (value === void 0) return void 0;
14963
+ const entries = String(value).split(",").map((entry2) => entry2.trim()).filter((entry2) => entry2.length > 0);
14964
+ if (entries.length === 0) {
14965
+ throw new CliError({
14966
+ message: "--trusted-urls must include at least one URL.",
14967
+ kind: "invalid_args",
14968
+ status: 400,
14969
+ exitCode: EXIT_CODES.invalidArgs
14970
+ });
14971
+ }
14972
+ return entries;
14973
+ }
14974
+ function parseJson(value, optionName) {
14975
+ try {
14976
+ return JSON.parse(value);
14977
+ } catch (error) {
14978
+ throw new CliError({
14979
+ message: error instanceof Error ? `Invalid ${optionName}: ${error.message}` : `Invalid ${optionName}.`,
14980
+ kind: "invalid_args",
14981
+ status: 400,
14982
+ exitCode: EXIT_CODES.invalidArgs
14983
+ });
14984
+ }
14985
+ }
14986
+ function normalizePersistedCreatePayload(payload) {
14987
+ const mutation = asRecord9(payload);
14988
+ const mutationData = asRecord9(mutation?.data);
14989
+ const persisted = asRecord9(mutationData?.data) ?? mutationData;
14990
+ const attributes = asRecord9(persisted?.attributes);
14991
+ const meta = asRecord9(mutationData?.meta);
14992
+ const idempotency = asRecord9(meta?.atlas_idempotency);
14993
+ const id = asRequiredString(persisted?.id);
14994
+ const slug = asRequiredString(persisted?.slug) ?? asRequiredString(attributes?.slug);
14995
+ const replay = idempotency?.replay;
14996
+ if (!mutation || !mutationData || !persisted || !id || !slug || !idempotency || typeof replay !== "boolean") {
14997
+ throw new CliError({
14998
+ message: "Create response did not include persisted id/slug and idempotency metadata.",
14999
+ kind: "malformed_response",
15000
+ status: 502,
15001
+ exitCode: EXIT_CODES.networkOrUpstream
15002
+ });
15003
+ }
15004
+ return {
15005
+ ok: mutation.ok,
15006
+ status: mutation.status,
15007
+ errorCode: mutation.errorCode ?? null,
15008
+ errors: mutation.errors ?? null,
15009
+ persisted: { id, slug },
15010
+ idempotency: {
15011
+ object_type: asRequiredString(idempotency.object_type),
15012
+ id: asRequiredString(idempotency.id),
15013
+ slug: asRequiredString(idempotency.slug),
15014
+ idempotency_key: asRequiredString(idempotency.idempotency_key),
15015
+ fingerprint: asRequiredString(idempotency.fingerprint),
15016
+ replay,
15017
+ action: asRequiredString(idempotency.action)
15018
+ }
15019
+ };
15020
+ }
15021
+ function registerAtlasAuthoringCommands(program) {
15022
+ const agents = program.command("agents").description("Bounded Agent authoring operations");
15023
+ agents.command("create").description("Create an Agent through the API-owned createAgent contract").requiredOption("--idempotency-key <key>", "Required create idempotency key").option("--name <name>").option("--description <description>").option("--notes <notes>").option("--member-id <memberId>").option("--status <status>").option("--visibility <visibility>").option("--model <model>").option("--run-when-mentioned <boolean>", "true or false").option("--web-access-enabled <boolean>", "true or false").option("--trusted-urls <urls>", "Comma-separated trusted URLs").action(async (opts, cmd) => {
15024
+ const idempotencyKey = idempotencyKeySchema.parse(opts.idempotencyKey);
15025
+ const runWhenMentioned = parseBooleanOption(opts.runWhenMentioned, "--run-when-mentioned");
15026
+ const webAccessEnabled = parseBooleanOption(opts.webAccessEnabled, "--web-access-enabled");
15027
+ const trustedUrls = parseCommaSeparatedStrings(opts.trustedUrls);
15028
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
15029
+ const organizationId = resolveOrganizationId(context.organizationId);
15030
+ await runGraphqlMutationCommand({
15031
+ command: "agents.create",
15032
+ operationName: "AgentsCreate",
15033
+ runtimeOptions: context.runtimeOptions,
15034
+ field: "create_agent",
15035
+ variableTypes: {
15036
+ organization_id: "ID!",
15037
+ params: "CreateAgentParamsInput!",
15038
+ idempotency_key: "String!"
15039
+ },
15040
+ variables: {
15041
+ organization_id: organizationId,
15042
+ params: {
15043
+ agent: {
15044
+ ...opts.name !== void 0 ? { name: String(opts.name) } : {},
15045
+ ...opts.description !== void 0 ? { description: String(opts.description) } : {},
15046
+ ...opts.notes !== void 0 ? { notes: String(opts.notes) } : {},
15047
+ ...opts.memberId !== void 0 ? { member_id: idSchema14.parse(opts.memberId) } : {},
15048
+ ...opts.status !== void 0 ? { status: String(opts.status) } : {},
15049
+ ...opts.visibility !== void 0 ? { visibility: String(opts.visibility) } : {},
15050
+ ...opts.model !== void 0 ? { model: String(opts.model) } : {},
15051
+ ...runWhenMentioned !== void 0 ? { run_when_mentioned: runWhenMentioned } : {},
15052
+ ...webAccessEnabled !== void 0 ? { web_access_enabled: webAccessEnabled } : {},
15053
+ ...trustedUrls !== void 0 ? { trusted_urls: trustedUrls } : {}
15054
+ }
15055
+ },
15056
+ idempotency_key: idempotencyKey
15057
+ },
15058
+ transformMutationPayload: normalizePersistedCreatePayload
15059
+ });
15060
+ });
15061
+ agents.command("show").description("Read one persisted Agent by id").requiredOption("--id <id>", "Agent id").action(async (opts, cmd) => {
15062
+ const id = idSchema14.parse(opts.id);
15063
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
15064
+ const organizationId = resolveOrganizationId(context.organizationId);
15065
+ await runGraphqlQueryCommand({
15066
+ command: "agents.show",
15067
+ operationName: "AgentsShow",
15068
+ runtimeOptions: context.runtimeOptions,
15069
+ field: "agent",
15070
+ variables: { organization_id: organizationId, id },
15071
+ variableTypes: { organization_id: "ID!", id: "ID!" },
15072
+ selectionSet: AGENT_SELECTION,
15073
+ isShow: true
15074
+ });
15075
+ });
15076
+ const automations = program.command("automations").description("Bounded Automation authoring operations");
15077
+ automations.command("create").description("Create an Automation through the API-owned createAutomation contract").requiredOption("--summary <summary>").requiredOption("--ai-task-config <json>", "Valid JSON for the API-owned ai_task_config field").requiredOption("--idempotency-key <key>", "Required create idempotency key").option("--description <description>").option("--notes <notes>").option("--member-id <memberId>").option("--status <status>").option("--priority <priority>").option("--due-date <date>", "ISO-8601 date (YYYY-MM-DD)").action(async (opts, cmd) => {
15078
+ const idempotencyKey = idempotencyKeySchema.parse(opts.idempotencyKey);
15079
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
15080
+ const organizationId = resolveOrganizationId(context.organizationId);
15081
+ await runGraphqlMutationCommand({
15082
+ command: "automations.create",
15083
+ operationName: "AutomationsCreate",
15084
+ runtimeOptions: context.runtimeOptions,
15085
+ field: "create_automation",
15086
+ variableTypes: {
15087
+ organization_id: "ID!",
15088
+ input: "CreateAutomationInput!",
15089
+ idempotency_key: "String!"
15090
+ },
15091
+ variables: {
15092
+ organization_id: organizationId,
15093
+ input: {
15094
+ summary: idSchema14.parse(opts.summary),
15095
+ ai_task_config: parseJson(String(opts.aiTaskConfig), "--ai-task-config"),
15096
+ ...opts.description !== void 0 ? { description: String(opts.description) } : {},
15097
+ ...opts.notes !== void 0 ? { notes: String(opts.notes) } : {},
15098
+ ...opts.memberId !== void 0 ? { member_id: idSchema14.parse(opts.memberId) } : {},
15099
+ ...opts.status !== void 0 ? { status: String(opts.status) } : {},
15100
+ ...opts.priority !== void 0 ? { priority: String(opts.priority) } : {},
15101
+ ...opts.dueDate !== void 0 ? { due_date: isoDateSchema.parse(opts.dueDate) } : {}
15102
+ },
15103
+ idempotency_key: idempotencyKey
15104
+ },
15105
+ transformMutationPayload: normalizePersistedCreatePayload
15106
+ });
15107
+ });
15108
+ automations.command("show").description("Read one persisted Automation by id").requiredOption("--id <id>", "Automation id").action(async (opts, cmd) => {
15109
+ const id = idSchema14.parse(opts.id);
15110
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
15111
+ const organizationId = resolveOrganizationId(context.organizationId);
15112
+ await runGraphqlQueryCommand({
15113
+ command: "automations.show",
15114
+ operationName: "AutomationsShow",
15115
+ runtimeOptions: context.runtimeOptions,
15116
+ field: "automation",
15117
+ variables: { organization_id: organizationId, id },
15118
+ variableTypes: { organization_id: "ID!", id: "ID!" },
15119
+ selectionSet: AUTOMATION_SELECTION,
15120
+ isShow: true
15121
+ });
15122
+ });
15123
+ const skills = program.commands.find((command) => command.name() === "skills");
15124
+ if (!skills) {
15125
+ throw new Error("Skills command must be registered before Atlas authoring commands.");
15126
+ }
15127
+ skills.command("create").description("Create a Skill through the API-owned createSkill contract").requiredOption("--name <name>").requiredOption("--scope <scope>", "ADMIN_GLOBAL or MEMBER_PERSONAL").requiredOption("--idempotency-key <key>", "Required create idempotency key").option("--emoji <emoji>").option("--description <description>").action(async (opts, cmd) => {
15128
+ const idempotencyKey = idempotencyKeySchema.parse(opts.idempotencyKey);
15129
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
15130
+ const organizationId = resolveOrganizationId(context.organizationId);
15131
+ await runGraphqlMutationCommand({
15132
+ command: "skills.create",
15133
+ operationName: "SkillsCreate",
15134
+ runtimeOptions: context.runtimeOptions,
15135
+ field: "create_skill",
15136
+ variableTypes: {
15137
+ organization_id: "ID!",
15138
+ input: "CreateSkillInput!",
15139
+ idempotency_key: "String!"
15140
+ },
15141
+ variables: {
15142
+ organization_id: organizationId,
15143
+ input: {
15144
+ name: idSchema14.parse(opts.name),
15145
+ scope: skillScopeSchema.parse(opts.scope),
15146
+ ...opts.emoji !== void 0 ? { emoji: String(opts.emoji) } : {},
15147
+ ...opts.description !== void 0 ? { description: String(opts.description) } : {}
15148
+ },
15149
+ idempotency_key: idempotencyKey
15150
+ },
15151
+ transformMutationPayload: normalizePersistedCreatePayload
15152
+ });
15153
+ });
15154
+ }
15155
+
14840
15156
  // src/commands/discovery.ts
14841
15157
  import { existsSync as existsSync3, readFileSync } from "fs";
14842
15158
  import { join as join3 } from "path";
@@ -14857,6 +15173,8 @@ var PRIMARY_NAMESPACES = [
14857
15173
  "rocks",
14858
15174
  "meetings",
14859
15175
  "members",
15176
+ "agents",
15177
+ "automations",
14860
15178
  "skills",
14861
15179
  "teams",
14862
15180
  "issues",
@@ -14970,20 +15288,62 @@ var NAMESPACE_DOCS = {
14970
15288
  skills: {
14971
15289
  name: "skills",
14972
15290
  tier: "primary",
14973
- description: "Read-only Skill record proof surfaces.",
15291
+ description: "Skill record readback and bounded create operations.",
14974
15292
  examples: [
14975
15293
  "wave skills list --json",
14976
15294
  "wave skills list --scope ADMIN_GLOBAL --json",
14977
- "wave skills show --id 123 --json"
15295
+ "wave skills show --id 123 --json",
15296
+ 'wave skills create --name "Weekly planning" --scope MEMBER_PERSONAL --idempotency-key skill-create-001'
14978
15297
  ],
14979
15298
  schema: {
14980
15299
  output: "json-envelope-default",
14981
- readOnly: true,
15300
+ mutates: true,
14982
15301
  safety: [
14983
15302
  "Uses API-owned Skill GraphQL read fields only.",
14984
- "Does not create, update, destroy, archive, approve, or apply Skill records."
15303
+ "Create calls only createSkill with an explicit idempotency key.",
15304
+ "Skill create supports the API-defined ADMIN_GLOBAL and MEMBER_PERSONAL scopes.",
15305
+ "Does not update, destroy, archive, approve, or apply Skill records."
14985
15306
  ],
14986
- commands: ["list", "show"]
15307
+ commands: ["list", "show", "create"]
15308
+ }
15309
+ },
15310
+ agents: {
15311
+ name: "agents",
15312
+ tier: "primary",
15313
+ description: "Bounded Agent create and persisted readback operations.",
15314
+ examples: [
15315
+ 'wave agents create --name "Planning helper" --idempotency-key agent-create-001',
15316
+ "wave agents show --id 123"
15317
+ ],
15318
+ schema: {
15319
+ output: "json-envelope-default",
15320
+ mutates: true,
15321
+ safety: [
15322
+ "Create calls only createAgent with an explicit idempotency key.",
15323
+ "Create preserves API-owned defaults by sending only supplied typed Agent fields.",
15324
+ "Show uses the API-owned agent query by id; no slug fallback is implemented."
15325
+ ],
15326
+ commands: ["create", "show"]
15327
+ }
15328
+ },
15329
+ automations: {
15330
+ name: "automations",
15331
+ tier: "primary",
15332
+ description: "Bounded Automation create and persisted readback operations.",
15333
+ examples: [
15334
+ `wave automations create --summary "Weekly review" --ai-task-config '{"prompt":"Review tasks"}' --idempotency-key automation-create-001`,
15335
+ "wave automations show --id 123"
15336
+ ],
15337
+ schema: {
15338
+ output: "json-envelope-default",
15339
+ mutates: true,
15340
+ safety: [
15341
+ "Create calls only createAutomation with an explicit idempotency key.",
15342
+ "Only the API-defined ai_task_config field accepts validated JSON.",
15343
+ "Does not create a project Task, run an Automation, or invoke AI OS actions.",
15344
+ "Show uses the API-owned automation query by id; no slug fallback is implemented."
15345
+ ],
15346
+ commands: ["create", "show"]
14987
15347
  }
14988
15348
  },
14989
15349
  broadcast: {
@@ -15797,7 +16157,7 @@ function attachDiscoveryHelp(program) {
15797
16157
  }
15798
16158
 
15799
16159
  // src/version.ts
15800
- var CLI_VERSION = "0.1.60";
16160
+ var CLI_VERSION = "0.1.62";
15801
16161
 
15802
16162
  // src/cli.ts
15803
16163
  function buildCli(options) {
@@ -15852,6 +16212,7 @@ function buildCli(options) {
15852
16212
  registerMeetingCommands(program);
15853
16213
  registerMemberCommands(program);
15854
16214
  registerSkillCommands(program);
16215
+ registerAtlasAuthoringCommands(program);
15855
16216
  registerTeamCommands(program);
15856
16217
  registerOrganizationCommands(program);
15857
16218
  registerIssueCommands(program);