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