@ted-galago/wave-cli 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -187,6 +187,16 @@ function inferStatusFromGraphqlErrors(errors) {
187
187
  if (!Array.isArray(errors) || errors.length === 0) {
188
188
  return 400;
189
189
  }
190
+ const codes = extractGraphqlErrorCodes(errors);
191
+ if (codes.includes("UNAUTHORIZED")) {
192
+ return 401;
193
+ }
194
+ if (codes.includes("NOT_FOUND")) {
195
+ return 404;
196
+ }
197
+ if (codes.includes("INVALID_SCOPE") || codes.includes("UNSUPPORTED_BRANCH")) {
198
+ return 400;
199
+ }
190
200
  const text = JSON.stringify(errors).toLowerCase();
191
201
  if (text.includes("unauthorized") || text.includes("not authenticated")) {
192
202
  return 401;
@@ -202,13 +212,260 @@ function inferStatusFromGraphqlErrors(errors) {
202
212
  }
203
213
  return 400;
204
214
  }
215
+ function extractGraphqlErrorCodes(errors) {
216
+ if (!Array.isArray(errors)) {
217
+ return [];
218
+ }
219
+ const codes = errors.map((entry) => {
220
+ if (!entry || typeof entry !== "object") return "";
221
+ const extensions = entry.extensions;
222
+ if (!extensions || typeof extensions !== "object") return "";
223
+ return String(extensions.code ?? "").toUpperCase();
224
+ }).filter((code) => code.length > 0);
225
+ return Array.from(new Set(codes));
226
+ }
227
+ function errorCodeFromGraphqlErrors(errors, status) {
228
+ const codes = extractGraphqlErrorCodes(errors);
229
+ if (codes.includes("UNAUTHORIZED")) {
230
+ return "missing_auth";
231
+ }
232
+ if (codes.includes("NOT_FOUND")) {
233
+ return "not_found";
234
+ }
235
+ if (codes.includes("INVALID_SCOPE")) {
236
+ return "invalid_scope";
237
+ }
238
+ if (codes.includes("UNSUPPORTED_BRANCH")) {
239
+ return "unsupported_branch";
240
+ }
241
+ if (status === 401) {
242
+ return "missing_auth";
243
+ }
244
+ if (status === 403) {
245
+ return "forbidden";
246
+ }
247
+ return `http_${status}`;
248
+ }
205
249
  function errorFromGraphqlErrors(errors, status) {
206
250
  return {
207
- code: status === 401 ? "missing_auth" : status === 403 ? "forbidden" : `http_${status}`,
251
+ code: errorCodeFromGraphqlErrors(errors, status),
208
252
  message: "GraphQL request failed.",
209
253
  details: { errors }
210
254
  };
211
255
  }
256
+ function findParentContextFromVariables(variables) {
257
+ const directParent = Object.entries(variables).find(([key, value]) => {
258
+ if (key === "organization_id" || key === "organizationId") return false;
259
+ if (!key.endsWith("_id") && !key.endsWith("Id")) return false;
260
+ return typeof value === "string" && value.trim().length > 0;
261
+ });
262
+ if (directParent) {
263
+ return { parentKey: directParent[0], parentId: String(directParent[1]) };
264
+ }
265
+ const params = variables.params && typeof variables.params === "object" && !Array.isArray(variables.params) ? variables.params : void 0;
266
+ if (!params) {
267
+ return {};
268
+ }
269
+ const rootObjectEntry = Object.entries(params).find(
270
+ ([, value]) => value && typeof value === "object" && !Array.isArray(value)
271
+ );
272
+ if (!rootObjectEntry) {
273
+ return {};
274
+ }
275
+ const [, rootObject] = rootObjectEntry;
276
+ const parentEntry = Object.entries(rootObject).find(([key, value]) => {
277
+ if (!key.endsWith("_id") && !key.endsWith("Id")) return false;
278
+ return typeof value === "string" && value.trim().length > 0;
279
+ });
280
+ if (!parentEntry) {
281
+ return {};
282
+ }
283
+ return { parentKey: parentEntry[0], parentId: String(parentEntry[1]) };
284
+ }
285
+ function shouldAddSparse422Diagnostic(status, mutationPayload) {
286
+ if (status !== 422) {
287
+ return false;
288
+ }
289
+ const rawErrors = mutationPayload.errors && typeof mutationPayload.errors === "object" ? mutationPayload.errors : void 0;
290
+ if (!rawErrors) {
291
+ return true;
292
+ }
293
+ const dataErrors = rawErrors.data;
294
+ return Array.isArray(dataErrors) && dataErrors.length === 0;
295
+ }
296
+ function buildSparse422Diagnostic(input) {
297
+ const parentContext = findParentContextFromVariables(input.variables);
298
+ return {
299
+ operation: input.command,
300
+ field: input.field,
301
+ context: parentContext.parentKey && parentContext.parentId ? {
302
+ parentKey: parentContext.parentKey,
303
+ parentId: parentContext.parentId
304
+ } : {
305
+ message: "No explicit parent id found in request variables."
306
+ }
307
+ };
308
+ }
309
+ function isFeedbackCreateCommand(input) {
310
+ return input.operationType === "mutation" && input.command === "feedbacks.create";
311
+ }
312
+ function asRecord(value) {
313
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
314
+ return null;
315
+ }
316
+ return value;
317
+ }
318
+ function asNonEmptyString(value) {
319
+ if (typeof value !== "string") {
320
+ return null;
321
+ }
322
+ const trimmed = value.trim();
323
+ return trimmed.length > 0 ? trimmed : null;
324
+ }
325
+ function extractFeedbackIdentity(variables) {
326
+ const organizationId = asNonEmptyString(variables.organization_id) ?? asNonEmptyString(variables.organizationId);
327
+ const params = asRecord(variables.params);
328
+ const feedback = params ? asRecord(params.feedback) : null;
329
+ const name = feedback ? asNonEmptyString(feedback.name) : null;
330
+ const quarter = feedback ? asNonEmptyString(feedback.quarter) : null;
331
+ const year = feedback ? asNonEmptyString(feedback.year) : null;
332
+ if (!organizationId || !name || !quarter || !year) {
333
+ return null;
334
+ }
335
+ return {
336
+ organizationId,
337
+ name,
338
+ quarter,
339
+ year
340
+ };
341
+ }
342
+ function collectMessageStrings(value) {
343
+ if (typeof value === "string") {
344
+ return [value];
345
+ }
346
+ if (Array.isArray(value)) {
347
+ return value.flatMap((entry) => collectMessageStrings(entry));
348
+ }
349
+ if (!value || typeof value !== "object") {
350
+ return [];
351
+ }
352
+ return Object.values(value).flatMap(
353
+ (entry) => collectMessageStrings(entry)
354
+ );
355
+ }
356
+ function isDuplicateFeedbackMutationError(mutationPayload) {
357
+ const messages = collectMessageStrings(mutationPayload.errors);
358
+ return messages.some(
359
+ (message) => message.toLowerCase().includes("already been taken")
360
+ );
361
+ }
362
+ function extractFeedbackListNode(graph) {
363
+ const data = asRecord(graph.data);
364
+ const feedbacks = data ? asRecord(data.feedbacks) : null;
365
+ if (!feedbacks) {
366
+ return null;
367
+ }
368
+ const rows = Array.isArray(feedbacks.data) ? feedbacks.data : [];
369
+ const first = rows.find((entry) => asRecord(entry));
370
+ return first ? first : null;
371
+ }
372
+ function buildFeedbackReuseEnvelope(params) {
373
+ return {
374
+ envelope: buildEnvelope({
375
+ ok: true,
376
+ command: params.command,
377
+ status: params.status,
378
+ data: {
379
+ [params.field]: {
380
+ ok: true,
381
+ status: params.status,
382
+ errorCode: null,
383
+ data: {
384
+ data: params.feedbackNode
385
+ },
386
+ errors: null,
387
+ reusedExisting: true,
388
+ idempotency: {
389
+ reason: params.reason
390
+ }
391
+ }
392
+ },
393
+ error: null,
394
+ requestId: params.requestId
395
+ }),
396
+ exitCode: EXIT_CODES.success
397
+ };
398
+ }
399
+ function buildFeedbackFindRequestBody(command, identity) {
400
+ return buildGraphqlBody({
401
+ config: {
402
+ baseUrl: "http://localhost",
403
+ token: "placeholder",
404
+ timeoutMs: 1e3,
405
+ debug: false
406
+ },
407
+ command,
408
+ operationType: "query",
409
+ field: "feedbacks",
410
+ variables: {
411
+ organization_id: identity.organizationId,
412
+ name: identity.name,
413
+ quarter: identity.quarter,
414
+ year: identity.year,
415
+ page: 1,
416
+ per: 1
417
+ },
418
+ selectionSet: "{ data { id type attributes } count currentPage totalPages }"
419
+ });
420
+ }
421
+ async function requestGraphqlHttp(params) {
422
+ const response = await fetch(params.url, {
423
+ method: "POST",
424
+ headers: {
425
+ Authorization: `Bearer ${params.input.config.token}`,
426
+ Accept: "application/json",
427
+ "Content-Type": "application/json",
428
+ "X-Origin": "langgraph-cli",
429
+ "X-Request-Id": params.requestId,
430
+ ...params.input.config.agentName ? { "X-Agent-Name": params.input.config.agentName } : {},
431
+ ...params.input.config.agentRunId ? { "X-Agent-Run-Id": params.input.config.agentRunId } : {}
432
+ },
433
+ body: JSON.stringify(params.body),
434
+ signal: params.controller.signal
435
+ });
436
+ const responseRequestId = response.headers.get("x-request-id") ?? params.requestId;
437
+ const text = await response.text();
438
+ const payload = text ? parseJsonSafely(text) : null;
439
+ const graph = payload && typeof payload === "object" ? payload : {};
440
+ return {
441
+ status: response.status,
442
+ requestId: responseRequestId,
443
+ graph
444
+ };
445
+ }
446
+ async function findExistingFeedback(params) {
447
+ const command = `${params.input.command}.find-existing`;
448
+ const body = buildFeedbackFindRequestBody(command, params.identity);
449
+ const http = await requestGraphqlHttp({
450
+ input: params.input,
451
+ url: params.url,
452
+ requestId: params.requestId,
453
+ body,
454
+ controller: params.controller
455
+ });
456
+ const gqlErrors = http.graph.errors;
457
+ if (Array.isArray(gqlErrors) && gqlErrors.length > 0) {
458
+ return null;
459
+ }
460
+ const feedbackNode = extractFeedbackListNode(http.graph);
461
+ if (!feedbackNode) {
462
+ return null;
463
+ }
464
+ return {
465
+ feedbackNode,
466
+ requestId: http.requestId
467
+ };
468
+ }
212
469
  function graphqlTypeForValue(value) {
213
470
  if (Array.isArray(value)) {
214
471
  const firstNonNull = value.find((item) => item !== null && item !== void 0);
@@ -251,9 +508,14 @@ function normalizeGraphqlVariables(variables) {
251
508
  function buildGraphqlBody(input) {
252
509
  const graphqlField = toCamelCase(input.field);
253
510
  const graphqlVariables = normalizeGraphqlVariables(input.variables);
254
- const operationName = graphqlOperationName(input.command);
511
+ const graphqlVariableTypes = normalizeGraphqlVariables(input.variableTypes ?? {});
512
+ const operationName = input.operationName ?? graphqlOperationName(input.command);
255
513
  const variableEntries = Object.entries(graphqlVariables).filter(([, value]) => value !== void 0);
256
- const variableDecl = variableEntries.map(([name, value]) => `$${name}: ${withNonNull(graphqlTypeForVariable(name, value))}`).join(", ");
514
+ const variableDecl = variableEntries.map(([name, value]) => {
515
+ const overriddenType = graphqlVariableTypes[name];
516
+ const typeName = typeof overriddenType === "string" && overriddenType.trim().length > 0 ? overriddenType.trim() : graphqlTypeForVariable(name, value);
517
+ return `$${name}: ${withNonNull(typeName)}`;
518
+ }).join(", ");
257
519
  const fieldArgs = variableEntries.map(([name]) => `${name}: $${name}`).join(", ");
258
520
  const signature = variableDecl.length > 0 ? `(${variableDecl})` : "";
259
521
  const args = fieldArgs.length > 0 ? `(${fieldArgs})` : "";
@@ -278,24 +540,37 @@ async function graphqlRequest(input) {
278
540
  const controller = new AbortController();
279
541
  const timeoutId = setTimeout(() => controller.abort(), input.config.timeoutMs);
280
542
  try {
281
- const response = await fetch(url, {
282
- method: "POST",
283
- headers: {
284
- Authorization: `Bearer ${input.config.token}`,
285
- Accept: "application/json",
286
- "Content-Type": "application/json",
287
- "X-Origin": "langgraph-cli",
288
- "X-Request-Id": requestId,
289
- ...input.config.agentName ? { "X-Agent-Name": input.config.agentName } : {},
290
- ...input.config.agentRunId ? { "X-Agent-Run-Id": input.config.agentRunId } : {}
291
- },
292
- body: JSON.stringify(body),
293
- signal: controller.signal
543
+ if (isFeedbackCreateCommand(input)) {
544
+ const feedbackIdentity = extractFeedbackIdentity(input.variables);
545
+ if (feedbackIdentity) {
546
+ const existing = await findExistingFeedback({
547
+ input,
548
+ url,
549
+ requestId,
550
+ controller,
551
+ identity: feedbackIdentity
552
+ });
553
+ if (existing) {
554
+ return buildFeedbackReuseEnvelope({
555
+ command: input.command,
556
+ field: input.field,
557
+ status: 200,
558
+ requestId: existing.requestId,
559
+ feedbackNode: existing.feedbackNode,
560
+ reason: "preexisting"
561
+ });
562
+ }
563
+ }
564
+ }
565
+ const http = await requestGraphqlHttp({
566
+ input,
567
+ url,
568
+ requestId,
569
+ body,
570
+ controller
294
571
  });
295
- const responseRequestId = response.headers.get("x-request-id") ?? requestId;
296
- const text = await response.text();
297
- const payload = text ? parseJsonSafely(text) : null;
298
- const graph = payload && typeof payload === "object" ? payload : {};
572
+ const responseRequestId = http.requestId;
573
+ const graph = http.graph;
299
574
  const gqlErrors = graph.errors;
300
575
  const gqlData = graph.data && typeof graph.data === "object" ? graph.data : {};
301
576
  if (Array.isArray(gqlErrors) && gqlErrors.length > 0) {
@@ -318,6 +593,36 @@ async function graphqlRequest(input) {
318
593
  const ok = Boolean(mutationPayload.ok);
319
594
  const status = typeof mutationPayload.status === "number" ? mutationPayload.status : ok ? 200 : 400;
320
595
  if (!ok) {
596
+ if (isFeedbackCreateCommand(input) && isDuplicateFeedbackMutationError(mutationPayload)) {
597
+ const feedbackIdentity = extractFeedbackIdentity(input.variables);
598
+ if (feedbackIdentity) {
599
+ const existing = await findExistingFeedback({
600
+ input,
601
+ url,
602
+ requestId: responseRequestId,
603
+ controller,
604
+ identity: feedbackIdentity
605
+ });
606
+ if (existing) {
607
+ return buildFeedbackReuseEnvelope({
608
+ command: input.command,
609
+ field: input.field,
610
+ status: 200,
611
+ requestId: existing.requestId,
612
+ feedbackNode: existing.feedbackNode,
613
+ reason: "duplicate_race"
614
+ });
615
+ }
616
+ }
617
+ }
618
+ const mutationErrors = mutationPayload.errors ?? null;
619
+ const details = {
620
+ errors: mutationErrors,
621
+ data: mutationPayload.data ?? null
622
+ };
623
+ if (shouldAddSparse422Diagnostic(status, mutationPayload)) {
624
+ details.fallbackDiagnostic = buildSparse422Diagnostic(input);
625
+ }
321
626
  return {
322
627
  envelope: buildEnvelope({
323
628
  ok: false,
@@ -329,10 +634,7 @@ async function graphqlRequest(input) {
329
634
  mutationPayload.errorCode ?? mutationPayload.error_code ?? `http_${status}`
330
635
  ),
331
636
  message: "Mutation failed.",
332
- details: {
333
- errors: mutationPayload.errors ?? null,
334
- data: mutationPayload.data ?? null
335
- }
637
+ details
336
638
  },
337
639
  requestId: responseRequestId
338
640
  }),
@@ -372,7 +674,7 @@ async function graphqlRequest(input) {
372
674
  envelope: buildEnvelope({
373
675
  ok: true,
374
676
  command: input.command,
375
- status: response.ok ? response.status : 200,
677
+ status: http.status >= 200 && http.status < 300 ? http.status : 200,
376
678
  data: { [input.field]: fieldPayload ?? null },
377
679
  error: null,
378
680
  requestId: responseRequestId
@@ -489,12 +791,33 @@ async function runGraphqlQueryCommand(input) {
489
791
  const result = await graphqlRequest({
490
792
  config,
491
793
  command: input.command,
794
+ operationName: input.operationName,
492
795
  operationType: "query",
493
796
  field: input.field,
494
797
  variables: input.variables ?? {},
798
+ variableTypes: input.variableTypes,
495
799
  selectionSet: input.selectionSet ?? defaultQuerySelectionSet(input.field, Boolean(input.isList)),
496
800
  isShow: input.isShow
497
801
  });
802
+ if (result.envelope.ok && input.transformData && result.envelope.data) {
803
+ const dataRecord = result.envelope.data;
804
+ const transformed = input.transformData(dataRecord[input.field]);
805
+ result.envelope.data = {
806
+ ...dataRecord,
807
+ [input.field]: transformed
808
+ };
809
+ if (input.isShow && (transformed === null || transformed === void 0)) {
810
+ result.envelope.ok = false;
811
+ result.envelope.status = 404;
812
+ result.envelope.data = null;
813
+ result.envelope.error = {
814
+ code: "not_found",
815
+ message: "Record not found.",
816
+ details: {}
817
+ };
818
+ result.exitCode = EXIT_CODES.notFound;
819
+ }
820
+ }
498
821
  printEnvelopeAndExit(result);
499
822
  } catch (error) {
500
823
  if (error instanceof CliError) {
@@ -527,9 +850,11 @@ async function runGraphqlMutationCommand(input) {
527
850
  const result = await graphqlRequest({
528
851
  config,
529
852
  command: input.command,
853
+ operationName: input.operationName,
530
854
  operationType: "mutation",
531
855
  field: input.field,
532
856
  variables: input.variables ?? {},
857
+ variableTypes: input.variableTypes,
533
858
  selectionSet: input.selectionSet ?? "{ ok status errorCode data errors }"
534
859
  });
535
860
  printEnvelopeAndExit(result);
@@ -839,7 +1164,7 @@ var dtoHelpCatalog = {
839
1164
  create: [
840
1165
  ["member_id", "string"],
841
1166
  ["name", "string"],
842
- ["type", "MeetingType"],
1167
+ ["type", "enum(TeamMeeting|OneOnOneMeeting)"],
843
1168
  ["date", "string"],
844
1169
  ["status", "enum(upcoming|active|completed)"],
845
1170
  ["start_time", "number"],
@@ -1464,37 +1789,70 @@ function registerEntityCrudCommands(program, config) {
1464
1789
  const id = idSchema.parse(opts.id);
1465
1790
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1466
1791
  const organizationId = resolveOrganizationId(context.organizationId);
1792
+ const defaultCommand = `${config.command}.show`;
1793
+ const defaultField = config.resourcePath === "feedback" ? "feedback" : toSingularResourceName(config.resourcePath);
1794
+ const defaultVariables = normalizeGraphqlVariables2({
1795
+ organization_id: organizationId,
1796
+ id
1797
+ });
1798
+ const showQuery = config.showQueryFactory ? config.showQueryFactory({
1799
+ command: defaultCommand,
1800
+ field: defaultField,
1801
+ variables: defaultVariables,
1802
+ id,
1803
+ organizationId
1804
+ }) : void 0;
1467
1805
  await runGraphqlQueryCommand({
1468
- command: `${config.command}.show`,
1806
+ command: showQuery?.command ?? defaultCommand,
1469
1807
  runtimeOptions: context.runtimeOptions,
1470
- field: config.resourcePath === "feedback" ? "feedback" : toSingularResourceName(config.resourcePath),
1471
- variables: normalizeGraphqlVariables2({
1472
- organization_id: organizationId,
1473
- id
1474
- }),
1475
- isShow: true
1808
+ operationName: showQuery?.operationName,
1809
+ field: showQuery?.field ?? defaultField,
1810
+ variables: showQuery?.variables ?? defaultVariables,
1811
+ variableTypes: showQuery?.variableTypes,
1812
+ selectionSet: showQuery?.selectionSet,
1813
+ isShow: true,
1814
+ transformData: showQuery?.transformData
1476
1815
  });
1477
1816
  });
1478
1817
  entityCommand.command("create").requiredOption("--data-json <dataJson>", createHelp4).action(async (opts, cmd) => {
1479
1818
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1480
1819
  const organizationId = resolveOrganizationId(context.organizationId);
1481
- const body = normalizeBody(String(opts.dataJson), config.rootKey);
1820
+ let body = normalizeBody(String(opts.dataJson), config.rootKey);
1821
+ if (config.normalizeCreateBody) {
1822
+ body = config.normalizeCreateBody(body);
1823
+ }
1482
1824
  assertRequiredCreateFields(body, config.rootKey, config.requiredCreateFields);
1825
+ const defaultCommand = `${config.command}.create`;
1826
+ const defaultField = `create_${toSingularResourceName(config.resourcePath)}`;
1827
+ const defaultVariables = {
1828
+ organization_id: organizationId,
1829
+ params: body
1830
+ };
1831
+ const createMutation = config.createMutationFactory ? config.createMutationFactory({
1832
+ command: defaultCommand,
1833
+ field: defaultField,
1834
+ variables: defaultVariables,
1835
+ body,
1836
+ organizationId
1837
+ }) : void 0;
1483
1838
  await runGraphqlMutationCommand({
1484
- command: `${config.command}.create`,
1839
+ command: createMutation?.command ?? defaultCommand,
1485
1840
  runtimeOptions: context.runtimeOptions,
1486
- field: `create_${toSingularResourceName(config.resourcePath)}`,
1487
- variables: {
1488
- organization_id: organizationId,
1489
- params: body
1490
- }
1841
+ operationName: createMutation?.operationName,
1842
+ field: createMutation?.field ?? defaultField,
1843
+ variables: createMutation?.variables ?? defaultVariables,
1844
+ variableTypes: createMutation?.variableTypes,
1845
+ selectionSet: createMutation?.selectionSet
1491
1846
  });
1492
1847
  });
1493
1848
  entityCommand.command("update").requiredOption("--id <id>").requiredOption("--data-json <dataJson>", updateHelp5).action(async (opts, cmd) => {
1494
1849
  const id = idSchema.parse(opts.id);
1495
1850
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1496
1851
  const organizationId = resolveOrganizationId(context.organizationId);
1497
- const body = normalizeBody(String(opts.dataJson), config.rootKey);
1852
+ let body = normalizeBody(String(opts.dataJson), config.rootKey);
1853
+ if (config.normalizeUpdateBody) {
1854
+ body = config.normalizeUpdateBody(body);
1855
+ }
1498
1856
  const singular = toSingularResourceName(config.resourcePath);
1499
1857
  await runGraphqlMutationCommand({
1500
1858
  command: `${config.command}.update`,
@@ -1646,7 +2004,8 @@ function registerProjectCommands(program) {
1646
2004
  member_id: opts.memberId,
1647
2005
  ...extra
1648
2006
  }),
1649
- isList: true
2007
+ isList: true,
2008
+ selectionSet: "{ data { id type } count currentPage totalPages }"
1650
2009
  });
1651
2010
  });
1652
2011
  projects.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
@@ -1661,7 +2020,8 @@ function registerProjectCommands(program) {
1661
2020
  organization_id: organizationId,
1662
2021
  id
1663
2022
  },
1664
- isShow: true
2023
+ isShow: true,
2024
+ selectionSet: "{ id type }"
1665
2025
  });
1666
2026
  });
1667
2027
  projects.command("create").requiredOption("--data-json <dataJson>", projectCreateDataJsonHelp).action(async (opts, cmd) => {
@@ -1691,6 +2051,11 @@ function registerProjectCommands(program) {
1691
2051
  organization_id: organizationId,
1692
2052
  project_id: id,
1693
2053
  params: body
2054
+ },
2055
+ variableTypes: {
2056
+ organization_id: "ID!",
2057
+ project_id: "ID!",
2058
+ params: "UpdateProjectParamsInput!"
1694
2059
  }
1695
2060
  });
1696
2061
  });
@@ -1803,8 +2168,142 @@ function registerRockCommands(program) {
1803
2168
  import { z as z6 } from "zod";
1804
2169
  var idSchema5 = z6.string().min(1);
1805
2170
  var notesSchema = z6.string().min(1);
2171
+ var MEETING_TYPES = /* @__PURE__ */ new Set(["TeamMeeting", "OneOnOneMeeting"]);
2172
+ var MEETING_STATUSES = /* @__PURE__ */ new Set(["upcoming", "active", "completed"]);
2173
+ var MEETING_REPEATS = /* @__PURE__ */ new Set(["never", "weekly", "biweekly", "monthly", "quarterly"]);
1806
2174
  var createHelp2 = buildDataJsonHelp("meeting", "create") ?? 'JSON object for meeting or {"meeting": {...}}';
1807
2175
  var updateHelp2 = buildDataJsonHelp("meeting", "update") ?? 'JSON object for meeting or {"meeting": {...}}';
2176
+ function asNonEmptyString2(value) {
2177
+ if (typeof value !== "string") {
2178
+ return void 0;
2179
+ }
2180
+ const trimmed = value.trim();
2181
+ return trimmed.length > 0 ? trimmed : void 0;
2182
+ }
2183
+ function toFiniteNumber(value, field) {
2184
+ if (value === void 0 || value === null) {
2185
+ return void 0;
2186
+ }
2187
+ if (typeof value === "number" && Number.isFinite(value)) {
2188
+ return value;
2189
+ }
2190
+ if (typeof value === "string") {
2191
+ const trimmed = value.trim();
2192
+ if (trimmed.length === 0) {
2193
+ return void 0;
2194
+ }
2195
+ const parsed = Number(trimmed);
2196
+ if (Number.isFinite(parsed)) {
2197
+ return parsed;
2198
+ }
2199
+ }
2200
+ throw new CliError({
2201
+ message: `Invalid ${field}. Expected a numeric value.`,
2202
+ kind: "invalid_args",
2203
+ status: 400,
2204
+ exitCode: EXIT_CODES.invalidArgs
2205
+ });
2206
+ }
2207
+ function toStringArray(value, field) {
2208
+ if (value === void 0 || value === null) {
2209
+ return void 0;
2210
+ }
2211
+ const items = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : null;
2212
+ if (!items) {
2213
+ throw new CliError({
2214
+ message: `Invalid ${field}. Expected an array or comma-separated string.`,
2215
+ kind: "invalid_args",
2216
+ status: 400,
2217
+ exitCode: EXIT_CODES.invalidArgs
2218
+ });
2219
+ }
2220
+ const normalized = items.map((item) => String(item).trim()).filter((item) => item.length > 0);
2221
+ return normalized.length > 0 ? normalized : void 0;
2222
+ }
2223
+ function normalizeMeetingCreateBody(body) {
2224
+ const entity = body.meeting;
2225
+ if (!entity || typeof entity !== "object" || Array.isArray(entity)) {
2226
+ throw new CliError({
2227
+ message: 'Invalid payload. Expected object at "meeting".',
2228
+ kind: "invalid_args",
2229
+ status: 400,
2230
+ exitCode: EXIT_CODES.invalidArgs
2231
+ });
2232
+ }
2233
+ const meeting = { ...entity };
2234
+ const type = asNonEmptyString2(meeting.type);
2235
+ if (!type || !MEETING_TYPES.has(type)) {
2236
+ throw new CliError({
2237
+ message: "Invalid meeting.type. Use one of: TeamMeeting, OneOnOneMeeting.",
2238
+ kind: "invalid_args",
2239
+ status: 400,
2240
+ exitCode: EXIT_CODES.invalidArgs,
2241
+ details: { field: "meeting.type", allowed: Array.from(MEETING_TYPES) }
2242
+ });
2243
+ }
2244
+ const memberId = asNonEmptyString2(meeting.member_id);
2245
+ const date = asNonEmptyString2(meeting.date);
2246
+ const startTime = toFiniteNumber(meeting.start_time, "meeting.start_time");
2247
+ const missingRequired = [];
2248
+ if (!memberId) missingRequired.push("member_id");
2249
+ if (!date) missingRequired.push("date");
2250
+ if (startTime === void 0) missingRequired.push("start_time");
2251
+ if (missingRequired.length > 0) {
2252
+ throw new CliError({
2253
+ message: `Missing required create fields for meeting: ${missingRequired.join(", ")}.`,
2254
+ kind: "invalid_args",
2255
+ status: 400,
2256
+ exitCode: EXIT_CODES.invalidArgs,
2257
+ details: { requiredFields: ["member_id", "date", "start_time"], rootKey: "meeting" }
2258
+ });
2259
+ }
2260
+ const status = asNonEmptyString2(meeting.status);
2261
+ if (status && !MEETING_STATUSES.has(status)) {
2262
+ throw new CliError({
2263
+ message: "Invalid meeting.status. Use one of: upcoming, active, completed.",
2264
+ kind: "invalid_args",
2265
+ status: 400,
2266
+ exitCode: EXIT_CODES.invalidArgs,
2267
+ details: { field: "meeting.status", allowed: Array.from(MEETING_STATUSES) }
2268
+ });
2269
+ }
2270
+ const repeats = asNonEmptyString2(meeting.repeats) ?? "never";
2271
+ if (!MEETING_REPEATS.has(repeats)) {
2272
+ throw new CliError({
2273
+ message: "Invalid meeting.repeats. Use one of: never, weekly, biweekly, monthly, quarterly.",
2274
+ kind: "invalid_args",
2275
+ status: 400,
2276
+ exitCode: EXIT_CODES.invalidArgs,
2277
+ details: { field: "meeting.repeats", allowed: Array.from(MEETING_REPEATS) }
2278
+ });
2279
+ }
2280
+ const teamsIds = toStringArray(meeting.teams_ids, "meeting.teams_ids");
2281
+ if (type === "TeamMeeting" && (!teamsIds || teamsIds.length === 0)) {
2282
+ throw new CliError({
2283
+ message: "Missing required create fields for meeting: teams_ids.",
2284
+ kind: "invalid_args",
2285
+ status: 400,
2286
+ exitCode: EXIT_CODES.invalidArgs,
2287
+ details: { requiredFields: ["teams_ids"], rootKey: "meeting" }
2288
+ });
2289
+ }
2290
+ const endTime = toFiniteNumber(meeting.end_time, "meeting.end_time");
2291
+ meeting.type = type;
2292
+ meeting.member_id = memberId;
2293
+ meeting.date = date;
2294
+ meeting.start_time = startTime;
2295
+ meeting.repeats = repeats;
2296
+ if (status) {
2297
+ meeting.status = status;
2298
+ }
2299
+ if (endTime !== void 0) {
2300
+ meeting.end_time = endTime;
2301
+ }
2302
+ if (teamsIds) {
2303
+ meeting.teams_ids = teamsIds;
2304
+ }
2305
+ return { ...body, meeting };
2306
+ }
1808
2307
  function registerMeetingCommands(program) {
1809
2308
  const meetings = program.command("meetings").description("Meeting operations");
1810
2309
  meetings.command("list").option("--per <per>").option("--date <date>").option("--occurrence-date <occurrenceDate>").option("--past <past>").option("--start-time <startTime>").option("--today-and-active <todayAndActive>").option("--upcoming <upcoming>").option("--query-json <queryJson>").action(async (opts, cmd) => {
@@ -1867,7 +2366,8 @@ function registerMeetingCommands(program) {
1867
2366
  meetings.command("create").requiredOption("--data-json <dataJson>", createHelp2).action(async (opts, cmd) => {
1868
2367
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1869
2368
  const organizationId = resolveOrganizationId(context.organizationId);
1870
- const body = __testables.normalizeBody(String(opts.dataJson), "meeting");
2369
+ const rawBody = __testables.normalizeBody(String(opts.dataJson), "meeting");
2370
+ const body = normalizeMeetingCreateBody(rawBody);
1871
2371
  await runGraphqlMutationCommand({
1872
2372
  command: "meetings.create",
1873
2373
  runtimeOptions: context.runtimeOptions,
@@ -1972,7 +2472,9 @@ import { z as z8 } from "zod";
1972
2472
  var issueGroupIdSchema = z8.string().min(1);
1973
2473
  var idSchema7 = z8.string().min(1);
1974
2474
  var nameSchema = z8.string().min(1);
1975
- var issueTypeSchema = z8.string().min(1);
2475
+ var issueTypeSchema = z8.string().min(1).refine((value) => value === "short_term" || value === "long_term", {
2476
+ message: "Invalid issue type. Use one of: short_term, long_term."
2477
+ });
1976
2478
  var updateHelp4 = buildDataJsonHelp("issue", "update") ?? 'JSON object for issue or {"issue": {...}}';
1977
2479
  function registerIssueCommands(program) {
1978
2480
  const issues = program.command("issues").description("Issue operations");
@@ -2015,7 +2517,7 @@ function registerIssueCommands(program) {
2015
2517
  isShow: true
2016
2518
  });
2017
2519
  });
2018
- issues.command("create").requiredOption("--issue-group-id <issueGroupId>").requiredOption("--name <name>").requiredOption("--issue-type <issueType>").option("--status <status>").option("--priority <priority>").option("--description <description>").option("--due-by <dueBy>").option("--member-id <memberId>").action(async (opts, cmd) => {
2520
+ issues.command("create").requiredOption("--issue-group-id <issueGroupId>").requiredOption("--name <name>").requiredOption("--issue-type <issueType>", "Issue type: short_term | long_term").option("--status <status>").option("--priority <priority>").option("--description <description>").option("--due-by <dueBy>").option("--member-id <memberId>").action(async (opts, cmd) => {
2019
2521
  const issueGroupId = issueGroupIdSchema.parse(opts.issueGroupId);
2020
2522
  const name = nameSchema.parse(opts.name);
2021
2523
  const issueType = issueTypeSchema.parse(opts.issueType);
@@ -2060,56 +2562,703 @@ function registerIssueCommands(program) {
2060
2562
  });
2061
2563
  }
2062
2564
 
2565
+ // src/commands/smartKpiNames.ts
2566
+ var SMART_KPI_NAMES = [
2567
+ "total_active_users",
2568
+ "total_new_users",
2569
+ "total_return_users",
2570
+ "total_engaged_sessions",
2571
+ "total_sessions",
2572
+ "engagement_rate",
2573
+ "bounce_rate",
2574
+ "page_call_phone_clicks_logged_in_unique",
2575
+ "page_cta_clicks_logged_in_unique",
2576
+ "page_engaged_users",
2577
+ "page_fan_adds_unique",
2578
+ "page_fan_adds",
2579
+ "page_fan_removes",
2580
+ "page_fans",
2581
+ "page_get_directions_clicks_logged_in_unique",
2582
+ "page_impressions_unique",
2583
+ "page_impressions",
2584
+ "page_negative_feedback",
2585
+ "page_positive_feedback_comment",
2586
+ "page_positive_feedback_like",
2587
+ "page_positive_feedback_other",
2588
+ "page_positive_feedback_share",
2589
+ "page_post_engagements",
2590
+ "page_total_actions",
2591
+ "page_views_logged_in_unique",
2592
+ "page_views_total",
2593
+ "page_website_clicks_logged_in_unique",
2594
+ "post_clicks_by_type_unique",
2595
+ "post_engaged_users",
2596
+ "post_impressions_fan_paid",
2597
+ "post_impressions_fan",
2598
+ "post_impressions_organic",
2599
+ "post_impressions_unique",
2600
+ "post_impressions",
2601
+ "post_reactions_like_total",
2602
+ "get_directions_clicks",
2603
+ "phone_call_clicks",
2604
+ "profile_views",
2605
+ "reach",
2606
+ "text_message_clicks",
2607
+ "website_clicks",
2608
+ "online_followers",
2609
+ "total_interactions",
2610
+ "accounts_engaged",
2611
+ "likes",
2612
+ "comments",
2613
+ "saves",
2614
+ "shares",
2615
+ "replies",
2616
+ "impressions",
2617
+ "email_contacts",
2618
+ "follower_count",
2619
+ "total_new_conversations",
2620
+ "total_unassigned_conversations",
2621
+ "total_closed_conversations",
2622
+ "total_new_contacts",
2623
+ "total_contacts",
2624
+ "total_revenue",
2625
+ "total_expenses",
2626
+ "cash_flow",
2627
+ "paid_invoices",
2628
+ "unpaid_invoices",
2629
+ "total_new_payments",
2630
+ "total_new_invoices",
2631
+ "total_paid_invoices",
2632
+ "total_refunds",
2633
+ "total_disputes",
2634
+ "calls",
2635
+ "sms",
2636
+ "mms",
2637
+ "verify_push",
2638
+ "verify_totp",
2639
+ "recordings",
2640
+ "transcriptions",
2641
+ "programmable_voice",
2642
+ "authy_phone_verifications",
2643
+ "authy_authentications",
2644
+ "twilio_errors",
2645
+ "twilio_warnings",
2646
+ "twilio_notices",
2647
+ "total_subscribers",
2648
+ "total_subscribers_gained",
2649
+ "total_subscribers_lost",
2650
+ "total_engagement",
2651
+ "total_views",
2652
+ "total_comments",
2653
+ "total_likes",
2654
+ "total_dislikes",
2655
+ "total_shares",
2656
+ "total_card_impressions",
2657
+ "total_card_clicks",
2658
+ "total_card_click_rate",
2659
+ "rock_total_new_rock_groups",
2660
+ "rock_total_rock_groups",
2661
+ "rock_total_new_rocks",
2662
+ "rock_total_new_milestones",
2663
+ "rock_total_completed_milestones",
2664
+ "rock_total_incomplete_milestones",
2665
+ "project_total_projects",
2666
+ "project_total_new_projects",
2667
+ "project_total_new_tasks",
2668
+ "project_total_completed_tasks",
2669
+ "project_total_incomplete_tasks",
2670
+ "project_total_new_sub_tasks",
2671
+ "project_total_completed_sub_tasks",
2672
+ "project_total_incomplete_sub_tasks",
2673
+ "list_total_list",
2674
+ "list_total_new_list",
2675
+ "list_total_new_list_items",
2676
+ "list_total_completed_list_items",
2677
+ "list_total_incomplete_list_items",
2678
+ "list_total_new_sub_items",
2679
+ "list_total_completed_sub_items",
2680
+ "list_total_incomplete_sub_items",
2681
+ "issue_total_issue_groups",
2682
+ "issue_total_new_issue_groups",
2683
+ "issue_total_new_issues",
2684
+ "issue_total_completed_issues",
2685
+ "issue_total_incomplete_issues",
2686
+ "issue_total_new_sub_issues",
2687
+ "issue_total_completed_sub_issues",
2688
+ "issue_total_incomplete_sub_issues",
2689
+ "todo_total_todo_groups",
2690
+ "todo_total_new_todo_groups",
2691
+ "todo_total_new_todos",
2692
+ "todo_total_completed_todos",
2693
+ "todo_total_incomplete_todos",
2694
+ "todo_total_new_sub_todos",
2695
+ "todo_total_completed_sub_todos",
2696
+ "todo_total_incomplete_sub_todos",
2697
+ "measurable_total_scorecards",
2698
+ "measurable_total_new_scorecards",
2699
+ "measurable_total_new_measurables",
2700
+ "stand_up_daily_stand_up_completion_rate",
2701
+ "stand_up_total_stand_ups_complete",
2702
+ "stand_up_daily_stand_up_block_rate",
2703
+ "stand_up_total_blocked_stand_ups",
2704
+ "headline_total_new_headlines",
2705
+ "content_total_content",
2706
+ "content_total_new_content",
2707
+ "question_total_questions",
2708
+ "question_total_new_questions",
2709
+ "question_total_questions_answered",
2710
+ "survey_new_surveys_sent",
2711
+ "member_total_new_members",
2712
+ "member_total_members",
2713
+ "responsibility_total_new_responsibilities_added",
2714
+ "responsibility_total_responsibilities",
2715
+ "customer_total_customers",
2716
+ "customer_total_new_customers",
2717
+ "customer_total_new_customer_logs",
2718
+ "contact_total_contacts",
2719
+ "contact_total_new_contacts",
2720
+ "contact_total_new_contact_logs"
2721
+ ];
2722
+ var SMART_KPI_NAME_SET = new Set(SMART_KPI_NAMES);
2723
+
2063
2724
  // src/commands/systemTools.ts
2064
- function registerSystemToolCommands(program) {
2065
- registerEntityCrudCommands(program, {
2066
- command: "lists",
2067
- description: "List operations",
2068
- resourcePath: "lists",
2069
- rootKey: "list",
2070
- listParams: ["include_archived", "member_id", "team_ids", "term"]
2071
- });
2072
- registerEntityCrudCommands(program, {
2073
- command: "list-items",
2074
- description: "List item operations",
2075
- resourcePath: "list_items",
2076
- rootKey: "list_item",
2077
- requiredCreateFields: ["list_id"],
2078
- listParams: [
2079
- "field_blank",
2080
- "field_name",
2081
- "field_value",
2082
- "include_archived",
2083
- "list_id",
2084
- "meeting_id",
2085
- "member_id",
2086
- "rank_direction",
2087
- "team_id",
2088
- "team_ids"
2089
- ]
2090
- });
2091
- registerEntityCrudCommands(program, {
2092
- command: "issue-groups",
2093
- description: "Issue group operations",
2094
- resourcePath: "issue_groups",
2095
- rootKey: "issue_group",
2096
- listParams: ["include_archived", "member_id", "team_ids", "term"]
2097
- });
2098
- registerEntityCrudCommands(program, {
2099
- command: "todo-groups",
2100
- description: "To-do group operations",
2101
- resourcePath: "todo_groups",
2102
- rootKey: "todo_group",
2103
- listParams: ["include_archived", "member_id", "team_ids", "term"]
2725
+ var TODO_STATUSES = /* @__PURE__ */ new Set(["open", "completed"]);
2726
+ var KNOWLEDGE_CONTENT_TYPES = /* @__PURE__ */ new Set(["company", "policy", "process"]);
2727
+ var KNOWLEDGE_STATUSES = /* @__PURE__ */ new Set(["draft", "published"]);
2728
+ var NEWS_STATUSES = /* @__PURE__ */ new Set(["active", "completed"]);
2729
+ var NEWS_HEADLINE_TYPES = /* @__PURE__ */ new Set(["team", "org_wide"]);
2730
+ var QUESTION_STATUSES = /* @__PURE__ */ new Set(["asked", "answered"]);
2731
+ var PULSE_STATUSES = /* @__PURE__ */ new Set(["on_track", "at_risk", "off_track"]);
2732
+ var SURVEY_RECIPIENT_TYPES = /* @__PURE__ */ new Set(["member", "team", "org_wide"]);
2733
+ var SURVEY_NAMES = /* @__PURE__ */ new Set([
2734
+ "employee_net_promoter_score",
2735
+ "continuous_performance_review",
2736
+ "core_value_alignment",
2737
+ "engagement",
2738
+ "wellness_and_mental_health",
2739
+ "workspace_culture",
2740
+ "peer_review",
2741
+ "manager_review",
2742
+ "onboarding"
2743
+ ]);
2744
+ var FEEDBACK_QUARTERS = /* @__PURE__ */ new Set(["q1", "q2", "q3", "q4"]);
2745
+ var FEEDBACK_NAMES = /* @__PURE__ */ new Set([
2746
+ "productivity_and_focus",
2747
+ "company_collaboration",
2748
+ "project_management",
2749
+ "employee_engagement",
2750
+ "training_and_development",
2751
+ "innovation_and_creativity",
2752
+ "customer_insights",
2753
+ "process_improvement",
2754
+ "leadership_and_management",
2755
+ "company_culture",
2756
+ "roadmap_and_strategy",
2757
+ "customer_testing_and_feedback"
2758
+ ]);
2759
+ var SCORECARD_INTERVALS = /* @__PURE__ */ new Set([
2760
+ "daily",
2761
+ "weekly",
2762
+ "monthly",
2763
+ "quarterly",
2764
+ "yearly"
2765
+ ]);
2766
+ var SCORECARD_TRENDS = /* @__PURE__ */ new Set(["average", "total"]);
2767
+ function isRecord(value) {
2768
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2769
+ }
2770
+ function ensureEntityObject(body, rootKey) {
2771
+ const entity = body[rootKey];
2772
+ if (!isRecord(entity)) {
2773
+ throw new CliError({
2774
+ message: `Invalid payload. Expected object at "${rootKey}".`,
2775
+ kind: "invalid_args",
2776
+ status: 400,
2777
+ exitCode: EXIT_CODES.invalidArgs
2778
+ });
2779
+ }
2780
+ return { ...entity };
2781
+ }
2782
+ function throwMissingRequiredCreateFields(rootKey, fields) {
2783
+ throw new CliError({
2784
+ message: `Missing required create fields for ${rootKey}: ${fields.join(", ")}.`,
2785
+ kind: "invalid_args",
2786
+ status: 400,
2787
+ exitCode: EXIT_CODES.invalidArgs,
2788
+ details: { requiredFields: fields, rootKey }
2104
2789
  });
2105
- registerEntityCrudCommands(program, {
2106
- command: "todos",
2107
- description: "To-do operations",
2108
- resourcePath: "todos",
2109
- rootKey: "todo",
2110
- requiredCreateFields: ["todo_group_id"],
2111
- listParams: [
2112
- "include_archived",
2790
+ }
2791
+ function normalizeTodosCreateBody(body) {
2792
+ const todo = ensureEntityObject(body, "todo");
2793
+ const rawStatus = todo.status;
2794
+ if (rawStatus === void 0 || rawStatus === null || String(rawStatus).trim().length === 0) {
2795
+ todo.status = "open";
2796
+ return { ...body, todo };
2797
+ }
2798
+ if (typeof rawStatus !== "string" || !TODO_STATUSES.has(rawStatus)) {
2799
+ throw new CliError({
2800
+ message: "Invalid todo status. Use one of: open, completed.",
2801
+ kind: "invalid_args",
2802
+ status: 400,
2803
+ exitCode: EXIT_CODES.invalidArgs,
2804
+ details: { allowed: Array.from(TODO_STATUSES) }
2805
+ });
2806
+ }
2807
+ return { ...body, todo };
2808
+ }
2809
+ function asNonEmptyString3(value) {
2810
+ if (typeof value !== "string") {
2811
+ return void 0;
2812
+ }
2813
+ const trimmed = value.trim();
2814
+ return trimmed.length > 0 ? trimmed : void 0;
2815
+ }
2816
+ function validateEnumField(params) {
2817
+ const value = asNonEmptyString3(params.rawValue);
2818
+ if (!value) {
2819
+ return void 0;
2820
+ }
2821
+ if (!params.allowed.has(value)) {
2822
+ throw new CliError({
2823
+ message: params.message,
2824
+ kind: "invalid_args",
2825
+ status: 400,
2826
+ exitCode: EXIT_CODES.invalidArgs,
2827
+ details: { field: params.field, allowed: Array.from(params.allowed) }
2828
+ });
2829
+ }
2830
+ return value;
2831
+ }
2832
+ function normalizeKnowledgeCreateBody(body) {
2833
+ const content = ensureEntityObject(body, "content");
2834
+ const contentType = validateEnumField({
2835
+ rawValue: content.content_type,
2836
+ field: "content.content_type",
2837
+ allowed: KNOWLEDGE_CONTENT_TYPES,
2838
+ message: "Invalid content.content_type. Use one of: company, policy, process."
2839
+ });
2840
+ if (!contentType) {
2841
+ throwMissingRequiredCreateFields("content", ["content_type"]);
2842
+ }
2843
+ content.content_type = contentType;
2844
+ const status = validateEnumField({
2845
+ rawValue: content.status,
2846
+ field: "content.status",
2847
+ allowed: KNOWLEDGE_STATUSES,
2848
+ message: "Invalid content.status. Use one of: draft, published."
2849
+ });
2850
+ content.status = status ?? "draft";
2851
+ const memberId = asNonEmptyString3(content.member_id);
2852
+ if (!memberId) {
2853
+ throwMissingRequiredCreateFields("content", ["member_id"]);
2854
+ }
2855
+ content.member_id = memberId;
2856
+ return { ...body, content };
2857
+ }
2858
+ function normalizeNewsCreateBody(body) {
2859
+ const headline = ensureEntityObject(body, "headline");
2860
+ const memberId = asNonEmptyString3(headline.member_id);
2861
+ if (!memberId) {
2862
+ throwMissingRequiredCreateFields("headline", ["member_id"]);
2863
+ }
2864
+ headline.member_id = memberId;
2865
+ const status = validateEnumField({
2866
+ rawValue: headline.status,
2867
+ field: "headline.status",
2868
+ allowed: NEWS_STATUSES,
2869
+ message: "Invalid headline.status. Use one of: active, completed."
2870
+ });
2871
+ if (!status) {
2872
+ throwMissingRequiredCreateFields("headline", ["status"]);
2873
+ }
2874
+ headline.status = status;
2875
+ const headlineType = validateEnumField({
2876
+ rawValue: headline.headline_type,
2877
+ field: "headline.headline_type",
2878
+ allowed: NEWS_HEADLINE_TYPES,
2879
+ message: "Invalid headline.headline_type. Use one of: team, org_wide."
2880
+ });
2881
+ if (!headlineType) {
2882
+ throwMissingRequiredCreateFields("headline", ["headline_type"]);
2883
+ }
2884
+ headline.headline_type = headlineType;
2885
+ return { ...body, headline };
2886
+ }
2887
+ function normalizeQuestionsCreateBody(body) {
2888
+ const question = ensureEntityObject(body, "question");
2889
+ const summary = asNonEmptyString3(question.summary);
2890
+ const currentName = asNonEmptyString3(question.name);
2891
+ if (!currentName && summary) {
2892
+ question.name = summary;
2893
+ }
2894
+ delete question.summary;
2895
+ const name = asNonEmptyString3(question.name);
2896
+ const memberId = asNonEmptyString3(question.member_id);
2897
+ const missing = [];
2898
+ if (!name) missing.push("name");
2899
+ if (!memberId) missing.push("member_id");
2900
+ if (missing.length > 0) {
2901
+ throwMissingRequiredCreateFields("question", missing);
2902
+ }
2903
+ question.name = name;
2904
+ question.member_id = memberId;
2905
+ const status = validateEnumField({
2906
+ rawValue: question.status,
2907
+ field: "question.status",
2908
+ allowed: QUESTION_STATUSES,
2909
+ message: "Invalid question.status. Use one of: asked, answered."
2910
+ });
2911
+ if (status) {
2912
+ question.status = status;
2913
+ }
2914
+ return { ...body, question };
2915
+ }
2916
+ function normalizeQuestionsUpdateBody(body) {
2917
+ const question = ensureEntityObject(body, "question");
2918
+ const summary = asNonEmptyString3(question.summary);
2919
+ const currentName = asNonEmptyString3(question.name);
2920
+ if (!currentName && summary) {
2921
+ question.name = summary;
2922
+ }
2923
+ delete question.summary;
2924
+ const name = asNonEmptyString3(question.name);
2925
+ if (name) {
2926
+ question.name = name;
2927
+ }
2928
+ const status = validateEnumField({
2929
+ rawValue: question.status,
2930
+ field: "question.status",
2931
+ allowed: QUESTION_STATUSES,
2932
+ message: "Invalid question.status. Use one of: asked, answered."
2933
+ });
2934
+ if (status) {
2935
+ question.status = status;
2936
+ }
2937
+ return { ...body, question };
2938
+ }
2939
+ function normalizePulseCreateBody(body) {
2940
+ const healthUpdate = ensureEntityObject(body, "health_update");
2941
+ const healthUpdatableId = asNonEmptyString3(healthUpdate.health_updatable_id) ?? asNonEmptyString3(healthUpdate.updatable_id);
2942
+ const healthUpdatableType = asNonEmptyString3(healthUpdate.health_updatable_type) ?? asNonEmptyString3(healthUpdate.updatable_type);
2943
+ const memberId = asNonEmptyString3(healthUpdate.member_id);
2944
+ const status = validateEnumField({
2945
+ rawValue: healthUpdate.status,
2946
+ field: "health_update.status",
2947
+ allowed: PULSE_STATUSES,
2948
+ message: "Invalid health_update.status. Use one of: on_track, at_risk, off_track."
2949
+ });
2950
+ const missing = [];
2951
+ if (!healthUpdatableId) missing.push("health_updatable_id");
2952
+ if (!healthUpdatableType) missing.push("health_updatable_type");
2953
+ if (!memberId) missing.push("member_id");
2954
+ if (!status) missing.push("status");
2955
+ if (missing.length > 0) {
2956
+ throwMissingRequiredCreateFields("health_update", missing);
2957
+ }
2958
+ healthUpdate.health_updatable_id = healthUpdatableId;
2959
+ healthUpdate.health_updatable_type = healthUpdatableType;
2960
+ healthUpdate.member_id = memberId;
2961
+ healthUpdate.status = status;
2962
+ delete healthUpdate.updatable_id;
2963
+ delete healthUpdate.updatable_type;
2964
+ return { ...body, health_update: healthUpdate };
2965
+ }
2966
+ function normalizeSurveysCreateBody(body) {
2967
+ const survey = ensureEntityObject(body, "survey");
2968
+ const title = asNonEmptyString3(survey.title);
2969
+ const currentName = asNonEmptyString3(survey.name);
2970
+ if (!currentName && title) {
2971
+ survey.name = title;
2972
+ }
2973
+ delete survey.title;
2974
+ const name = validateEnumField({
2975
+ rawValue: survey.name,
2976
+ field: "survey.name",
2977
+ allowed: SURVEY_NAMES,
2978
+ message: "Invalid survey.name. Use one of: employee_net_promoter_score, continuous_performance_review, core_value_alignment, engagement, wellness_and_mental_health, workspace_culture, peer_review, manager_review, onboarding."
2979
+ });
2980
+ const recipientType = validateEnumField({
2981
+ rawValue: survey.recipient_type,
2982
+ field: "survey.recipient_type",
2983
+ allowed: SURVEY_RECIPIENT_TYPES,
2984
+ message: "Invalid survey.recipient_type. Use one of: member, team, org_wide."
2985
+ });
2986
+ const missing = [];
2987
+ if (!name) missing.push("name");
2988
+ if (!recipientType) missing.push("recipient_type");
2989
+ if (missing.length > 0) {
2990
+ throwMissingRequiredCreateFields("survey", missing);
2991
+ }
2992
+ survey.name = name;
2993
+ survey.recipient_type = recipientType;
2994
+ return { ...body, survey };
2995
+ }
2996
+ function normalizeSurveysUpdateBody(body) {
2997
+ const survey = ensureEntityObject(body, "survey");
2998
+ const title = asNonEmptyString3(survey.title);
2999
+ const currentName = asNonEmptyString3(survey.name);
3000
+ if (!currentName && title) {
3001
+ survey.name = title;
3002
+ }
3003
+ delete survey.title;
3004
+ const name = validateEnumField({
3005
+ rawValue: survey.name,
3006
+ field: "survey.name",
3007
+ allowed: SURVEY_NAMES,
3008
+ message: "Invalid survey.name. Use one of: employee_net_promoter_score, continuous_performance_review, core_value_alignment, engagement, wellness_and_mental_health, workspace_culture, peer_review, manager_review, onboarding."
3009
+ });
3010
+ if (name) {
3011
+ survey.name = name;
3012
+ }
3013
+ const recipientType = validateEnumField({
3014
+ rawValue: survey.recipient_type,
3015
+ field: "survey.recipient_type",
3016
+ allowed: SURVEY_RECIPIENT_TYPES,
3017
+ message: "Invalid survey.recipient_type. Use one of: member, team, org_wide."
3018
+ });
3019
+ if (recipientType) {
3020
+ survey.recipient_type = recipientType;
3021
+ }
3022
+ return { ...body, survey };
3023
+ }
3024
+ function normalizeFeedbacksCreateBody(body) {
3025
+ const feedback = ensureEntityObject(body, "feedback");
3026
+ const title = asNonEmptyString3(feedback.title);
3027
+ const currentName = asNonEmptyString3(feedback.name);
3028
+ if (!currentName && title) {
3029
+ feedback.name = title;
3030
+ }
3031
+ delete feedback.title;
3032
+ const name = validateEnumField({
3033
+ rawValue: feedback.name,
3034
+ field: "feedback.name",
3035
+ allowed: FEEDBACK_NAMES,
3036
+ message: "Invalid feedback.name. Use one of: productivity_and_focus, company_collaboration, project_management, employee_engagement, training_and_development, innovation_and_creativity, customer_insights, process_improvement, leadership_and_management, company_culture, roadmap_and_strategy, customer_testing_and_feedback."
3037
+ });
3038
+ const quarter = validateEnumField({
3039
+ rawValue: feedback.quarter,
3040
+ field: "feedback.quarter",
3041
+ allowed: FEEDBACK_QUARTERS,
3042
+ message: "Invalid feedback.quarter. Use one of: q1, q2, q3, q4."
3043
+ });
3044
+ const year = asNonEmptyString3(feedback.year);
3045
+ const missing = [];
3046
+ if (!name) missing.push("name");
3047
+ if (!quarter) missing.push("quarter");
3048
+ if (!year) missing.push("year");
3049
+ if (missing.length > 0) {
3050
+ throwMissingRequiredCreateFields("feedback", missing);
3051
+ }
3052
+ feedback.name = name;
3053
+ feedback.quarter = quarter;
3054
+ feedback.year = year;
3055
+ return { ...body, feedback };
3056
+ }
3057
+ function normalizeFeedbacksUpdateBody(body) {
3058
+ const feedback = ensureEntityObject(body, "feedback");
3059
+ const title = asNonEmptyString3(feedback.title);
3060
+ const currentName = asNonEmptyString3(feedback.name);
3061
+ if (!currentName && title) {
3062
+ feedback.name = title;
3063
+ }
3064
+ delete feedback.title;
3065
+ const name = validateEnumField({
3066
+ rawValue: feedback.name,
3067
+ field: "feedback.name",
3068
+ allowed: FEEDBACK_NAMES,
3069
+ message: "Invalid feedback.name. Use one of: productivity_and_focus, company_collaboration, project_management, employee_engagement, training_and_development, innovation_and_creativity, customer_insights, process_improvement, leadership_and_management, company_culture, roadmap_and_strategy, customer_testing_and_feedback."
3070
+ });
3071
+ if (name) {
3072
+ feedback.name = name;
3073
+ }
3074
+ const quarter = validateEnumField({
3075
+ rawValue: feedback.quarter,
3076
+ field: "feedback.quarter",
3077
+ allowed: FEEDBACK_QUARTERS,
3078
+ message: "Invalid feedback.quarter. Use one of: q1, q2, q3, q4."
3079
+ });
3080
+ if (quarter) {
3081
+ feedback.quarter = quarter;
3082
+ }
3083
+ return { ...body, feedback };
3084
+ }
3085
+ function normalizeAccountabilityCreateBody(body) {
3086
+ const responsibility = ensureEntityObject(body, "responsibility");
3087
+ const summary = asNonEmptyString3(responsibility.summary);
3088
+ const currentName = asNonEmptyString3(responsibility.name);
3089
+ if (!currentName && summary) {
3090
+ responsibility.name = summary;
3091
+ }
3092
+ delete responsibility.summary;
3093
+ const name = asNonEmptyString3(responsibility.name);
3094
+ const memberId = asNonEmptyString3(responsibility.member_id);
3095
+ const missing = [];
3096
+ if (!name) missing.push("name");
3097
+ if (!memberId) missing.push("member_id");
3098
+ if (missing.length > 0) {
3099
+ throwMissingRequiredCreateFields("responsibility", missing);
3100
+ }
3101
+ responsibility.name = name;
3102
+ responsibility.member_id = memberId;
3103
+ return { ...body, responsibility };
3104
+ }
3105
+ function normalizeAccountabilityUpdateBody(body) {
3106
+ const responsibility = ensureEntityObject(body, "responsibility");
3107
+ const summary = asNonEmptyString3(responsibility.summary);
3108
+ const currentName = asNonEmptyString3(responsibility.name);
3109
+ if (!currentName && summary) {
3110
+ responsibility.name = summary;
3111
+ }
3112
+ delete responsibility.summary;
3113
+ return { ...body, responsibility };
3114
+ }
3115
+ function normalizeScorecardsCreateBody(body) {
3116
+ const measurable = ensureEntityObject(body, "measurable");
3117
+ const interval = validateEnumField({
3118
+ rawValue: measurable.interval,
3119
+ field: "measurable.interval",
3120
+ allowed: SCORECARD_INTERVALS,
3121
+ message: "Invalid measurable.interval. Use one of: daily, weekly, monthly, quarterly, yearly."
3122
+ });
3123
+ measurable.interval = interval ?? "weekly";
3124
+ const trend = validateEnumField({
3125
+ rawValue: measurable.trend,
3126
+ field: "measurable.trend",
3127
+ allowed: SCORECARD_TRENDS,
3128
+ message: "Invalid measurable.trend. Use one of: average, total."
3129
+ });
3130
+ measurable.trend = trend ?? "average";
3131
+ return { ...body, measurable };
3132
+ }
3133
+ function buildKpisCreateMutation(params) {
3134
+ const entity = params.body.smart_kpi;
3135
+ if (!entity || typeof entity !== "object" || Array.isArray(entity)) {
3136
+ throw new CliError({
3137
+ message: 'Invalid payload. Expected object at "smart_kpi".',
3138
+ kind: "invalid_args",
3139
+ status: 400,
3140
+ exitCode: EXIT_CODES.invalidArgs
3141
+ });
3142
+ }
3143
+ const smartKpi = { ...entity };
3144
+ const name = asNonEmptyString3(smartKpi.name);
3145
+ const smartKpiViewId = asNonEmptyString3(smartKpi.smart_kpi_view_id);
3146
+ const measurableGroupId = asNonEmptyString3(smartKpi.measurable_group_id);
3147
+ const hasAllowedName = typeof name === "string" && SMART_KPI_NAME_SET.has(name);
3148
+ if (!name) {
3149
+ throw new CliError({
3150
+ message: "Missing required create fields for smart_kpi: name.",
3151
+ kind: "invalid_args",
3152
+ status: 400,
3153
+ exitCode: EXIT_CODES.invalidArgs,
3154
+ details: { requiredFields: ["name"], rootKey: "smart_kpi" }
3155
+ });
3156
+ }
3157
+ if (measurableGroupId && !hasAllowedName) {
3158
+ const measurable = {
3159
+ measurable_group_id: measurableGroupId,
3160
+ name,
3161
+ interval: "daily",
3162
+ trend: "average",
3163
+ measurable_type: "number",
3164
+ condition: "greater_than_or_equal_to"
3165
+ };
3166
+ const notes = asNonEmptyString3(smartKpi.notes);
3167
+ if (notes) {
3168
+ measurable.notes = notes;
3169
+ }
3170
+ return {
3171
+ command: "measurables.create",
3172
+ field: "create_measurable",
3173
+ variables: {
3174
+ organization_id: params.organizationId,
3175
+ params: { measurable }
3176
+ }
3177
+ };
3178
+ }
3179
+ if (!smartKpiViewId) {
3180
+ throw new CliError({
3181
+ message: "Missing required create fields for smart_kpi: smart_kpi_view_id.",
3182
+ kind: "invalid_args",
3183
+ status: 400,
3184
+ exitCode: EXIT_CODES.invalidArgs,
3185
+ details: { requiredFields: ["smart_kpi_view_id"], rootKey: "smart_kpi" }
3186
+ });
3187
+ }
3188
+ if (!hasAllowedName) {
3189
+ throw new CliError({
3190
+ message: "Invalid smart_kpi.name for kpis.create. Use an allowed enum value or route free-text KPI names to measurable create.",
3191
+ kind: "invalid_args",
3192
+ status: 400,
3193
+ exitCode: EXIT_CODES.invalidArgs,
3194
+ details: {
3195
+ field: "smart_kpi.name",
3196
+ allowedValues: SMART_KPI_NAMES
3197
+ }
3198
+ });
3199
+ }
3200
+ delete smartKpi.measurable_group_id;
3201
+ smartKpi.name = name;
3202
+ smartKpi.smart_kpi_view_id = smartKpiViewId;
3203
+ return {
3204
+ command: "kpis.create",
3205
+ field: "create_smart_kpi",
3206
+ variables: {
3207
+ organization_id: params.organizationId,
3208
+ params: { smart_kpi: smartKpi }
3209
+ }
3210
+ };
3211
+ }
3212
+ function registerSystemToolCommands(program) {
3213
+ registerEntityCrudCommands(program, {
3214
+ command: "lists",
3215
+ description: "List operations",
3216
+ resourcePath: "lists",
3217
+ rootKey: "list",
3218
+ listParams: ["include_archived", "member_id", "team_ids", "term"]
3219
+ });
3220
+ registerEntityCrudCommands(program, {
3221
+ command: "list-items",
3222
+ description: "List item operations",
3223
+ resourcePath: "list_items",
3224
+ rootKey: "list_item",
3225
+ requiredCreateFields: ["list_id"],
3226
+ listParams: [
3227
+ "field_blank",
3228
+ "field_name",
3229
+ "field_value",
3230
+ "include_archived",
3231
+ "list_id",
3232
+ "meeting_id",
3233
+ "member_id",
3234
+ "rank_direction",
3235
+ "team_id",
3236
+ "team_ids"
3237
+ ]
3238
+ });
3239
+ registerEntityCrudCommands(program, {
3240
+ command: "issue-groups",
3241
+ description: "Issue group operations",
3242
+ resourcePath: "issue_groups",
3243
+ rootKey: "issue_group",
3244
+ listParams: ["include_archived", "member_id", "team_ids", "term"]
3245
+ });
3246
+ registerEntityCrudCommands(program, {
3247
+ command: "todo-groups",
3248
+ description: "To-do group operations",
3249
+ resourcePath: "todo_groups",
3250
+ rootKey: "todo_group",
3251
+ listParams: ["include_archived", "member_id", "team_ids", "term"]
3252
+ });
3253
+ registerEntityCrudCommands(program, {
3254
+ command: "todos",
3255
+ description: "To-do operations",
3256
+ resourcePath: "todos",
3257
+ rootKey: "todo",
3258
+ requiredCreateFields: ["todo_group_id"],
3259
+ normalizeCreateBody: normalizeTodosCreateBody,
3260
+ listParams: [
3261
+ "include_archived",
2113
3262
  "meeting_id",
2114
3263
  "member_id",
2115
3264
  "rank_direction",
@@ -2130,6 +3279,7 @@ function registerSystemToolCommands(program) {
2130
3279
  description: "Knowledge content operations",
2131
3280
  resourcePath: "contents",
2132
3281
  rootKey: "content",
3282
+ normalizeCreateBody: normalizeKnowledgeCreateBody,
2133
3283
  listParams: [
2134
3284
  "assigned",
2135
3285
  "contentable_id",
@@ -2160,13 +3310,40 @@ function registerSystemToolCommands(program) {
2160
3310
  description: "News operations",
2161
3311
  resourcePath: "headlines",
2162
3312
  rootKey: "headline",
2163
- listParams: ["meeting_id", "unread"]
3313
+ requiredCreateFields: ["member_id", "status", "headline_type"],
3314
+ normalizeCreateBody: normalizeNewsCreateBody,
3315
+ listParams: ["meeting_id", "unread"],
3316
+ showQueryFactory: ({ id, organizationId }) => ({
3317
+ field: "headlines",
3318
+ variables: {
3319
+ organization_id: organizationId,
3320
+ page: 1,
3321
+ per: 200
3322
+ },
3323
+ selectionSet: "{ data { id type attributes } count currentPage totalPages }",
3324
+ transformData: (value) => {
3325
+ if (!value || typeof value !== "object") {
3326
+ return null;
3327
+ }
3328
+ const payload = value;
3329
+ const rows = Array.isArray(payload.data) ? payload.data : [];
3330
+ return rows.find((row) => {
3331
+ if (!row || typeof row !== "object") {
3332
+ return false;
3333
+ }
3334
+ return String(row.id ?? "") === id;
3335
+ }) ?? null;
3336
+ }
3337
+ })
2164
3338
  });
2165
3339
  registerEntityCrudCommands(program, {
2166
3340
  command: "questions",
2167
3341
  description: "Q&A forum operations",
2168
3342
  resourcePath: "questions",
2169
3343
  rootKey: "question",
3344
+ requiredCreateFields: ["member_id", "name"],
3345
+ normalizeCreateBody: normalizeQuestionsCreateBody,
3346
+ normalizeUpdateBody: normalizeQuestionsUpdateBody,
2170
3347
  listParams: ["answered", "asked", "member_id", "team_id", "term"]
2171
3348
  });
2172
3349
  registerEntityCrudCommands(program, {
@@ -2174,6 +3351,8 @@ function registerSystemToolCommands(program) {
2174
3351
  description: "Pulse operations",
2175
3352
  resourcePath: "health_updates",
2176
3353
  rootKey: "health_update",
3354
+ requiredCreateFields: ["health_updatable_id", "health_updatable_type", "member_id", "status"],
3355
+ normalizeCreateBody: normalizePulseCreateBody,
2177
3356
  listParams: ["health_updatable_id", "health_updatable_type"]
2178
3357
  });
2179
3358
  registerEntityCrudCommands(program, {
@@ -2181,6 +3360,9 @@ function registerSystemToolCommands(program) {
2181
3360
  description: "Survey operations",
2182
3361
  resourcePath: "surveys",
2183
3362
  rootKey: "survey",
3363
+ requiredCreateFields: ["name", "recipient_type"],
3364
+ normalizeCreateBody: normalizeSurveysCreateBody,
3365
+ normalizeUpdateBody: normalizeSurveysUpdateBody,
2184
3366
  listParams: ["completed", "current_member", "due", "exclude_completed"]
2185
3367
  });
2186
3368
  registerEntityCrudCommands(program, {
@@ -2188,6 +3370,9 @@ function registerSystemToolCommands(program) {
2188
3370
  description: "Feedback operations",
2189
3371
  resourcePath: "feedback",
2190
3372
  rootKey: "feedback",
3373
+ requiredCreateFields: ["name", "quarter", "year"],
3374
+ normalizeCreateBody: normalizeFeedbacksCreateBody,
3375
+ normalizeUpdateBody: normalizeFeedbacksUpdateBody,
2191
3376
  listParams: ["last", "latest", "start_date"]
2192
3377
  });
2193
3378
  registerEntityCrudCommands(program, {
@@ -2195,6 +3380,9 @@ function registerSystemToolCommands(program) {
2195
3380
  description: "Accountability operations",
2196
3381
  resourcePath: "responsibilities",
2197
3382
  rootKey: "responsibility",
3383
+ requiredCreateFields: ["name", "member_id"],
3384
+ normalizeCreateBody: normalizeAccountabilityCreateBody,
3385
+ normalizeUpdateBody: normalizeAccountabilityUpdateBody,
2198
3386
  listParams: ["meeting_id", "term"]
2199
3387
  });
2200
3388
  registerEntityCrudCommands(program, {
@@ -2202,6 +3390,10 @@ function registerSystemToolCommands(program) {
2202
3390
  description: "KPI operations",
2203
3391
  resourcePath: "smart_kpis",
2204
3392
  rootKey: "smart_kpi",
3393
+ createMutationFactory: ({ body, organizationId }) => buildKpisCreateMutation({
3394
+ body,
3395
+ organizationId
3396
+ }),
2205
3397
  listParams: [
2206
3398
  "annual_objective_id",
2207
3399
  "include_archived",
@@ -2227,6 +3419,7 @@ function registerSystemToolCommands(program) {
2227
3419
  resourcePath: "measurables",
2228
3420
  rootKey: "measurable",
2229
3421
  requiredCreateFields: ["measurable_group_id"],
3422
+ normalizeCreateBody: normalizeScorecardsCreateBody,
2230
3423
  listParams: [
2231
3424
  "annual_objective_id",
2232
3425
  "include_archived",
@@ -2328,6 +3521,103 @@ function registerTeamCommands(program) {
2328
3521
  // src/commands/organizations.ts
2329
3522
  import { z as z10 } from "zod";
2330
3523
  var idSchema9 = z10.string().min(1);
3524
+ function isRecord2(value) {
3525
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3526
+ }
3527
+ function ensureRootObject(body, rootKey) {
3528
+ const root = body[rootKey];
3529
+ if (!isRecord2(root)) {
3530
+ throw new CliError({
3531
+ message: `Invalid payload. Expected object at "${rootKey}".`,
3532
+ kind: "invalid_args",
3533
+ status: 400,
3534
+ exitCode: EXIT_CODES.invalidArgs
3535
+ });
3536
+ }
3537
+ return { ...root };
3538
+ }
3539
+ function asNonEmptyString4(value) {
3540
+ if (typeof value !== "string") {
3541
+ return void 0;
3542
+ }
3543
+ const trimmed = value.trim();
3544
+ return trimmed.length > 0 ? trimmed : void 0;
3545
+ }
3546
+ function normalizeOrganizationUpdateBody(body) {
3547
+ const organization = ensureRootObject(body, "organization");
3548
+ const detail = isRecord2(organization.organization_detail_attributes) ? { ...organization.organization_detail_attributes } : {};
3549
+ const workspaceName = asNonEmptyString4(organization.workspace_name);
3550
+ if (workspaceName) {
3551
+ detail.workspace_name = workspaceName;
3552
+ }
3553
+ delete organization.workspace_name;
3554
+ if (Object.keys(detail).length > 0) {
3555
+ organization.organization_detail_attributes = detail;
3556
+ }
3557
+ return { organization };
3558
+ }
3559
+ function normalizeOrganizationMetaProfileUpdateBody(body) {
3560
+ const root = ensureRootObject(body, "organization_meta_profile");
3561
+ const profile = isRecord2(root.profile) ? { ...root.profile } : {};
3562
+ const title = asNonEmptyString4(root.title);
3563
+ if (title) {
3564
+ const companyIdentity = isRecord2(profile.company_identity) ? { ...profile.company_identity } : {};
3565
+ companyIdentity.one_sentence_summary = title;
3566
+ profile.company_identity = companyIdentity;
3567
+ }
3568
+ const unsupported = Object.keys(root).filter((key) => key !== "profile" && key !== "title");
3569
+ if (unsupported.length > 0) {
3570
+ throw new CliError({
3571
+ message: "Invalid organization_meta_profile update payload. Use organization_meta_profile.profile.<section>.<field>.",
3572
+ kind: "invalid_args",
3573
+ status: 400,
3574
+ exitCode: EXIT_CODES.invalidArgs,
3575
+ details: { unsupportedKeys: unsupported, expectedRootKey: "profile" }
3576
+ });
3577
+ }
3578
+ if (Object.keys(profile).length === 0) {
3579
+ throw new CliError({
3580
+ message: "Missing required update fields for organization_meta_profile: profile.",
3581
+ kind: "invalid_args",
3582
+ status: 400,
3583
+ exitCode: EXIT_CODES.invalidArgs,
3584
+ details: { requiredFields: ["profile"], rootKey: "organization_meta_profile" }
3585
+ });
3586
+ }
3587
+ return { organization_meta_profile: { profile } };
3588
+ }
3589
+ function normalizeKeyMetricMetaProfileUpdateBody(body) {
3590
+ const root = ensureRootObject(body, "key_metric_meta_profile");
3591
+ const profile = isRecord2(root.profile) ? { ...root.profile } : {};
3592
+ const annualRevenue = asNonEmptyString4(root.annual_revenue);
3593
+ if (annualRevenue) {
3594
+ const financial = isRecord2(profile.financial) ? { ...profile.financial } : {};
3595
+ financial.revenue = annualRevenue;
3596
+ profile.financial = financial;
3597
+ }
3598
+ const unsupported = Object.keys(root).filter(
3599
+ (key) => key !== "profile" && key !== "annual_revenue"
3600
+ );
3601
+ if (unsupported.length > 0) {
3602
+ throw new CliError({
3603
+ message: "Invalid key_metric_meta_profile update payload. Use key_metric_meta_profile.profile.<section>.<field>.",
3604
+ kind: "invalid_args",
3605
+ status: 400,
3606
+ exitCode: EXIT_CODES.invalidArgs,
3607
+ details: { unsupportedKeys: unsupported, expectedRootKey: "profile" }
3608
+ });
3609
+ }
3610
+ if (Object.keys(profile).length === 0) {
3611
+ throw new CliError({
3612
+ message: "Missing required update fields for key_metric_meta_profile: profile.",
3613
+ kind: "invalid_args",
3614
+ status: 400,
3615
+ exitCode: EXIT_CODES.invalidArgs,
3616
+ details: { requiredFields: ["profile"], rootKey: "key_metric_meta_profile" }
3617
+ });
3618
+ }
3619
+ return { key_metric_meta_profile: { profile } };
3620
+ }
2331
3621
  function registerOrganizationCommands(program) {
2332
3622
  const organizations = program.command("organizations").description("Organization operations");
2333
3623
  organizations.command("show").option("--id <id>", "Organization ID (defaults to resolved organization context)").action(async (opts, cmd) => {
@@ -2349,7 +3639,8 @@ function registerOrganizationCommands(program) {
2349
3639
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2350
3640
  const fallbackId = resolveOrganizationId(context.organizationId);
2351
3641
  const id = idSchema9.parse(opts.id ?? fallbackId);
2352
- const body = __testables.normalizeBody(String(opts.dataJson), "organization");
3642
+ const rawBody = __testables.normalizeBody(String(opts.dataJson), "organization");
3643
+ const body = normalizeOrganizationUpdateBody(rawBody);
2353
3644
  await runGraphqlMutationCommand({
2354
3645
  command: "organizations.update",
2355
3646
  runtimeOptions: context.runtimeOptions,
@@ -2383,10 +3674,11 @@ function registerOrganizationCommands(program) {
2383
3674
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2384
3675
  const organizationId = resolveOrganizationId(context.organizationId);
2385
3676
  const id = idSchema9.parse(opts.id ?? organizationId);
2386
- const body = __testables.normalizeBody(
3677
+ const rawBody = __testables.normalizeBody(
2387
3678
  String(opts.dataJson),
2388
3679
  "organization_meta_profile"
2389
3680
  );
3681
+ const body = normalizeOrganizationMetaProfileUpdateBody(rawBody);
2390
3682
  await runGraphqlMutationCommand({
2391
3683
  command: "organizations.meta-profile.update",
2392
3684
  runtimeOptions: context.runtimeOptions,
@@ -2421,10 +3713,11 @@ function registerOrganizationCommands(program) {
2421
3713
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2422
3714
  const organizationId = resolveOrganizationId(context.organizationId);
2423
3715
  const id = idSchema9.parse(opts.id ?? organizationId);
2424
- const body = __testables.normalizeBody(
3716
+ const rawBody = __testables.normalizeBody(
2425
3717
  String(opts.dataJson),
2426
3718
  "key_metric_meta_profile"
2427
3719
  );
3720
+ const body = normalizeKeyMetricMetaProfileUpdateBody(rawBody);
2428
3721
  await runGraphqlMutationCommand({
2429
3722
  command: "organizations.key-metric-meta-profile.update",
2430
3723
  runtimeOptions: context.runtimeOptions,
@@ -2441,36 +3734,131 @@ function registerOrganizationCommands(program) {
2441
3734
  // src/commands/foundation.ts
2442
3735
  import { z as z11 } from "zod";
2443
3736
  var idSchema10 = z11.string().min(1);
2444
- function registerFoundationCommands(program) {
2445
- const foundation = program.command("foundation").description("Foundation operations");
2446
- const strategicPlans = foundation.command("strategic-plans").description("Strategic plan operations");
2447
- const strategicObjectives = foundation.command("strategic-objectives").description("Strategic objective operations");
2448
- strategicPlans.command("show").option("--id <id>", "Strategic plan ID (defaults to organization context)").option("--progress-scope <progressScope>").option("--all-progress <allProgress>").option("--all <all>").action(async (opts, cmd) => {
2449
- const context = await resolveCommandContext(cmd.optsWithGlobals());
2450
- const organizationId = resolveOrganizationId(context.organizationId);
2451
- const id = idSchema10.parse(opts.id ?? organizationId);
2452
- await runGraphqlQueryCommand({
2453
- command: "foundation.strategic-plans.show",
2454
- runtimeOptions: context.runtimeOptions,
2455
- field: "strategic_plan",
2456
- variables: normalizeGraphqlVariables2({
2457
- organization_id: organizationId,
2458
- id,
2459
- progress_scope: opts.progressScope,
2460
- all_progress: opts.allProgress,
2461
- all: opts.all
2462
- }),
2463
- isShow: true
3737
+ var STRATEGIC_PLAN_ALLOWED_UPDATE_KEYS = /* @__PURE__ */ new Set([
3738
+ "published_at",
3739
+ "profile",
3740
+ "strategic_plan_reads_attributes"
3741
+ ]);
3742
+ var STRATEGIC_OBJECTIVE_ALLOWED_UPDATE_KEYS = /* @__PURE__ */ new Set([
3743
+ "summary",
3744
+ "alignment_score",
3745
+ "published_at",
3746
+ "strategic_objective_reads_attributes"
3747
+ ]);
3748
+ function isRecord3(value) {
3749
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3750
+ }
3751
+ function ensureRootObject2(body, rootKey) {
3752
+ const root = body[rootKey];
3753
+ if (!isRecord3(root)) {
3754
+ throw new CliError({
3755
+ message: `Invalid payload. Expected object at "${rootKey}".`,
3756
+ kind: "invalid_args",
3757
+ status: 400,
3758
+ exitCode: EXIT_CODES.invalidArgs
2464
3759
  });
2465
- });
2466
- strategicPlans.command("update").option("--id <id>", "Strategic plan ID (defaults to organization context)").requiredOption(
2467
- "--data-json <dataJson>",
2468
- 'JSON object for strategic_plan or {"strategic_plan": {...}}'
2469
- ).action(async (opts, cmd) => {
3760
+ }
3761
+ return { ...root };
3762
+ }
3763
+ function asNonEmptyString5(value) {
3764
+ if (typeof value !== "string") {
3765
+ return void 0;
3766
+ }
3767
+ const trimmed = value.trim();
3768
+ return trimmed.length > 0 ? trimmed : void 0;
3769
+ }
3770
+ function normalizeStrategicPlanUpdateBody(body) {
3771
+ const strategicPlan = ensureRootObject2(body, "strategic_plan");
3772
+ const unsupported = Object.keys(strategicPlan).filter(
3773
+ (key) => !STRATEGIC_PLAN_ALLOWED_UPDATE_KEYS.has(key)
3774
+ );
3775
+ if (unsupported.length > 0) {
3776
+ throw new CliError({
3777
+ message: "Invalid strategic_plan update payload. Allowed keys: published_at, profile, strategic_plan_reads_attributes.",
3778
+ kind: "invalid_args",
3779
+ status: 400,
3780
+ exitCode: EXIT_CODES.invalidArgs,
3781
+ details: {
3782
+ unsupportedKeys: unsupported,
3783
+ allowedKeys: Array.from(STRATEGIC_PLAN_ALLOWED_UPDATE_KEYS)
3784
+ }
3785
+ });
3786
+ }
3787
+ return { strategic_plan: strategicPlan };
3788
+ }
3789
+ function normalizeStrategicObjectiveUpdateBody(body) {
3790
+ const strategicObjective = ensureRootObject2(body, "strategic_objective");
3791
+ const title = asNonEmptyString5(strategicObjective.title);
3792
+ if (!asNonEmptyString5(strategicObjective.summary) && title) {
3793
+ strategicObjective.summary = title;
3794
+ }
3795
+ delete strategicObjective.title;
3796
+ const unsupported = Object.keys(strategicObjective).filter(
3797
+ (key) => !STRATEGIC_OBJECTIVE_ALLOWED_UPDATE_KEYS.has(key)
3798
+ );
3799
+ if (unsupported.length > 0) {
3800
+ throw new CliError({
3801
+ message: "Invalid strategic_objective update payload. Allowed keys: summary, alignment_score, published_at, strategic_objective_reads_attributes.",
3802
+ kind: "invalid_args",
3803
+ status: 400,
3804
+ exitCode: EXIT_CODES.invalidArgs,
3805
+ details: {
3806
+ unsupportedKeys: unsupported,
3807
+ allowedKeys: Array.from(STRATEGIC_OBJECTIVE_ALLOWED_UPDATE_KEYS)
3808
+ }
3809
+ });
3810
+ }
3811
+ return { strategic_objective: strategicObjective };
3812
+ }
3813
+ function normalizeAnnualObjectiveCreateBody(body) {
3814
+ const annualObjective = ensureRootObject2(body, "annual_objective");
3815
+ const title = asNonEmptyString5(annualObjective.title);
3816
+ if (!asNonEmptyString5(annualObjective.name) && title) {
3817
+ annualObjective.name = title;
3818
+ }
3819
+ delete annualObjective.title;
3820
+ return { annual_objective: annualObjective };
3821
+ }
3822
+ function normalizeQuarterlyObjectiveCreateBody(body) {
3823
+ const quarterlyObjective = ensureRootObject2(body, "quarterly_objective");
3824
+ const title = asNonEmptyString5(quarterlyObjective.title);
3825
+ if (!asNonEmptyString5(quarterlyObjective.name) && title) {
3826
+ quarterlyObjective.name = title;
3827
+ }
3828
+ delete quarterlyObjective.title;
3829
+ return { quarterly_objective: quarterlyObjective };
3830
+ }
3831
+ function registerFoundationCommands(program) {
3832
+ const foundation = program.command("foundation").description("Foundation operations");
3833
+ const strategicPlans = foundation.command("strategic-plans").description("Strategic plan operations");
3834
+ const strategicObjectives = foundation.command("strategic-objectives").description("Strategic objective operations");
3835
+ strategicPlans.command("show").option("--id <id>", "Strategic plan ID (defaults to organization context)").option("--progress-scope <progressScope>").option("--all-progress <allProgress>").option("--all <all>").action(async (opts, cmd) => {
3836
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
3837
+ const organizationId = resolveOrganizationId(context.organizationId);
3838
+ const id = idSchema10.parse(opts.id ?? organizationId);
3839
+ await runGraphqlQueryCommand({
3840
+ command: "foundation.strategic-plans.show",
3841
+ runtimeOptions: context.runtimeOptions,
3842
+ field: "strategic_plan",
3843
+ variables: normalizeGraphqlVariables2({
3844
+ organization_id: organizationId,
3845
+ id,
3846
+ progress_scope: opts.progressScope,
3847
+ all_progress: opts.allProgress,
3848
+ all: opts.all
3849
+ }),
3850
+ isShow: true
3851
+ });
3852
+ });
3853
+ strategicPlans.command("update").option("--id <id>", "Strategic plan ID (defaults to organization context)").requiredOption(
3854
+ "--data-json <dataJson>",
3855
+ 'JSON object for strategic_plan or {"strategic_plan": {...}}'
3856
+ ).action(async (opts, cmd) => {
2470
3857
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2471
3858
  const organizationId = resolveOrganizationId(context.organizationId);
2472
3859
  const id = idSchema10.parse(opts.id ?? organizationId);
2473
- const body = __testables.normalizeBody(String(opts.dataJson), "strategic_plan");
3860
+ const rawBody = __testables.normalizeBody(String(opts.dataJson), "strategic_plan");
3861
+ const body = normalizeStrategicPlanUpdateBody(rawBody);
2474
3862
  await runGraphqlMutationCommand({
2475
3863
  command: "foundation.strategic-plans.update",
2476
3864
  runtimeOptions: context.runtimeOptions,
@@ -2507,10 +3895,11 @@ function registerFoundationCommands(program) {
2507
3895
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2508
3896
  const organizationId = resolveOrganizationId(context.organizationId);
2509
3897
  const id = idSchema10.parse(opts.id ?? organizationId);
2510
- const body = __testables.normalizeBody(
3898
+ const rawBody = __testables.normalizeBody(
2511
3899
  String(opts.dataJson),
2512
3900
  "strategic_objective"
2513
3901
  );
3902
+ const body = normalizeStrategicObjectiveUpdateBody(rawBody);
2514
3903
  await runGraphqlMutationCommand({
2515
3904
  command: "foundation.strategic-objectives.update",
2516
3905
  runtimeOptions: context.runtimeOptions,
@@ -2527,7 +3916,8 @@ function registerFoundationCommands(program) {
2527
3916
  description: "Foundation annual objective operations",
2528
3917
  resourcePath: "annual_objectives",
2529
3918
  rootKey: "annual_objective",
2530
- requiredCreateFields: ["strategic_objective_id"],
3919
+ requiredCreateFields: ["strategic_objective_id", "name"],
3920
+ normalizeCreateBody: normalizeAnnualObjectiveCreateBody,
2531
3921
  listParams: []
2532
3922
  });
2533
3923
  registerEntityCrudCommands(foundation, {
@@ -2535,13 +3925,1478 @@ function registerFoundationCommands(program) {
2535
3925
  description: "Foundation quarterly objective operations",
2536
3926
  resourcePath: "quarterly_objectives",
2537
3927
  rootKey: "quarterly_objective",
2538
- requiredCreateFields: ["strategic_objective_id", "annual_objective_id"],
3928
+ requiredCreateFields: ["strategic_objective_id", "annual_objective_id", "name"],
3929
+ normalizeCreateBody: normalizeQuarterlyObjectiveCreateBody,
2539
3930
  listParams: ["annual_objective_id"]
2540
3931
  });
2541
3932
  }
2542
3933
 
3934
+ // src/commands/childEntities.ts
3935
+ import { z as z12 } from "zod";
3936
+ var idSchema11 = z12.string().min(1);
3937
+ var jsonObjectSchema = z12.record(z12.string(), z12.unknown());
3938
+ function parseJsonObject2(raw) {
3939
+ try {
3940
+ const parsed = JSON.parse(raw);
3941
+ return jsonObjectSchema.parse(parsed);
3942
+ } catch (error) {
3943
+ throw new CliError({
3944
+ message: error instanceof Error ? `Invalid --data-json: ${error.message}` : "Invalid --data-json.",
3945
+ kind: "invalid_args",
3946
+ status: 400,
3947
+ exitCode: EXIT_CODES.invalidArgs
3948
+ });
3949
+ }
3950
+ }
3951
+ function normalizeBody2(raw, rootKey) {
3952
+ const payload = parseJsonObject2(raw);
3953
+ const rooted = payload[rootKey];
3954
+ if (rooted && typeof rooted === "object" && !Array.isArray(rooted)) {
3955
+ return payload;
3956
+ }
3957
+ return { [rootKey]: payload };
3958
+ }
3959
+ function assertRequiredParent(body, rootKey, parentKey) {
3960
+ const entity = body[rootKey];
3961
+ if (!entity || typeof entity !== "object" || Array.isArray(entity)) {
3962
+ throw new CliError({
3963
+ message: `Invalid payload. Expected object at "${rootKey}".`,
3964
+ kind: "invalid_args",
3965
+ status: 400,
3966
+ exitCode: EXIT_CODES.invalidArgs
3967
+ });
3968
+ }
3969
+ const value = entity[parentKey];
3970
+ if (!(typeof value === "string" && value.trim().length > 0)) {
3971
+ throw new CliError({
3972
+ message: `Missing required create field for ${rootKey}: ${parentKey}.`,
3973
+ kind: "invalid_args",
3974
+ status: 400,
3975
+ exitCode: EXIT_CODES.invalidArgs
3976
+ });
3977
+ }
3978
+ }
3979
+ function attrValue(attrs, keys) {
3980
+ if (!attrs || typeof attrs !== "object" || Array.isArray(attrs)) {
3981
+ return void 0;
3982
+ }
3983
+ const record = attrs;
3984
+ for (const key of keys) {
3985
+ if (record[key] !== void 0 && record[key] !== null && `${record[key]}`.trim() !== "") {
3986
+ return record[key];
3987
+ }
3988
+ }
3989
+ return void 0;
3990
+ }
3991
+ function normalizePlacementRow(row, parentKind, parentIdFallback, parentTypedField) {
3992
+ const typedParent = parentTypedField ? row[parentTypedField] : void 0;
3993
+ const parentId = (typeof typedParent === "string" && typedParent.trim().length > 0 ? typedParent : void 0) ?? parentIdFallback ?? null;
3994
+ const attrs = row.attributes;
3995
+ const memberId = (typeof row.memberId === "string" ? row.memberId : void 0) ?? attrValue(attrs, ["memberId", "member_id"]) ?? null;
3996
+ const creatorId = (typeof row.creatorId === "string" ? row.creatorId : void 0) ?? attrValue(attrs, ["creatorId", "creator_id"]) ?? null;
3997
+ const ownerRaw = attrValue(attrs, ["memberId", "member_id", "creatorId", "creator_id"]) ?? null;
3998
+ const description = (typeof row.description === "string" && row.description.length > 0 ? row.description : attrValue(attrs, ["description"])) ?? null;
3999
+ return {
4000
+ id: row.id ?? null,
4001
+ type: row.type ?? null,
4002
+ parent: {
4003
+ kind: parentKind,
4004
+ id: parentId
4005
+ },
4006
+ owner: {
4007
+ memberId,
4008
+ creatorId,
4009
+ raw: ownerRaw
4010
+ },
4011
+ description,
4012
+ attributes: attrs ?? {}
4013
+ };
4014
+ }
4015
+ function normalizeListPayload(payload, parentKind, parentIdFallback, parentTypedField) {
4016
+ const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
4017
+ const rows = Array.isArray(record.data) ? record.data : [];
4018
+ const normalizedRows = rows.map(
4019
+ (row) => normalizePlacementRow(
4020
+ row,
4021
+ parentKind,
4022
+ parentIdFallback,
4023
+ parentTypedField
4024
+ )
4025
+ );
4026
+ return {
4027
+ data: normalizedRows,
4028
+ count: record.count ?? normalizedRows.length,
4029
+ currentPage: record.currentPage ?? 1,
4030
+ totalPages: record.totalPages ?? 1
4031
+ };
4032
+ }
4033
+ function normalizeSubtaskCreateBody(body) {
4034
+ const subtask = body.subtask;
4035
+ if (!subtask || typeof subtask !== "object" || Array.isArray(subtask)) {
4036
+ return body;
4037
+ }
4038
+ const subtaskRecord = subtask;
4039
+ const summary = typeof subtaskRecord.summary === "string" ? subtaskRecord.summary.trim() : void 0;
4040
+ const hasName = typeof subtaskRecord.name === "string" && subtaskRecord.name.trim().length > 0;
4041
+ if (!hasName && summary && summary.length > 0) {
4042
+ subtaskRecord.name = summary;
4043
+ }
4044
+ delete subtaskRecord.summary;
4045
+ return body;
4046
+ }
4047
+ function registerChildCommands(program, config) {
4048
+ const command = program.command(config.command).description(config.description);
4049
+ command.command("list").requiredOption(`--${config.parentFlag} <${config.parentFlag}>`).option("--page <page>").option("--per <per>").action(async (opts, cmd) => {
4050
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4051
+ const organizationId = resolveOrganizationId(context.organizationId);
4052
+ const parentId = idSchema11.parse(opts[config.parentFlag.replace(/-([a-z])/g, (_, c) => c.toUpperCase())]);
4053
+ await runGraphqlQueryCommand({
4054
+ command: `${config.command}.list`,
4055
+ operationName: config.listOperationName,
4056
+ runtimeOptions: context.runtimeOptions,
4057
+ field: config.listField,
4058
+ variables: {
4059
+ organization_id: organizationId,
4060
+ [config.parentFlag.replace(/-/g, "_")]: parentId,
4061
+ page: opts.page,
4062
+ per: opts.per
4063
+ },
4064
+ isList: true,
4065
+ selectionSet: config.listSelectionSet,
4066
+ transformData: (payload) => normalizeListPayload(
4067
+ payload,
4068
+ config.parentKind,
4069
+ parentId,
4070
+ config.listParentTypedField
4071
+ )
4072
+ });
4073
+ });
4074
+ command.command("create").requiredOption("--data-json <dataJson>").action(async (opts, cmd) => {
4075
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4076
+ const organizationId = resolveOrganizationId(context.organizationId);
4077
+ let body = normalizeBody2(String(opts.dataJson), config.rootKey);
4078
+ if (config.normalizeCreateBody) {
4079
+ body = config.normalizeCreateBody(body);
4080
+ }
4081
+ assertRequiredParent(body, config.rootKey, config.parentFlag.replace(/-/g, "_"));
4082
+ await runGraphqlMutationCommand({
4083
+ command: `${config.command}.create`,
4084
+ operationName: config.createOperationName,
4085
+ runtimeOptions: context.runtimeOptions,
4086
+ field: config.createField,
4087
+ variables: {
4088
+ organization_id: organizationId,
4089
+ params: body
4090
+ }
4091
+ });
4092
+ });
4093
+ command.command("update").requiredOption("--id <id>").requiredOption("--data-json <dataJson>").action(async (opts, cmd) => {
4094
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4095
+ const organizationId = resolveOrganizationId(context.organizationId);
4096
+ const id = idSchema11.parse(opts.id);
4097
+ const body = normalizeBody2(String(opts.dataJson), config.rootKey);
4098
+ await runGraphqlMutationCommand({
4099
+ command: `${config.command}.update`,
4100
+ operationName: config.updateOperationName,
4101
+ runtimeOptions: context.runtimeOptions,
4102
+ field: config.updateField,
4103
+ variables: {
4104
+ organization_id: organizationId,
4105
+ [config.idVariable]: id,
4106
+ params: body
4107
+ }
4108
+ });
4109
+ });
4110
+ command.command("destroy").requiredOption("--id <id>").action(async (opts, cmd) => {
4111
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4112
+ const organizationId = resolveOrganizationId(context.organizationId);
4113
+ const id = idSchema11.parse(opts.id);
4114
+ await runGraphqlMutationCommand({
4115
+ command: `${config.command}.destroy`,
4116
+ operationName: config.destroyOperationName,
4117
+ runtimeOptions: context.runtimeOptions,
4118
+ field: config.destroyField,
4119
+ variables: {
4120
+ organization_id: organizationId,
4121
+ [config.idVariable]: id
4122
+ }
4123
+ });
4124
+ });
4125
+ }
4126
+ function registerChildEntityCommands(program) {
4127
+ registerChildCommands(program, {
4128
+ command: "subtasks",
4129
+ description: "Subtask operations",
4130
+ parentFlag: "task-id",
4131
+ parentKind: "task",
4132
+ rootKey: "subtask",
4133
+ listField: "subtasks",
4134
+ createField: "create_subtask",
4135
+ updateField: "update_subtask",
4136
+ destroyField: "destroy_subtask",
4137
+ idVariable: "subtask_id",
4138
+ listOperationName: "SubtasksForTask",
4139
+ createOperationName: "CreateSubtask",
4140
+ updateOperationName: "UpdateSubtask",
4141
+ destroyOperationName: "DestroySubtask",
4142
+ listSelectionSet: "{ data { id type name status taskId attributes } count currentPage totalPages }",
4143
+ listParentTypedField: "taskId",
4144
+ normalizeCreateBody: normalizeSubtaskCreateBody
4145
+ });
4146
+ registerChildCommands(program, {
4147
+ command: "milestones",
4148
+ description: "Milestone operations",
4149
+ parentFlag: "rock-id",
4150
+ parentKind: "rock",
4151
+ rootKey: "milestone",
4152
+ listField: "milestones",
4153
+ createField: "create_milestone",
4154
+ updateField: "update_milestone",
4155
+ destroyField: "destroy_milestone",
4156
+ idVariable: "milestone_id",
4157
+ listOperationName: "MilestonesForRock",
4158
+ createOperationName: "CreateMilestone",
4159
+ updateOperationName: "UpdateMilestone",
4160
+ destroyOperationName: "DestroyMilestone",
4161
+ listSelectionSet: "{ data { id type name slug status attributes } count currentPage totalPages }"
4162
+ });
4163
+ registerChildCommands(program, {
4164
+ command: "subitems",
4165
+ description: "Subitem operations",
4166
+ parentFlag: "list-item-id",
4167
+ parentKind: "listItem",
4168
+ rootKey: "subitem",
4169
+ listField: "subitems",
4170
+ createField: "create_subitem",
4171
+ updateField: "update_subitem",
4172
+ destroyField: "destroy_subitem",
4173
+ idVariable: "subitem_id",
4174
+ listOperationName: "SubitemsForListItem",
4175
+ createOperationName: "CreateSubitem",
4176
+ updateOperationName: "UpdateSubitem",
4177
+ destroyOperationName: "DestroySubitem",
4178
+ listSelectionSet: "{ data { id type name status listItemId attributes } count currentPage totalPages }",
4179
+ listParentTypedField: "listItemId"
4180
+ });
4181
+ registerChildCommands(program, {
4182
+ command: "subtodos",
4183
+ description: "Subtodo operations",
4184
+ parentFlag: "todo-id",
4185
+ parentKind: "todo",
4186
+ rootKey: "sub_todo",
4187
+ listField: "sub_todos",
4188
+ createField: "create_sub_todo",
4189
+ updateField: "update_sub_todo",
4190
+ destroyField: "destroy_sub_todo",
4191
+ idVariable: "sub_todo_id",
4192
+ listOperationName: "SubtodosForTodo",
4193
+ createOperationName: "CreateSubTodo",
4194
+ updateOperationName: "UpdateSubTodo",
4195
+ destroyOperationName: "DestroySubTodo",
4196
+ listSelectionSet: "{ data { id type name status todoId attributes } count currentPage totalPages }",
4197
+ listParentTypedField: "todoId"
4198
+ });
4199
+ registerChildCommands(program, {
4200
+ command: "subissues",
4201
+ description: "Subissue operations",
4202
+ parentFlag: "issue-id",
4203
+ parentKind: "issue",
4204
+ rootKey: "sub_issue",
4205
+ listField: "sub_issues",
4206
+ createField: "create_sub_issue",
4207
+ updateField: "update_sub_issue",
4208
+ destroyField: "destroy_sub_issue",
4209
+ idVariable: "sub_issue_id",
4210
+ listOperationName: "SubissuesForIssue",
4211
+ createOperationName: "CreateSubIssue",
4212
+ updateOperationName: "UpdateSubIssue",
4213
+ destroyOperationName: "DestroySubIssue",
4214
+ listSelectionSet: "{ data { id type name status issueId attributes } count currentPage totalPages }",
4215
+ listParentTypedField: "issueId"
4216
+ });
4217
+ registerChildCommands(program, {
4218
+ command: "talking-points",
4219
+ description: "Talking point operations",
4220
+ parentFlag: "meeting-id",
4221
+ parentKind: "meeting",
4222
+ rootKey: "talking_point",
4223
+ listField: "talking_points",
4224
+ createField: "create_talking_point",
4225
+ updateField: "update_talking_point",
4226
+ destroyField: "destroy_talking_point",
4227
+ idVariable: "talking_point_id",
4228
+ listOperationName: "TalkingPointsForMeeting",
4229
+ createOperationName: "CreateTalkingPoint",
4230
+ updateOperationName: "UpdateTalkingPoint",
4231
+ destroyOperationName: "DestroyTalkingPoint",
4232
+ listSelectionSet: "{ data { id type name description status priority rank dueDate memberId creatorId meetingId attributes } count currentPage totalPages }",
4233
+ listParentTypedField: "meetingId"
4234
+ });
4235
+ }
4236
+
4237
+ // src/commands/notes.ts
4238
+ import { z as z13 } from "zod";
4239
+ var idSchema12 = z13.string().min(1);
4240
+ var nonEmptyString = z13.string().min(1);
4241
+ function assertUpdateFields(params) {
4242
+ if (!params.name && !params.content && !params.status) {
4243
+ throw new CliError({
4244
+ message: "notes update requires at least one of --name, --body, or --status.",
4245
+ kind: "invalid_args",
4246
+ status: 400,
4247
+ exitCode: EXIT_CODES.invalidArgs
4248
+ });
4249
+ }
4250
+ }
4251
+ async function createContent(command, cmd, payload) {
4252
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4253
+ const organizationId = resolveOrganizationId(context.organizationId);
4254
+ return runGraphqlMutationCommand({
4255
+ command,
4256
+ operationName: "CreateContent",
4257
+ runtimeOptions: context.runtimeOptions,
4258
+ field: "create_content",
4259
+ variables: normalizeGraphqlVariables2({
4260
+ organization_id: organizationId,
4261
+ params: {
4262
+ content: payload
4263
+ }
4264
+ })
4265
+ });
4266
+ }
4267
+ function registerNoteCommands(program) {
4268
+ const notes = program.command("notes").description("Content note operations");
4269
+ notes.command("list").option("--contentable-type <contentableType>").option("--contentable-id <contentableId>").option("--member-id <memberId>").option("--focus-member-id <focusMemberId>").option("--focus-team-id <focusTeamId>").option("--page <page>").option("--per <per>").action(async (opts, cmd) => {
4270
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4271
+ const organizationId = resolveOrganizationId(context.organizationId);
4272
+ await runGraphqlQueryCommand({
4273
+ command: "notes.list",
4274
+ operationName: "ContentsIndex",
4275
+ runtimeOptions: context.runtimeOptions,
4276
+ field: "contents",
4277
+ variables: normalizeGraphqlVariables2({
4278
+ organization_id: organizationId,
4279
+ contentable_type: opts.contentableType,
4280
+ contentable_id: opts.contentableId,
4281
+ member_id: opts.memberId,
4282
+ focus_member_id: opts.focusMemberId,
4283
+ focus_team_id: opts.focusTeamId,
4284
+ page: opts.page,
4285
+ per: opts.per
4286
+ }),
4287
+ isList: true,
4288
+ selectionSet: "{ count currentPage totalPages data { id type name contentableType contentableId memberId focusMemberId focusTeamId attributes } }"
4289
+ });
4290
+ });
4291
+ notes.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
4292
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4293
+ const organizationId = resolveOrganizationId(context.organizationId);
4294
+ const id = idSchema12.parse(opts.id);
4295
+ await runGraphqlQueryCommand({
4296
+ command: "notes.show",
4297
+ operationName: "ContentShow",
4298
+ runtimeOptions: context.runtimeOptions,
4299
+ field: "content",
4300
+ variables: normalizeGraphqlVariables2({
4301
+ organization_id: organizationId,
4302
+ id
4303
+ }),
4304
+ isShow: true,
4305
+ selectionSet: "{ id type name contentableType contentableId memberId focusMemberId focusTeamId attributes }"
4306
+ });
4307
+ });
4308
+ notes.command("update").requiredOption("--id <id>").option("--name <name>").option("--body <body>").option("--status <status>").action(async (opts, cmd) => {
4309
+ assertUpdateFields({
4310
+ name: opts.name,
4311
+ content: opts.body,
4312
+ status: opts.status
4313
+ });
4314
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4315
+ const organizationId = resolveOrganizationId(context.organizationId);
4316
+ const contentId = idSchema12.parse(opts.id);
4317
+ await runGraphqlMutationCommand({
4318
+ command: "notes.update",
4319
+ operationName: "UpdateContent",
4320
+ runtimeOptions: context.runtimeOptions,
4321
+ field: "update_content",
4322
+ variables: normalizeGraphqlVariables2({
4323
+ organization_id: organizationId,
4324
+ content_id: contentId,
4325
+ params: {
4326
+ content: normalizeGraphqlVariables2({
4327
+ name: opts.name,
4328
+ content: opts.body,
4329
+ status: opts.status
4330
+ })
4331
+ }
4332
+ })
4333
+ });
4334
+ });
4335
+ notes.command("destroy").requiredOption("--id <id>").action(async (opts, cmd) => {
4336
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4337
+ const organizationId = resolveOrganizationId(context.organizationId);
4338
+ const contentId = idSchema12.parse(opts.id);
4339
+ await runGraphqlMutationCommand({
4340
+ command: "notes.destroy",
4341
+ operationName: "DestroyContent",
4342
+ runtimeOptions: context.runtimeOptions,
4343
+ field: "destroy_content",
4344
+ variables: normalizeGraphqlVariables2({
4345
+ organization_id: organizationId,
4346
+ content_id: contentId
4347
+ })
4348
+ });
4349
+ });
4350
+ notes.command("create-member").requiredOption("--target-member-id <targetMemberId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
4351
+ const targetMemberId = nonEmptyString.parse(opts.targetMemberId);
4352
+ await createContent("notes.create-member", cmd, {
4353
+ type: "WrittenContent",
4354
+ name: nonEmptyString.parse(opts.name),
4355
+ content: nonEmptyString.parse(opts.body),
4356
+ status: String(opts.status ?? "draft"),
4357
+ contentable_type: "Member",
4358
+ contentable_id: targetMemberId,
4359
+ member_id: targetMemberId,
4360
+ focus_member_id: null,
4361
+ focus_team_id: null
4362
+ });
4363
+ });
4364
+ notes.command("create-manager").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--target-member-id <targetMemberId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
4365
+ const actorMemberId = nonEmptyString.parse(opts.actorMemberId);
4366
+ await createContent("notes.create-manager", cmd, {
4367
+ type: "WrittenContent",
4368
+ name: nonEmptyString.parse(opts.name),
4369
+ content: nonEmptyString.parse(opts.body),
4370
+ status: String(opts.status ?? "draft"),
4371
+ contentable_type: "Member",
4372
+ contentable_id: actorMemberId,
4373
+ member_id: actorMemberId,
4374
+ focus_member_id: nonEmptyString.parse(opts.targetMemberId)
4375
+ });
4376
+ });
4377
+ notes.command("create-team").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--team-id <teamId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
4378
+ const actorMemberId = nonEmptyString.parse(opts.actorMemberId);
4379
+ const teamId = nonEmptyString.parse(opts.teamId);
4380
+ await createContent("notes.create-team", cmd, {
4381
+ type: "WrittenContent",
4382
+ name: nonEmptyString.parse(opts.name),
4383
+ content: nonEmptyString.parse(opts.body),
4384
+ status: String(opts.status ?? "draft"),
4385
+ contentable_type: "Team",
4386
+ contentable_id: teamId,
4387
+ member_id: actorMemberId,
4388
+ focus_team_id: teamId
4389
+ });
4390
+ });
4391
+ notes.command("create-project").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--project-id <projectId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
4392
+ await createContent("notes.create-project", cmd, {
4393
+ type: "WrittenContent",
4394
+ name: nonEmptyString.parse(opts.name),
4395
+ content: nonEmptyString.parse(opts.body),
4396
+ status: String(opts.status ?? "draft"),
4397
+ contentable_type: "Project",
4398
+ contentable_id: nonEmptyString.parse(opts.projectId),
4399
+ member_id: nonEmptyString.parse(opts.actorMemberId)
4400
+ });
4401
+ });
4402
+ notes.command("create-customer").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--customer-id <customerId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
4403
+ await createContent("notes.create-customer", cmd, {
4404
+ type: "WrittenContent",
4405
+ name: nonEmptyString.parse(opts.name),
4406
+ content: nonEmptyString.parse(opts.body),
4407
+ status: String(opts.status ?? "draft"),
4408
+ contentable_type: "Customer",
4409
+ contentable_id: nonEmptyString.parse(opts.customerId),
4410
+ member_id: nonEmptyString.parse(opts.actorMemberId)
4411
+ });
4412
+ });
4413
+ notes.command("create-contact").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--contact-id <contactId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
4414
+ await createContent("notes.create-contact", cmd, {
4415
+ type: "WrittenContent",
4416
+ name: nonEmptyString.parse(opts.name),
4417
+ content: nonEmptyString.parse(opts.body),
4418
+ status: String(opts.status ?? "draft"),
4419
+ contentable_type: "Contact",
4420
+ contentable_id: nonEmptyString.parse(opts.contactId),
4421
+ member_id: nonEmptyString.parse(opts.actorMemberId)
4422
+ });
4423
+ });
4424
+ }
4425
+
4426
+ // src/commands/markdownTree.ts
4427
+ import { z as z14 } from "zod";
4428
+ var nonEmptyString2 = z14.string().min(1);
4429
+ var nonNegativeInt = z14.coerce.number().int().min(0);
4430
+ function addScopeOptions(command) {
4431
+ return command.requiredOption("--tool-key <toolKey>").requiredOption("--node-key <nodeKey>").option("--parent-id <parentId>").option("--record-id <recordId>").option("--member-id <memberId>").option("--team-id <teamId>").option("--content-type <contentType>").option("--tree-view");
4432
+ }
4433
+ function parseScopeOptions(raw) {
4434
+ const parsed = {
4435
+ toolKey: nonEmptyString2.parse(raw.toolKey),
4436
+ nodeKey: nonEmptyString2.parse(raw.nodeKey)
4437
+ };
4438
+ if (typeof raw.parentId === "string" && raw.parentId.trim() !== "") {
4439
+ parsed.parentId = raw.parentId.trim();
4440
+ }
4441
+ if (typeof raw.recordId === "string" && raw.recordId.trim() !== "") {
4442
+ parsed.recordId = raw.recordId.trim();
4443
+ }
4444
+ if (typeof raw.memberId === "string" && raw.memberId.trim() !== "") {
4445
+ parsed.memberId = raw.memberId.trim();
4446
+ }
4447
+ if (typeof raw.teamId === "string" && raw.teamId.trim() !== "") {
4448
+ parsed.teamId = raw.teamId.trim();
4449
+ }
4450
+ if (typeof raw.contentType === "string" && raw.contentType.trim() !== "") {
4451
+ parsed.contentType = raw.contentType.trim();
4452
+ }
4453
+ if (raw.treeView === true) {
4454
+ parsed.treeView = true;
4455
+ }
4456
+ return parsed;
4457
+ }
4458
+ function baseNodeFields() {
4459
+ return [
4460
+ "toolKey",
4461
+ "nodeKey",
4462
+ "nodeKind",
4463
+ "runtimeLabel",
4464
+ "resolvedScope { parentId recordId memberId teamId contentType }",
4465
+ "isLeaf",
4466
+ "treeView",
4467
+ "details"
4468
+ ].join(" ");
4469
+ }
4470
+ function buildChildSelection(depth) {
4471
+ if (depth <= 0) return "";
4472
+ const nested = buildChildSelection(depth - 1);
4473
+ return nested.length > 0 ? `children { ${baseNodeFields()} ${nested} }` : `children { ${baseNodeFields()} }`;
4474
+ }
4475
+ function buildNodeSelectionSet(depth) {
4476
+ const nested = buildChildSelection(depth);
4477
+ return nested.length > 0 ? `{ ${baseNodeFields()} ${nested} }` : `{ ${baseNodeFields()} }`;
4478
+ }
4479
+ function requireExplicitDepth(rawDepth) {
4480
+ if (rawDepth === void 0 || rawDepth === null || rawDepth === "") {
4481
+ throw new CliError({
4482
+ message: "Missing required --depth for markdown-tree subtree.",
4483
+ kind: "invalid_args",
4484
+ status: 400,
4485
+ exitCode: EXIT_CODES.invalidArgs
4486
+ });
4487
+ }
4488
+ return nonNegativeInt.parse(rawDepth);
4489
+ }
4490
+ function registerMarkdownTreeCommands(program) {
4491
+ const markdownTree = program.command("markdown-tree").description("Markdown tree traversal operations");
4492
+ markdownTree.command("root").option("--tree-view").action(async (opts, cmd) => {
4493
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4494
+ const organizationId = resolveOrganizationId(context.organizationId);
4495
+ await runGraphqlQueryCommand({
4496
+ command: "markdown-tree.root",
4497
+ operationName: "MarkdownTreeRoot",
4498
+ runtimeOptions: context.runtimeOptions,
4499
+ field: "markdown_tree_root",
4500
+ variables: {
4501
+ organization_id: organizationId,
4502
+ tree_view: opts.treeView === true ? true : void 0
4503
+ },
4504
+ selectionSet: buildNodeSelectionSet(1),
4505
+ isShow: true
4506
+ });
4507
+ });
4508
+ addScopeOptions(markdownTree.command("resolve")).action(async (opts, cmd) => {
4509
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4510
+ const organizationId = resolveOrganizationId(context.organizationId);
4511
+ const scope = parseScopeOptions(opts);
4512
+ await runGraphqlQueryCommand({
4513
+ command: "markdown-tree.resolve",
4514
+ operationName: "MarkdownTreeNode",
4515
+ runtimeOptions: context.runtimeOptions,
4516
+ field: "markdown_tree_node",
4517
+ variables: {
4518
+ organization_id: organizationId,
4519
+ tool_key: scope.toolKey,
4520
+ node_key: scope.nodeKey,
4521
+ parent_id: scope.parentId,
4522
+ record_id: scope.recordId,
4523
+ member_id: scope.memberId,
4524
+ team_id: scope.teamId,
4525
+ content_type: scope.contentType,
4526
+ tree_view: scope.treeView
4527
+ },
4528
+ selectionSet: buildNodeSelectionSet(1),
4529
+ isShow: true
4530
+ });
4531
+ });
4532
+ addScopeOptions(markdownTree.command("children")).action(async (opts, cmd) => {
4533
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4534
+ const organizationId = resolveOrganizationId(context.organizationId);
4535
+ const scope = parseScopeOptions(opts);
4536
+ await runGraphqlQueryCommand({
4537
+ command: "markdown-tree.children",
4538
+ operationName: "MarkdownTreeChildren",
4539
+ runtimeOptions: context.runtimeOptions,
4540
+ field: "markdown_tree_children",
4541
+ variables: {
4542
+ organization_id: organizationId,
4543
+ tool_key: scope.toolKey,
4544
+ node_key: scope.nodeKey,
4545
+ parent_id: scope.parentId,
4546
+ record_id: scope.recordId,
4547
+ member_id: scope.memberId,
4548
+ team_id: scope.teamId,
4549
+ content_type: scope.contentType,
4550
+ tree_view: scope.treeView
4551
+ },
4552
+ selectionSet: buildNodeSelectionSet(1),
4553
+ isShow: true
4554
+ });
4555
+ });
4556
+ addScopeOptions(
4557
+ markdownTree.command("subtree").requiredOption("--depth <depth>")
4558
+ ).action(async (opts, cmd) => {
4559
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4560
+ const organizationId = resolveOrganizationId(context.organizationId);
4561
+ const scope = parseScopeOptions(opts);
4562
+ const depth = requireExplicitDepth(opts.depth);
4563
+ await runGraphqlQueryCommand({
4564
+ command: "markdown-tree.subtree",
4565
+ operationName: "MarkdownTreeSubtree",
4566
+ runtimeOptions: context.runtimeOptions,
4567
+ field: "markdown_tree_subtree",
4568
+ variables: {
4569
+ organization_id: organizationId,
4570
+ tool_key: scope.toolKey,
4571
+ node_key: scope.nodeKey,
4572
+ parent_id: scope.parentId,
4573
+ record_id: scope.recordId,
4574
+ member_id: scope.memberId,
4575
+ team_id: scope.teamId,
4576
+ content_type: scope.contentType,
4577
+ tree_view: scope.treeView,
4578
+ depth
4579
+ },
4580
+ selectionSet: buildNodeSelectionSet(depth + 1),
4581
+ isShow: true
4582
+ });
4583
+ });
4584
+ }
4585
+
4586
+ // src/commands/navigation.ts
4587
+ import { z as z15 } from "zod";
4588
+
4589
+ // src/internalOptions.ts
4590
+ var INTERNAL_OPTIONS_KEY = "__waveInternalOptions";
4591
+ function asRecord2(value) {
4592
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
4593
+ return null;
4594
+ }
4595
+ return value;
4596
+ }
4597
+ function setInternalCliOptions(program, options) {
4598
+ if (!options) return;
4599
+ const target = program;
4600
+ target[INTERNAL_OPTIONS_KEY] = { ...options };
4601
+ }
4602
+ function getInternalCliOptions(command) {
4603
+ let current = command;
4604
+ while (current) {
4605
+ const record = asRecord2(current[INTERNAL_OPTIONS_KEY]);
4606
+ if (record) {
4607
+ return {
4608
+ enableRetryOnEmptyPhrase: record.enableRetryOnEmptyPhrase === true
4609
+ };
4610
+ }
4611
+ current = current.parent ?? null;
4612
+ }
4613
+ return {};
4614
+ }
4615
+
4616
+ // src/commands/navigation.ts
4617
+ var nonEmpty = z15.string().min(1);
4618
+ var nonNegativeInt2 = z15.coerce.number().int().min(0);
4619
+ var MIGRATED_BRANCHES = ["directory", "projects", "knowledge"];
4620
+ function normalizeText(input) {
4621
+ if (typeof input !== "string") return "";
4622
+ return input.trim().toLowerCase().replace(/\s+/g, " ");
4623
+ }
4624
+ function toDisplay(input) {
4625
+ if (typeof input !== "string") return "";
4626
+ const value = input.trim();
4627
+ return value.length > 0 ? value : "";
4628
+ }
4629
+ function asObject(value) {
4630
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
4631
+ }
4632
+ function asArray(value) {
4633
+ return Array.isArray(value) ? value : [];
4634
+ }
4635
+ function parseScopeFromOptions(raw) {
4636
+ const scope = {
4637
+ toolKey: nonEmpty.parse(raw.toolKey),
4638
+ nodeKey: nonEmpty.parse(raw.nodeKey)
4639
+ };
4640
+ if (typeof raw.parentId === "string" && raw.parentId.trim() !== "") {
4641
+ scope.parentId = raw.parentId.trim();
4642
+ }
4643
+ if (typeof raw.recordId === "string" && raw.recordId.trim() !== "") {
4644
+ scope.recordId = raw.recordId.trim();
4645
+ }
4646
+ if (typeof raw.memberId === "string" && raw.memberId.trim() !== "") {
4647
+ scope.memberId = raw.memberId.trim();
4648
+ }
4649
+ if (typeof raw.teamId === "string" && raw.teamId.trim() !== "") {
4650
+ scope.teamId = raw.teamId.trim();
4651
+ }
4652
+ if (typeof raw.contentType === "string" && raw.contentType.trim() !== "") {
4653
+ scope.contentType = raw.contentType.trim();
4654
+ }
4655
+ if (raw.treeView === true) {
4656
+ scope.treeView = true;
4657
+ }
4658
+ return scope;
4659
+ }
4660
+ function parseOptionalScopeFromOptions(raw) {
4661
+ if (typeof raw.toolKey !== "string" || raw.toolKey.trim() === "") {
4662
+ return null;
4663
+ }
4664
+ if (typeof raw.nodeKey !== "string" || raw.nodeKey.trim() === "") {
4665
+ return null;
4666
+ }
4667
+ return parseScopeFromOptions(raw);
4668
+ }
4669
+ function scopeFromCandidate(candidate, treeView) {
4670
+ const scopeObj = asObject(candidate.scope);
4671
+ const resolvedScopeObj = asObject(candidate.resolvedScope);
4672
+ const normalizedScope = Object.keys(scopeObj).length > 0 ? scopeObj : resolvedScopeObj;
4673
+ const toolKey = toDisplay(candidate.toolKey);
4674
+ const nodeKey = toDisplay(candidate.nodeKey);
4675
+ return {
4676
+ toolKey,
4677
+ nodeKey,
4678
+ parentId: toDisplay(normalizedScope.parentId) || void 0,
4679
+ recordId: toDisplay(normalizedScope.recordId) || void 0,
4680
+ memberId: toDisplay(normalizedScope.memberId) || void 0,
4681
+ teamId: toDisplay(normalizedScope.teamId) || void 0,
4682
+ contentType: toDisplay(normalizedScope.contentType) || void 0,
4683
+ treeView
4684
+ };
4685
+ }
4686
+ function notFoundEnvelope(params) {
4687
+ return {
4688
+ ok: false,
4689
+ command: params.command,
4690
+ status: 404,
4691
+ data: null,
4692
+ error: {
4693
+ code: "not_found",
4694
+ message: params.message,
4695
+ details: {}
4696
+ },
4697
+ meta: {
4698
+ requestId: params.requestId ?? "local_error"
4699
+ }
4700
+ };
4701
+ }
4702
+ function ambiguityEnvelope(params) {
4703
+ return {
4704
+ ok: false,
4705
+ command: params.command,
4706
+ status: 409,
4707
+ data: null,
4708
+ error: {
4709
+ code: "ambiguous_match",
4710
+ message: params.message,
4711
+ details: {
4712
+ candidates: params.candidates
4713
+ }
4714
+ },
4715
+ meta: {
4716
+ requestId: params.requestId ?? "local_error"
4717
+ }
4718
+ };
4719
+ }
4720
+ function unsupportedBranchEnvelope(params) {
4721
+ const tool = params.tool ?? "unknown";
4722
+ return {
4723
+ ok: false,
4724
+ command: params.command,
4725
+ status: 400,
4726
+ data: null,
4727
+ error: {
4728
+ code: "unsupported_branch",
4729
+ message: `This branch isn't migrated to markdown-tree yet: ${tool}. Try directory/projects/knowledge.`,
4730
+ details: {
4731
+ tool,
4732
+ migratedBranches: [...MIGRATED_BRANCHES],
4733
+ originalError: params.originalError ?? null
4734
+ }
4735
+ },
4736
+ meta: {
4737
+ requestId: params.requestId ?? "local_error"
4738
+ }
4739
+ };
4740
+ }
4741
+ function parseToolFromGraphqlError(errorBody) {
4742
+ const errorObj = asObject(errorBody);
4743
+ const details = asObject(errorObj.details);
4744
+ const errors = asArray(details.errors);
4745
+ for (const item of errors) {
4746
+ const message = toDisplay(item.message);
4747
+ if (message === "") continue;
4748
+ const match = message.match(/tool_key=([a-zA-Z0-9_]+)/);
4749
+ if (match?.[1]) {
4750
+ return match[1];
4751
+ }
4752
+ }
4753
+ return null;
4754
+ }
4755
+ function toolHintFromPathLike(value) {
4756
+ const text = toDisplay(value);
4757
+ if (text === "") return null;
4758
+ const [first] = text.split("/");
4759
+ return first ? first.trim() : null;
4760
+ }
4761
+ function unsupportedToolFromHints(params) {
4762
+ const fromError = parseToolFromGraphqlError(params.envelopeError);
4763
+ if (fromError) return fromError;
4764
+ return toDisplay(params.explicitTool) || toolHintFromPathLike(params.underPath) || toolHintFromPathLike(params.queryLike) || "unknown";
4765
+ }
4766
+ async function requestTraversal(params) {
4767
+ const config = getConfig(params.runtimeOptions);
4768
+ const result = await graphqlRequest({
4769
+ config,
4770
+ command: params.command,
4771
+ operationName: params.operationName,
4772
+ operationType: "query",
4773
+ field: params.field,
4774
+ variables: params.variables,
4775
+ selectionSet: buildNodeSelectionSet(params.depth),
4776
+ isShow: true
4777
+ });
4778
+ if (!result.envelope.ok) {
4779
+ if (result.envelope.error?.code === "unsupported_branch") {
4780
+ printEnvelopeAndExit({
4781
+ envelope: unsupportedBranchEnvelope({
4782
+ command: params.command,
4783
+ requestId: result.envelope.meta.requestId,
4784
+ tool: unsupportedToolFromHints({
4785
+ explicitTool: params.variables.tool_key,
4786
+ envelopeError: result.envelope.error
4787
+ }),
4788
+ originalError: asObject(result.envelope.error)
4789
+ }),
4790
+ exitCode: result.exitCode
4791
+ });
4792
+ }
4793
+ printEnvelopeAndExit({
4794
+ envelope: result.envelope,
4795
+ exitCode: result.exitCode
4796
+ });
4797
+ }
4798
+ const data = asObject(result.envelope.data);
4799
+ return asObject(data[params.field]);
4800
+ }
4801
+ function findSelectionSet() {
4802
+ return `{
4803
+ query
4804
+ underPath
4805
+ candidates {
4806
+ label
4807
+ canonicalPath
4808
+ toolKey
4809
+ nodeKey
4810
+ nodeKind
4811
+ isLeaf
4812
+ scope { parentId recordId memberId teamId contentType }
4813
+ resolvedScope { parentId recordId memberId teamId contentType }
4814
+ matchType
4815
+ rank
4816
+ aliasMatched
4817
+ breadcrumb
4818
+ }
4819
+ }`;
4820
+ }
4821
+ async function requestFind(params) {
4822
+ const config = getConfig(params.runtimeOptions);
4823
+ const result = await graphqlRequest({
4824
+ config,
4825
+ command: params.command,
4826
+ operationName: "MarkdownTreeFind",
4827
+ operationType: "query",
4828
+ field: "markdown_tree_find",
4829
+ variables: {
4830
+ organization_id: params.organizationId,
4831
+ query: params.query,
4832
+ under_path: params.underPath,
4833
+ tool_key: params.toolKey,
4834
+ node_key: params.nodeKey,
4835
+ limit: params.limit
4836
+ },
4837
+ selectionSet: findSelectionSet(),
4838
+ isShow: true
4839
+ });
4840
+ if (!result.envelope.ok) {
4841
+ if (result.envelope.error?.code === "unsupported_branch") {
4842
+ printEnvelopeAndExit({
4843
+ envelope: unsupportedBranchEnvelope({
4844
+ command: params.command,
4845
+ requestId: result.envelope.meta.requestId,
4846
+ tool: unsupportedToolFromHints({
4847
+ explicitTool: params.toolKey,
4848
+ underPath: params.underPath,
4849
+ queryLike: params.query,
4850
+ envelopeError: result.envelope.error
4851
+ }),
4852
+ originalError: asObject(result.envelope.error)
4853
+ }),
4854
+ exitCode: result.exitCode
4855
+ });
4856
+ }
4857
+ printEnvelopeAndExit({
4858
+ envelope: result.envelope,
4859
+ exitCode: result.exitCode
4860
+ });
4861
+ }
4862
+ const data = asObject(result.envelope.data);
4863
+ const payload = asObject(data.markdown_tree_find);
4864
+ return {
4865
+ ...payload,
4866
+ candidates: asArray(payload.candidates)
4867
+ };
4868
+ }
4869
+ function matchTypePrecedence(candidate) {
4870
+ const matchType = toDisplay(candidate.matchType).toLowerCase();
4871
+ const order = {
4872
+ exact_label: 0,
4873
+ exact_path: 1,
4874
+ prefix_label: 2,
4875
+ path_prefix: 3,
4876
+ path_fragment: 4,
4877
+ alias_match: 5,
4878
+ fuzzy: 6
4879
+ };
4880
+ return order[matchType] ?? Number.POSITIVE_INFINITY;
4881
+ }
4882
+ function isTopCandidateDominant(candidates) {
4883
+ if (candidates.length <= 1) {
4884
+ return true;
4885
+ }
4886
+ const first = candidates[0];
4887
+ const second = candidates[1];
4888
+ if (typeof first.rank === "number" && typeof second.rank === "number") {
4889
+ return first.rank < second.rank;
4890
+ }
4891
+ const firstMatch = matchTypePrecedence(first);
4892
+ const secondMatch = matchTypePrecedence(second);
4893
+ if (Number.isFinite(firstMatch) || Number.isFinite(secondMatch)) {
4894
+ return firstMatch < secondMatch;
4895
+ }
4896
+ return false;
4897
+ }
4898
+ function findExactPathMatches(candidates, path) {
4899
+ const target = normalizeText(path);
4900
+ if (target === "") return [];
4901
+ return candidates.filter((candidate) => {
4902
+ const canonicalPath = toDisplay(candidate.canonicalPath);
4903
+ return normalizeText(canonicalPath) === target;
4904
+ });
4905
+ }
4906
+ async function resolvePathScope(params) {
4907
+ const findPayload = await requestFind({
4908
+ command: params.command,
4909
+ runtimeOptions: params.runtimeOptions,
4910
+ organizationId: params.organizationId,
4911
+ query: params.path,
4912
+ underPath: params.underPath,
4913
+ limit: 25
4914
+ });
4915
+ const exactMatches = findExactPathMatches(findPayload.candidates, params.path);
4916
+ if (exactMatches.length === 1) {
4917
+ return {
4918
+ scope: scopeFromCandidate(exactMatches[0], params.treeView),
4919
+ match: exactMatches[0],
4920
+ ambiguous: []
4921
+ };
4922
+ }
4923
+ if (exactMatches.length > 1) {
4924
+ return {
4925
+ ambiguous: exactMatches.slice(0, 10)
4926
+ };
4927
+ }
4928
+ return {
4929
+ ambiguous: []
4930
+ };
4931
+ }
4932
+ function isMultiWordQuery(query) {
4933
+ const parts = query.trim().split(/\s+/).filter((part) => part.length > 0);
4934
+ return parts.length > 1;
4935
+ }
4936
+ function reduceMultiWordQuery(query) {
4937
+ const tokens = query.trim().split(/\s+/).map((token) => token.replace(/^[^a-zA-Z0-9]+|[^a-zA-Z0-9]+$/g, "")).filter((token) => token.length > 0);
4938
+ if (tokens.length <= 1) return null;
4939
+ const meaningful = tokens.filter((token) => token.length >= 3);
4940
+ const selected = meaningful.length > 0 ? meaningful[meaningful.length - 1] : tokens[tokens.length - 1];
4941
+ return selected ?? null;
4942
+ }
4943
+ function registerNavigationCommands(program) {
4944
+ program.command("find <query>").description("Find nodes via backend-native markdown tree discovery").option("--under <under>").option("--path <path>").option("--tool-key <toolKey>").option("--node-key <nodeKey>").option("--limit <limit>").action(async (query, opts, cmd) => {
4945
+ const globals = cmd.optsWithGlobals();
4946
+ const context = await resolveCommandContext(globals);
4947
+ const organizationId = resolveOrganizationId(context.organizationId);
4948
+ const internalOptions = getInternalCliOptions(cmd);
4949
+ const limit = typeof opts.limit === "string" && opts.limit.trim() !== "" ? Math.max(1, Number.parseInt(opts.limit, 10) || 20) : 20;
4950
+ const underPath = typeof opts.under === "string" && opts.under.trim() !== "" ? opts.under.trim() : typeof opts.path === "string" && opts.path.trim() !== "" ? opts.path.trim() : void 0;
4951
+ const payload = await requestFind({
4952
+ command: "find",
4953
+ runtimeOptions: context.runtimeOptions,
4954
+ organizationId,
4955
+ query,
4956
+ underPath,
4957
+ toolKey: typeof opts.toolKey === "string" ? opts.toolKey : void 0,
4958
+ nodeKey: typeof opts.nodeKey === "string" ? opts.nodeKey : void 0,
4959
+ limit
4960
+ });
4961
+ let finalPayload = payload;
4962
+ let assistantRecovery;
4963
+ if (internalOptions.enableRetryOnEmptyPhrase === true && payload.candidates.length === 0 && isMultiWordQuery(query)) {
4964
+ const retryQuery = reduceMultiWordQuery(query);
4965
+ if (retryQuery && normalizeText(retryQuery) !== normalizeText(query)) {
4966
+ finalPayload = await requestFind({
4967
+ command: "find",
4968
+ runtimeOptions: context.runtimeOptions,
4969
+ organizationId,
4970
+ query: retryQuery,
4971
+ underPath,
4972
+ toolKey: typeof opts.toolKey === "string" ? opts.toolKey : void 0,
4973
+ nodeKey: typeof opts.nodeKey === "string" ? opts.nodeKey : void 0,
4974
+ limit
4975
+ });
4976
+ assistantRecovery = {
4977
+ triggered: true,
4978
+ originalQuery: query,
4979
+ retryQuery,
4980
+ reason: "empty_multi_word_query"
4981
+ };
4982
+ }
4983
+ }
4984
+ printEnvelopeAndExit({
4985
+ envelope: {
4986
+ ok: true,
4987
+ command: "find",
4988
+ status: 200,
4989
+ data: assistantRecovery ? {
4990
+ ...finalPayload,
4991
+ assistantRecovery
4992
+ } : finalPayload,
4993
+ error: null,
4994
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
4995
+ }
4996
+ });
4997
+ });
4998
+ program.command("open <name>").description("Resolve one node by backend discovery").option("--under <under>").option("--path <path>").option("--tool-key <toolKey>").option("--node-key <nodeKey>").option("--limit <limit>").option("--tree-view").action(async (name, opts, cmd) => {
4999
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5000
+ const organizationId = resolveOrganizationId(context.organizationId);
5001
+ const limit = typeof opts.limit === "string" && opts.limit.trim() !== "" ? Math.max(1, Number.parseInt(opts.limit, 10) || 10) : 10;
5002
+ const underPath = typeof opts.under === "string" && opts.under.trim() !== "" ? opts.under.trim() : typeof opts.path === "string" && opts.path.trim() !== "" ? opts.path.trim() : void 0;
5003
+ const payload = await requestFind({
5004
+ command: "open",
5005
+ runtimeOptions: context.runtimeOptions,
5006
+ organizationId,
5007
+ query: name,
5008
+ underPath,
5009
+ toolKey: typeof opts.toolKey === "string" ? opts.toolKey : void 0,
5010
+ nodeKey: typeof opts.nodeKey === "string" ? opts.nodeKey : void 0,
5011
+ limit
5012
+ });
5013
+ const candidates = payload.candidates;
5014
+ if (candidates.length === 0) {
5015
+ printEnvelopeAndExit({
5016
+ envelope: notFoundEnvelope({
5017
+ command: "open",
5018
+ message: `No node matched "${name}".`
5019
+ }),
5020
+ exitCode: EXIT_CODES.notFound
5021
+ });
5022
+ }
5023
+ if (candidates.length > 1 && !isTopCandidateDominant(candidates)) {
5024
+ printEnvelopeAndExit({
5025
+ envelope: ambiguityEnvelope({
5026
+ command: "open",
5027
+ message: `Multiple nodes matched "${name}".`,
5028
+ candidates: candidates.slice(0, 10)
5029
+ }),
5030
+ exitCode: EXIT_CODES.generic
5031
+ });
5032
+ }
5033
+ const selected = candidates[0];
5034
+ const scope = scopeFromCandidate(selected, opts.treeView === true);
5035
+ const node = await requestTraversal({
5036
+ command: "open",
5037
+ runtimeOptions: context.runtimeOptions,
5038
+ operationName: "MarkdownTreeNode",
5039
+ field: "markdown_tree_node",
5040
+ variables: {
5041
+ organization_id: organizationId,
5042
+ tool_key: scope.toolKey,
5043
+ node_key: scope.nodeKey,
5044
+ parent_id: scope.parentId,
5045
+ record_id: scope.recordId,
5046
+ member_id: scope.memberId,
5047
+ team_id: scope.teamId,
5048
+ content_type: scope.contentType,
5049
+ tree_view: scope.treeView
5050
+ },
5051
+ depth: 1
5052
+ });
5053
+ printEnvelopeAndExit({
5054
+ envelope: {
5055
+ ok: true,
5056
+ command: "open",
5057
+ status: 200,
5058
+ data: {
5059
+ match: selected,
5060
+ node
5061
+ },
5062
+ error: null,
5063
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
5064
+ }
5065
+ });
5066
+ });
5067
+ program.command("ls [query]").description("List direct children for a target").option("--path <path>").option("--under <under>").option("--tree-view").option("--tool-key <toolKey>").option("--node-key <nodeKey>").option("--parent-id <parentId>").option("--record-id <recordId>").option("--member-id <memberId>").option("--team-id <teamId>").option("--content-type <contentType>").action(async (query, opts, cmd) => {
5068
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5069
+ const organizationId = resolveOrganizationId(context.organizationId);
5070
+ let scope = null;
5071
+ let pathMatch = null;
5072
+ if (typeof opts.path === "string" && opts.path.trim() !== "") {
5073
+ const resolved = await resolvePathScope({
5074
+ command: "ls",
5075
+ runtimeOptions: context.runtimeOptions,
5076
+ organizationId,
5077
+ path: opts.path,
5078
+ underPath: typeof opts.under === "string" ? opts.under : void 0,
5079
+ treeView: opts.treeView === true
5080
+ });
5081
+ if (!resolved.scope) {
5082
+ if (resolved.ambiguous.length > 0) {
5083
+ printEnvelopeAndExit({
5084
+ envelope: ambiguityEnvelope({
5085
+ command: "ls",
5086
+ message: `Path "${opts.path}" is ambiguous.`,
5087
+ candidates: resolved.ambiguous
5088
+ }),
5089
+ exitCode: EXIT_CODES.generic
5090
+ });
5091
+ }
5092
+ printEnvelopeAndExit({
5093
+ envelope: notFoundEnvelope({
5094
+ command: "ls",
5095
+ message: `Path "${opts.path}" was not found.`
5096
+ }),
5097
+ exitCode: EXIT_CODES.notFound
5098
+ });
5099
+ }
5100
+ scope = resolved.scope;
5101
+ pathMatch = resolved.match ?? null;
5102
+ } else {
5103
+ scope = parseOptionalScopeFromOptions(opts);
5104
+ }
5105
+ if (!scope) {
5106
+ printEnvelopeAndExit({
5107
+ envelope: {
5108
+ ok: false,
5109
+ command: "ls",
5110
+ status: 400,
5111
+ data: null,
5112
+ error: {
5113
+ code: "invalid_args",
5114
+ message: "Provide either --path or full scope args (--tool-key and --node-key).",
5115
+ details: {}
5116
+ },
5117
+ meta: { requestId: context.runtimeOptions.requestId ?? "local_error" }
5118
+ },
5119
+ exitCode: EXIT_CODES.invalidArgs
5120
+ });
5121
+ }
5122
+ const node = await requestTraversal({
5123
+ command: "ls",
5124
+ runtimeOptions: context.runtimeOptions,
5125
+ operationName: "MarkdownTreeChildren",
5126
+ field: "markdown_tree_children",
5127
+ variables: {
5128
+ organization_id: organizationId,
5129
+ tool_key: scope.toolKey,
5130
+ node_key: scope.nodeKey,
5131
+ parent_id: scope.parentId,
5132
+ record_id: scope.recordId,
5133
+ member_id: scope.memberId,
5134
+ team_id: scope.teamId,
5135
+ content_type: scope.contentType,
5136
+ tree_view: scope.treeView
5137
+ },
5138
+ depth: 1
5139
+ });
5140
+ const children = asArray(node.children);
5141
+ const filtered = typeof query === "string" && query.trim() !== "" ? children.filter(
5142
+ (child) => normalizeText(child.runtimeLabel).includes(normalizeText(query))
5143
+ ) : children;
5144
+ printEnvelopeAndExit({
5145
+ envelope: {
5146
+ ok: true,
5147
+ command: "ls",
5148
+ status: 200,
5149
+ data: {
5150
+ target: pathMatch,
5151
+ children: filtered
5152
+ },
5153
+ error: null,
5154
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
5155
+ }
5156
+ });
5157
+ });
5158
+ program.command("cat").description("Read one node").option("--path <path>").option("--under <under>").option("--tree-view").option("--tool-key <toolKey>").option("--node-key <nodeKey>").option("--parent-id <parentId>").option("--record-id <recordId>").option("--member-id <memberId>").option("--team-id <teamId>").option("--content-type <contentType>").action(async (opts, cmd) => {
5159
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5160
+ const organizationId = resolveOrganizationId(context.organizationId);
5161
+ let scope = null;
5162
+ let pathMatch = null;
5163
+ if (typeof opts.path === "string" && opts.path.trim() !== "") {
5164
+ const resolved = await resolvePathScope({
5165
+ command: "cat",
5166
+ runtimeOptions: context.runtimeOptions,
5167
+ organizationId,
5168
+ path: opts.path,
5169
+ underPath: typeof opts.under === "string" ? opts.under : void 0,
5170
+ treeView: opts.treeView === true
5171
+ });
5172
+ if (!resolved.scope) {
5173
+ if (resolved.ambiguous.length > 0) {
5174
+ printEnvelopeAndExit({
5175
+ envelope: ambiguityEnvelope({
5176
+ command: "cat",
5177
+ message: `Path "${opts.path}" is ambiguous.`,
5178
+ candidates: resolved.ambiguous
5179
+ }),
5180
+ exitCode: EXIT_CODES.generic
5181
+ });
5182
+ }
5183
+ printEnvelopeAndExit({
5184
+ envelope: notFoundEnvelope({
5185
+ command: "cat",
5186
+ message: `Path "${opts.path}" was not found.`
5187
+ }),
5188
+ exitCode: EXIT_CODES.notFound
5189
+ });
5190
+ }
5191
+ scope = resolved.scope;
5192
+ pathMatch = resolved.match ?? null;
5193
+ } else {
5194
+ scope = parseOptionalScopeFromOptions(opts);
5195
+ }
5196
+ if (!scope) {
5197
+ printEnvelopeAndExit({
5198
+ envelope: {
5199
+ ok: false,
5200
+ command: "cat",
5201
+ status: 400,
5202
+ data: null,
5203
+ error: {
5204
+ code: "invalid_args",
5205
+ message: "Provide either --path or full scope args (--tool-key and --node-key).",
5206
+ details: {}
5207
+ },
5208
+ meta: { requestId: context.runtimeOptions.requestId ?? "local_error" }
5209
+ },
5210
+ exitCode: EXIT_CODES.invalidArgs
5211
+ });
5212
+ }
5213
+ const node = await requestTraversal({
5214
+ command: "cat",
5215
+ runtimeOptions: context.runtimeOptions,
5216
+ operationName: "MarkdownTreeNode",
5217
+ field: "markdown_tree_node",
5218
+ variables: {
5219
+ organization_id: organizationId,
5220
+ tool_key: scope.toolKey,
5221
+ node_key: scope.nodeKey,
5222
+ parent_id: scope.parentId,
5223
+ record_id: scope.recordId,
5224
+ member_id: scope.memberId,
5225
+ team_id: scope.teamId,
5226
+ content_type: scope.contentType,
5227
+ tree_view: scope.treeView
5228
+ },
5229
+ depth: 1
5230
+ });
5231
+ printEnvelopeAndExit({
5232
+ envelope: {
5233
+ ok: true,
5234
+ command: "cat",
5235
+ status: 200,
5236
+ data: {
5237
+ target: pathMatch,
5238
+ node
5239
+ },
5240
+ error: null,
5241
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
5242
+ }
5243
+ });
5244
+ });
5245
+ program.command("tree").description("Read bounded subtree").requiredOption("--depth <depth>").option("--path <path>").option("--under <under>").option("--tree-view").option("--tool-key <toolKey>").option("--node-key <nodeKey>").option("--parent-id <parentId>").option("--record-id <recordId>").option("--member-id <memberId>").option("--team-id <teamId>").option("--content-type <contentType>").action(async (opts, cmd) => {
5246
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5247
+ const organizationId = resolveOrganizationId(context.organizationId);
5248
+ const depth = nonNegativeInt2.parse(opts.depth);
5249
+ let scope = null;
5250
+ let pathMatch = null;
5251
+ if (typeof opts.path === "string" && opts.path.trim() !== "") {
5252
+ const resolved = await resolvePathScope({
5253
+ command: "tree",
5254
+ runtimeOptions: context.runtimeOptions,
5255
+ organizationId,
5256
+ path: opts.path,
5257
+ underPath: typeof opts.under === "string" ? opts.under : void 0,
5258
+ treeView: opts.treeView === true
5259
+ });
5260
+ if (!resolved.scope) {
5261
+ if (resolved.ambiguous.length > 0) {
5262
+ printEnvelopeAndExit({
5263
+ envelope: ambiguityEnvelope({
5264
+ command: "tree",
5265
+ message: `Path "${opts.path}" is ambiguous.`,
5266
+ candidates: resolved.ambiguous
5267
+ }),
5268
+ exitCode: EXIT_CODES.generic
5269
+ });
5270
+ }
5271
+ printEnvelopeAndExit({
5272
+ envelope: notFoundEnvelope({
5273
+ command: "tree",
5274
+ message: `Path "${opts.path}" was not found.`
5275
+ }),
5276
+ exitCode: EXIT_CODES.notFound
5277
+ });
5278
+ }
5279
+ scope = resolved.scope;
5280
+ pathMatch = resolved.match ?? null;
5281
+ } else {
5282
+ scope = parseOptionalScopeFromOptions(opts);
5283
+ }
5284
+ if (!scope) {
5285
+ printEnvelopeAndExit({
5286
+ envelope: {
5287
+ ok: false,
5288
+ command: "tree",
5289
+ status: 400,
5290
+ data: null,
5291
+ error: {
5292
+ code: "invalid_args",
5293
+ message: "Provide either --path or full scope args (--tool-key and --node-key).",
5294
+ details: {}
5295
+ },
5296
+ meta: { requestId: context.runtimeOptions.requestId ?? "local_error" }
5297
+ },
5298
+ exitCode: EXIT_CODES.invalidArgs
5299
+ });
5300
+ }
5301
+ const node = await requestTraversal({
5302
+ command: "tree",
5303
+ runtimeOptions: context.runtimeOptions,
5304
+ operationName: "MarkdownTreeSubtree",
5305
+ field: "markdown_tree_subtree",
5306
+ variables: {
5307
+ organization_id: organizationId,
5308
+ tool_key: scope.toolKey,
5309
+ node_key: scope.nodeKey,
5310
+ parent_id: scope.parentId,
5311
+ record_id: scope.recordId,
5312
+ member_id: scope.memberId,
5313
+ team_id: scope.teamId,
5314
+ content_type: scope.contentType,
5315
+ tree_view: scope.treeView,
5316
+ depth
5317
+ },
5318
+ depth: depth + 1
5319
+ });
5320
+ printEnvelopeAndExit({
5321
+ envelope: {
5322
+ ok: true,
5323
+ command: "tree",
5324
+ status: 200,
5325
+ data: {
5326
+ target: pathMatch,
5327
+ depth,
5328
+ node
5329
+ },
5330
+ error: null,
5331
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
5332
+ }
5333
+ });
5334
+ });
5335
+ }
5336
+
5337
+ // src/commands/mutationCapability.ts
5338
+ function unsupportedMutationEnvelope(params) {
5339
+ return {
5340
+ ok: false,
5341
+ command: params.command,
5342
+ status: 400,
5343
+ data: null,
5344
+ error: {
5345
+ code: "mutation_unsupported",
5346
+ message: "No mutation command is supported for this node type.",
5347
+ details: {
5348
+ node: params.node
5349
+ }
5350
+ },
5351
+ meta: {
5352
+ requestId: "local_error"
5353
+ }
5354
+ };
5355
+ }
5356
+ function emitUnsupportedMutation(params) {
5357
+ const canonicalPath = typeof params.canonicalPath === "string" && params.canonicalPath.trim().length > 0 ? params.canonicalPath.trim() : null;
5358
+ printEnvelopeAndExit({
5359
+ envelope: unsupportedMutationEnvelope({
5360
+ command: params.command,
5361
+ node: {
5362
+ toolKey: params.toolKey,
5363
+ nodeKey: params.nodeKey,
5364
+ canonicalPath
5365
+ }
5366
+ }),
5367
+ exitCode: EXIT_CODES.invalidArgs
5368
+ });
5369
+ }
5370
+ function registerMutationCapabilityCommands(program) {
5371
+ const projectNotes = program.command("project-notes").description("Project notes node (read-only in CLI mutation surface)");
5372
+ projectNotes.command("create").option("--path <path>", "Canonical path for the selected node").action((opts) => {
5373
+ emitUnsupportedMutation({
5374
+ command: "project-notes.create",
5375
+ toolKey: "projects",
5376
+ nodeKey: "project_notes",
5377
+ canonicalPath: opts.path
5378
+ });
5379
+ });
5380
+ projectNotes.command("update").option("--path <path>", "Canonical path for the selected node").action((opts) => {
5381
+ emitUnsupportedMutation({
5382
+ command: "project-notes.update",
5383
+ toolKey: "projects",
5384
+ nodeKey: "project_notes",
5385
+ canonicalPath: opts.path
5386
+ });
5387
+ });
5388
+ projectNotes.command("destroy").option("--path <path>", "Canonical path for the selected node").action((opts) => {
5389
+ emitUnsupportedMutation({
5390
+ command: "project-notes.destroy",
5391
+ toolKey: "projects",
5392
+ nodeKey: "project_notes",
5393
+ canonicalPath: opts.path
5394
+ });
5395
+ });
5396
+ }
5397
+
2543
5398
  // src/cli.ts
2544
- function buildCli() {
5399
+ function buildCli(options) {
2545
5400
  const program = new Command();
2546
5401
  program.name("wave").description("Wave agent CLI").showHelpAfterError(false).allowExcessArguments(false).option("--token <token>", "API token (prefer WAVE_API_TOKEN env var)").option("--jwt <jwt>", "Legacy alias for --token (prefer WAVE_API_TOKEN env var)").option("--token-stdin", "Read API token from stdin").option(
2547
5402
  "--auth-json-stdin",
@@ -2562,6 +5417,7 @@ function buildCli() {
2562
5417
  "--openapi-version <openapiVersion>",
2563
5418
  "Optional pinned OpenAPI version/hash"
2564
5419
  ).exitOverride();
5420
+ setInternalCliOptions(program, options?.internal);
2565
5421
  registerTaskCommands(program);
2566
5422
  registerProjectCommands(program);
2567
5423
  registerRockCommands(program);
@@ -2572,6 +5428,11 @@ function buildCli() {
2572
5428
  registerIssueCommands(program);
2573
5429
  registerSystemToolCommands(program);
2574
5430
  registerFoundationCommands(program);
5431
+ registerChildEntityCommands(program);
5432
+ registerNoteCommands(program);
5433
+ registerMutationCapabilityCommands(program);
5434
+ registerMarkdownTreeCommands(program);
5435
+ registerNavigationCommands(program);
2575
5436
  return program;
2576
5437
  }
2577
5438