@ted-galago/wave-cli 0.1.5 → 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.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  // src/index.ts
5
5
  var import_commander2 = require("commander");
6
- var import_zod14 = require("zod");
6
+ var import_zod16 = require("zod");
7
7
 
8
8
  // src/cli.ts
9
9
  var import_commander = require("commander");
@@ -188,6 +188,16 @@ function inferStatusFromGraphqlErrors(errors) {
188
188
  if (!Array.isArray(errors) || errors.length === 0) {
189
189
  return 400;
190
190
  }
191
+ const codes = extractGraphqlErrorCodes(errors);
192
+ if (codes.includes("UNAUTHORIZED")) {
193
+ return 401;
194
+ }
195
+ if (codes.includes("NOT_FOUND")) {
196
+ return 404;
197
+ }
198
+ if (codes.includes("INVALID_SCOPE") || codes.includes("UNSUPPORTED_BRANCH")) {
199
+ return 400;
200
+ }
191
201
  const text = JSON.stringify(errors).toLowerCase();
192
202
  if (text.includes("unauthorized") || text.includes("not authenticated")) {
193
203
  return 401;
@@ -203,13 +213,260 @@ function inferStatusFromGraphqlErrors(errors) {
203
213
  }
204
214
  return 400;
205
215
  }
216
+ function extractGraphqlErrorCodes(errors) {
217
+ if (!Array.isArray(errors)) {
218
+ return [];
219
+ }
220
+ const codes = errors.map((entry) => {
221
+ if (!entry || typeof entry !== "object") return "";
222
+ const extensions = entry.extensions;
223
+ if (!extensions || typeof extensions !== "object") return "";
224
+ return String(extensions.code ?? "").toUpperCase();
225
+ }).filter((code) => code.length > 0);
226
+ return Array.from(new Set(codes));
227
+ }
228
+ function errorCodeFromGraphqlErrors(errors, status) {
229
+ const codes = extractGraphqlErrorCodes(errors);
230
+ if (codes.includes("UNAUTHORIZED")) {
231
+ return "missing_auth";
232
+ }
233
+ if (codes.includes("NOT_FOUND")) {
234
+ return "not_found";
235
+ }
236
+ if (codes.includes("INVALID_SCOPE")) {
237
+ return "invalid_scope";
238
+ }
239
+ if (codes.includes("UNSUPPORTED_BRANCH")) {
240
+ return "unsupported_branch";
241
+ }
242
+ if (status === 401) {
243
+ return "missing_auth";
244
+ }
245
+ if (status === 403) {
246
+ return "forbidden";
247
+ }
248
+ return `http_${status}`;
249
+ }
206
250
  function errorFromGraphqlErrors(errors, status) {
207
251
  return {
208
- code: status === 401 ? "missing_auth" : status === 403 ? "forbidden" : `http_${status}`,
252
+ code: errorCodeFromGraphqlErrors(errors, status),
209
253
  message: "GraphQL request failed.",
210
254
  details: { errors }
211
255
  };
212
256
  }
257
+ function findParentContextFromVariables(variables) {
258
+ const directParent = Object.entries(variables).find(([key, value]) => {
259
+ if (key === "organization_id" || key === "organizationId") return false;
260
+ if (!key.endsWith("_id") && !key.endsWith("Id")) return false;
261
+ return typeof value === "string" && value.trim().length > 0;
262
+ });
263
+ if (directParent) {
264
+ return { parentKey: directParent[0], parentId: String(directParent[1]) };
265
+ }
266
+ const params = variables.params && typeof variables.params === "object" && !Array.isArray(variables.params) ? variables.params : void 0;
267
+ if (!params) {
268
+ return {};
269
+ }
270
+ const rootObjectEntry = Object.entries(params).find(
271
+ ([, value]) => value && typeof value === "object" && !Array.isArray(value)
272
+ );
273
+ if (!rootObjectEntry) {
274
+ return {};
275
+ }
276
+ const [, rootObject] = rootObjectEntry;
277
+ const parentEntry = Object.entries(rootObject).find(([key, value]) => {
278
+ if (!key.endsWith("_id") && !key.endsWith("Id")) return false;
279
+ return typeof value === "string" && value.trim().length > 0;
280
+ });
281
+ if (!parentEntry) {
282
+ return {};
283
+ }
284
+ return { parentKey: parentEntry[0], parentId: String(parentEntry[1]) };
285
+ }
286
+ function shouldAddSparse422Diagnostic(status, mutationPayload) {
287
+ if (status !== 422) {
288
+ return false;
289
+ }
290
+ const rawErrors = mutationPayload.errors && typeof mutationPayload.errors === "object" ? mutationPayload.errors : void 0;
291
+ if (!rawErrors) {
292
+ return true;
293
+ }
294
+ const dataErrors = rawErrors.data;
295
+ return Array.isArray(dataErrors) && dataErrors.length === 0;
296
+ }
297
+ function buildSparse422Diagnostic(input) {
298
+ const parentContext = findParentContextFromVariables(input.variables);
299
+ return {
300
+ operation: input.command,
301
+ field: input.field,
302
+ context: parentContext.parentKey && parentContext.parentId ? {
303
+ parentKey: parentContext.parentKey,
304
+ parentId: parentContext.parentId
305
+ } : {
306
+ message: "No explicit parent id found in request variables."
307
+ }
308
+ };
309
+ }
310
+ function isFeedbackCreateCommand(input) {
311
+ return input.operationType === "mutation" && input.command === "feedbacks.create";
312
+ }
313
+ function asRecord(value) {
314
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
315
+ return null;
316
+ }
317
+ return value;
318
+ }
319
+ function asNonEmptyString(value) {
320
+ if (typeof value !== "string") {
321
+ return null;
322
+ }
323
+ const trimmed = value.trim();
324
+ return trimmed.length > 0 ? trimmed : null;
325
+ }
326
+ function extractFeedbackIdentity(variables) {
327
+ const organizationId = asNonEmptyString(variables.organization_id) ?? asNonEmptyString(variables.organizationId);
328
+ const params = asRecord(variables.params);
329
+ const feedback = params ? asRecord(params.feedback) : null;
330
+ const name = feedback ? asNonEmptyString(feedback.name) : null;
331
+ const quarter = feedback ? asNonEmptyString(feedback.quarter) : null;
332
+ const year = feedback ? asNonEmptyString(feedback.year) : null;
333
+ if (!organizationId || !name || !quarter || !year) {
334
+ return null;
335
+ }
336
+ return {
337
+ organizationId,
338
+ name,
339
+ quarter,
340
+ year
341
+ };
342
+ }
343
+ function collectMessageStrings(value) {
344
+ if (typeof value === "string") {
345
+ return [value];
346
+ }
347
+ if (Array.isArray(value)) {
348
+ return value.flatMap((entry) => collectMessageStrings(entry));
349
+ }
350
+ if (!value || typeof value !== "object") {
351
+ return [];
352
+ }
353
+ return Object.values(value).flatMap(
354
+ (entry) => collectMessageStrings(entry)
355
+ );
356
+ }
357
+ function isDuplicateFeedbackMutationError(mutationPayload) {
358
+ const messages = collectMessageStrings(mutationPayload.errors);
359
+ return messages.some(
360
+ (message) => message.toLowerCase().includes("already been taken")
361
+ );
362
+ }
363
+ function extractFeedbackListNode(graph) {
364
+ const data = asRecord(graph.data);
365
+ const feedbacks = data ? asRecord(data.feedbacks) : null;
366
+ if (!feedbacks) {
367
+ return null;
368
+ }
369
+ const rows = Array.isArray(feedbacks.data) ? feedbacks.data : [];
370
+ const first = rows.find((entry) => asRecord(entry));
371
+ return first ? first : null;
372
+ }
373
+ function buildFeedbackReuseEnvelope(params) {
374
+ return {
375
+ envelope: buildEnvelope({
376
+ ok: true,
377
+ command: params.command,
378
+ status: params.status,
379
+ data: {
380
+ [params.field]: {
381
+ ok: true,
382
+ status: params.status,
383
+ errorCode: null,
384
+ data: {
385
+ data: params.feedbackNode
386
+ },
387
+ errors: null,
388
+ reusedExisting: true,
389
+ idempotency: {
390
+ reason: params.reason
391
+ }
392
+ }
393
+ },
394
+ error: null,
395
+ requestId: params.requestId
396
+ }),
397
+ exitCode: EXIT_CODES.success
398
+ };
399
+ }
400
+ function buildFeedbackFindRequestBody(command, identity) {
401
+ return buildGraphqlBody({
402
+ config: {
403
+ baseUrl: "http://localhost",
404
+ token: "placeholder",
405
+ timeoutMs: 1e3,
406
+ debug: false
407
+ },
408
+ command,
409
+ operationType: "query",
410
+ field: "feedbacks",
411
+ variables: {
412
+ organization_id: identity.organizationId,
413
+ name: identity.name,
414
+ quarter: identity.quarter,
415
+ year: identity.year,
416
+ page: 1,
417
+ per: 1
418
+ },
419
+ selectionSet: "{ data { id type attributes } count currentPage totalPages }"
420
+ });
421
+ }
422
+ async function requestGraphqlHttp(params) {
423
+ const response = await fetch(params.url, {
424
+ method: "POST",
425
+ headers: {
426
+ Authorization: `Bearer ${params.input.config.token}`,
427
+ Accept: "application/json",
428
+ "Content-Type": "application/json",
429
+ "X-Origin": "langgraph-cli",
430
+ "X-Request-Id": params.requestId,
431
+ ...params.input.config.agentName ? { "X-Agent-Name": params.input.config.agentName } : {},
432
+ ...params.input.config.agentRunId ? { "X-Agent-Run-Id": params.input.config.agentRunId } : {}
433
+ },
434
+ body: JSON.stringify(params.body),
435
+ signal: params.controller.signal
436
+ });
437
+ const responseRequestId = response.headers.get("x-request-id") ?? params.requestId;
438
+ const text = await response.text();
439
+ const payload = text ? parseJsonSafely(text) : null;
440
+ const graph = payload && typeof payload === "object" ? payload : {};
441
+ return {
442
+ status: response.status,
443
+ requestId: responseRequestId,
444
+ graph
445
+ };
446
+ }
447
+ async function findExistingFeedback(params) {
448
+ const command = `${params.input.command}.find-existing`;
449
+ const body = buildFeedbackFindRequestBody(command, params.identity);
450
+ const http = await requestGraphqlHttp({
451
+ input: params.input,
452
+ url: params.url,
453
+ requestId: params.requestId,
454
+ body,
455
+ controller: params.controller
456
+ });
457
+ const gqlErrors = http.graph.errors;
458
+ if (Array.isArray(gqlErrors) && gqlErrors.length > 0) {
459
+ return null;
460
+ }
461
+ const feedbackNode = extractFeedbackListNode(http.graph);
462
+ if (!feedbackNode) {
463
+ return null;
464
+ }
465
+ return {
466
+ feedbackNode,
467
+ requestId: http.requestId
468
+ };
469
+ }
213
470
  function graphqlTypeForValue(value) {
214
471
  if (Array.isArray(value)) {
215
472
  const firstNonNull = value.find((item) => item !== null && item !== void 0);
@@ -252,9 +509,14 @@ function normalizeGraphqlVariables(variables) {
252
509
  function buildGraphqlBody(input) {
253
510
  const graphqlField = toCamelCase(input.field);
254
511
  const graphqlVariables = normalizeGraphqlVariables(input.variables);
512
+ const graphqlVariableTypes = normalizeGraphqlVariables(input.variableTypes ?? {});
255
513
  const operationName = input.operationName ?? graphqlOperationName(input.command);
256
514
  const variableEntries = Object.entries(graphqlVariables).filter(([, value]) => value !== void 0);
257
- const variableDecl = variableEntries.map(([name, value]) => `$${name}: ${withNonNull(graphqlTypeForVariable(name, value))}`).join(", ");
515
+ const variableDecl = variableEntries.map(([name, value]) => {
516
+ const overriddenType = graphqlVariableTypes[name];
517
+ const typeName = typeof overriddenType === "string" && overriddenType.trim().length > 0 ? overriddenType.trim() : graphqlTypeForVariable(name, value);
518
+ return `$${name}: ${withNonNull(typeName)}`;
519
+ }).join(", ");
258
520
  const fieldArgs = variableEntries.map(([name]) => `${name}: $${name}`).join(", ");
259
521
  const signature = variableDecl.length > 0 ? `(${variableDecl})` : "";
260
522
  const args = fieldArgs.length > 0 ? `(${fieldArgs})` : "";
@@ -279,24 +541,37 @@ async function graphqlRequest(input) {
279
541
  const controller = new AbortController();
280
542
  const timeoutId = setTimeout(() => controller.abort(), input.config.timeoutMs);
281
543
  try {
282
- const response = await fetch(url, {
283
- method: "POST",
284
- headers: {
285
- Authorization: `Bearer ${input.config.token}`,
286
- Accept: "application/json",
287
- "Content-Type": "application/json",
288
- "X-Origin": "langgraph-cli",
289
- "X-Request-Id": requestId,
290
- ...input.config.agentName ? { "X-Agent-Name": input.config.agentName } : {},
291
- ...input.config.agentRunId ? { "X-Agent-Run-Id": input.config.agentRunId } : {}
292
- },
293
- body: JSON.stringify(body),
294
- signal: controller.signal
544
+ if (isFeedbackCreateCommand(input)) {
545
+ const feedbackIdentity = extractFeedbackIdentity(input.variables);
546
+ if (feedbackIdentity) {
547
+ const existing = await findExistingFeedback({
548
+ input,
549
+ url,
550
+ requestId,
551
+ controller,
552
+ identity: feedbackIdentity
553
+ });
554
+ if (existing) {
555
+ return buildFeedbackReuseEnvelope({
556
+ command: input.command,
557
+ field: input.field,
558
+ status: 200,
559
+ requestId: existing.requestId,
560
+ feedbackNode: existing.feedbackNode,
561
+ reason: "preexisting"
562
+ });
563
+ }
564
+ }
565
+ }
566
+ const http = await requestGraphqlHttp({
567
+ input,
568
+ url,
569
+ requestId,
570
+ body,
571
+ controller
295
572
  });
296
- const responseRequestId = response.headers.get("x-request-id") ?? requestId;
297
- const text = await response.text();
298
- const payload = text ? parseJsonSafely(text) : null;
299
- const graph = payload && typeof payload === "object" ? payload : {};
573
+ const responseRequestId = http.requestId;
574
+ const graph = http.graph;
300
575
  const gqlErrors = graph.errors;
301
576
  const gqlData = graph.data && typeof graph.data === "object" ? graph.data : {};
302
577
  if (Array.isArray(gqlErrors) && gqlErrors.length > 0) {
@@ -319,6 +594,36 @@ async function graphqlRequest(input) {
319
594
  const ok = Boolean(mutationPayload.ok);
320
595
  const status = typeof mutationPayload.status === "number" ? mutationPayload.status : ok ? 200 : 400;
321
596
  if (!ok) {
597
+ if (isFeedbackCreateCommand(input) && isDuplicateFeedbackMutationError(mutationPayload)) {
598
+ const feedbackIdentity = extractFeedbackIdentity(input.variables);
599
+ if (feedbackIdentity) {
600
+ const existing = await findExistingFeedback({
601
+ input,
602
+ url,
603
+ requestId: responseRequestId,
604
+ controller,
605
+ identity: feedbackIdentity
606
+ });
607
+ if (existing) {
608
+ return buildFeedbackReuseEnvelope({
609
+ command: input.command,
610
+ field: input.field,
611
+ status: 200,
612
+ requestId: existing.requestId,
613
+ feedbackNode: existing.feedbackNode,
614
+ reason: "duplicate_race"
615
+ });
616
+ }
617
+ }
618
+ }
619
+ const mutationErrors = mutationPayload.errors ?? null;
620
+ const details = {
621
+ errors: mutationErrors,
622
+ data: mutationPayload.data ?? null
623
+ };
624
+ if (shouldAddSparse422Diagnostic(status, mutationPayload)) {
625
+ details.fallbackDiagnostic = buildSparse422Diagnostic(input);
626
+ }
322
627
  return {
323
628
  envelope: buildEnvelope({
324
629
  ok: false,
@@ -330,10 +635,7 @@ async function graphqlRequest(input) {
330
635
  mutationPayload.errorCode ?? mutationPayload.error_code ?? `http_${status}`
331
636
  ),
332
637
  message: "Mutation failed.",
333
- details: {
334
- errors: mutationPayload.errors ?? null,
335
- data: mutationPayload.data ?? null
336
- }
638
+ details
337
639
  },
338
640
  requestId: responseRequestId
339
641
  }),
@@ -373,7 +675,7 @@ async function graphqlRequest(input) {
373
675
  envelope: buildEnvelope({
374
676
  ok: true,
375
677
  command: input.command,
376
- status: response.ok ? response.status : 200,
678
+ status: http.status >= 200 && http.status < 300 ? http.status : 200,
377
679
  data: { [input.field]: fieldPayload ?? null },
378
680
  error: null,
379
681
  requestId: responseRequestId
@@ -494,6 +796,7 @@ async function runGraphqlQueryCommand(input) {
494
796
  operationType: "query",
495
797
  field: input.field,
496
798
  variables: input.variables ?? {},
799
+ variableTypes: input.variableTypes,
497
800
  selectionSet: input.selectionSet ?? defaultQuerySelectionSet(input.field, Boolean(input.isList)),
498
801
  isShow: input.isShow
499
802
  });
@@ -504,6 +807,17 @@ async function runGraphqlQueryCommand(input) {
504
807
  ...dataRecord,
505
808
  [input.field]: transformed
506
809
  };
810
+ if (input.isShow && (transformed === null || transformed === void 0)) {
811
+ result.envelope.ok = false;
812
+ result.envelope.status = 404;
813
+ result.envelope.data = null;
814
+ result.envelope.error = {
815
+ code: "not_found",
816
+ message: "Record not found.",
817
+ details: {}
818
+ };
819
+ result.exitCode = EXIT_CODES.notFound;
820
+ }
507
821
  }
508
822
  printEnvelopeAndExit(result);
509
823
  } catch (error) {
@@ -541,6 +855,7 @@ async function runGraphqlMutationCommand(input) {
541
855
  operationType: "mutation",
542
856
  field: input.field,
543
857
  variables: input.variables ?? {},
858
+ variableTypes: input.variableTypes,
544
859
  selectionSet: input.selectionSet ?? "{ ok status errorCode data errors }"
545
860
  });
546
861
  printEnvelopeAndExit(result);
@@ -850,7 +1165,7 @@ var dtoHelpCatalog = {
850
1165
  create: [
851
1166
  ["member_id", "string"],
852
1167
  ["name", "string"],
853
- ["type", "MeetingType"],
1168
+ ["type", "enum(TeamMeeting|OneOnOneMeeting)"],
854
1169
  ["date", "string"],
855
1170
  ["status", "enum(upcoming|active|completed)"],
856
1171
  ["start_time", "number"],
@@ -1475,37 +1790,70 @@ function registerEntityCrudCommands(program, config) {
1475
1790
  const id = idSchema.parse(opts.id);
1476
1791
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1477
1792
  const organizationId = resolveOrganizationId(context.organizationId);
1793
+ const defaultCommand = `${config.command}.show`;
1794
+ const defaultField = config.resourcePath === "feedback" ? "feedback" : toSingularResourceName(config.resourcePath);
1795
+ const defaultVariables = normalizeGraphqlVariables2({
1796
+ organization_id: organizationId,
1797
+ id
1798
+ });
1799
+ const showQuery = config.showQueryFactory ? config.showQueryFactory({
1800
+ command: defaultCommand,
1801
+ field: defaultField,
1802
+ variables: defaultVariables,
1803
+ id,
1804
+ organizationId
1805
+ }) : void 0;
1478
1806
  await runGraphqlQueryCommand({
1479
- command: `${config.command}.show`,
1807
+ command: showQuery?.command ?? defaultCommand,
1480
1808
  runtimeOptions: context.runtimeOptions,
1481
- field: config.resourcePath === "feedback" ? "feedback" : toSingularResourceName(config.resourcePath),
1482
- variables: normalizeGraphqlVariables2({
1483
- organization_id: organizationId,
1484
- id
1485
- }),
1486
- isShow: true
1809
+ operationName: showQuery?.operationName,
1810
+ field: showQuery?.field ?? defaultField,
1811
+ variables: showQuery?.variables ?? defaultVariables,
1812
+ variableTypes: showQuery?.variableTypes,
1813
+ selectionSet: showQuery?.selectionSet,
1814
+ isShow: true,
1815
+ transformData: showQuery?.transformData
1487
1816
  });
1488
1817
  });
1489
1818
  entityCommand.command("create").requiredOption("--data-json <dataJson>", createHelp4).action(async (opts, cmd) => {
1490
1819
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1491
1820
  const organizationId = resolveOrganizationId(context.organizationId);
1492
- const body = normalizeBody(String(opts.dataJson), config.rootKey);
1821
+ let body = normalizeBody(String(opts.dataJson), config.rootKey);
1822
+ if (config.normalizeCreateBody) {
1823
+ body = config.normalizeCreateBody(body);
1824
+ }
1493
1825
  assertRequiredCreateFields(body, config.rootKey, config.requiredCreateFields);
1826
+ const defaultCommand = `${config.command}.create`;
1827
+ const defaultField = `create_${toSingularResourceName(config.resourcePath)}`;
1828
+ const defaultVariables = {
1829
+ organization_id: organizationId,
1830
+ params: body
1831
+ };
1832
+ const createMutation = config.createMutationFactory ? config.createMutationFactory({
1833
+ command: defaultCommand,
1834
+ field: defaultField,
1835
+ variables: defaultVariables,
1836
+ body,
1837
+ organizationId
1838
+ }) : void 0;
1494
1839
  await runGraphqlMutationCommand({
1495
- command: `${config.command}.create`,
1840
+ command: createMutation?.command ?? defaultCommand,
1496
1841
  runtimeOptions: context.runtimeOptions,
1497
- field: `create_${toSingularResourceName(config.resourcePath)}`,
1498
- variables: {
1499
- organization_id: organizationId,
1500
- params: body
1501
- }
1842
+ operationName: createMutation?.operationName,
1843
+ field: createMutation?.field ?? defaultField,
1844
+ variables: createMutation?.variables ?? defaultVariables,
1845
+ variableTypes: createMutation?.variableTypes,
1846
+ selectionSet: createMutation?.selectionSet
1502
1847
  });
1503
1848
  });
1504
1849
  entityCommand.command("update").requiredOption("--id <id>").requiredOption("--data-json <dataJson>", updateHelp5).action(async (opts, cmd) => {
1505
1850
  const id = idSchema.parse(opts.id);
1506
1851
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1507
1852
  const organizationId = resolveOrganizationId(context.organizationId);
1508
- const body = normalizeBody(String(opts.dataJson), config.rootKey);
1853
+ let body = normalizeBody(String(opts.dataJson), config.rootKey);
1854
+ if (config.normalizeUpdateBody) {
1855
+ body = config.normalizeUpdateBody(body);
1856
+ }
1509
1857
  const singular = toSingularResourceName(config.resourcePath);
1510
1858
  await runGraphqlMutationCommand({
1511
1859
  command: `${config.command}.update`,
@@ -1657,7 +2005,8 @@ function registerProjectCommands(program) {
1657
2005
  member_id: opts.memberId,
1658
2006
  ...extra
1659
2007
  }),
1660
- isList: true
2008
+ isList: true,
2009
+ selectionSet: "{ data { id type } count currentPage totalPages }"
1661
2010
  });
1662
2011
  });
1663
2012
  projects.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
@@ -1672,7 +2021,8 @@ function registerProjectCommands(program) {
1672
2021
  organization_id: organizationId,
1673
2022
  id
1674
2023
  },
1675
- isShow: true
2024
+ isShow: true,
2025
+ selectionSet: "{ id type }"
1676
2026
  });
1677
2027
  });
1678
2028
  projects.command("create").requiredOption("--data-json <dataJson>", projectCreateDataJsonHelp).action(async (opts, cmd) => {
@@ -1702,6 +2052,11 @@ function registerProjectCommands(program) {
1702
2052
  organization_id: organizationId,
1703
2053
  project_id: id,
1704
2054
  params: body
2055
+ },
2056
+ variableTypes: {
2057
+ organization_id: "ID!",
2058
+ project_id: "ID!",
2059
+ params: "UpdateProjectParamsInput!"
1705
2060
  }
1706
2061
  });
1707
2062
  });
@@ -1814,8 +2169,142 @@ function registerRockCommands(program) {
1814
2169
  var import_zod6 = require("zod");
1815
2170
  var idSchema5 = import_zod6.z.string().min(1);
1816
2171
  var notesSchema = import_zod6.z.string().min(1);
2172
+ var MEETING_TYPES = /* @__PURE__ */ new Set(["TeamMeeting", "OneOnOneMeeting"]);
2173
+ var MEETING_STATUSES = /* @__PURE__ */ new Set(["upcoming", "active", "completed"]);
2174
+ var MEETING_REPEATS = /* @__PURE__ */ new Set(["never", "weekly", "biweekly", "monthly", "quarterly"]);
1817
2175
  var createHelp2 = buildDataJsonHelp("meeting", "create") ?? 'JSON object for meeting or {"meeting": {...}}';
1818
2176
  var updateHelp2 = buildDataJsonHelp("meeting", "update") ?? 'JSON object for meeting or {"meeting": {...}}';
2177
+ function asNonEmptyString2(value) {
2178
+ if (typeof value !== "string") {
2179
+ return void 0;
2180
+ }
2181
+ const trimmed = value.trim();
2182
+ return trimmed.length > 0 ? trimmed : void 0;
2183
+ }
2184
+ function toFiniteNumber(value, field) {
2185
+ if (value === void 0 || value === null) {
2186
+ return void 0;
2187
+ }
2188
+ if (typeof value === "number" && Number.isFinite(value)) {
2189
+ return value;
2190
+ }
2191
+ if (typeof value === "string") {
2192
+ const trimmed = value.trim();
2193
+ if (trimmed.length === 0) {
2194
+ return void 0;
2195
+ }
2196
+ const parsed = Number(trimmed);
2197
+ if (Number.isFinite(parsed)) {
2198
+ return parsed;
2199
+ }
2200
+ }
2201
+ throw new CliError({
2202
+ message: `Invalid ${field}. Expected a numeric value.`,
2203
+ kind: "invalid_args",
2204
+ status: 400,
2205
+ exitCode: EXIT_CODES.invalidArgs
2206
+ });
2207
+ }
2208
+ function toStringArray(value, field) {
2209
+ if (value === void 0 || value === null) {
2210
+ return void 0;
2211
+ }
2212
+ const items = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : null;
2213
+ if (!items) {
2214
+ throw new CliError({
2215
+ message: `Invalid ${field}. Expected an array or comma-separated string.`,
2216
+ kind: "invalid_args",
2217
+ status: 400,
2218
+ exitCode: EXIT_CODES.invalidArgs
2219
+ });
2220
+ }
2221
+ const normalized = items.map((item) => String(item).trim()).filter((item) => item.length > 0);
2222
+ return normalized.length > 0 ? normalized : void 0;
2223
+ }
2224
+ function normalizeMeetingCreateBody(body) {
2225
+ const entity = body.meeting;
2226
+ if (!entity || typeof entity !== "object" || Array.isArray(entity)) {
2227
+ throw new CliError({
2228
+ message: 'Invalid payload. Expected object at "meeting".',
2229
+ kind: "invalid_args",
2230
+ status: 400,
2231
+ exitCode: EXIT_CODES.invalidArgs
2232
+ });
2233
+ }
2234
+ const meeting = { ...entity };
2235
+ const type = asNonEmptyString2(meeting.type);
2236
+ if (!type || !MEETING_TYPES.has(type)) {
2237
+ throw new CliError({
2238
+ message: "Invalid meeting.type. Use one of: TeamMeeting, OneOnOneMeeting.",
2239
+ kind: "invalid_args",
2240
+ status: 400,
2241
+ exitCode: EXIT_CODES.invalidArgs,
2242
+ details: { field: "meeting.type", allowed: Array.from(MEETING_TYPES) }
2243
+ });
2244
+ }
2245
+ const memberId = asNonEmptyString2(meeting.member_id);
2246
+ const date = asNonEmptyString2(meeting.date);
2247
+ const startTime = toFiniteNumber(meeting.start_time, "meeting.start_time");
2248
+ const missingRequired = [];
2249
+ if (!memberId) missingRequired.push("member_id");
2250
+ if (!date) missingRequired.push("date");
2251
+ if (startTime === void 0) missingRequired.push("start_time");
2252
+ if (missingRequired.length > 0) {
2253
+ throw new CliError({
2254
+ message: `Missing required create fields for meeting: ${missingRequired.join(", ")}.`,
2255
+ kind: "invalid_args",
2256
+ status: 400,
2257
+ exitCode: EXIT_CODES.invalidArgs,
2258
+ details: { requiredFields: ["member_id", "date", "start_time"], rootKey: "meeting" }
2259
+ });
2260
+ }
2261
+ const status = asNonEmptyString2(meeting.status);
2262
+ if (status && !MEETING_STATUSES.has(status)) {
2263
+ throw new CliError({
2264
+ message: "Invalid meeting.status. Use one of: upcoming, active, completed.",
2265
+ kind: "invalid_args",
2266
+ status: 400,
2267
+ exitCode: EXIT_CODES.invalidArgs,
2268
+ details: { field: "meeting.status", allowed: Array.from(MEETING_STATUSES) }
2269
+ });
2270
+ }
2271
+ const repeats = asNonEmptyString2(meeting.repeats) ?? "never";
2272
+ if (!MEETING_REPEATS.has(repeats)) {
2273
+ throw new CliError({
2274
+ message: "Invalid meeting.repeats. Use one of: never, weekly, biweekly, monthly, quarterly.",
2275
+ kind: "invalid_args",
2276
+ status: 400,
2277
+ exitCode: EXIT_CODES.invalidArgs,
2278
+ details: { field: "meeting.repeats", allowed: Array.from(MEETING_REPEATS) }
2279
+ });
2280
+ }
2281
+ const teamsIds = toStringArray(meeting.teams_ids, "meeting.teams_ids");
2282
+ if (type === "TeamMeeting" && (!teamsIds || teamsIds.length === 0)) {
2283
+ throw new CliError({
2284
+ message: "Missing required create fields for meeting: teams_ids.",
2285
+ kind: "invalid_args",
2286
+ status: 400,
2287
+ exitCode: EXIT_CODES.invalidArgs,
2288
+ details: { requiredFields: ["teams_ids"], rootKey: "meeting" }
2289
+ });
2290
+ }
2291
+ const endTime = toFiniteNumber(meeting.end_time, "meeting.end_time");
2292
+ meeting.type = type;
2293
+ meeting.member_id = memberId;
2294
+ meeting.date = date;
2295
+ meeting.start_time = startTime;
2296
+ meeting.repeats = repeats;
2297
+ if (status) {
2298
+ meeting.status = status;
2299
+ }
2300
+ if (endTime !== void 0) {
2301
+ meeting.end_time = endTime;
2302
+ }
2303
+ if (teamsIds) {
2304
+ meeting.teams_ids = teamsIds;
2305
+ }
2306
+ return { ...body, meeting };
2307
+ }
1819
2308
  function registerMeetingCommands(program) {
1820
2309
  const meetings = program.command("meetings").description("Meeting operations");
1821
2310
  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) => {
@@ -1878,7 +2367,8 @@ function registerMeetingCommands(program) {
1878
2367
  meetings.command("create").requiredOption("--data-json <dataJson>", createHelp2).action(async (opts, cmd) => {
1879
2368
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1880
2369
  const organizationId = resolveOrganizationId(context.organizationId);
1881
- const body = __testables.normalizeBody(String(opts.dataJson), "meeting");
2370
+ const rawBody = __testables.normalizeBody(String(opts.dataJson), "meeting");
2371
+ const body = normalizeMeetingCreateBody(rawBody);
1882
2372
  await runGraphqlMutationCommand({
1883
2373
  command: "meetings.create",
1884
2374
  runtimeOptions: context.runtimeOptions,
@@ -1983,7 +2473,9 @@ var import_zod8 = require("zod");
1983
2473
  var issueGroupIdSchema = import_zod8.z.string().min(1);
1984
2474
  var idSchema7 = import_zod8.z.string().min(1);
1985
2475
  var nameSchema = import_zod8.z.string().min(1);
1986
- var issueTypeSchema = import_zod8.z.string().min(1);
2476
+ var issueTypeSchema = import_zod8.z.string().min(1).refine((value) => value === "short_term" || value === "long_term", {
2477
+ message: "Invalid issue type. Use one of: short_term, long_term."
2478
+ });
1987
2479
  var updateHelp4 = buildDataJsonHelp("issue", "update") ?? 'JSON object for issue or {"issue": {...}}';
1988
2480
  function registerIssueCommands(program) {
1989
2481
  const issues = program.command("issues").description("Issue operations");
@@ -2026,7 +2518,7 @@ function registerIssueCommands(program) {
2026
2518
  isShow: true
2027
2519
  });
2028
2520
  });
2029
- 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) => {
2521
+ 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) => {
2030
2522
  const issueGroupId = issueGroupIdSchema.parse(opts.issueGroupId);
2031
2523
  const name = nameSchema.parse(opts.name);
2032
2524
  const issueType = issueTypeSchema.parse(opts.issueType);
@@ -2071,54 +2563,701 @@ function registerIssueCommands(program) {
2071
2563
  });
2072
2564
  }
2073
2565
 
2566
+ // src/commands/smartKpiNames.ts
2567
+ var SMART_KPI_NAMES = [
2568
+ "total_active_users",
2569
+ "total_new_users",
2570
+ "total_return_users",
2571
+ "total_engaged_sessions",
2572
+ "total_sessions",
2573
+ "engagement_rate",
2574
+ "bounce_rate",
2575
+ "page_call_phone_clicks_logged_in_unique",
2576
+ "page_cta_clicks_logged_in_unique",
2577
+ "page_engaged_users",
2578
+ "page_fan_adds_unique",
2579
+ "page_fan_adds",
2580
+ "page_fan_removes",
2581
+ "page_fans",
2582
+ "page_get_directions_clicks_logged_in_unique",
2583
+ "page_impressions_unique",
2584
+ "page_impressions",
2585
+ "page_negative_feedback",
2586
+ "page_positive_feedback_comment",
2587
+ "page_positive_feedback_like",
2588
+ "page_positive_feedback_other",
2589
+ "page_positive_feedback_share",
2590
+ "page_post_engagements",
2591
+ "page_total_actions",
2592
+ "page_views_logged_in_unique",
2593
+ "page_views_total",
2594
+ "page_website_clicks_logged_in_unique",
2595
+ "post_clicks_by_type_unique",
2596
+ "post_engaged_users",
2597
+ "post_impressions_fan_paid",
2598
+ "post_impressions_fan",
2599
+ "post_impressions_organic",
2600
+ "post_impressions_unique",
2601
+ "post_impressions",
2602
+ "post_reactions_like_total",
2603
+ "get_directions_clicks",
2604
+ "phone_call_clicks",
2605
+ "profile_views",
2606
+ "reach",
2607
+ "text_message_clicks",
2608
+ "website_clicks",
2609
+ "online_followers",
2610
+ "total_interactions",
2611
+ "accounts_engaged",
2612
+ "likes",
2613
+ "comments",
2614
+ "saves",
2615
+ "shares",
2616
+ "replies",
2617
+ "impressions",
2618
+ "email_contacts",
2619
+ "follower_count",
2620
+ "total_new_conversations",
2621
+ "total_unassigned_conversations",
2622
+ "total_closed_conversations",
2623
+ "total_new_contacts",
2624
+ "total_contacts",
2625
+ "total_revenue",
2626
+ "total_expenses",
2627
+ "cash_flow",
2628
+ "paid_invoices",
2629
+ "unpaid_invoices",
2630
+ "total_new_payments",
2631
+ "total_new_invoices",
2632
+ "total_paid_invoices",
2633
+ "total_refunds",
2634
+ "total_disputes",
2635
+ "calls",
2636
+ "sms",
2637
+ "mms",
2638
+ "verify_push",
2639
+ "verify_totp",
2640
+ "recordings",
2641
+ "transcriptions",
2642
+ "programmable_voice",
2643
+ "authy_phone_verifications",
2644
+ "authy_authentications",
2645
+ "twilio_errors",
2646
+ "twilio_warnings",
2647
+ "twilio_notices",
2648
+ "total_subscribers",
2649
+ "total_subscribers_gained",
2650
+ "total_subscribers_lost",
2651
+ "total_engagement",
2652
+ "total_views",
2653
+ "total_comments",
2654
+ "total_likes",
2655
+ "total_dislikes",
2656
+ "total_shares",
2657
+ "total_card_impressions",
2658
+ "total_card_clicks",
2659
+ "total_card_click_rate",
2660
+ "rock_total_new_rock_groups",
2661
+ "rock_total_rock_groups",
2662
+ "rock_total_new_rocks",
2663
+ "rock_total_new_milestones",
2664
+ "rock_total_completed_milestones",
2665
+ "rock_total_incomplete_milestones",
2666
+ "project_total_projects",
2667
+ "project_total_new_projects",
2668
+ "project_total_new_tasks",
2669
+ "project_total_completed_tasks",
2670
+ "project_total_incomplete_tasks",
2671
+ "project_total_new_sub_tasks",
2672
+ "project_total_completed_sub_tasks",
2673
+ "project_total_incomplete_sub_tasks",
2674
+ "list_total_list",
2675
+ "list_total_new_list",
2676
+ "list_total_new_list_items",
2677
+ "list_total_completed_list_items",
2678
+ "list_total_incomplete_list_items",
2679
+ "list_total_new_sub_items",
2680
+ "list_total_completed_sub_items",
2681
+ "list_total_incomplete_sub_items",
2682
+ "issue_total_issue_groups",
2683
+ "issue_total_new_issue_groups",
2684
+ "issue_total_new_issues",
2685
+ "issue_total_completed_issues",
2686
+ "issue_total_incomplete_issues",
2687
+ "issue_total_new_sub_issues",
2688
+ "issue_total_completed_sub_issues",
2689
+ "issue_total_incomplete_sub_issues",
2690
+ "todo_total_todo_groups",
2691
+ "todo_total_new_todo_groups",
2692
+ "todo_total_new_todos",
2693
+ "todo_total_completed_todos",
2694
+ "todo_total_incomplete_todos",
2695
+ "todo_total_new_sub_todos",
2696
+ "todo_total_completed_sub_todos",
2697
+ "todo_total_incomplete_sub_todos",
2698
+ "measurable_total_scorecards",
2699
+ "measurable_total_new_scorecards",
2700
+ "measurable_total_new_measurables",
2701
+ "stand_up_daily_stand_up_completion_rate",
2702
+ "stand_up_total_stand_ups_complete",
2703
+ "stand_up_daily_stand_up_block_rate",
2704
+ "stand_up_total_blocked_stand_ups",
2705
+ "headline_total_new_headlines",
2706
+ "content_total_content",
2707
+ "content_total_new_content",
2708
+ "question_total_questions",
2709
+ "question_total_new_questions",
2710
+ "question_total_questions_answered",
2711
+ "survey_new_surveys_sent",
2712
+ "member_total_new_members",
2713
+ "member_total_members",
2714
+ "responsibility_total_new_responsibilities_added",
2715
+ "responsibility_total_responsibilities",
2716
+ "customer_total_customers",
2717
+ "customer_total_new_customers",
2718
+ "customer_total_new_customer_logs",
2719
+ "contact_total_contacts",
2720
+ "contact_total_new_contacts",
2721
+ "contact_total_new_contact_logs"
2722
+ ];
2723
+ var SMART_KPI_NAME_SET = new Set(SMART_KPI_NAMES);
2724
+
2074
2725
  // src/commands/systemTools.ts
2075
- function registerSystemToolCommands(program) {
2076
- registerEntityCrudCommands(program, {
2077
- command: "lists",
2078
- description: "List operations",
2079
- resourcePath: "lists",
2080
- rootKey: "list",
2081
- listParams: ["include_archived", "member_id", "team_ids", "term"]
2082
- });
2083
- registerEntityCrudCommands(program, {
2084
- command: "list-items",
2085
- description: "List item operations",
2086
- resourcePath: "list_items",
2087
- rootKey: "list_item",
2088
- requiredCreateFields: ["list_id"],
2089
- listParams: [
2090
- "field_blank",
2091
- "field_name",
2092
- "field_value",
2093
- "include_archived",
2094
- "list_id",
2095
- "meeting_id",
2096
- "member_id",
2097
- "rank_direction",
2098
- "team_id",
2099
- "team_ids"
2100
- ]
2101
- });
2102
- registerEntityCrudCommands(program, {
2103
- command: "issue-groups",
2104
- description: "Issue group operations",
2105
- resourcePath: "issue_groups",
2106
- rootKey: "issue_group",
2107
- listParams: ["include_archived", "member_id", "team_ids", "term"]
2108
- });
2109
- registerEntityCrudCommands(program, {
2110
- command: "todo-groups",
2111
- description: "To-do group operations",
2112
- resourcePath: "todo_groups",
2113
- rootKey: "todo_group",
2114
- listParams: ["include_archived", "member_id", "team_ids", "term"]
2726
+ var TODO_STATUSES = /* @__PURE__ */ new Set(["open", "completed"]);
2727
+ var KNOWLEDGE_CONTENT_TYPES = /* @__PURE__ */ new Set(["company", "policy", "process"]);
2728
+ var KNOWLEDGE_STATUSES = /* @__PURE__ */ new Set(["draft", "published"]);
2729
+ var NEWS_STATUSES = /* @__PURE__ */ new Set(["active", "completed"]);
2730
+ var NEWS_HEADLINE_TYPES = /* @__PURE__ */ new Set(["team", "org_wide"]);
2731
+ var QUESTION_STATUSES = /* @__PURE__ */ new Set(["asked", "answered"]);
2732
+ var PULSE_STATUSES = /* @__PURE__ */ new Set(["on_track", "at_risk", "off_track"]);
2733
+ var SURVEY_RECIPIENT_TYPES = /* @__PURE__ */ new Set(["member", "team", "org_wide"]);
2734
+ var SURVEY_NAMES = /* @__PURE__ */ new Set([
2735
+ "employee_net_promoter_score",
2736
+ "continuous_performance_review",
2737
+ "core_value_alignment",
2738
+ "engagement",
2739
+ "wellness_and_mental_health",
2740
+ "workspace_culture",
2741
+ "peer_review",
2742
+ "manager_review",
2743
+ "onboarding"
2744
+ ]);
2745
+ var FEEDBACK_QUARTERS = /* @__PURE__ */ new Set(["q1", "q2", "q3", "q4"]);
2746
+ var FEEDBACK_NAMES = /* @__PURE__ */ new Set([
2747
+ "productivity_and_focus",
2748
+ "company_collaboration",
2749
+ "project_management",
2750
+ "employee_engagement",
2751
+ "training_and_development",
2752
+ "innovation_and_creativity",
2753
+ "customer_insights",
2754
+ "process_improvement",
2755
+ "leadership_and_management",
2756
+ "company_culture",
2757
+ "roadmap_and_strategy",
2758
+ "customer_testing_and_feedback"
2759
+ ]);
2760
+ var SCORECARD_INTERVALS = /* @__PURE__ */ new Set([
2761
+ "daily",
2762
+ "weekly",
2763
+ "monthly",
2764
+ "quarterly",
2765
+ "yearly"
2766
+ ]);
2767
+ var SCORECARD_TRENDS = /* @__PURE__ */ new Set(["average", "total"]);
2768
+ function isRecord(value) {
2769
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2770
+ }
2771
+ function ensureEntityObject(body, rootKey) {
2772
+ const entity = body[rootKey];
2773
+ if (!isRecord(entity)) {
2774
+ throw new CliError({
2775
+ message: `Invalid payload. Expected object at "${rootKey}".`,
2776
+ kind: "invalid_args",
2777
+ status: 400,
2778
+ exitCode: EXIT_CODES.invalidArgs
2779
+ });
2780
+ }
2781
+ return { ...entity };
2782
+ }
2783
+ function throwMissingRequiredCreateFields(rootKey, fields) {
2784
+ throw new CliError({
2785
+ message: `Missing required create fields for ${rootKey}: ${fields.join(", ")}.`,
2786
+ kind: "invalid_args",
2787
+ status: 400,
2788
+ exitCode: EXIT_CODES.invalidArgs,
2789
+ details: { requiredFields: fields, rootKey }
2115
2790
  });
2116
- registerEntityCrudCommands(program, {
2117
- command: "todos",
2118
- description: "To-do operations",
2119
- resourcePath: "todos",
2120
- rootKey: "todo",
2791
+ }
2792
+ function normalizeTodosCreateBody(body) {
2793
+ const todo = ensureEntityObject(body, "todo");
2794
+ const rawStatus = todo.status;
2795
+ if (rawStatus === void 0 || rawStatus === null || String(rawStatus).trim().length === 0) {
2796
+ todo.status = "open";
2797
+ return { ...body, todo };
2798
+ }
2799
+ if (typeof rawStatus !== "string" || !TODO_STATUSES.has(rawStatus)) {
2800
+ throw new CliError({
2801
+ message: "Invalid todo status. Use one of: open, completed.",
2802
+ kind: "invalid_args",
2803
+ status: 400,
2804
+ exitCode: EXIT_CODES.invalidArgs,
2805
+ details: { allowed: Array.from(TODO_STATUSES) }
2806
+ });
2807
+ }
2808
+ return { ...body, todo };
2809
+ }
2810
+ function asNonEmptyString3(value) {
2811
+ if (typeof value !== "string") {
2812
+ return void 0;
2813
+ }
2814
+ const trimmed = value.trim();
2815
+ return trimmed.length > 0 ? trimmed : void 0;
2816
+ }
2817
+ function validateEnumField(params) {
2818
+ const value = asNonEmptyString3(params.rawValue);
2819
+ if (!value) {
2820
+ return void 0;
2821
+ }
2822
+ if (!params.allowed.has(value)) {
2823
+ throw new CliError({
2824
+ message: params.message,
2825
+ kind: "invalid_args",
2826
+ status: 400,
2827
+ exitCode: EXIT_CODES.invalidArgs,
2828
+ details: { field: params.field, allowed: Array.from(params.allowed) }
2829
+ });
2830
+ }
2831
+ return value;
2832
+ }
2833
+ function normalizeKnowledgeCreateBody(body) {
2834
+ const content = ensureEntityObject(body, "content");
2835
+ const contentType = validateEnumField({
2836
+ rawValue: content.content_type,
2837
+ field: "content.content_type",
2838
+ allowed: KNOWLEDGE_CONTENT_TYPES,
2839
+ message: "Invalid content.content_type. Use one of: company, policy, process."
2840
+ });
2841
+ if (!contentType) {
2842
+ throwMissingRequiredCreateFields("content", ["content_type"]);
2843
+ }
2844
+ content.content_type = contentType;
2845
+ const status = validateEnumField({
2846
+ rawValue: content.status,
2847
+ field: "content.status",
2848
+ allowed: KNOWLEDGE_STATUSES,
2849
+ message: "Invalid content.status. Use one of: draft, published."
2850
+ });
2851
+ content.status = status ?? "draft";
2852
+ const memberId = asNonEmptyString3(content.member_id);
2853
+ if (!memberId) {
2854
+ throwMissingRequiredCreateFields("content", ["member_id"]);
2855
+ }
2856
+ content.member_id = memberId;
2857
+ return { ...body, content };
2858
+ }
2859
+ function normalizeNewsCreateBody(body) {
2860
+ const headline = ensureEntityObject(body, "headline");
2861
+ const memberId = asNonEmptyString3(headline.member_id);
2862
+ if (!memberId) {
2863
+ throwMissingRequiredCreateFields("headline", ["member_id"]);
2864
+ }
2865
+ headline.member_id = memberId;
2866
+ const status = validateEnumField({
2867
+ rawValue: headline.status,
2868
+ field: "headline.status",
2869
+ allowed: NEWS_STATUSES,
2870
+ message: "Invalid headline.status. Use one of: active, completed."
2871
+ });
2872
+ if (!status) {
2873
+ throwMissingRequiredCreateFields("headline", ["status"]);
2874
+ }
2875
+ headline.status = status;
2876
+ const headlineType = validateEnumField({
2877
+ rawValue: headline.headline_type,
2878
+ field: "headline.headline_type",
2879
+ allowed: NEWS_HEADLINE_TYPES,
2880
+ message: "Invalid headline.headline_type. Use one of: team, org_wide."
2881
+ });
2882
+ if (!headlineType) {
2883
+ throwMissingRequiredCreateFields("headline", ["headline_type"]);
2884
+ }
2885
+ headline.headline_type = headlineType;
2886
+ return { ...body, headline };
2887
+ }
2888
+ function normalizeQuestionsCreateBody(body) {
2889
+ const question = ensureEntityObject(body, "question");
2890
+ const summary = asNonEmptyString3(question.summary);
2891
+ const currentName = asNonEmptyString3(question.name);
2892
+ if (!currentName && summary) {
2893
+ question.name = summary;
2894
+ }
2895
+ delete question.summary;
2896
+ const name = asNonEmptyString3(question.name);
2897
+ const memberId = asNonEmptyString3(question.member_id);
2898
+ const missing = [];
2899
+ if (!name) missing.push("name");
2900
+ if (!memberId) missing.push("member_id");
2901
+ if (missing.length > 0) {
2902
+ throwMissingRequiredCreateFields("question", missing);
2903
+ }
2904
+ question.name = name;
2905
+ question.member_id = memberId;
2906
+ const status = validateEnumField({
2907
+ rawValue: question.status,
2908
+ field: "question.status",
2909
+ allowed: QUESTION_STATUSES,
2910
+ message: "Invalid question.status. Use one of: asked, answered."
2911
+ });
2912
+ if (status) {
2913
+ question.status = status;
2914
+ }
2915
+ return { ...body, question };
2916
+ }
2917
+ function normalizeQuestionsUpdateBody(body) {
2918
+ const question = ensureEntityObject(body, "question");
2919
+ const summary = asNonEmptyString3(question.summary);
2920
+ const currentName = asNonEmptyString3(question.name);
2921
+ if (!currentName && summary) {
2922
+ question.name = summary;
2923
+ }
2924
+ delete question.summary;
2925
+ const name = asNonEmptyString3(question.name);
2926
+ if (name) {
2927
+ question.name = name;
2928
+ }
2929
+ const status = validateEnumField({
2930
+ rawValue: question.status,
2931
+ field: "question.status",
2932
+ allowed: QUESTION_STATUSES,
2933
+ message: "Invalid question.status. Use one of: asked, answered."
2934
+ });
2935
+ if (status) {
2936
+ question.status = status;
2937
+ }
2938
+ return { ...body, question };
2939
+ }
2940
+ function normalizePulseCreateBody(body) {
2941
+ const healthUpdate = ensureEntityObject(body, "health_update");
2942
+ const healthUpdatableId = asNonEmptyString3(healthUpdate.health_updatable_id) ?? asNonEmptyString3(healthUpdate.updatable_id);
2943
+ const healthUpdatableType = asNonEmptyString3(healthUpdate.health_updatable_type) ?? asNonEmptyString3(healthUpdate.updatable_type);
2944
+ const memberId = asNonEmptyString3(healthUpdate.member_id);
2945
+ const status = validateEnumField({
2946
+ rawValue: healthUpdate.status,
2947
+ field: "health_update.status",
2948
+ allowed: PULSE_STATUSES,
2949
+ message: "Invalid health_update.status. Use one of: on_track, at_risk, off_track."
2950
+ });
2951
+ const missing = [];
2952
+ if (!healthUpdatableId) missing.push("health_updatable_id");
2953
+ if (!healthUpdatableType) missing.push("health_updatable_type");
2954
+ if (!memberId) missing.push("member_id");
2955
+ if (!status) missing.push("status");
2956
+ if (missing.length > 0) {
2957
+ throwMissingRequiredCreateFields("health_update", missing);
2958
+ }
2959
+ healthUpdate.health_updatable_id = healthUpdatableId;
2960
+ healthUpdate.health_updatable_type = healthUpdatableType;
2961
+ healthUpdate.member_id = memberId;
2962
+ healthUpdate.status = status;
2963
+ delete healthUpdate.updatable_id;
2964
+ delete healthUpdate.updatable_type;
2965
+ return { ...body, health_update: healthUpdate };
2966
+ }
2967
+ function normalizeSurveysCreateBody(body) {
2968
+ const survey = ensureEntityObject(body, "survey");
2969
+ const title = asNonEmptyString3(survey.title);
2970
+ const currentName = asNonEmptyString3(survey.name);
2971
+ if (!currentName && title) {
2972
+ survey.name = title;
2973
+ }
2974
+ delete survey.title;
2975
+ const name = validateEnumField({
2976
+ rawValue: survey.name,
2977
+ field: "survey.name",
2978
+ allowed: SURVEY_NAMES,
2979
+ 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."
2980
+ });
2981
+ const recipientType = validateEnumField({
2982
+ rawValue: survey.recipient_type,
2983
+ field: "survey.recipient_type",
2984
+ allowed: SURVEY_RECIPIENT_TYPES,
2985
+ message: "Invalid survey.recipient_type. Use one of: member, team, org_wide."
2986
+ });
2987
+ const missing = [];
2988
+ if (!name) missing.push("name");
2989
+ if (!recipientType) missing.push("recipient_type");
2990
+ if (missing.length > 0) {
2991
+ throwMissingRequiredCreateFields("survey", missing);
2992
+ }
2993
+ survey.name = name;
2994
+ survey.recipient_type = recipientType;
2995
+ return { ...body, survey };
2996
+ }
2997
+ function normalizeSurveysUpdateBody(body) {
2998
+ const survey = ensureEntityObject(body, "survey");
2999
+ const title = asNonEmptyString3(survey.title);
3000
+ const currentName = asNonEmptyString3(survey.name);
3001
+ if (!currentName && title) {
3002
+ survey.name = title;
3003
+ }
3004
+ delete survey.title;
3005
+ const name = validateEnumField({
3006
+ rawValue: survey.name,
3007
+ field: "survey.name",
3008
+ allowed: SURVEY_NAMES,
3009
+ 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."
3010
+ });
3011
+ if (name) {
3012
+ survey.name = name;
3013
+ }
3014
+ const recipientType = validateEnumField({
3015
+ rawValue: survey.recipient_type,
3016
+ field: "survey.recipient_type",
3017
+ allowed: SURVEY_RECIPIENT_TYPES,
3018
+ message: "Invalid survey.recipient_type. Use one of: member, team, org_wide."
3019
+ });
3020
+ if (recipientType) {
3021
+ survey.recipient_type = recipientType;
3022
+ }
3023
+ return { ...body, survey };
3024
+ }
3025
+ function normalizeFeedbacksCreateBody(body) {
3026
+ const feedback = ensureEntityObject(body, "feedback");
3027
+ const title = asNonEmptyString3(feedback.title);
3028
+ const currentName = asNonEmptyString3(feedback.name);
3029
+ if (!currentName && title) {
3030
+ feedback.name = title;
3031
+ }
3032
+ delete feedback.title;
3033
+ const name = validateEnumField({
3034
+ rawValue: feedback.name,
3035
+ field: "feedback.name",
3036
+ allowed: FEEDBACK_NAMES,
3037
+ 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."
3038
+ });
3039
+ const quarter = validateEnumField({
3040
+ rawValue: feedback.quarter,
3041
+ field: "feedback.quarter",
3042
+ allowed: FEEDBACK_QUARTERS,
3043
+ message: "Invalid feedback.quarter. Use one of: q1, q2, q3, q4."
3044
+ });
3045
+ const year = asNonEmptyString3(feedback.year);
3046
+ const missing = [];
3047
+ if (!name) missing.push("name");
3048
+ if (!quarter) missing.push("quarter");
3049
+ if (!year) missing.push("year");
3050
+ if (missing.length > 0) {
3051
+ throwMissingRequiredCreateFields("feedback", missing);
3052
+ }
3053
+ feedback.name = name;
3054
+ feedback.quarter = quarter;
3055
+ feedback.year = year;
3056
+ return { ...body, feedback };
3057
+ }
3058
+ function normalizeFeedbacksUpdateBody(body) {
3059
+ const feedback = ensureEntityObject(body, "feedback");
3060
+ const title = asNonEmptyString3(feedback.title);
3061
+ const currentName = asNonEmptyString3(feedback.name);
3062
+ if (!currentName && title) {
3063
+ feedback.name = title;
3064
+ }
3065
+ delete feedback.title;
3066
+ const name = validateEnumField({
3067
+ rawValue: feedback.name,
3068
+ field: "feedback.name",
3069
+ allowed: FEEDBACK_NAMES,
3070
+ 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."
3071
+ });
3072
+ if (name) {
3073
+ feedback.name = name;
3074
+ }
3075
+ const quarter = validateEnumField({
3076
+ rawValue: feedback.quarter,
3077
+ field: "feedback.quarter",
3078
+ allowed: FEEDBACK_QUARTERS,
3079
+ message: "Invalid feedback.quarter. Use one of: q1, q2, q3, q4."
3080
+ });
3081
+ if (quarter) {
3082
+ feedback.quarter = quarter;
3083
+ }
3084
+ return { ...body, feedback };
3085
+ }
3086
+ function normalizeAccountabilityCreateBody(body) {
3087
+ const responsibility = ensureEntityObject(body, "responsibility");
3088
+ const summary = asNonEmptyString3(responsibility.summary);
3089
+ const currentName = asNonEmptyString3(responsibility.name);
3090
+ if (!currentName && summary) {
3091
+ responsibility.name = summary;
3092
+ }
3093
+ delete responsibility.summary;
3094
+ const name = asNonEmptyString3(responsibility.name);
3095
+ const memberId = asNonEmptyString3(responsibility.member_id);
3096
+ const missing = [];
3097
+ if (!name) missing.push("name");
3098
+ if (!memberId) missing.push("member_id");
3099
+ if (missing.length > 0) {
3100
+ throwMissingRequiredCreateFields("responsibility", missing);
3101
+ }
3102
+ responsibility.name = name;
3103
+ responsibility.member_id = memberId;
3104
+ return { ...body, responsibility };
3105
+ }
3106
+ function normalizeAccountabilityUpdateBody(body) {
3107
+ const responsibility = ensureEntityObject(body, "responsibility");
3108
+ const summary = asNonEmptyString3(responsibility.summary);
3109
+ const currentName = asNonEmptyString3(responsibility.name);
3110
+ if (!currentName && summary) {
3111
+ responsibility.name = summary;
3112
+ }
3113
+ delete responsibility.summary;
3114
+ return { ...body, responsibility };
3115
+ }
3116
+ function normalizeScorecardsCreateBody(body) {
3117
+ const measurable = ensureEntityObject(body, "measurable");
3118
+ const interval = validateEnumField({
3119
+ rawValue: measurable.interval,
3120
+ field: "measurable.interval",
3121
+ allowed: SCORECARD_INTERVALS,
3122
+ message: "Invalid measurable.interval. Use one of: daily, weekly, monthly, quarterly, yearly."
3123
+ });
3124
+ measurable.interval = interval ?? "weekly";
3125
+ const trend = validateEnumField({
3126
+ rawValue: measurable.trend,
3127
+ field: "measurable.trend",
3128
+ allowed: SCORECARD_TRENDS,
3129
+ message: "Invalid measurable.trend. Use one of: average, total."
3130
+ });
3131
+ measurable.trend = trend ?? "average";
3132
+ return { ...body, measurable };
3133
+ }
3134
+ function buildKpisCreateMutation(params) {
3135
+ const entity = params.body.smart_kpi;
3136
+ if (!entity || typeof entity !== "object" || Array.isArray(entity)) {
3137
+ throw new CliError({
3138
+ message: 'Invalid payload. Expected object at "smart_kpi".',
3139
+ kind: "invalid_args",
3140
+ status: 400,
3141
+ exitCode: EXIT_CODES.invalidArgs
3142
+ });
3143
+ }
3144
+ const smartKpi = { ...entity };
3145
+ const name = asNonEmptyString3(smartKpi.name);
3146
+ const smartKpiViewId = asNonEmptyString3(smartKpi.smart_kpi_view_id);
3147
+ const measurableGroupId = asNonEmptyString3(smartKpi.measurable_group_id);
3148
+ const hasAllowedName = typeof name === "string" && SMART_KPI_NAME_SET.has(name);
3149
+ if (!name) {
3150
+ throw new CliError({
3151
+ message: "Missing required create fields for smart_kpi: name.",
3152
+ kind: "invalid_args",
3153
+ status: 400,
3154
+ exitCode: EXIT_CODES.invalidArgs,
3155
+ details: { requiredFields: ["name"], rootKey: "smart_kpi" }
3156
+ });
3157
+ }
3158
+ if (measurableGroupId && !hasAllowedName) {
3159
+ const measurable = {
3160
+ measurable_group_id: measurableGroupId,
3161
+ name,
3162
+ interval: "daily",
3163
+ trend: "average",
3164
+ measurable_type: "number",
3165
+ condition: "greater_than_or_equal_to"
3166
+ };
3167
+ const notes = asNonEmptyString3(smartKpi.notes);
3168
+ if (notes) {
3169
+ measurable.notes = notes;
3170
+ }
3171
+ return {
3172
+ command: "measurables.create",
3173
+ field: "create_measurable",
3174
+ variables: {
3175
+ organization_id: params.organizationId,
3176
+ params: { measurable }
3177
+ }
3178
+ };
3179
+ }
3180
+ if (!smartKpiViewId) {
3181
+ throw new CliError({
3182
+ message: "Missing required create fields for smart_kpi: smart_kpi_view_id.",
3183
+ kind: "invalid_args",
3184
+ status: 400,
3185
+ exitCode: EXIT_CODES.invalidArgs,
3186
+ details: { requiredFields: ["smart_kpi_view_id"], rootKey: "smart_kpi" }
3187
+ });
3188
+ }
3189
+ if (!hasAllowedName) {
3190
+ throw new CliError({
3191
+ message: "Invalid smart_kpi.name for kpis.create. Use an allowed enum value or route free-text KPI names to measurable create.",
3192
+ kind: "invalid_args",
3193
+ status: 400,
3194
+ exitCode: EXIT_CODES.invalidArgs,
3195
+ details: {
3196
+ field: "smart_kpi.name",
3197
+ allowedValues: SMART_KPI_NAMES
3198
+ }
3199
+ });
3200
+ }
3201
+ delete smartKpi.measurable_group_id;
3202
+ smartKpi.name = name;
3203
+ smartKpi.smart_kpi_view_id = smartKpiViewId;
3204
+ return {
3205
+ command: "kpis.create",
3206
+ field: "create_smart_kpi",
3207
+ variables: {
3208
+ organization_id: params.organizationId,
3209
+ params: { smart_kpi: smartKpi }
3210
+ }
3211
+ };
3212
+ }
3213
+ function registerSystemToolCommands(program) {
3214
+ registerEntityCrudCommands(program, {
3215
+ command: "lists",
3216
+ description: "List operations",
3217
+ resourcePath: "lists",
3218
+ rootKey: "list",
3219
+ listParams: ["include_archived", "member_id", "team_ids", "term"]
3220
+ });
3221
+ registerEntityCrudCommands(program, {
3222
+ command: "list-items",
3223
+ description: "List item operations",
3224
+ resourcePath: "list_items",
3225
+ rootKey: "list_item",
3226
+ requiredCreateFields: ["list_id"],
3227
+ listParams: [
3228
+ "field_blank",
3229
+ "field_name",
3230
+ "field_value",
3231
+ "include_archived",
3232
+ "list_id",
3233
+ "meeting_id",
3234
+ "member_id",
3235
+ "rank_direction",
3236
+ "team_id",
3237
+ "team_ids"
3238
+ ]
3239
+ });
3240
+ registerEntityCrudCommands(program, {
3241
+ command: "issue-groups",
3242
+ description: "Issue group operations",
3243
+ resourcePath: "issue_groups",
3244
+ rootKey: "issue_group",
3245
+ listParams: ["include_archived", "member_id", "team_ids", "term"]
3246
+ });
3247
+ registerEntityCrudCommands(program, {
3248
+ command: "todo-groups",
3249
+ description: "To-do group operations",
3250
+ resourcePath: "todo_groups",
3251
+ rootKey: "todo_group",
3252
+ listParams: ["include_archived", "member_id", "team_ids", "term"]
3253
+ });
3254
+ registerEntityCrudCommands(program, {
3255
+ command: "todos",
3256
+ description: "To-do operations",
3257
+ resourcePath: "todos",
3258
+ rootKey: "todo",
2121
3259
  requiredCreateFields: ["todo_group_id"],
3260
+ normalizeCreateBody: normalizeTodosCreateBody,
2122
3261
  listParams: [
2123
3262
  "include_archived",
2124
3263
  "meeting_id",
@@ -2141,6 +3280,7 @@ function registerSystemToolCommands(program) {
2141
3280
  description: "Knowledge content operations",
2142
3281
  resourcePath: "contents",
2143
3282
  rootKey: "content",
3283
+ normalizeCreateBody: normalizeKnowledgeCreateBody,
2144
3284
  listParams: [
2145
3285
  "assigned",
2146
3286
  "contentable_id",
@@ -2171,13 +3311,40 @@ function registerSystemToolCommands(program) {
2171
3311
  description: "News operations",
2172
3312
  resourcePath: "headlines",
2173
3313
  rootKey: "headline",
2174
- listParams: ["meeting_id", "unread"]
3314
+ requiredCreateFields: ["member_id", "status", "headline_type"],
3315
+ normalizeCreateBody: normalizeNewsCreateBody,
3316
+ listParams: ["meeting_id", "unread"],
3317
+ showQueryFactory: ({ id, organizationId }) => ({
3318
+ field: "headlines",
3319
+ variables: {
3320
+ organization_id: organizationId,
3321
+ page: 1,
3322
+ per: 200
3323
+ },
3324
+ selectionSet: "{ data { id type attributes } count currentPage totalPages }",
3325
+ transformData: (value) => {
3326
+ if (!value || typeof value !== "object") {
3327
+ return null;
3328
+ }
3329
+ const payload = value;
3330
+ const rows = Array.isArray(payload.data) ? payload.data : [];
3331
+ return rows.find((row) => {
3332
+ if (!row || typeof row !== "object") {
3333
+ return false;
3334
+ }
3335
+ return String(row.id ?? "") === id;
3336
+ }) ?? null;
3337
+ }
3338
+ })
2175
3339
  });
2176
3340
  registerEntityCrudCommands(program, {
2177
3341
  command: "questions",
2178
3342
  description: "Q&A forum operations",
2179
3343
  resourcePath: "questions",
2180
3344
  rootKey: "question",
3345
+ requiredCreateFields: ["member_id", "name"],
3346
+ normalizeCreateBody: normalizeQuestionsCreateBody,
3347
+ normalizeUpdateBody: normalizeQuestionsUpdateBody,
2181
3348
  listParams: ["answered", "asked", "member_id", "team_id", "term"]
2182
3349
  });
2183
3350
  registerEntityCrudCommands(program, {
@@ -2185,6 +3352,8 @@ function registerSystemToolCommands(program) {
2185
3352
  description: "Pulse operations",
2186
3353
  resourcePath: "health_updates",
2187
3354
  rootKey: "health_update",
3355
+ requiredCreateFields: ["health_updatable_id", "health_updatable_type", "member_id", "status"],
3356
+ normalizeCreateBody: normalizePulseCreateBody,
2188
3357
  listParams: ["health_updatable_id", "health_updatable_type"]
2189
3358
  });
2190
3359
  registerEntityCrudCommands(program, {
@@ -2192,6 +3361,9 @@ function registerSystemToolCommands(program) {
2192
3361
  description: "Survey operations",
2193
3362
  resourcePath: "surveys",
2194
3363
  rootKey: "survey",
3364
+ requiredCreateFields: ["name", "recipient_type"],
3365
+ normalizeCreateBody: normalizeSurveysCreateBody,
3366
+ normalizeUpdateBody: normalizeSurveysUpdateBody,
2195
3367
  listParams: ["completed", "current_member", "due", "exclude_completed"]
2196
3368
  });
2197
3369
  registerEntityCrudCommands(program, {
@@ -2199,6 +3371,9 @@ function registerSystemToolCommands(program) {
2199
3371
  description: "Feedback operations",
2200
3372
  resourcePath: "feedback",
2201
3373
  rootKey: "feedback",
3374
+ requiredCreateFields: ["name", "quarter", "year"],
3375
+ normalizeCreateBody: normalizeFeedbacksCreateBody,
3376
+ normalizeUpdateBody: normalizeFeedbacksUpdateBody,
2202
3377
  listParams: ["last", "latest", "start_date"]
2203
3378
  });
2204
3379
  registerEntityCrudCommands(program, {
@@ -2206,6 +3381,9 @@ function registerSystemToolCommands(program) {
2206
3381
  description: "Accountability operations",
2207
3382
  resourcePath: "responsibilities",
2208
3383
  rootKey: "responsibility",
3384
+ requiredCreateFields: ["name", "member_id"],
3385
+ normalizeCreateBody: normalizeAccountabilityCreateBody,
3386
+ normalizeUpdateBody: normalizeAccountabilityUpdateBody,
2209
3387
  listParams: ["meeting_id", "term"]
2210
3388
  });
2211
3389
  registerEntityCrudCommands(program, {
@@ -2213,6 +3391,10 @@ function registerSystemToolCommands(program) {
2213
3391
  description: "KPI operations",
2214
3392
  resourcePath: "smart_kpis",
2215
3393
  rootKey: "smart_kpi",
3394
+ createMutationFactory: ({ body, organizationId }) => buildKpisCreateMutation({
3395
+ body,
3396
+ organizationId
3397
+ }),
2216
3398
  listParams: [
2217
3399
  "annual_objective_id",
2218
3400
  "include_archived",
@@ -2238,6 +3420,7 @@ function registerSystemToolCommands(program) {
2238
3420
  resourcePath: "measurables",
2239
3421
  rootKey: "measurable",
2240
3422
  requiredCreateFields: ["measurable_group_id"],
3423
+ normalizeCreateBody: normalizeScorecardsCreateBody,
2241
3424
  listParams: [
2242
3425
  "annual_objective_id",
2243
3426
  "include_archived",
@@ -2339,6 +3522,103 @@ function registerTeamCommands(program) {
2339
3522
  // src/commands/organizations.ts
2340
3523
  var import_zod10 = require("zod");
2341
3524
  var idSchema9 = import_zod10.z.string().min(1);
3525
+ function isRecord2(value) {
3526
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3527
+ }
3528
+ function ensureRootObject(body, rootKey) {
3529
+ const root = body[rootKey];
3530
+ if (!isRecord2(root)) {
3531
+ throw new CliError({
3532
+ message: `Invalid payload. Expected object at "${rootKey}".`,
3533
+ kind: "invalid_args",
3534
+ status: 400,
3535
+ exitCode: EXIT_CODES.invalidArgs
3536
+ });
3537
+ }
3538
+ return { ...root };
3539
+ }
3540
+ function asNonEmptyString4(value) {
3541
+ if (typeof value !== "string") {
3542
+ return void 0;
3543
+ }
3544
+ const trimmed = value.trim();
3545
+ return trimmed.length > 0 ? trimmed : void 0;
3546
+ }
3547
+ function normalizeOrganizationUpdateBody(body) {
3548
+ const organization = ensureRootObject(body, "organization");
3549
+ const detail = isRecord2(organization.organization_detail_attributes) ? { ...organization.organization_detail_attributes } : {};
3550
+ const workspaceName = asNonEmptyString4(organization.workspace_name);
3551
+ if (workspaceName) {
3552
+ detail.workspace_name = workspaceName;
3553
+ }
3554
+ delete organization.workspace_name;
3555
+ if (Object.keys(detail).length > 0) {
3556
+ organization.organization_detail_attributes = detail;
3557
+ }
3558
+ return { organization };
3559
+ }
3560
+ function normalizeOrganizationMetaProfileUpdateBody(body) {
3561
+ const root = ensureRootObject(body, "organization_meta_profile");
3562
+ const profile = isRecord2(root.profile) ? { ...root.profile } : {};
3563
+ const title = asNonEmptyString4(root.title);
3564
+ if (title) {
3565
+ const companyIdentity = isRecord2(profile.company_identity) ? { ...profile.company_identity } : {};
3566
+ companyIdentity.one_sentence_summary = title;
3567
+ profile.company_identity = companyIdentity;
3568
+ }
3569
+ const unsupported = Object.keys(root).filter((key) => key !== "profile" && key !== "title");
3570
+ if (unsupported.length > 0) {
3571
+ throw new CliError({
3572
+ message: "Invalid organization_meta_profile update payload. Use organization_meta_profile.profile.<section>.<field>.",
3573
+ kind: "invalid_args",
3574
+ status: 400,
3575
+ exitCode: EXIT_CODES.invalidArgs,
3576
+ details: { unsupportedKeys: unsupported, expectedRootKey: "profile" }
3577
+ });
3578
+ }
3579
+ if (Object.keys(profile).length === 0) {
3580
+ throw new CliError({
3581
+ message: "Missing required update fields for organization_meta_profile: profile.",
3582
+ kind: "invalid_args",
3583
+ status: 400,
3584
+ exitCode: EXIT_CODES.invalidArgs,
3585
+ details: { requiredFields: ["profile"], rootKey: "organization_meta_profile" }
3586
+ });
3587
+ }
3588
+ return { organization_meta_profile: { profile } };
3589
+ }
3590
+ function normalizeKeyMetricMetaProfileUpdateBody(body) {
3591
+ const root = ensureRootObject(body, "key_metric_meta_profile");
3592
+ const profile = isRecord2(root.profile) ? { ...root.profile } : {};
3593
+ const annualRevenue = asNonEmptyString4(root.annual_revenue);
3594
+ if (annualRevenue) {
3595
+ const financial = isRecord2(profile.financial) ? { ...profile.financial } : {};
3596
+ financial.revenue = annualRevenue;
3597
+ profile.financial = financial;
3598
+ }
3599
+ const unsupported = Object.keys(root).filter(
3600
+ (key) => key !== "profile" && key !== "annual_revenue"
3601
+ );
3602
+ if (unsupported.length > 0) {
3603
+ throw new CliError({
3604
+ message: "Invalid key_metric_meta_profile update payload. Use key_metric_meta_profile.profile.<section>.<field>.",
3605
+ kind: "invalid_args",
3606
+ status: 400,
3607
+ exitCode: EXIT_CODES.invalidArgs,
3608
+ details: { unsupportedKeys: unsupported, expectedRootKey: "profile" }
3609
+ });
3610
+ }
3611
+ if (Object.keys(profile).length === 0) {
3612
+ throw new CliError({
3613
+ message: "Missing required update fields for key_metric_meta_profile: profile.",
3614
+ kind: "invalid_args",
3615
+ status: 400,
3616
+ exitCode: EXIT_CODES.invalidArgs,
3617
+ details: { requiredFields: ["profile"], rootKey: "key_metric_meta_profile" }
3618
+ });
3619
+ }
3620
+ return { key_metric_meta_profile: { profile } };
3621
+ }
2342
3622
  function registerOrganizationCommands(program) {
2343
3623
  const organizations = program.command("organizations").description("Organization operations");
2344
3624
  organizations.command("show").option("--id <id>", "Organization ID (defaults to resolved organization context)").action(async (opts, cmd) => {
@@ -2360,7 +3640,8 @@ function registerOrganizationCommands(program) {
2360
3640
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2361
3641
  const fallbackId = resolveOrganizationId(context.organizationId);
2362
3642
  const id = idSchema9.parse(opts.id ?? fallbackId);
2363
- const body = __testables.normalizeBody(String(opts.dataJson), "organization");
3643
+ const rawBody = __testables.normalizeBody(String(opts.dataJson), "organization");
3644
+ const body = normalizeOrganizationUpdateBody(rawBody);
2364
3645
  await runGraphqlMutationCommand({
2365
3646
  command: "organizations.update",
2366
3647
  runtimeOptions: context.runtimeOptions,
@@ -2394,10 +3675,11 @@ function registerOrganizationCommands(program) {
2394
3675
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2395
3676
  const organizationId = resolveOrganizationId(context.organizationId);
2396
3677
  const id = idSchema9.parse(opts.id ?? organizationId);
2397
- const body = __testables.normalizeBody(
3678
+ const rawBody = __testables.normalizeBody(
2398
3679
  String(opts.dataJson),
2399
3680
  "organization_meta_profile"
2400
3681
  );
3682
+ const body = normalizeOrganizationMetaProfileUpdateBody(rawBody);
2401
3683
  await runGraphqlMutationCommand({
2402
3684
  command: "organizations.meta-profile.update",
2403
3685
  runtimeOptions: context.runtimeOptions,
@@ -2432,10 +3714,11 @@ function registerOrganizationCommands(program) {
2432
3714
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2433
3715
  const organizationId = resolveOrganizationId(context.organizationId);
2434
3716
  const id = idSchema9.parse(opts.id ?? organizationId);
2435
- const body = __testables.normalizeBody(
3717
+ const rawBody = __testables.normalizeBody(
2436
3718
  String(opts.dataJson),
2437
3719
  "key_metric_meta_profile"
2438
3720
  );
3721
+ const body = normalizeKeyMetricMetaProfileUpdateBody(rawBody);
2439
3722
  await runGraphqlMutationCommand({
2440
3723
  command: "organizations.key-metric-meta-profile.update",
2441
3724
  runtimeOptions: context.runtimeOptions,
@@ -2452,36 +3735,131 @@ function registerOrganizationCommands(program) {
2452
3735
  // src/commands/foundation.ts
2453
3736
  var import_zod11 = require("zod");
2454
3737
  var idSchema10 = import_zod11.z.string().min(1);
2455
- function registerFoundationCommands(program) {
2456
- const foundation = program.command("foundation").description("Foundation operations");
2457
- const strategicPlans = foundation.command("strategic-plans").description("Strategic plan operations");
2458
- const strategicObjectives = foundation.command("strategic-objectives").description("Strategic objective operations");
2459
- 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) => {
2460
- const context = await resolveCommandContext(cmd.optsWithGlobals());
2461
- const organizationId = resolveOrganizationId(context.organizationId);
2462
- const id = idSchema10.parse(opts.id ?? organizationId);
2463
- await runGraphqlQueryCommand({
2464
- command: "foundation.strategic-plans.show",
2465
- runtimeOptions: context.runtimeOptions,
2466
- field: "strategic_plan",
2467
- variables: normalizeGraphqlVariables2({
2468
- organization_id: organizationId,
2469
- id,
2470
- progress_scope: opts.progressScope,
2471
- all_progress: opts.allProgress,
2472
- all: opts.all
2473
- }),
2474
- isShow: true
3738
+ var STRATEGIC_PLAN_ALLOWED_UPDATE_KEYS = /* @__PURE__ */ new Set([
3739
+ "published_at",
3740
+ "profile",
3741
+ "strategic_plan_reads_attributes"
3742
+ ]);
3743
+ var STRATEGIC_OBJECTIVE_ALLOWED_UPDATE_KEYS = /* @__PURE__ */ new Set([
3744
+ "summary",
3745
+ "alignment_score",
3746
+ "published_at",
3747
+ "strategic_objective_reads_attributes"
3748
+ ]);
3749
+ function isRecord3(value) {
3750
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3751
+ }
3752
+ function ensureRootObject2(body, rootKey) {
3753
+ const root = body[rootKey];
3754
+ if (!isRecord3(root)) {
3755
+ throw new CliError({
3756
+ message: `Invalid payload. Expected object at "${rootKey}".`,
3757
+ kind: "invalid_args",
3758
+ status: 400,
3759
+ exitCode: EXIT_CODES.invalidArgs
2475
3760
  });
2476
- });
2477
- strategicPlans.command("update").option("--id <id>", "Strategic plan ID (defaults to organization context)").requiredOption(
2478
- "--data-json <dataJson>",
2479
- 'JSON object for strategic_plan or {"strategic_plan": {...}}'
2480
- ).action(async (opts, cmd) => {
2481
- const context = await resolveCommandContext(cmd.optsWithGlobals());
2482
- const organizationId = resolveOrganizationId(context.organizationId);
3761
+ }
3762
+ return { ...root };
3763
+ }
3764
+ function asNonEmptyString5(value) {
3765
+ if (typeof value !== "string") {
3766
+ return void 0;
3767
+ }
3768
+ const trimmed = value.trim();
3769
+ return trimmed.length > 0 ? trimmed : void 0;
3770
+ }
3771
+ function normalizeStrategicPlanUpdateBody(body) {
3772
+ const strategicPlan = ensureRootObject2(body, "strategic_plan");
3773
+ const unsupported = Object.keys(strategicPlan).filter(
3774
+ (key) => !STRATEGIC_PLAN_ALLOWED_UPDATE_KEYS.has(key)
3775
+ );
3776
+ if (unsupported.length > 0) {
3777
+ throw new CliError({
3778
+ message: "Invalid strategic_plan update payload. Allowed keys: published_at, profile, strategic_plan_reads_attributes.",
3779
+ kind: "invalid_args",
3780
+ status: 400,
3781
+ exitCode: EXIT_CODES.invalidArgs,
3782
+ details: {
3783
+ unsupportedKeys: unsupported,
3784
+ allowedKeys: Array.from(STRATEGIC_PLAN_ALLOWED_UPDATE_KEYS)
3785
+ }
3786
+ });
3787
+ }
3788
+ return { strategic_plan: strategicPlan };
3789
+ }
3790
+ function normalizeStrategicObjectiveUpdateBody(body) {
3791
+ const strategicObjective = ensureRootObject2(body, "strategic_objective");
3792
+ const title = asNonEmptyString5(strategicObjective.title);
3793
+ if (!asNonEmptyString5(strategicObjective.summary) && title) {
3794
+ strategicObjective.summary = title;
3795
+ }
3796
+ delete strategicObjective.title;
3797
+ const unsupported = Object.keys(strategicObjective).filter(
3798
+ (key) => !STRATEGIC_OBJECTIVE_ALLOWED_UPDATE_KEYS.has(key)
3799
+ );
3800
+ if (unsupported.length > 0) {
3801
+ throw new CliError({
3802
+ message: "Invalid strategic_objective update payload. Allowed keys: summary, alignment_score, published_at, strategic_objective_reads_attributes.",
3803
+ kind: "invalid_args",
3804
+ status: 400,
3805
+ exitCode: EXIT_CODES.invalidArgs,
3806
+ details: {
3807
+ unsupportedKeys: unsupported,
3808
+ allowedKeys: Array.from(STRATEGIC_OBJECTIVE_ALLOWED_UPDATE_KEYS)
3809
+ }
3810
+ });
3811
+ }
3812
+ return { strategic_objective: strategicObjective };
3813
+ }
3814
+ function normalizeAnnualObjectiveCreateBody(body) {
3815
+ const annualObjective = ensureRootObject2(body, "annual_objective");
3816
+ const title = asNonEmptyString5(annualObjective.title);
3817
+ if (!asNonEmptyString5(annualObjective.name) && title) {
3818
+ annualObjective.name = title;
3819
+ }
3820
+ delete annualObjective.title;
3821
+ return { annual_objective: annualObjective };
3822
+ }
3823
+ function normalizeQuarterlyObjectiveCreateBody(body) {
3824
+ const quarterlyObjective = ensureRootObject2(body, "quarterly_objective");
3825
+ const title = asNonEmptyString5(quarterlyObjective.title);
3826
+ if (!asNonEmptyString5(quarterlyObjective.name) && title) {
3827
+ quarterlyObjective.name = title;
3828
+ }
3829
+ delete quarterlyObjective.title;
3830
+ return { quarterly_objective: quarterlyObjective };
3831
+ }
3832
+ function registerFoundationCommands(program) {
3833
+ const foundation = program.command("foundation").description("Foundation operations");
3834
+ const strategicPlans = foundation.command("strategic-plans").description("Strategic plan operations");
3835
+ const strategicObjectives = foundation.command("strategic-objectives").description("Strategic objective operations");
3836
+ 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) => {
3837
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
3838
+ const organizationId = resolveOrganizationId(context.organizationId);
2483
3839
  const id = idSchema10.parse(opts.id ?? organizationId);
2484
- const body = __testables.normalizeBody(String(opts.dataJson), "strategic_plan");
3840
+ await runGraphqlQueryCommand({
3841
+ command: "foundation.strategic-plans.show",
3842
+ runtimeOptions: context.runtimeOptions,
3843
+ field: "strategic_plan",
3844
+ variables: normalizeGraphqlVariables2({
3845
+ organization_id: organizationId,
3846
+ id,
3847
+ progress_scope: opts.progressScope,
3848
+ all_progress: opts.allProgress,
3849
+ all: opts.all
3850
+ }),
3851
+ isShow: true
3852
+ });
3853
+ });
3854
+ strategicPlans.command("update").option("--id <id>", "Strategic plan ID (defaults to organization context)").requiredOption(
3855
+ "--data-json <dataJson>",
3856
+ 'JSON object for strategic_plan or {"strategic_plan": {...}}'
3857
+ ).action(async (opts, cmd) => {
3858
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
3859
+ const organizationId = resolveOrganizationId(context.organizationId);
3860
+ const id = idSchema10.parse(opts.id ?? organizationId);
3861
+ const rawBody = __testables.normalizeBody(String(opts.dataJson), "strategic_plan");
3862
+ const body = normalizeStrategicPlanUpdateBody(rawBody);
2485
3863
  await runGraphqlMutationCommand({
2486
3864
  command: "foundation.strategic-plans.update",
2487
3865
  runtimeOptions: context.runtimeOptions,
@@ -2518,10 +3896,11 @@ function registerFoundationCommands(program) {
2518
3896
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2519
3897
  const organizationId = resolveOrganizationId(context.organizationId);
2520
3898
  const id = idSchema10.parse(opts.id ?? organizationId);
2521
- const body = __testables.normalizeBody(
3899
+ const rawBody = __testables.normalizeBody(
2522
3900
  String(opts.dataJson),
2523
3901
  "strategic_objective"
2524
3902
  );
3903
+ const body = normalizeStrategicObjectiveUpdateBody(rawBody);
2525
3904
  await runGraphqlMutationCommand({
2526
3905
  command: "foundation.strategic-objectives.update",
2527
3906
  runtimeOptions: context.runtimeOptions,
@@ -2538,7 +3917,8 @@ function registerFoundationCommands(program) {
2538
3917
  description: "Foundation annual objective operations",
2539
3918
  resourcePath: "annual_objectives",
2540
3919
  rootKey: "annual_objective",
2541
- requiredCreateFields: ["strategic_objective_id"],
3920
+ requiredCreateFields: ["strategic_objective_id", "name"],
3921
+ normalizeCreateBody: normalizeAnnualObjectiveCreateBody,
2542
3922
  listParams: []
2543
3923
  });
2544
3924
  registerEntityCrudCommands(foundation, {
@@ -2546,7 +3926,8 @@ function registerFoundationCommands(program) {
2546
3926
  description: "Foundation quarterly objective operations",
2547
3927
  resourcePath: "quarterly_objectives",
2548
3928
  rootKey: "quarterly_objective",
2549
- requiredCreateFields: ["strategic_objective_id", "annual_objective_id"],
3929
+ requiredCreateFields: ["strategic_objective_id", "annual_objective_id", "name"],
3930
+ normalizeCreateBody: normalizeQuarterlyObjectiveCreateBody,
2550
3931
  listParams: ["annual_objective_id"]
2551
3932
  });
2552
3933
  }
@@ -2650,6 +4031,20 @@ function normalizeListPayload(payload, parentKind, parentIdFallback, parentTyped
2650
4031
  totalPages: record.totalPages ?? 1
2651
4032
  };
2652
4033
  }
4034
+ function normalizeSubtaskCreateBody(body) {
4035
+ const subtask = body.subtask;
4036
+ if (!subtask || typeof subtask !== "object" || Array.isArray(subtask)) {
4037
+ return body;
4038
+ }
4039
+ const subtaskRecord = subtask;
4040
+ const summary = typeof subtaskRecord.summary === "string" ? subtaskRecord.summary.trim() : void 0;
4041
+ const hasName = typeof subtaskRecord.name === "string" && subtaskRecord.name.trim().length > 0;
4042
+ if (!hasName && summary && summary.length > 0) {
4043
+ subtaskRecord.name = summary;
4044
+ }
4045
+ delete subtaskRecord.summary;
4046
+ return body;
4047
+ }
2653
4048
  function registerChildCommands(program, config) {
2654
4049
  const command = program.command(config.command).description(config.description);
2655
4050
  command.command("list").requiredOption(`--${config.parentFlag} <${config.parentFlag}>`).option("--page <page>").option("--per <per>").action(async (opts, cmd) => {
@@ -2680,7 +4075,10 @@ function registerChildCommands(program, config) {
2680
4075
  command.command("create").requiredOption("--data-json <dataJson>").action(async (opts, cmd) => {
2681
4076
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2682
4077
  const organizationId = resolveOrganizationId(context.organizationId);
2683
- const body = normalizeBody2(String(opts.dataJson), config.rootKey);
4078
+ let body = normalizeBody2(String(opts.dataJson), config.rootKey);
4079
+ if (config.normalizeCreateBody) {
4080
+ body = config.normalizeCreateBody(body);
4081
+ }
2684
4082
  assertRequiredParent(body, config.rootKey, config.parentFlag.replace(/-/g, "_"));
2685
4083
  await runGraphqlMutationCommand({
2686
4084
  command: `${config.command}.create`,
@@ -2743,7 +4141,8 @@ function registerChildEntityCommands(program) {
2743
4141
  updateOperationName: "UpdateSubtask",
2744
4142
  destroyOperationName: "DestroySubtask",
2745
4143
  listSelectionSet: "{ data { id type name status taskId attributes } count currentPage totalPages }",
2746
- listParentTypedField: "taskId"
4144
+ listParentTypedField: "taskId",
4145
+ normalizeCreateBody: normalizeSubtaskCreateBody
2747
4146
  });
2748
4147
  registerChildCommands(program, {
2749
4148
  command: "milestones",
@@ -3025,8 +4424,980 @@ function registerNoteCommands(program) {
3025
4424
  });
3026
4425
  }
3027
4426
 
4427
+ // src/commands/markdownTree.ts
4428
+ var import_zod14 = require("zod");
4429
+ var nonEmptyString2 = import_zod14.z.string().min(1);
4430
+ var nonNegativeInt = import_zod14.z.coerce.number().int().min(0);
4431
+ function addScopeOptions(command) {
4432
+ 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");
4433
+ }
4434
+ function parseScopeOptions(raw) {
4435
+ const parsed = {
4436
+ toolKey: nonEmptyString2.parse(raw.toolKey),
4437
+ nodeKey: nonEmptyString2.parse(raw.nodeKey)
4438
+ };
4439
+ if (typeof raw.parentId === "string" && raw.parentId.trim() !== "") {
4440
+ parsed.parentId = raw.parentId.trim();
4441
+ }
4442
+ if (typeof raw.recordId === "string" && raw.recordId.trim() !== "") {
4443
+ parsed.recordId = raw.recordId.trim();
4444
+ }
4445
+ if (typeof raw.memberId === "string" && raw.memberId.trim() !== "") {
4446
+ parsed.memberId = raw.memberId.trim();
4447
+ }
4448
+ if (typeof raw.teamId === "string" && raw.teamId.trim() !== "") {
4449
+ parsed.teamId = raw.teamId.trim();
4450
+ }
4451
+ if (typeof raw.contentType === "string" && raw.contentType.trim() !== "") {
4452
+ parsed.contentType = raw.contentType.trim();
4453
+ }
4454
+ if (raw.treeView === true) {
4455
+ parsed.treeView = true;
4456
+ }
4457
+ return parsed;
4458
+ }
4459
+ function baseNodeFields() {
4460
+ return [
4461
+ "toolKey",
4462
+ "nodeKey",
4463
+ "nodeKind",
4464
+ "runtimeLabel",
4465
+ "resolvedScope { parentId recordId memberId teamId contentType }",
4466
+ "isLeaf",
4467
+ "treeView",
4468
+ "details"
4469
+ ].join(" ");
4470
+ }
4471
+ function buildChildSelection(depth) {
4472
+ if (depth <= 0) return "";
4473
+ const nested = buildChildSelection(depth - 1);
4474
+ return nested.length > 0 ? `children { ${baseNodeFields()} ${nested} }` : `children { ${baseNodeFields()} }`;
4475
+ }
4476
+ function buildNodeSelectionSet(depth) {
4477
+ const nested = buildChildSelection(depth);
4478
+ return nested.length > 0 ? `{ ${baseNodeFields()} ${nested} }` : `{ ${baseNodeFields()} }`;
4479
+ }
4480
+ function requireExplicitDepth(rawDepth) {
4481
+ if (rawDepth === void 0 || rawDepth === null || rawDepth === "") {
4482
+ throw new CliError({
4483
+ message: "Missing required --depth for markdown-tree subtree.",
4484
+ kind: "invalid_args",
4485
+ status: 400,
4486
+ exitCode: EXIT_CODES.invalidArgs
4487
+ });
4488
+ }
4489
+ return nonNegativeInt.parse(rawDepth);
4490
+ }
4491
+ function registerMarkdownTreeCommands(program) {
4492
+ const markdownTree = program.command("markdown-tree").description("Markdown tree traversal operations");
4493
+ markdownTree.command("root").option("--tree-view").action(async (opts, cmd) => {
4494
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4495
+ const organizationId = resolveOrganizationId(context.organizationId);
4496
+ await runGraphqlQueryCommand({
4497
+ command: "markdown-tree.root",
4498
+ operationName: "MarkdownTreeRoot",
4499
+ runtimeOptions: context.runtimeOptions,
4500
+ field: "markdown_tree_root",
4501
+ variables: {
4502
+ organization_id: organizationId,
4503
+ tree_view: opts.treeView === true ? true : void 0
4504
+ },
4505
+ selectionSet: buildNodeSelectionSet(1),
4506
+ isShow: true
4507
+ });
4508
+ });
4509
+ addScopeOptions(markdownTree.command("resolve")).action(async (opts, cmd) => {
4510
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4511
+ const organizationId = resolveOrganizationId(context.organizationId);
4512
+ const scope = parseScopeOptions(opts);
4513
+ await runGraphqlQueryCommand({
4514
+ command: "markdown-tree.resolve",
4515
+ operationName: "MarkdownTreeNode",
4516
+ runtimeOptions: context.runtimeOptions,
4517
+ field: "markdown_tree_node",
4518
+ variables: {
4519
+ organization_id: organizationId,
4520
+ tool_key: scope.toolKey,
4521
+ node_key: scope.nodeKey,
4522
+ parent_id: scope.parentId,
4523
+ record_id: scope.recordId,
4524
+ member_id: scope.memberId,
4525
+ team_id: scope.teamId,
4526
+ content_type: scope.contentType,
4527
+ tree_view: scope.treeView
4528
+ },
4529
+ selectionSet: buildNodeSelectionSet(1),
4530
+ isShow: true
4531
+ });
4532
+ });
4533
+ addScopeOptions(markdownTree.command("children")).action(async (opts, cmd) => {
4534
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4535
+ const organizationId = resolveOrganizationId(context.organizationId);
4536
+ const scope = parseScopeOptions(opts);
4537
+ await runGraphqlQueryCommand({
4538
+ command: "markdown-tree.children",
4539
+ operationName: "MarkdownTreeChildren",
4540
+ runtimeOptions: context.runtimeOptions,
4541
+ field: "markdown_tree_children",
4542
+ variables: {
4543
+ organization_id: organizationId,
4544
+ tool_key: scope.toolKey,
4545
+ node_key: scope.nodeKey,
4546
+ parent_id: scope.parentId,
4547
+ record_id: scope.recordId,
4548
+ member_id: scope.memberId,
4549
+ team_id: scope.teamId,
4550
+ content_type: scope.contentType,
4551
+ tree_view: scope.treeView
4552
+ },
4553
+ selectionSet: buildNodeSelectionSet(1),
4554
+ isShow: true
4555
+ });
4556
+ });
4557
+ addScopeOptions(
4558
+ markdownTree.command("subtree").requiredOption("--depth <depth>")
4559
+ ).action(async (opts, cmd) => {
4560
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4561
+ const organizationId = resolveOrganizationId(context.organizationId);
4562
+ const scope = parseScopeOptions(opts);
4563
+ const depth = requireExplicitDepth(opts.depth);
4564
+ await runGraphqlQueryCommand({
4565
+ command: "markdown-tree.subtree",
4566
+ operationName: "MarkdownTreeSubtree",
4567
+ runtimeOptions: context.runtimeOptions,
4568
+ field: "markdown_tree_subtree",
4569
+ variables: {
4570
+ organization_id: organizationId,
4571
+ tool_key: scope.toolKey,
4572
+ node_key: scope.nodeKey,
4573
+ parent_id: scope.parentId,
4574
+ record_id: scope.recordId,
4575
+ member_id: scope.memberId,
4576
+ team_id: scope.teamId,
4577
+ content_type: scope.contentType,
4578
+ tree_view: scope.treeView,
4579
+ depth
4580
+ },
4581
+ selectionSet: buildNodeSelectionSet(depth + 1),
4582
+ isShow: true
4583
+ });
4584
+ });
4585
+ }
4586
+
4587
+ // src/commands/navigation.ts
4588
+ var import_zod15 = require("zod");
4589
+
4590
+ // src/internalOptions.ts
4591
+ var INTERNAL_OPTIONS_KEY = "__waveInternalOptions";
4592
+ function asRecord2(value) {
4593
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
4594
+ return null;
4595
+ }
4596
+ return value;
4597
+ }
4598
+ function setInternalCliOptions(program, options) {
4599
+ if (!options) return;
4600
+ const target = program;
4601
+ target[INTERNAL_OPTIONS_KEY] = { ...options };
4602
+ }
4603
+ function getInternalCliOptions(command) {
4604
+ let current = command;
4605
+ while (current) {
4606
+ const record = asRecord2(current[INTERNAL_OPTIONS_KEY]);
4607
+ if (record) {
4608
+ return {
4609
+ enableRetryOnEmptyPhrase: record.enableRetryOnEmptyPhrase === true
4610
+ };
4611
+ }
4612
+ current = current.parent ?? null;
4613
+ }
4614
+ return {};
4615
+ }
4616
+
4617
+ // src/commands/navigation.ts
4618
+ var nonEmpty = import_zod15.z.string().min(1);
4619
+ var nonNegativeInt2 = import_zod15.z.coerce.number().int().min(0);
4620
+ var MIGRATED_BRANCHES = ["directory", "projects", "knowledge"];
4621
+ function normalizeText(input) {
4622
+ if (typeof input !== "string") return "";
4623
+ return input.trim().toLowerCase().replace(/\s+/g, " ");
4624
+ }
4625
+ function toDisplay(input) {
4626
+ if (typeof input !== "string") return "";
4627
+ const value = input.trim();
4628
+ return value.length > 0 ? value : "";
4629
+ }
4630
+ function asObject(value) {
4631
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
4632
+ }
4633
+ function asArray(value) {
4634
+ return Array.isArray(value) ? value : [];
4635
+ }
4636
+ function parseScopeFromOptions(raw) {
4637
+ const scope = {
4638
+ toolKey: nonEmpty.parse(raw.toolKey),
4639
+ nodeKey: nonEmpty.parse(raw.nodeKey)
4640
+ };
4641
+ if (typeof raw.parentId === "string" && raw.parentId.trim() !== "") {
4642
+ scope.parentId = raw.parentId.trim();
4643
+ }
4644
+ if (typeof raw.recordId === "string" && raw.recordId.trim() !== "") {
4645
+ scope.recordId = raw.recordId.trim();
4646
+ }
4647
+ if (typeof raw.memberId === "string" && raw.memberId.trim() !== "") {
4648
+ scope.memberId = raw.memberId.trim();
4649
+ }
4650
+ if (typeof raw.teamId === "string" && raw.teamId.trim() !== "") {
4651
+ scope.teamId = raw.teamId.trim();
4652
+ }
4653
+ if (typeof raw.contentType === "string" && raw.contentType.trim() !== "") {
4654
+ scope.contentType = raw.contentType.trim();
4655
+ }
4656
+ if (raw.treeView === true) {
4657
+ scope.treeView = true;
4658
+ }
4659
+ return scope;
4660
+ }
4661
+ function parseOptionalScopeFromOptions(raw) {
4662
+ if (typeof raw.toolKey !== "string" || raw.toolKey.trim() === "") {
4663
+ return null;
4664
+ }
4665
+ if (typeof raw.nodeKey !== "string" || raw.nodeKey.trim() === "") {
4666
+ return null;
4667
+ }
4668
+ return parseScopeFromOptions(raw);
4669
+ }
4670
+ function scopeFromCandidate(candidate, treeView) {
4671
+ const scopeObj = asObject(candidate.scope);
4672
+ const resolvedScopeObj = asObject(candidate.resolvedScope);
4673
+ const normalizedScope = Object.keys(scopeObj).length > 0 ? scopeObj : resolvedScopeObj;
4674
+ const toolKey = toDisplay(candidate.toolKey);
4675
+ const nodeKey = toDisplay(candidate.nodeKey);
4676
+ return {
4677
+ toolKey,
4678
+ nodeKey,
4679
+ parentId: toDisplay(normalizedScope.parentId) || void 0,
4680
+ recordId: toDisplay(normalizedScope.recordId) || void 0,
4681
+ memberId: toDisplay(normalizedScope.memberId) || void 0,
4682
+ teamId: toDisplay(normalizedScope.teamId) || void 0,
4683
+ contentType: toDisplay(normalizedScope.contentType) || void 0,
4684
+ treeView
4685
+ };
4686
+ }
4687
+ function notFoundEnvelope(params) {
4688
+ return {
4689
+ ok: false,
4690
+ command: params.command,
4691
+ status: 404,
4692
+ data: null,
4693
+ error: {
4694
+ code: "not_found",
4695
+ message: params.message,
4696
+ details: {}
4697
+ },
4698
+ meta: {
4699
+ requestId: params.requestId ?? "local_error"
4700
+ }
4701
+ };
4702
+ }
4703
+ function ambiguityEnvelope(params) {
4704
+ return {
4705
+ ok: false,
4706
+ command: params.command,
4707
+ status: 409,
4708
+ data: null,
4709
+ error: {
4710
+ code: "ambiguous_match",
4711
+ message: params.message,
4712
+ details: {
4713
+ candidates: params.candidates
4714
+ }
4715
+ },
4716
+ meta: {
4717
+ requestId: params.requestId ?? "local_error"
4718
+ }
4719
+ };
4720
+ }
4721
+ function unsupportedBranchEnvelope(params) {
4722
+ const tool = params.tool ?? "unknown";
4723
+ return {
4724
+ ok: false,
4725
+ command: params.command,
4726
+ status: 400,
4727
+ data: null,
4728
+ error: {
4729
+ code: "unsupported_branch",
4730
+ message: `This branch isn't migrated to markdown-tree yet: ${tool}. Try directory/projects/knowledge.`,
4731
+ details: {
4732
+ tool,
4733
+ migratedBranches: [...MIGRATED_BRANCHES],
4734
+ originalError: params.originalError ?? null
4735
+ }
4736
+ },
4737
+ meta: {
4738
+ requestId: params.requestId ?? "local_error"
4739
+ }
4740
+ };
4741
+ }
4742
+ function parseToolFromGraphqlError(errorBody) {
4743
+ const errorObj = asObject(errorBody);
4744
+ const details = asObject(errorObj.details);
4745
+ const errors = asArray(details.errors);
4746
+ for (const item of errors) {
4747
+ const message = toDisplay(item.message);
4748
+ if (message === "") continue;
4749
+ const match = message.match(/tool_key=([a-zA-Z0-9_]+)/);
4750
+ if (match?.[1]) {
4751
+ return match[1];
4752
+ }
4753
+ }
4754
+ return null;
4755
+ }
4756
+ function toolHintFromPathLike(value) {
4757
+ const text = toDisplay(value);
4758
+ if (text === "") return null;
4759
+ const [first] = text.split("/");
4760
+ return first ? first.trim() : null;
4761
+ }
4762
+ function unsupportedToolFromHints(params) {
4763
+ const fromError = parseToolFromGraphqlError(params.envelopeError);
4764
+ if (fromError) return fromError;
4765
+ return toDisplay(params.explicitTool) || toolHintFromPathLike(params.underPath) || toolHintFromPathLike(params.queryLike) || "unknown";
4766
+ }
4767
+ async function requestTraversal(params) {
4768
+ const config = getConfig(params.runtimeOptions);
4769
+ const result = await graphqlRequest({
4770
+ config,
4771
+ command: params.command,
4772
+ operationName: params.operationName,
4773
+ operationType: "query",
4774
+ field: params.field,
4775
+ variables: params.variables,
4776
+ selectionSet: buildNodeSelectionSet(params.depth),
4777
+ isShow: true
4778
+ });
4779
+ if (!result.envelope.ok) {
4780
+ if (result.envelope.error?.code === "unsupported_branch") {
4781
+ printEnvelopeAndExit({
4782
+ envelope: unsupportedBranchEnvelope({
4783
+ command: params.command,
4784
+ requestId: result.envelope.meta.requestId,
4785
+ tool: unsupportedToolFromHints({
4786
+ explicitTool: params.variables.tool_key,
4787
+ envelopeError: result.envelope.error
4788
+ }),
4789
+ originalError: asObject(result.envelope.error)
4790
+ }),
4791
+ exitCode: result.exitCode
4792
+ });
4793
+ }
4794
+ printEnvelopeAndExit({
4795
+ envelope: result.envelope,
4796
+ exitCode: result.exitCode
4797
+ });
4798
+ }
4799
+ const data = asObject(result.envelope.data);
4800
+ return asObject(data[params.field]);
4801
+ }
4802
+ function findSelectionSet() {
4803
+ return `{
4804
+ query
4805
+ underPath
4806
+ candidates {
4807
+ label
4808
+ canonicalPath
4809
+ toolKey
4810
+ nodeKey
4811
+ nodeKind
4812
+ isLeaf
4813
+ scope { parentId recordId memberId teamId contentType }
4814
+ resolvedScope { parentId recordId memberId teamId contentType }
4815
+ matchType
4816
+ rank
4817
+ aliasMatched
4818
+ breadcrumb
4819
+ }
4820
+ }`;
4821
+ }
4822
+ async function requestFind(params) {
4823
+ const config = getConfig(params.runtimeOptions);
4824
+ const result = await graphqlRequest({
4825
+ config,
4826
+ command: params.command,
4827
+ operationName: "MarkdownTreeFind",
4828
+ operationType: "query",
4829
+ field: "markdown_tree_find",
4830
+ variables: {
4831
+ organization_id: params.organizationId,
4832
+ query: params.query,
4833
+ under_path: params.underPath,
4834
+ tool_key: params.toolKey,
4835
+ node_key: params.nodeKey,
4836
+ limit: params.limit
4837
+ },
4838
+ selectionSet: findSelectionSet(),
4839
+ isShow: true
4840
+ });
4841
+ if (!result.envelope.ok) {
4842
+ if (result.envelope.error?.code === "unsupported_branch") {
4843
+ printEnvelopeAndExit({
4844
+ envelope: unsupportedBranchEnvelope({
4845
+ command: params.command,
4846
+ requestId: result.envelope.meta.requestId,
4847
+ tool: unsupportedToolFromHints({
4848
+ explicitTool: params.toolKey,
4849
+ underPath: params.underPath,
4850
+ queryLike: params.query,
4851
+ envelopeError: result.envelope.error
4852
+ }),
4853
+ originalError: asObject(result.envelope.error)
4854
+ }),
4855
+ exitCode: result.exitCode
4856
+ });
4857
+ }
4858
+ printEnvelopeAndExit({
4859
+ envelope: result.envelope,
4860
+ exitCode: result.exitCode
4861
+ });
4862
+ }
4863
+ const data = asObject(result.envelope.data);
4864
+ const payload = asObject(data.markdown_tree_find);
4865
+ return {
4866
+ ...payload,
4867
+ candidates: asArray(payload.candidates)
4868
+ };
4869
+ }
4870
+ function matchTypePrecedence(candidate) {
4871
+ const matchType = toDisplay(candidate.matchType).toLowerCase();
4872
+ const order = {
4873
+ exact_label: 0,
4874
+ exact_path: 1,
4875
+ prefix_label: 2,
4876
+ path_prefix: 3,
4877
+ path_fragment: 4,
4878
+ alias_match: 5,
4879
+ fuzzy: 6
4880
+ };
4881
+ return order[matchType] ?? Number.POSITIVE_INFINITY;
4882
+ }
4883
+ function isTopCandidateDominant(candidates) {
4884
+ if (candidates.length <= 1) {
4885
+ return true;
4886
+ }
4887
+ const first = candidates[0];
4888
+ const second = candidates[1];
4889
+ if (typeof first.rank === "number" && typeof second.rank === "number") {
4890
+ return first.rank < second.rank;
4891
+ }
4892
+ const firstMatch = matchTypePrecedence(first);
4893
+ const secondMatch = matchTypePrecedence(second);
4894
+ if (Number.isFinite(firstMatch) || Number.isFinite(secondMatch)) {
4895
+ return firstMatch < secondMatch;
4896
+ }
4897
+ return false;
4898
+ }
4899
+ function findExactPathMatches(candidates, path) {
4900
+ const target = normalizeText(path);
4901
+ if (target === "") return [];
4902
+ return candidates.filter((candidate) => {
4903
+ const canonicalPath = toDisplay(candidate.canonicalPath);
4904
+ return normalizeText(canonicalPath) === target;
4905
+ });
4906
+ }
4907
+ async function resolvePathScope(params) {
4908
+ const findPayload = await requestFind({
4909
+ command: params.command,
4910
+ runtimeOptions: params.runtimeOptions,
4911
+ organizationId: params.organizationId,
4912
+ query: params.path,
4913
+ underPath: params.underPath,
4914
+ limit: 25
4915
+ });
4916
+ const exactMatches = findExactPathMatches(findPayload.candidates, params.path);
4917
+ if (exactMatches.length === 1) {
4918
+ return {
4919
+ scope: scopeFromCandidate(exactMatches[0], params.treeView),
4920
+ match: exactMatches[0],
4921
+ ambiguous: []
4922
+ };
4923
+ }
4924
+ if (exactMatches.length > 1) {
4925
+ return {
4926
+ ambiguous: exactMatches.slice(0, 10)
4927
+ };
4928
+ }
4929
+ return {
4930
+ ambiguous: []
4931
+ };
4932
+ }
4933
+ function isMultiWordQuery(query) {
4934
+ const parts = query.trim().split(/\s+/).filter((part) => part.length > 0);
4935
+ return parts.length > 1;
4936
+ }
4937
+ function reduceMultiWordQuery(query) {
4938
+ const tokens = query.trim().split(/\s+/).map((token) => token.replace(/^[^a-zA-Z0-9]+|[^a-zA-Z0-9]+$/g, "")).filter((token) => token.length > 0);
4939
+ if (tokens.length <= 1) return null;
4940
+ const meaningful = tokens.filter((token) => token.length >= 3);
4941
+ const selected = meaningful.length > 0 ? meaningful[meaningful.length - 1] : tokens[tokens.length - 1];
4942
+ return selected ?? null;
4943
+ }
4944
+ function registerNavigationCommands(program) {
4945
+ 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) => {
4946
+ const globals = cmd.optsWithGlobals();
4947
+ const context = await resolveCommandContext(globals);
4948
+ const organizationId = resolveOrganizationId(context.organizationId);
4949
+ const internalOptions = getInternalCliOptions(cmd);
4950
+ const limit = typeof opts.limit === "string" && opts.limit.trim() !== "" ? Math.max(1, Number.parseInt(opts.limit, 10) || 20) : 20;
4951
+ const underPath = typeof opts.under === "string" && opts.under.trim() !== "" ? opts.under.trim() : typeof opts.path === "string" && opts.path.trim() !== "" ? opts.path.trim() : void 0;
4952
+ const payload = await requestFind({
4953
+ command: "find",
4954
+ runtimeOptions: context.runtimeOptions,
4955
+ organizationId,
4956
+ query,
4957
+ underPath,
4958
+ toolKey: typeof opts.toolKey === "string" ? opts.toolKey : void 0,
4959
+ nodeKey: typeof opts.nodeKey === "string" ? opts.nodeKey : void 0,
4960
+ limit
4961
+ });
4962
+ let finalPayload = payload;
4963
+ let assistantRecovery;
4964
+ if (internalOptions.enableRetryOnEmptyPhrase === true && payload.candidates.length === 0 && isMultiWordQuery(query)) {
4965
+ const retryQuery = reduceMultiWordQuery(query);
4966
+ if (retryQuery && normalizeText(retryQuery) !== normalizeText(query)) {
4967
+ finalPayload = await requestFind({
4968
+ command: "find",
4969
+ runtimeOptions: context.runtimeOptions,
4970
+ organizationId,
4971
+ query: retryQuery,
4972
+ underPath,
4973
+ toolKey: typeof opts.toolKey === "string" ? opts.toolKey : void 0,
4974
+ nodeKey: typeof opts.nodeKey === "string" ? opts.nodeKey : void 0,
4975
+ limit
4976
+ });
4977
+ assistantRecovery = {
4978
+ triggered: true,
4979
+ originalQuery: query,
4980
+ retryQuery,
4981
+ reason: "empty_multi_word_query"
4982
+ };
4983
+ }
4984
+ }
4985
+ printEnvelopeAndExit({
4986
+ envelope: {
4987
+ ok: true,
4988
+ command: "find",
4989
+ status: 200,
4990
+ data: assistantRecovery ? {
4991
+ ...finalPayload,
4992
+ assistantRecovery
4993
+ } : finalPayload,
4994
+ error: null,
4995
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
4996
+ }
4997
+ });
4998
+ });
4999
+ 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) => {
5000
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5001
+ const organizationId = resolveOrganizationId(context.organizationId);
5002
+ const limit = typeof opts.limit === "string" && opts.limit.trim() !== "" ? Math.max(1, Number.parseInt(opts.limit, 10) || 10) : 10;
5003
+ const underPath = typeof opts.under === "string" && opts.under.trim() !== "" ? opts.under.trim() : typeof opts.path === "string" && opts.path.trim() !== "" ? opts.path.trim() : void 0;
5004
+ const payload = await requestFind({
5005
+ command: "open",
5006
+ runtimeOptions: context.runtimeOptions,
5007
+ organizationId,
5008
+ query: name,
5009
+ underPath,
5010
+ toolKey: typeof opts.toolKey === "string" ? opts.toolKey : void 0,
5011
+ nodeKey: typeof opts.nodeKey === "string" ? opts.nodeKey : void 0,
5012
+ limit
5013
+ });
5014
+ const candidates = payload.candidates;
5015
+ if (candidates.length === 0) {
5016
+ printEnvelopeAndExit({
5017
+ envelope: notFoundEnvelope({
5018
+ command: "open",
5019
+ message: `No node matched "${name}".`
5020
+ }),
5021
+ exitCode: EXIT_CODES.notFound
5022
+ });
5023
+ }
5024
+ if (candidates.length > 1 && !isTopCandidateDominant(candidates)) {
5025
+ printEnvelopeAndExit({
5026
+ envelope: ambiguityEnvelope({
5027
+ command: "open",
5028
+ message: `Multiple nodes matched "${name}".`,
5029
+ candidates: candidates.slice(0, 10)
5030
+ }),
5031
+ exitCode: EXIT_CODES.generic
5032
+ });
5033
+ }
5034
+ const selected = candidates[0];
5035
+ const scope = scopeFromCandidate(selected, opts.treeView === true);
5036
+ const node = await requestTraversal({
5037
+ command: "open",
5038
+ runtimeOptions: context.runtimeOptions,
5039
+ operationName: "MarkdownTreeNode",
5040
+ field: "markdown_tree_node",
5041
+ variables: {
5042
+ organization_id: organizationId,
5043
+ tool_key: scope.toolKey,
5044
+ node_key: scope.nodeKey,
5045
+ parent_id: scope.parentId,
5046
+ record_id: scope.recordId,
5047
+ member_id: scope.memberId,
5048
+ team_id: scope.teamId,
5049
+ content_type: scope.contentType,
5050
+ tree_view: scope.treeView
5051
+ },
5052
+ depth: 1
5053
+ });
5054
+ printEnvelopeAndExit({
5055
+ envelope: {
5056
+ ok: true,
5057
+ command: "open",
5058
+ status: 200,
5059
+ data: {
5060
+ match: selected,
5061
+ node
5062
+ },
5063
+ error: null,
5064
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
5065
+ }
5066
+ });
5067
+ });
5068
+ 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) => {
5069
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5070
+ const organizationId = resolveOrganizationId(context.organizationId);
5071
+ let scope = null;
5072
+ let pathMatch = null;
5073
+ if (typeof opts.path === "string" && opts.path.trim() !== "") {
5074
+ const resolved = await resolvePathScope({
5075
+ command: "ls",
5076
+ runtimeOptions: context.runtimeOptions,
5077
+ organizationId,
5078
+ path: opts.path,
5079
+ underPath: typeof opts.under === "string" ? opts.under : void 0,
5080
+ treeView: opts.treeView === true
5081
+ });
5082
+ if (!resolved.scope) {
5083
+ if (resolved.ambiguous.length > 0) {
5084
+ printEnvelopeAndExit({
5085
+ envelope: ambiguityEnvelope({
5086
+ command: "ls",
5087
+ message: `Path "${opts.path}" is ambiguous.`,
5088
+ candidates: resolved.ambiguous
5089
+ }),
5090
+ exitCode: EXIT_CODES.generic
5091
+ });
5092
+ }
5093
+ printEnvelopeAndExit({
5094
+ envelope: notFoundEnvelope({
5095
+ command: "ls",
5096
+ message: `Path "${opts.path}" was not found.`
5097
+ }),
5098
+ exitCode: EXIT_CODES.notFound
5099
+ });
5100
+ }
5101
+ scope = resolved.scope;
5102
+ pathMatch = resolved.match ?? null;
5103
+ } else {
5104
+ scope = parseOptionalScopeFromOptions(opts);
5105
+ }
5106
+ if (!scope) {
5107
+ printEnvelopeAndExit({
5108
+ envelope: {
5109
+ ok: false,
5110
+ command: "ls",
5111
+ status: 400,
5112
+ data: null,
5113
+ error: {
5114
+ code: "invalid_args",
5115
+ message: "Provide either --path or full scope args (--tool-key and --node-key).",
5116
+ details: {}
5117
+ },
5118
+ meta: { requestId: context.runtimeOptions.requestId ?? "local_error" }
5119
+ },
5120
+ exitCode: EXIT_CODES.invalidArgs
5121
+ });
5122
+ }
5123
+ const node = await requestTraversal({
5124
+ command: "ls",
5125
+ runtimeOptions: context.runtimeOptions,
5126
+ operationName: "MarkdownTreeChildren",
5127
+ field: "markdown_tree_children",
5128
+ variables: {
5129
+ organization_id: organizationId,
5130
+ tool_key: scope.toolKey,
5131
+ node_key: scope.nodeKey,
5132
+ parent_id: scope.parentId,
5133
+ record_id: scope.recordId,
5134
+ member_id: scope.memberId,
5135
+ team_id: scope.teamId,
5136
+ content_type: scope.contentType,
5137
+ tree_view: scope.treeView
5138
+ },
5139
+ depth: 1
5140
+ });
5141
+ const children = asArray(node.children);
5142
+ const filtered = typeof query === "string" && query.trim() !== "" ? children.filter(
5143
+ (child) => normalizeText(child.runtimeLabel).includes(normalizeText(query))
5144
+ ) : children;
5145
+ printEnvelopeAndExit({
5146
+ envelope: {
5147
+ ok: true,
5148
+ command: "ls",
5149
+ status: 200,
5150
+ data: {
5151
+ target: pathMatch,
5152
+ children: filtered
5153
+ },
5154
+ error: null,
5155
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
5156
+ }
5157
+ });
5158
+ });
5159
+ 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) => {
5160
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5161
+ const organizationId = resolveOrganizationId(context.organizationId);
5162
+ let scope = null;
5163
+ let pathMatch = null;
5164
+ if (typeof opts.path === "string" && opts.path.trim() !== "") {
5165
+ const resolved = await resolvePathScope({
5166
+ command: "cat",
5167
+ runtimeOptions: context.runtimeOptions,
5168
+ organizationId,
5169
+ path: opts.path,
5170
+ underPath: typeof opts.under === "string" ? opts.under : void 0,
5171
+ treeView: opts.treeView === true
5172
+ });
5173
+ if (!resolved.scope) {
5174
+ if (resolved.ambiguous.length > 0) {
5175
+ printEnvelopeAndExit({
5176
+ envelope: ambiguityEnvelope({
5177
+ command: "cat",
5178
+ message: `Path "${opts.path}" is ambiguous.`,
5179
+ candidates: resolved.ambiguous
5180
+ }),
5181
+ exitCode: EXIT_CODES.generic
5182
+ });
5183
+ }
5184
+ printEnvelopeAndExit({
5185
+ envelope: notFoundEnvelope({
5186
+ command: "cat",
5187
+ message: `Path "${opts.path}" was not found.`
5188
+ }),
5189
+ exitCode: EXIT_CODES.notFound
5190
+ });
5191
+ }
5192
+ scope = resolved.scope;
5193
+ pathMatch = resolved.match ?? null;
5194
+ } else {
5195
+ scope = parseOptionalScopeFromOptions(opts);
5196
+ }
5197
+ if (!scope) {
5198
+ printEnvelopeAndExit({
5199
+ envelope: {
5200
+ ok: false,
5201
+ command: "cat",
5202
+ status: 400,
5203
+ data: null,
5204
+ error: {
5205
+ code: "invalid_args",
5206
+ message: "Provide either --path or full scope args (--tool-key and --node-key).",
5207
+ details: {}
5208
+ },
5209
+ meta: { requestId: context.runtimeOptions.requestId ?? "local_error" }
5210
+ },
5211
+ exitCode: EXIT_CODES.invalidArgs
5212
+ });
5213
+ }
5214
+ const node = await requestTraversal({
5215
+ command: "cat",
5216
+ runtimeOptions: context.runtimeOptions,
5217
+ operationName: "MarkdownTreeNode",
5218
+ field: "markdown_tree_node",
5219
+ variables: {
5220
+ organization_id: organizationId,
5221
+ tool_key: scope.toolKey,
5222
+ node_key: scope.nodeKey,
5223
+ parent_id: scope.parentId,
5224
+ record_id: scope.recordId,
5225
+ member_id: scope.memberId,
5226
+ team_id: scope.teamId,
5227
+ content_type: scope.contentType,
5228
+ tree_view: scope.treeView
5229
+ },
5230
+ depth: 1
5231
+ });
5232
+ printEnvelopeAndExit({
5233
+ envelope: {
5234
+ ok: true,
5235
+ command: "cat",
5236
+ status: 200,
5237
+ data: {
5238
+ target: pathMatch,
5239
+ node
5240
+ },
5241
+ error: null,
5242
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
5243
+ }
5244
+ });
5245
+ });
5246
+ 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) => {
5247
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5248
+ const organizationId = resolveOrganizationId(context.organizationId);
5249
+ const depth = nonNegativeInt2.parse(opts.depth);
5250
+ let scope = null;
5251
+ let pathMatch = null;
5252
+ if (typeof opts.path === "string" && opts.path.trim() !== "") {
5253
+ const resolved = await resolvePathScope({
5254
+ command: "tree",
5255
+ runtimeOptions: context.runtimeOptions,
5256
+ organizationId,
5257
+ path: opts.path,
5258
+ underPath: typeof opts.under === "string" ? opts.under : void 0,
5259
+ treeView: opts.treeView === true
5260
+ });
5261
+ if (!resolved.scope) {
5262
+ if (resolved.ambiguous.length > 0) {
5263
+ printEnvelopeAndExit({
5264
+ envelope: ambiguityEnvelope({
5265
+ command: "tree",
5266
+ message: `Path "${opts.path}" is ambiguous.`,
5267
+ candidates: resolved.ambiguous
5268
+ }),
5269
+ exitCode: EXIT_CODES.generic
5270
+ });
5271
+ }
5272
+ printEnvelopeAndExit({
5273
+ envelope: notFoundEnvelope({
5274
+ command: "tree",
5275
+ message: `Path "${opts.path}" was not found.`
5276
+ }),
5277
+ exitCode: EXIT_CODES.notFound
5278
+ });
5279
+ }
5280
+ scope = resolved.scope;
5281
+ pathMatch = resolved.match ?? null;
5282
+ } else {
5283
+ scope = parseOptionalScopeFromOptions(opts);
5284
+ }
5285
+ if (!scope) {
5286
+ printEnvelopeAndExit({
5287
+ envelope: {
5288
+ ok: false,
5289
+ command: "tree",
5290
+ status: 400,
5291
+ data: null,
5292
+ error: {
5293
+ code: "invalid_args",
5294
+ message: "Provide either --path or full scope args (--tool-key and --node-key).",
5295
+ details: {}
5296
+ },
5297
+ meta: { requestId: context.runtimeOptions.requestId ?? "local_error" }
5298
+ },
5299
+ exitCode: EXIT_CODES.invalidArgs
5300
+ });
5301
+ }
5302
+ const node = await requestTraversal({
5303
+ command: "tree",
5304
+ runtimeOptions: context.runtimeOptions,
5305
+ operationName: "MarkdownTreeSubtree",
5306
+ field: "markdown_tree_subtree",
5307
+ variables: {
5308
+ organization_id: organizationId,
5309
+ tool_key: scope.toolKey,
5310
+ node_key: scope.nodeKey,
5311
+ parent_id: scope.parentId,
5312
+ record_id: scope.recordId,
5313
+ member_id: scope.memberId,
5314
+ team_id: scope.teamId,
5315
+ content_type: scope.contentType,
5316
+ tree_view: scope.treeView,
5317
+ depth
5318
+ },
5319
+ depth: depth + 1
5320
+ });
5321
+ printEnvelopeAndExit({
5322
+ envelope: {
5323
+ ok: true,
5324
+ command: "tree",
5325
+ status: 200,
5326
+ data: {
5327
+ target: pathMatch,
5328
+ depth,
5329
+ node
5330
+ },
5331
+ error: null,
5332
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
5333
+ }
5334
+ });
5335
+ });
5336
+ }
5337
+
5338
+ // src/commands/mutationCapability.ts
5339
+ function unsupportedMutationEnvelope(params) {
5340
+ return {
5341
+ ok: false,
5342
+ command: params.command,
5343
+ status: 400,
5344
+ data: null,
5345
+ error: {
5346
+ code: "mutation_unsupported",
5347
+ message: "No mutation command is supported for this node type.",
5348
+ details: {
5349
+ node: params.node
5350
+ }
5351
+ },
5352
+ meta: {
5353
+ requestId: "local_error"
5354
+ }
5355
+ };
5356
+ }
5357
+ function emitUnsupportedMutation(params) {
5358
+ const canonicalPath = typeof params.canonicalPath === "string" && params.canonicalPath.trim().length > 0 ? params.canonicalPath.trim() : null;
5359
+ printEnvelopeAndExit({
5360
+ envelope: unsupportedMutationEnvelope({
5361
+ command: params.command,
5362
+ node: {
5363
+ toolKey: params.toolKey,
5364
+ nodeKey: params.nodeKey,
5365
+ canonicalPath
5366
+ }
5367
+ }),
5368
+ exitCode: EXIT_CODES.invalidArgs
5369
+ });
5370
+ }
5371
+ function registerMutationCapabilityCommands(program) {
5372
+ const projectNotes = program.command("project-notes").description("Project notes node (read-only in CLI mutation surface)");
5373
+ projectNotes.command("create").option("--path <path>", "Canonical path for the selected node").action((opts) => {
5374
+ emitUnsupportedMutation({
5375
+ command: "project-notes.create",
5376
+ toolKey: "projects",
5377
+ nodeKey: "project_notes",
5378
+ canonicalPath: opts.path
5379
+ });
5380
+ });
5381
+ projectNotes.command("update").option("--path <path>", "Canonical path for the selected node").action((opts) => {
5382
+ emitUnsupportedMutation({
5383
+ command: "project-notes.update",
5384
+ toolKey: "projects",
5385
+ nodeKey: "project_notes",
5386
+ canonicalPath: opts.path
5387
+ });
5388
+ });
5389
+ projectNotes.command("destroy").option("--path <path>", "Canonical path for the selected node").action((opts) => {
5390
+ emitUnsupportedMutation({
5391
+ command: "project-notes.destroy",
5392
+ toolKey: "projects",
5393
+ nodeKey: "project_notes",
5394
+ canonicalPath: opts.path
5395
+ });
5396
+ });
5397
+ }
5398
+
3028
5399
  // src/cli.ts
3029
- function buildCli() {
5400
+ function buildCli(options) {
3030
5401
  const program = new import_commander.Command();
3031
5402
  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(
3032
5403
  "--auth-json-stdin",
@@ -3047,6 +5418,7 @@ function buildCli() {
3047
5418
  "--openapi-version <openapiVersion>",
3048
5419
  "Optional pinned OpenAPI version/hash"
3049
5420
  ).exitOverride();
5421
+ setInternalCliOptions(program, options?.internal);
3050
5422
  registerTaskCommands(program);
3051
5423
  registerProjectCommands(program);
3052
5424
  registerRockCommands(program);
@@ -3059,6 +5431,9 @@ function buildCli() {
3059
5431
  registerFoundationCommands(program);
3060
5432
  registerChildEntityCommands(program);
3061
5433
  registerNoteCommands(program);
5434
+ registerMutationCapabilityCommands(program);
5435
+ registerMarkdownTreeCommands(program);
5436
+ registerNavigationCommands(program);
3062
5437
  return program;
3063
5438
  }
3064
5439
 
@@ -3107,13 +5482,13 @@ main().catch((error) => {
3107
5482
  exitCode: EXIT_CODES.invalidArgs
3108
5483
  });
3109
5484
  }
3110
- if (error instanceof import_zod14.ZodError || error instanceof import_commander2.InvalidArgumentError) {
5485
+ if (error instanceof import_zod16.ZodError || error instanceof import_commander2.InvalidArgumentError) {
3111
5486
  printCliFailure({
3112
5487
  status: 400,
3113
5488
  code: "invalid_args",
3114
5489
  message: "Invalid command arguments.",
3115
5490
  details: {
3116
- issues: error instanceof import_zod14.ZodError ? error.issues : [{ message: error.message, code: "invalid_argument" }]
5491
+ issues: error instanceof import_zod16.ZodError ? error.issues : [{ message: error.message, code: "invalid_argument" }]
3117
5492
  },
3118
5493
  exitCode: EXIT_CODES.invalidArgs
3119
5494
  });