@ted-galago/wave-cli 0.1.5 → 0.1.7

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,13 +3,13 @@
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");
10
10
 
11
11
  // src/commands/tasks.ts
12
- var import_zod3 = require("zod");
12
+ var import_zod2 = require("zod");
13
13
 
14
14
  // src/config.ts
15
15
  var import_zod = require("zod");
@@ -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);
@@ -242,6 +499,22 @@ function graphqlTypeForVariable(name, value) {
242
499
  function withNonNull(typeName) {
243
500
  return typeName.endsWith("!") ? typeName : `${typeName}!`;
244
501
  }
502
+ function splitSelectionAndFragments(selectionSet) {
503
+ const trimmed = selectionSet.trim();
504
+ if (trimmed.length === 0) {
505
+ return { fieldSelection: "{}", fragmentDefinitions: "" };
506
+ }
507
+ const fragmentMatch = /\bfragment\s+[A-Za-z0-9_]+\s+on\s+[A-Za-z0-9_]+\s*\{/.exec(trimmed);
508
+ if (!fragmentMatch || fragmentMatch.index <= 0) {
509
+ return { fieldSelection: trimmed, fragmentDefinitions: "" };
510
+ }
511
+ const fieldSelection = trimmed.slice(0, fragmentMatch.index).trim();
512
+ const fragmentDefinitions = trimmed.slice(fragmentMatch.index).trim();
513
+ return {
514
+ fieldSelection: fieldSelection.length > 0 ? fieldSelection : "{}",
515
+ fragmentDefinitions
516
+ };
517
+ }
245
518
  function normalizeGraphqlVariables(variables) {
246
519
  const normalized = {};
247
520
  Object.entries(variables).forEach(([key, value]) => {
@@ -252,13 +525,20 @@ function normalizeGraphqlVariables(variables) {
252
525
  function buildGraphqlBody(input) {
253
526
  const graphqlField = toCamelCase(input.field);
254
527
  const graphqlVariables = normalizeGraphqlVariables(input.variables);
528
+ const graphqlVariableTypes = normalizeGraphqlVariables(input.variableTypes ?? {});
255
529
  const operationName = input.operationName ?? graphqlOperationName(input.command);
256
530
  const variableEntries = Object.entries(graphqlVariables).filter(([, value]) => value !== void 0);
257
- const variableDecl = variableEntries.map(([name, value]) => `$${name}: ${withNonNull(graphqlTypeForVariable(name, value))}`).join(", ");
531
+ const variableDecl = variableEntries.map(([name, value]) => {
532
+ const overriddenType = graphqlVariableTypes[name];
533
+ const hasOverriddenType = typeof overriddenType === "string" && overriddenType.trim().length > 0;
534
+ const typeName = hasOverriddenType ? overriddenType.trim() : graphqlTypeForVariable(name, value);
535
+ return `$${name}: ${hasOverriddenType ? typeName : withNonNull(typeName)}`;
536
+ }).join(", ");
258
537
  const fieldArgs = variableEntries.map(([name]) => `${name}: $${name}`).join(", ");
259
538
  const signature = variableDecl.length > 0 ? `(${variableDecl})` : "";
260
539
  const args = fieldArgs.length > 0 ? `(${fieldArgs})` : "";
261
- const query = `${input.operationType} ${operationName}${signature} { ${graphqlField}${args} ${input.selectionSet} }`;
540
+ const selection = splitSelectionAndFragments(input.selectionSet);
541
+ const query = `${input.operationType} ${operationName}${signature} { ${graphqlField}${args} ${selection.fieldSelection} }${selection.fragmentDefinitions.length > 0 ? ` ${selection.fragmentDefinitions}` : ""}`;
262
542
  return {
263
543
  operationName,
264
544
  query,
@@ -279,24 +559,37 @@ async function graphqlRequest(input) {
279
559
  const controller = new AbortController();
280
560
  const timeoutId = setTimeout(() => controller.abort(), input.config.timeoutMs);
281
561
  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
562
+ if (isFeedbackCreateCommand(input)) {
563
+ const feedbackIdentity = extractFeedbackIdentity(input.variables);
564
+ if (feedbackIdentity) {
565
+ const existing = await findExistingFeedback({
566
+ input,
567
+ url,
568
+ requestId,
569
+ controller,
570
+ identity: feedbackIdentity
571
+ });
572
+ if (existing) {
573
+ return buildFeedbackReuseEnvelope({
574
+ command: input.command,
575
+ field: input.field,
576
+ status: 200,
577
+ requestId: existing.requestId,
578
+ feedbackNode: existing.feedbackNode,
579
+ reason: "preexisting"
580
+ });
581
+ }
582
+ }
583
+ }
584
+ const http = await requestGraphqlHttp({
585
+ input,
586
+ url,
587
+ requestId,
588
+ body,
589
+ controller
295
590
  });
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 : {};
591
+ const responseRequestId = http.requestId;
592
+ const graph = http.graph;
300
593
  const gqlErrors = graph.errors;
301
594
  const gqlData = graph.data && typeof graph.data === "object" ? graph.data : {};
302
595
  if (Array.isArray(gqlErrors) && gqlErrors.length > 0) {
@@ -319,6 +612,36 @@ async function graphqlRequest(input) {
319
612
  const ok = Boolean(mutationPayload.ok);
320
613
  const status = typeof mutationPayload.status === "number" ? mutationPayload.status : ok ? 200 : 400;
321
614
  if (!ok) {
615
+ if (isFeedbackCreateCommand(input) && isDuplicateFeedbackMutationError(mutationPayload)) {
616
+ const feedbackIdentity = extractFeedbackIdentity(input.variables);
617
+ if (feedbackIdentity) {
618
+ const existing = await findExistingFeedback({
619
+ input,
620
+ url,
621
+ requestId: responseRequestId,
622
+ controller,
623
+ identity: feedbackIdentity
624
+ });
625
+ if (existing) {
626
+ return buildFeedbackReuseEnvelope({
627
+ command: input.command,
628
+ field: input.field,
629
+ status: 200,
630
+ requestId: existing.requestId,
631
+ feedbackNode: existing.feedbackNode,
632
+ reason: "duplicate_race"
633
+ });
634
+ }
635
+ }
636
+ }
637
+ const mutationErrors = mutationPayload.errors ?? null;
638
+ const details = {
639
+ errors: mutationErrors,
640
+ data: mutationPayload.data ?? null
641
+ };
642
+ if (shouldAddSparse422Diagnostic(status, mutationPayload)) {
643
+ details.fallbackDiagnostic = buildSparse422Diagnostic(input);
644
+ }
322
645
  return {
323
646
  envelope: buildEnvelope({
324
647
  ok: false,
@@ -330,10 +653,7 @@ async function graphqlRequest(input) {
330
653
  mutationPayload.errorCode ?? mutationPayload.error_code ?? `http_${status}`
331
654
  ),
332
655
  message: "Mutation failed.",
333
- details: {
334
- errors: mutationPayload.errors ?? null,
335
- data: mutationPayload.data ?? null
336
- }
656
+ details
337
657
  },
338
658
  requestId: responseRequestId
339
659
  }),
@@ -373,7 +693,7 @@ async function graphqlRequest(input) {
373
693
  envelope: buildEnvelope({
374
694
  ok: true,
375
695
  command: input.command,
376
- status: response.ok ? response.status : 200,
696
+ status: http.status >= 200 && http.status < 300 ? http.status : 200,
377
697
  data: { [input.field]: fieldPayload ?? null },
378
698
  error: null,
379
699
  requestId: responseRequestId
@@ -413,6 +733,494 @@ function printEnvelopeAndExit(params) {
413
733
  }
414
734
 
415
735
  // src/commandRunner.ts
736
+ var RESOURCE_QUERY_FIELDS = {
737
+ task: [
738
+ "summary",
739
+ "slug",
740
+ "description",
741
+ "notes",
742
+ "status",
743
+ "priority",
744
+ "rank",
745
+ "dueDate",
746
+ "createdAt",
747
+ "updatedAt",
748
+ "archivedAt",
749
+ "organizationId",
750
+ "memberId",
751
+ "creatorId",
752
+ "projectId",
753
+ "projectSlug",
754
+ "taskId",
755
+ "labelIds",
756
+ "estimateIds",
757
+ "subtasksCount",
758
+ "completedSubtasksCount"
759
+ ],
760
+ issue: [
761
+ "name",
762
+ "slug",
763
+ "description",
764
+ "notes",
765
+ "status",
766
+ "priority",
767
+ "rank",
768
+ "dueBy",
769
+ "createdAt",
770
+ "updatedAt",
771
+ "archivedAt",
772
+ "organizationId",
773
+ "memberId",
774
+ "creatorId",
775
+ "issueGroupId",
776
+ "issueGroupSlug",
777
+ "issueType",
778
+ "labelIds",
779
+ "subIssuesCount",
780
+ "completedSubIssuesCount"
781
+ ],
782
+ team: [
783
+ "name",
784
+ "slug",
785
+ "createdAt",
786
+ "updatedAt",
787
+ "memberIds",
788
+ "leadMemberId",
789
+ "organizationId",
790
+ "responsibilities",
791
+ "keyMetric"
792
+ ],
793
+ member: [
794
+ "slug",
795
+ "email",
796
+ "role",
797
+ "status",
798
+ "title",
799
+ "firstName",
800
+ "lastName",
801
+ "createdAt",
802
+ "updatedAt",
803
+ "lastActiveAt",
804
+ "deactivatedAt",
805
+ "organizationId",
806
+ "organizationSlug",
807
+ "userId",
808
+ "coachId",
809
+ "timezone",
810
+ "province",
811
+ "birthdate",
812
+ "workAnniversary",
813
+ "phone",
814
+ "pinned",
815
+ "rocksCount",
816
+ "measurablesCount",
817
+ "smartKpisCount"
818
+ ],
819
+ rock: [
820
+ "name",
821
+ "slug",
822
+ "description",
823
+ "notes",
824
+ "status",
825
+ "priority",
826
+ "rank",
827
+ "dueBy",
828
+ "createdAt",
829
+ "updatedAt",
830
+ "archivedAt",
831
+ "organizationId",
832
+ "memberId",
833
+ "creatorId",
834
+ "rockCollectionId",
835
+ "rockCollectionSlug",
836
+ "quarterlyObjectiveId",
837
+ "rockType",
838
+ "labelIds",
839
+ "milestonesCount",
840
+ "completedMilestonesCount"
841
+ ],
842
+ meeting: [
843
+ "createdAt",
844
+ "updatedAt",
845
+ "name",
846
+ "slug",
847
+ "status",
848
+ "description",
849
+ "notes",
850
+ "useAiTranscript",
851
+ "aiTranscript",
852
+ "aiTranscriptStatus",
853
+ "aiTranscriptError",
854
+ "aiTranscriptUpdatedAt",
855
+ "aiSummary",
856
+ "aiSummaryStatus",
857
+ "aiSummaryError",
858
+ "aiSummaryUpdatedAt",
859
+ "repeats",
860
+ "color",
861
+ "talkingPointsCount",
862
+ "completedTalkingPointsCount",
863
+ "date",
864
+ "startTime",
865
+ "endTime",
866
+ "meetingStartTime",
867
+ "meetingEndTime",
868
+ "currentAgendaItemId",
869
+ "memberId",
870
+ "memberIds",
871
+ "teamIds",
872
+ "organizationId",
873
+ "agendaId",
874
+ "parentMeetingId",
875
+ "childMeetingIds",
876
+ "agendaName",
877
+ "occurrenceDate"
878
+ ],
879
+ list: [
880
+ "name",
881
+ "slug",
882
+ "description",
883
+ "status",
884
+ "priority",
885
+ "createdAt",
886
+ "updatedAt",
887
+ "startDate",
888
+ "targetDate",
889
+ "archivedAt",
890
+ "memberId",
891
+ "organizationId",
892
+ "teamIds"
893
+ ],
894
+ list_item: [
895
+ "summary",
896
+ "slug",
897
+ "description",
898
+ "notes",
899
+ "status",
900
+ "priority",
901
+ "rank",
902
+ "dueDate",
903
+ "createdAt",
904
+ "updatedAt",
905
+ "archivedAt",
906
+ "organizationId",
907
+ "memberId",
908
+ "creatorId",
909
+ "listId",
910
+ "listSlug",
911
+ "labelIds",
912
+ "estimateIds",
913
+ "subitemsCount",
914
+ "completedSubitemsCount"
915
+ ],
916
+ issue_group: [
917
+ "name",
918
+ "slug",
919
+ "description",
920
+ "status",
921
+ "priority",
922
+ "startDate",
923
+ "targetDate",
924
+ "createdAt",
925
+ "updatedAt",
926
+ "memberId",
927
+ "organizationId",
928
+ "teamIds"
929
+ ],
930
+ todo_group: [
931
+ "name",
932
+ "slug",
933
+ "description",
934
+ "status",
935
+ "priority",
936
+ "startDate",
937
+ "targetDate",
938
+ "createdAt",
939
+ "updatedAt",
940
+ "memberId",
941
+ "organizationId",
942
+ "teamIds"
943
+ ],
944
+ todo: [
945
+ "name",
946
+ "slug",
947
+ "description",
948
+ "status",
949
+ "priority",
950
+ "rank",
951
+ "dueBy",
952
+ "createdAt",
953
+ "updatedAt",
954
+ "archivedAt",
955
+ "organizationId",
956
+ "meetingId",
957
+ "memberId",
958
+ "creatorId",
959
+ "todoGroupId",
960
+ "todoGroupSlug",
961
+ "labelIds",
962
+ "subTodosCount",
963
+ "completedSubTodosCount"
964
+ ],
965
+ rock_collection: [
966
+ "name",
967
+ "slug",
968
+ "description",
969
+ "status",
970
+ "priority",
971
+ "rockType",
972
+ "createdAt",
973
+ "updatedAt",
974
+ "startDate",
975
+ "targetDate",
976
+ "archivedAt",
977
+ "memberId",
978
+ "organizationId",
979
+ "teamIds"
980
+ ],
981
+ content: [
982
+ "name",
983
+ "slug",
984
+ "firstChildSlug",
985
+ "rootParentSlug",
986
+ "status",
987
+ "contentType",
988
+ "lastEdited",
989
+ "organizationId",
990
+ "memberId",
991
+ "focusMemberId",
992
+ "focusTeamId",
993
+ "teamId",
994
+ "creatorId",
995
+ "createdAt",
996
+ "updatedAt",
997
+ "childCount",
998
+ "assignmentType",
999
+ "contentableId",
1000
+ "contentableSlug",
1001
+ "contentableType",
1002
+ "votesTotal",
1003
+ "labelIds",
1004
+ "rootContentId",
1005
+ "parentContentId"
1006
+ ],
1007
+ stand_up: [
1008
+ "completedDate",
1009
+ "blockers",
1010
+ "plannedWork",
1011
+ "slug",
1012
+ "memberId",
1013
+ "organizationId"
1014
+ ],
1015
+ headline: [
1016
+ "slug",
1017
+ "summary",
1018
+ "description",
1019
+ "memberId",
1020
+ "status",
1021
+ "rank",
1022
+ "createdAt",
1023
+ "updatedAt",
1024
+ "headlineType",
1025
+ "teamIds",
1026
+ "meetingId",
1027
+ "labelIds"
1028
+ ],
1029
+ question: [
1030
+ "name",
1031
+ "description",
1032
+ "status",
1033
+ "votesTotal",
1034
+ "slug",
1035
+ "createdAt",
1036
+ "updatedAt",
1037
+ "memberId",
1038
+ "creatorId",
1039
+ "organizationId",
1040
+ "acceptedAnswerIds",
1041
+ "labelIds"
1042
+ ],
1043
+ feedback: [
1044
+ "name",
1045
+ "slug",
1046
+ "year",
1047
+ "quarter",
1048
+ "organizationId",
1049
+ "memberIds"
1050
+ ],
1051
+ survey: [
1052
+ "name",
1053
+ "slug",
1054
+ "createdAt",
1055
+ "dueDate",
1056
+ "updatedAt",
1057
+ "recipientType",
1058
+ "organizationId",
1059
+ "memberIds"
1060
+ ],
1061
+ responsibility: ["name", "description", "rank", "slug", "memberId", "organizationId"],
1062
+ smart_kpi_view: [
1063
+ "name",
1064
+ "slug",
1065
+ "description",
1066
+ "status",
1067
+ "priority",
1068
+ "createdAt",
1069
+ "updatedAt",
1070
+ "archivedAt",
1071
+ "memberId",
1072
+ "organizationId",
1073
+ "teamIds"
1074
+ ],
1075
+ smart_kpi: [
1076
+ "name",
1077
+ "slug",
1078
+ "notes",
1079
+ "interval",
1080
+ "trend",
1081
+ "smartKpiType",
1082
+ "condition",
1083
+ "status",
1084
+ "progressStatus",
1085
+ "autoIncrease",
1086
+ "createdAt",
1087
+ "updatedAt",
1088
+ "archivedAt",
1089
+ "organizationId",
1090
+ "smartKpiViewId",
1091
+ "smartKpiViewSlug",
1092
+ "memberId",
1093
+ "integrationId",
1094
+ "quarterlyObjectiveId"
1095
+ ],
1096
+ measurable_group: [
1097
+ "name",
1098
+ "slug",
1099
+ "description",
1100
+ "status",
1101
+ "priority",
1102
+ "createdAt",
1103
+ "updatedAt",
1104
+ "memberId",
1105
+ "organizationId",
1106
+ "teamIds"
1107
+ ],
1108
+ measurable: [
1109
+ "name",
1110
+ "slug",
1111
+ "description",
1112
+ "notes",
1113
+ "interval",
1114
+ "trend",
1115
+ "measurableType",
1116
+ "condition",
1117
+ "status",
1118
+ "rank",
1119
+ "createdAt",
1120
+ "updatedAt",
1121
+ "archivedAt",
1122
+ "organizationId",
1123
+ "measurableGroupId",
1124
+ "measurableGroupSlug",
1125
+ "memberId",
1126
+ "creatorId",
1127
+ "quarterlyObjectiveId",
1128
+ "labelIds"
1129
+ ],
1130
+ customer: [
1131
+ "name",
1132
+ "slug",
1133
+ "createdAt",
1134
+ "updatedAt",
1135
+ "memberId",
1136
+ "organizationId",
1137
+ "status",
1138
+ "rank",
1139
+ "revenue",
1140
+ "companySize",
1141
+ "domain",
1142
+ "primaryEmail",
1143
+ "primaryPhone",
1144
+ "primaryLocation"
1145
+ ],
1146
+ contact: [
1147
+ "name",
1148
+ "slug",
1149
+ "createdAt",
1150
+ "updatedAt",
1151
+ "memberId",
1152
+ "organizationId",
1153
+ "customerId",
1154
+ "status",
1155
+ "rank",
1156
+ "jobTitle",
1157
+ "email",
1158
+ "phone",
1159
+ "location"
1160
+ ],
1161
+ annual_objective: [
1162
+ "name",
1163
+ "description",
1164
+ "status",
1165
+ "createdAt",
1166
+ "updatedAt",
1167
+ "organizationId",
1168
+ "strategicObjectiveId",
1169
+ "ownerId",
1170
+ "creatorId"
1171
+ ],
1172
+ quarterly_objective: [
1173
+ "name",
1174
+ "description",
1175
+ "status",
1176
+ "alignmentScore",
1177
+ "alignmentLabel",
1178
+ "rocksCount",
1179
+ "measurablesCount",
1180
+ "smartKpisCount",
1181
+ "createdAt",
1182
+ "updatedAt",
1183
+ "organizationId",
1184
+ "strategicObjectiveId",
1185
+ "annualObjectiveId",
1186
+ "departmentId",
1187
+ "ownerId",
1188
+ "creatorId"
1189
+ ],
1190
+ organization_meta_profile: ["summary", "profile"],
1191
+ key_metric_meta_profile: ["summary", "profile"],
1192
+ strategic_plan: [],
1193
+ strategic_objective: []
1194
+ };
1195
+ var RESOURCE_FIELD_ALIASES = {
1196
+ tasks: "task",
1197
+ issues: "issue",
1198
+ teams: "team",
1199
+ members: "member",
1200
+ rocks: "rock",
1201
+ meetings: "meeting",
1202
+ lists: "list",
1203
+ list_items: "list_item",
1204
+ issue_groups: "issue_group",
1205
+ todo_groups: "todo_group",
1206
+ todos: "todo",
1207
+ rock_collections: "rock_collection",
1208
+ contents: "content",
1209
+ stand_ups: "stand_up",
1210
+ headlines: "headline",
1211
+ questions: "question",
1212
+ feedbacks: "feedback",
1213
+ surveys: "survey",
1214
+ responsibilities: "responsibility",
1215
+ smart_kpi_views: "smart_kpi_view",
1216
+ smart_kpis: "smart_kpi",
1217
+ measurable_groups: "measurable_group",
1218
+ measurables: "measurable",
1219
+ customers: "customer",
1220
+ contacts: "contact",
1221
+ annual_objectives: "annual_objective",
1222
+ quarterly_objectives: "quarterly_objective"
1223
+ };
416
1224
  function buildCliErrorEnvelope(params) {
417
1225
  return {
418
1226
  ok: false,
@@ -433,11 +1241,47 @@ function defaultQuerySelectionSet(field, isList) {
433
1241
  if (field === "organization") {
434
1242
  return "{ id slug membersCount organizationDetail { title name description timezone workspaceName } }";
435
1243
  }
1244
+ const canonicalField = RESOURCE_FIELD_ALIASES[field] ?? field;
1245
+ const explicitFields = RESOURCE_QUERY_FIELDS[canonicalField];
1246
+ if (explicitFields) {
1247
+ const fields = Array.from(/* @__PURE__ */ new Set(["id", "type", ...explicitFields, "attributes"])).join(" ");
1248
+ return isList ? `{ data { ${fields} } count currentPage totalPages }` : `{ ${fields} }`;
1249
+ }
436
1250
  if (isList) {
437
1251
  return "{ data { id type attributes } count currentPage totalPages }";
438
1252
  }
439
1253
  return "{ id type attributes }";
440
1254
  }
1255
+ function isRecord(value) {
1256
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1257
+ }
1258
+ function normalizeDisplayFieldsInRow(row) {
1259
+ if (!isRecord(row)) return row;
1260
+ const attributes = isRecord(row.attributes) ? row.attributes : null;
1261
+ if (!attributes) return row;
1262
+ const normalized = { ...row };
1263
+ for (const [key, value] of Object.entries(attributes)) {
1264
+ if (!Object.prototype.hasOwnProperty.call(normalized, key)) {
1265
+ normalized[key] = value;
1266
+ }
1267
+ }
1268
+ return normalized;
1269
+ }
1270
+ function normalizeQueryFieldPayloadForDisplay(fieldPayload) {
1271
+ if (Array.isArray(fieldPayload)) {
1272
+ return fieldPayload.map((row) => normalizeDisplayFieldsInRow(row));
1273
+ }
1274
+ if (!isRecord(fieldPayload)) {
1275
+ return fieldPayload;
1276
+ }
1277
+ if (Array.isArray(fieldPayload.data)) {
1278
+ return {
1279
+ ...fieldPayload,
1280
+ data: fieldPayload.data.map((row) => normalizeDisplayFieldsInRow(row))
1281
+ };
1282
+ }
1283
+ return normalizeDisplayFieldsInRow(fieldPayload);
1284
+ }
441
1285
  function parseBooleanMaybe(value) {
442
1286
  const lowered = value.toLowerCase();
443
1287
  if (lowered === "true") {
@@ -494,9 +1338,15 @@ async function runGraphqlQueryCommand(input) {
494
1338
  operationType: "query",
495
1339
  field: input.field,
496
1340
  variables: input.variables ?? {},
1341
+ variableTypes: input.variableTypes,
497
1342
  selectionSet: input.selectionSet ?? defaultQuerySelectionSet(input.field, Boolean(input.isList)),
498
1343
  isShow: input.isShow
499
1344
  });
1345
+ const envelopeData = result.envelope.data;
1346
+ if (result.envelope.ok && envelopeData && Object.prototype.hasOwnProperty.call(envelopeData, input.field)) {
1347
+ envelopeData[input.field] = normalizeQueryFieldPayloadForDisplay(envelopeData[input.field]);
1348
+ result.envelope.data = envelopeData;
1349
+ }
500
1350
  if (result.envelope.ok && input.transformData && result.envelope.data) {
501
1351
  const dataRecord = result.envelope.data;
502
1352
  const transformed = input.transformData(dataRecord[input.field]);
@@ -504,6 +1354,17 @@ async function runGraphqlQueryCommand(input) {
504
1354
  ...dataRecord,
505
1355
  [input.field]: transformed
506
1356
  };
1357
+ if (input.isShow && (transformed === null || transformed === void 0)) {
1358
+ result.envelope.ok = false;
1359
+ result.envelope.status = 404;
1360
+ result.envelope.data = null;
1361
+ result.envelope.error = {
1362
+ code: "not_found",
1363
+ message: "Record not found.",
1364
+ details: {}
1365
+ };
1366
+ result.exitCode = EXIT_CODES.notFound;
1367
+ }
507
1368
  }
508
1369
  printEnvelopeAndExit(result);
509
1370
  } catch (error) {
@@ -541,6 +1402,7 @@ async function runGraphqlMutationCommand(input) {
541
1402
  operationType: "mutation",
542
1403
  field: input.field,
543
1404
  variables: input.variables ?? {},
1405
+ variableTypes: input.variableTypes,
544
1406
  selectionSet: input.selectionSet ?? "{ ok status errorCode data errors }"
545
1407
  });
546
1408
  printEnvelopeAndExit(result);
@@ -780,8 +1642,114 @@ function resolveOrganizationId(raw) {
780
1642
  return organizationId;
781
1643
  }
782
1644
 
1645
+ // src/commands/tasks.ts
1646
+ var projectIdSchema = import_zod2.z.string().min(1);
1647
+ var idSchema = import_zod2.z.string().min(1);
1648
+ var summarySchema = import_zod2.z.string().min(1);
1649
+ function registerTaskCommands(program) {
1650
+ const tasks = program.command("tasks").description("Task operations");
1651
+ tasks.command("list").option("--project-id <projectId>").option("--page <page>").option("--per <per>").option("--team-id <teamId>").option("--team-ids <teamIds>").option("--member-id <memberId>").option("--meeting-id <meetingId>").option("--field-name <fieldName>").option("--field-value <fieldValue>").option("--field-blank <fieldBlank>").option("--open <open>").option("--rank-direction <rankDirection>").option("--include-archived <includeArchived>").action(async (opts, cmd) => {
1652
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
1653
+ const organizationId = resolveOrganizationId(context.organizationId);
1654
+ const projectId = opts.projectId ? projectIdSchema.parse(opts.projectId) : void 0;
1655
+ await runGraphqlQueryCommand({
1656
+ command: "tasks.list",
1657
+ runtimeOptions: context.runtimeOptions,
1658
+ field: "tasks",
1659
+ variables: normalizeGraphqlVariables2({
1660
+ organization_id: organizationId,
1661
+ page: opts.page,
1662
+ per: opts.per,
1663
+ project_id: projectId,
1664
+ team_id: opts.teamId,
1665
+ team_ids: opts.teamIds,
1666
+ member_id: opts.memberId,
1667
+ meeting_id: opts.meetingId,
1668
+ field_name: opts.fieldName,
1669
+ field_value: opts.fieldValue,
1670
+ field_blank: opts.fieldBlank,
1671
+ open: opts.open,
1672
+ rank_direction: opts.rankDirection,
1673
+ include_archived: opts.includeArchived
1674
+ }),
1675
+ isList: true
1676
+ });
1677
+ });
1678
+ tasks.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
1679
+ const parsed = idSchema.parse(opts.id);
1680
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
1681
+ const organizationId = resolveOrganizationId(context.organizationId);
1682
+ await runGraphqlQueryCommand({
1683
+ command: "tasks.show",
1684
+ runtimeOptions: context.runtimeOptions,
1685
+ field: "task",
1686
+ variables: {
1687
+ organization_id: organizationId,
1688
+ id: parsed
1689
+ },
1690
+ isShow: true
1691
+ });
1692
+ });
1693
+ tasks.command("create").requiredOption("--project-id <projectId>").option("--title <title>", "Legacy alias for --summary").option("--summary <summary>").action(async (opts, cmd) => {
1694
+ const projectId = projectIdSchema.parse(opts.projectId);
1695
+ const summary = summarySchema.parse(opts.summary ?? opts.title);
1696
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
1697
+ const organizationId = resolveOrganizationId(context.organizationId);
1698
+ await runGraphqlMutationCommand({
1699
+ command: "tasks.create",
1700
+ runtimeOptions: context.runtimeOptions,
1701
+ field: "create_task",
1702
+ variables: {
1703
+ organization_id: organizationId,
1704
+ params: {
1705
+ task: {
1706
+ project_id: projectId,
1707
+ summary
1708
+ }
1709
+ }
1710
+ }
1711
+ });
1712
+ });
1713
+ tasks.command("update").requiredOption("--id <id>").option("--summary <summary>").option("--description <description>").option("--status <status>").option("--priority <priority>").option("--due-date <dueDate>").option("--member-id <memberId>").action(async (opts, cmd) => {
1714
+ const id = idSchema.parse(opts.id);
1715
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
1716
+ const organizationId = resolveOrganizationId(context.organizationId);
1717
+ const taskPayload = {
1718
+ ...opts.summary ? { summary: String(opts.summary) } : {},
1719
+ ...opts.description ? { description: String(opts.description) } : {},
1720
+ ...opts.status ? { status: String(opts.status) } : {},
1721
+ ...opts.priority ? { priority: String(opts.priority) } : {},
1722
+ ...opts.dueDate ? { due_date: String(opts.dueDate) } : {},
1723
+ ...opts.memberId ? { member_id: String(opts.memberId) } : {}
1724
+ };
1725
+ if (Object.keys(taskPayload).length === 0) {
1726
+ throw new CliError({
1727
+ message: "tasks update requires at least one patch field (summary, description, status, priority, due-date, member-id).",
1728
+ kind: "invalid_args",
1729
+ status: 400,
1730
+ exitCode: EXIT_CODES.invalidArgs
1731
+ });
1732
+ }
1733
+ await runGraphqlMutationCommand({
1734
+ command: "tasks.update",
1735
+ runtimeOptions: context.runtimeOptions,
1736
+ field: "update_task",
1737
+ variables: {
1738
+ organization_id: organizationId,
1739
+ task_id: id,
1740
+ params: {
1741
+ task: taskPayload
1742
+ }
1743
+ }
1744
+ });
1745
+ });
1746
+ }
1747
+
1748
+ // src/commands/projects.ts
1749
+ var import_zod4 = require("zod");
1750
+
783
1751
  // src/commands/entityCrud.ts
784
- var import_zod2 = require("zod");
1752
+ var import_zod3 = require("zod");
785
1753
 
786
1754
  // src/commands/dtoHelpCatalog.ts
787
1755
  var dtoHelpCatalog = {
@@ -850,7 +1818,7 @@ var dtoHelpCatalog = {
850
1818
  create: [
851
1819
  ["member_id", "string"],
852
1820
  ["name", "string"],
853
- ["type", "MeetingType"],
1821
+ ["type", "enum(TeamMeeting|OneOnOneMeeting)"],
854
1822
  ["date", "string"],
855
1823
  ["status", "enum(upcoming|active|completed)"],
856
1824
  ["start_time", "number"],
@@ -1362,7 +2330,7 @@ function buildDataJsonHelp(rootKey, mode) {
1362
2330
  }
1363
2331
 
1364
2332
  // src/commands/entityCrud.ts
1365
- var idSchema = import_zod2.z.string().min(1);
2333
+ var idSchema2 = import_zod3.z.string().min(1);
1366
2334
  function toSingularResourceName(resourcePath) {
1367
2335
  if (resourcePath === "organization_meta_profiles") {
1368
2336
  return "organization_meta_profile";
@@ -1442,14 +2410,19 @@ function registerEntityCrudCommands(program, config) {
1442
2410
  const updateHelp5 = buildDataJsonHelp(config.rootKey, "update") ?? "JSON object, optionally wrapped with root key";
1443
2411
  const list = entityCommand.command("list").option("--page <page>").option("--per <per>");
1444
2412
  const listParams = config.listParams ?? [];
2413
+ const showParams = config.showParams ?? [];
2414
+ const allowQueryJson = config.allowQueryJson !== false;
1445
2415
  listParams.forEach((param) => {
1446
2416
  const cliParam = param.replace(/_/g, "-");
1447
2417
  list.option(`--${cliParam} <${cliParam}>`);
1448
2418
  });
1449
- list.option("--query-json <queryJson>", "Additional query params as JSON object").action(async (opts, cmd) => {
2419
+ if (allowQueryJson) {
2420
+ list.option("--query-json <queryJson>", "Additional query params as JSON object");
2421
+ }
2422
+ list.action(async (opts, cmd) => {
1450
2423
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1451
2424
  const organizationId = resolveOrganizationId(context.organizationId);
1452
- const extraQuery = parseQueryJson(opts.queryJson ? String(opts.queryJson) : void 0);
2425
+ const extraQuery = allowQueryJson ? parseQueryJson(opts.queryJson ? String(opts.queryJson) : void 0) : {};
1453
2426
  const mappedKnownParams = Object.fromEntries(
1454
2427
  listParams.map((param) => {
1455
2428
  const optionKey = param.replace(/_([a-z])/g, (_, char) => char.toUpperCase());
@@ -1466,46 +2439,93 @@ function registerEntityCrudCommands(program, config) {
1466
2439
  await runGraphqlQueryCommand({
1467
2440
  command: `${config.command}.list`,
1468
2441
  runtimeOptions: context.runtimeOptions,
1469
- field: config.resourcePath === "feedback" ? "feedbacks" : config.resourcePath,
2442
+ field: config.listField ?? (config.resourcePath === "feedback" ? "feedbacks" : config.resourcePath),
1470
2443
  variables,
2444
+ variableTypes: config.listVariableTypes,
2445
+ selectionSet: config.listSelectionSet,
1471
2446
  isList: true
1472
2447
  });
1473
2448
  });
1474
- entityCommand.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
1475
- const id = idSchema.parse(opts.id);
2449
+ const show = entityCommand.command("show").requiredOption("--id <id>");
2450
+ showParams.forEach((param) => {
2451
+ const cliParam = param.replace(/_/g, "-");
2452
+ show.option(`--${cliParam} <${cliParam}>`);
2453
+ });
2454
+ show.action(async (opts, cmd) => {
2455
+ const id = idSchema2.parse(opts.id);
1476
2456
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1477
2457
  const organizationId = resolveOrganizationId(context.organizationId);
2458
+ const defaultCommand = `${config.command}.show`;
2459
+ const defaultField = config.showField ?? (config.resourcePath === "feedback" ? "feedback" : toSingularResourceName(config.resourcePath));
2460
+ const mappedShowParams = Object.fromEntries(
2461
+ showParams.map((param) => {
2462
+ const optionKey = param.replace(/_([a-z])/g, (_, char) => char.toUpperCase());
2463
+ return [param, opts[optionKey]];
2464
+ })
2465
+ );
2466
+ const defaultVariables = normalizeGraphqlVariables2({
2467
+ organization_id: organizationId,
2468
+ id,
2469
+ ...mappedShowParams
2470
+ });
2471
+ const showQuery = config.showQueryFactory ? config.showQueryFactory({
2472
+ command: defaultCommand,
2473
+ field: defaultField,
2474
+ variables: defaultVariables,
2475
+ id,
2476
+ organizationId
2477
+ }) : void 0;
1478
2478
  await runGraphqlQueryCommand({
1479
- command: `${config.command}.show`,
2479
+ command: showQuery?.command ?? defaultCommand,
1480
2480
  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
2481
+ operationName: showQuery?.operationName,
2482
+ field: showQuery?.field ?? defaultField,
2483
+ variables: showQuery?.variables ?? defaultVariables,
2484
+ variableTypes: showQuery?.variableTypes ?? config.showVariableTypes,
2485
+ selectionSet: showQuery?.selectionSet ?? config.showSelectionSet,
2486
+ isShow: true,
2487
+ transformData: showQuery?.transformData
1487
2488
  });
1488
2489
  });
1489
2490
  entityCommand.command("create").requiredOption("--data-json <dataJson>", createHelp4).action(async (opts, cmd) => {
1490
2491
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1491
2492
  const organizationId = resolveOrganizationId(context.organizationId);
1492
- const body = normalizeBody(String(opts.dataJson), config.rootKey);
2493
+ let body = normalizeBody(String(opts.dataJson), config.rootKey);
2494
+ if (config.normalizeCreateBody) {
2495
+ body = config.normalizeCreateBody(body);
2496
+ }
1493
2497
  assertRequiredCreateFields(body, config.rootKey, config.requiredCreateFields);
2498
+ const defaultCommand = `${config.command}.create`;
2499
+ const defaultField = `create_${toSingularResourceName(config.resourcePath)}`;
2500
+ const defaultVariables = {
2501
+ organization_id: organizationId,
2502
+ params: body
2503
+ };
2504
+ const createMutation = config.createMutationFactory ? config.createMutationFactory({
2505
+ command: defaultCommand,
2506
+ field: defaultField,
2507
+ variables: defaultVariables,
2508
+ body,
2509
+ organizationId
2510
+ }) : void 0;
1494
2511
  await runGraphqlMutationCommand({
1495
- command: `${config.command}.create`,
2512
+ command: createMutation?.command ?? defaultCommand,
1496
2513
  runtimeOptions: context.runtimeOptions,
1497
- field: `create_${toSingularResourceName(config.resourcePath)}`,
1498
- variables: {
1499
- organization_id: organizationId,
1500
- params: body
1501
- }
2514
+ operationName: createMutation?.operationName,
2515
+ field: createMutation?.field ?? defaultField,
2516
+ variables: createMutation?.variables ?? defaultVariables,
2517
+ variableTypes: createMutation?.variableTypes,
2518
+ selectionSet: createMutation?.selectionSet
1502
2519
  });
1503
2520
  });
1504
2521
  entityCommand.command("update").requiredOption("--id <id>").requiredOption("--data-json <dataJson>", updateHelp5).action(async (opts, cmd) => {
1505
- const id = idSchema.parse(opts.id);
2522
+ const id = idSchema2.parse(opts.id);
1506
2523
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1507
2524
  const organizationId = resolveOrganizationId(context.organizationId);
1508
- const body = normalizeBody(String(opts.dataJson), config.rootKey);
2525
+ let body = normalizeBody(String(opts.dataJson), config.rootKey);
2526
+ if (config.normalizeUpdateBody) {
2527
+ body = config.normalizeUpdateBody(body);
2528
+ }
1509
2529
  const singular = toSingularResourceName(config.resourcePath);
1510
2530
  await runGraphqlMutationCommand({
1511
2531
  command: `${config.command}.update`,
@@ -1527,137 +2547,69 @@ var __testables = {
1527
2547
  parseQueryJson
1528
2548
  };
1529
2549
 
1530
- // src/commands/tasks.ts
1531
- var projectIdSchema = import_zod3.z.string().min(1);
1532
- var idSchema2 = import_zod3.z.string().min(1);
1533
- var summarySchema = import_zod3.z.string().min(1);
1534
- function registerTaskCommands(program) {
1535
- const tasks = program.command("tasks").description("Task operations");
1536
- tasks.command("list").option("--project-id <projectId>").option("--page <page>").option("--per <per>").option("--team-id <teamId>").option("--team-ids <teamIds>").option("--member-id <memberId>").option("--meeting-id <meetingId>").option("--field-name <fieldName>").option("--field-value <fieldValue>").option("--field-blank <fieldBlank>").option("--rank-direction <rankDirection>").option("--include-archived <includeArchived>").option("--query-json <queryJson>").action(async (opts, cmd) => {
1537
- const context = await resolveCommandContext(cmd.optsWithGlobals());
1538
- const organizationId = resolveOrganizationId(context.organizationId);
1539
- const projectId = opts.projectId ? projectIdSchema.parse(opts.projectId) : void 0;
1540
- const extra = parseQueryJson(opts.queryJson ? String(opts.queryJson) : void 0);
1541
- await runGraphqlQueryCommand({
1542
- command: "tasks.list",
1543
- runtimeOptions: context.runtimeOptions,
1544
- field: "tasks",
1545
- variables: normalizeGraphqlVariables2({
1546
- organization_id: organizationId,
1547
- page: opts.page,
1548
- per: opts.per,
1549
- project_id: projectId,
1550
- team_id: opts.teamId,
1551
- team_ids: opts.teamIds,
1552
- member_id: opts.memberId,
1553
- meeting_id: opts.meetingId,
1554
- field_name: opts.fieldName,
1555
- field_value: opts.fieldValue,
1556
- field_blank: opts.fieldBlank,
1557
- rank_direction: opts.rankDirection,
1558
- include_archived: opts.includeArchived,
1559
- ...extra
1560
- }),
1561
- isList: true
1562
- });
1563
- });
1564
- tasks.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
1565
- const parsed = idSchema2.parse(opts.id);
1566
- const context = await resolveCommandContext(cmd.optsWithGlobals());
1567
- const organizationId = resolveOrganizationId(context.organizationId);
1568
- await runGraphqlQueryCommand({
1569
- command: "tasks.show",
1570
- runtimeOptions: context.runtimeOptions,
1571
- field: "task",
1572
- variables: {
1573
- organization_id: organizationId,
1574
- id: parsed
1575
- },
1576
- isShow: true
1577
- });
1578
- });
1579
- tasks.command("create").requiredOption("--project-id <projectId>").option("--title <title>", "Legacy alias for --summary").option("--summary <summary>").action(async (opts, cmd) => {
1580
- const projectId = projectIdSchema.parse(opts.projectId);
1581
- const summary = summarySchema.parse(opts.summary ?? opts.title);
1582
- const context = await resolveCommandContext(cmd.optsWithGlobals());
1583
- const organizationId = resolveOrganizationId(context.organizationId);
1584
- await runGraphqlMutationCommand({
1585
- command: "tasks.create",
1586
- runtimeOptions: context.runtimeOptions,
1587
- field: "create_task",
1588
- variables: {
1589
- organization_id: organizationId,
1590
- params: {
1591
- task: {
1592
- project_id: projectId,
1593
- summary
1594
- }
1595
- }
1596
- }
1597
- });
1598
- });
1599
- tasks.command("update").requiredOption("--id <id>").option("--summary <summary>").option("--description <description>").option("--status <status>").option("--priority <priority>").option("--due-date <dueDate>").option("--member-id <memberId>").action(async (opts, cmd) => {
1600
- const id = idSchema2.parse(opts.id);
1601
- const context = await resolveCommandContext(cmd.optsWithGlobals());
1602
- const organizationId = resolveOrganizationId(context.organizationId);
1603
- const taskPayload = {
1604
- ...opts.summary ? { summary: String(opts.summary) } : {},
1605
- ...opts.description ? { description: String(opts.description) } : {},
1606
- ...opts.status ? { status: String(opts.status) } : {},
1607
- ...opts.priority ? { priority: String(opts.priority) } : {},
1608
- ...opts.dueDate ? { due_date: String(opts.dueDate) } : {},
1609
- ...opts.memberId ? { member_id: String(opts.memberId) } : {}
1610
- };
1611
- if (Object.keys(taskPayload).length === 0) {
1612
- throw new CliError({
1613
- message: "tasks update requires at least one patch field (summary, description, status, priority, due-date, member-id).",
1614
- kind: "invalid_args",
1615
- status: 400,
1616
- exitCode: EXIT_CODES.invalidArgs
1617
- });
1618
- }
1619
- await runGraphqlMutationCommand({
1620
- command: "tasks.update",
1621
- runtimeOptions: context.runtimeOptions,
1622
- field: "update_task",
1623
- variables: {
1624
- organization_id: organizationId,
1625
- task_id: id,
1626
- params: {
1627
- task: taskPayload
1628
- }
1629
- }
1630
- });
1631
- });
1632
- }
1633
-
1634
2550
  // src/commands/projects.ts
1635
- var import_zod4 = require("zod");
1636
2551
  var idSchema3 = import_zod4.z.string().min(1);
1637
2552
  var projectCreateDataJsonHelp = buildDataJsonHelp("project", "create") ?? 'JSON object for project or {"project": {...}}';
1638
2553
  var projectUpdateDataJsonHelp = buildDataJsonHelp("project", "update") ?? 'JSON object for project or {"project": {...}}';
2554
+ var projectsIndexFullSelectionSet = "{ count currentPage totalPages data { id type attributes { name slug description status priority createdAt updatedAt startDate targetDate archivedAt memberId organizationId teamIds favorites { id memberId } resources { ...ResourceSummaryFull } } name slug description status priority createdAt updatedAt startDate targetDate archivedAt memberId organizationId teamIds emoji { id name memberId } backgroundImage { backgroundType gradientStart gradientEnd gradientDegrees color imageUrl image { url lowUrl } } favorites { id memberId } resources { ...ResourceSummaryFull } displayPreference { id type attributes viewType favorite groupingField groupToggleState memberId focusMemberId focusTeamId displayableId displayableType preferenceType agendaItemId } filterPreferences { id type attributes filterType filter memberId focusMemberId focusTeamId filterableId filterableType preferenceType agendaItemId } healthUpdates { id type attributes value memberId status createdAt updatedAt updatableType updatableId parentUpdateId emojis { id name memberId } resources { ...ResourceSummaryFull } replies { id type attributes value memberId createdAt updatedAt commentType commentableId commentableType parentCommentId emojis { id name memberId } resources { ...ResourceSummaryFull } replies { id type } } } } } fragment ResourceSummaryFull on ResourceSummary { id resourceType slug url skillId skill { id name slug emoji scope description } metadata { urlName imageUrl siteName providerName mediaType skillId skillName skillSlug skillScope skillEmoji skillDescription } attachment { id fileKey filename url } content { id name slug type firstChildSlug childCount } }";
2555
+ function asRecord2(value) {
2556
+ return value && typeof value === "object" ? value : null;
2557
+ }
2558
+ function toNonEmptyString(value) {
2559
+ return typeof value === "string" && value.trim() !== "" ? value : void 0;
2560
+ }
2561
+ function normalizeProjectRowForDisplay(row) {
2562
+ const record = asRecord2(row);
2563
+ if (!record) return row;
2564
+ const attributes = asRecord2(record.attributes);
2565
+ const topLevelName = toNonEmptyString(record.name);
2566
+ const topLevelTitle = toNonEmptyString(record.title);
2567
+ const attributeName = toNonEmptyString(attributes?.name);
2568
+ const attributeTitle = toNonEmptyString(attributes?.title);
2569
+ if (!topLevelName && !topLevelTitle && !attributeName && !attributeTitle) {
2570
+ return record;
2571
+ }
2572
+ return {
2573
+ ...record,
2574
+ ...topLevelName ? {} : attributeName ? { name: attributeName } : {},
2575
+ ...topLevelTitle ? {} : attributeTitle ? { title: attributeTitle } : {}
2576
+ };
2577
+ }
2578
+ function normalizeProjectsListForDisplay(payload) {
2579
+ const record = asRecord2(payload);
2580
+ if (!record || !Array.isArray(record.data)) return payload;
2581
+ return {
2582
+ ...record,
2583
+ data: record.data.map((row) => normalizeProjectRowForDisplay(row))
2584
+ };
2585
+ }
1639
2586
  function registerProjectCommands(program) {
1640
2587
  const projects = program.command("projects").description("Project operations");
1641
- projects.command("list").option("--page <page>").option("--per <per>").option("--include-archived <includeArchived>").option("--status <status>").option("--term <term>").option("--team-ids <teamIds>").option("--member-id <memberId>").option("--query-json <queryJson>").action(async (opts, cmd) => {
2588
+ projects.command("list").option("--page <page>").option("--per <per>").option("--team-ids <teamIds>").option("--member-id <memberId>").action(async (opts, cmd) => {
1642
2589
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1643
2590
  const organizationId = resolveOrganizationId(context.organizationId);
1644
- const extra = parseQueryJson(opts.queryJson ? String(opts.queryJson) : void 0);
1645
2591
  await runGraphqlQueryCommand({
1646
2592
  command: "projects.list",
2593
+ operationName: "ProjectsIndexFull",
1647
2594
  runtimeOptions: context.runtimeOptions,
1648
2595
  field: "projects",
1649
2596
  variables: normalizeGraphqlVariables2({
1650
2597
  organization_id: organizationId,
1651
2598
  page: opts.page,
1652
2599
  per: opts.per,
1653
- include_archived: opts.includeArchived,
1654
- status: opts.status,
1655
- term: opts.term,
1656
2600
  team_ids: opts.teamIds,
1657
- member_id: opts.memberId,
1658
- ...extra
2601
+ member_id: opts.memberId
1659
2602
  }),
1660
- isList: true
2603
+ variableTypes: {
2604
+ organization_id: "ID!",
2605
+ page: "Int",
2606
+ per: "Int",
2607
+ team_ids: "[ID!]",
2608
+ member_id: "ID"
2609
+ },
2610
+ isList: true,
2611
+ selectionSet: projectsIndexFullSelectionSet,
2612
+ transformData: normalizeProjectsListForDisplay
1661
2613
  });
1662
2614
  });
1663
2615
  projects.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
@@ -1672,7 +2624,9 @@ function registerProjectCommands(program) {
1672
2624
  organization_id: organizationId,
1673
2625
  id
1674
2626
  },
1675
- isShow: true
2627
+ isShow: true,
2628
+ selectionSet: "{ id type name }",
2629
+ transformData: normalizeProjectRowForDisplay
1676
2630
  });
1677
2631
  });
1678
2632
  projects.command("create").requiredOption("--data-json <dataJson>", projectCreateDataJsonHelp).action(async (opts, cmd) => {
@@ -1702,6 +2656,11 @@ function registerProjectCommands(program) {
1702
2656
  organization_id: organizationId,
1703
2657
  project_id: id,
1704
2658
  params: body
2659
+ },
2660
+ variableTypes: {
2661
+ organization_id: "ID!",
2662
+ project_id: "ID!",
2663
+ params: "UpdateProjectParamsInput!"
1705
2664
  }
1706
2665
  });
1707
2666
  });
@@ -1716,11 +2675,10 @@ var createHelp = buildDataJsonHelp("rock", "create") ?? 'JSON object for rock or
1716
2675
  var updateHelp = buildDataJsonHelp("rock", "update") ?? 'JSON object for rock or {"rock": {...}}';
1717
2676
  function registerRockCommands(program) {
1718
2677
  const rocks = program.command("rocks").description("Rock operations");
1719
- rocks.command("list").option("--page <page>").option("--per <per>").option("--rock-collection-id <rockCollectionId>").option("--team-id <teamId>").option("--team-ids <teamIds>").option("--member-id <memberId>").option("--meeting-id <meetingId>").option("--annual-objective-id <annualObjectiveId>").option("--quarterly-objective-id <quarterlyObjectiveId>").option("--field-name <fieldName>").option("--field-value <fieldValue>").option("--field-blank <fieldBlank>").option("--rank-direction <rankDirection>").option("--include-archived <includeArchived>").option("--query-json <queryJson>").action(async (opts, cmd) => {
2678
+ rocks.command("list").option("--page <page>").option("--per <per>").option("--rock-collection-id <rockCollectionId>").option("--start-date <startDate>").option("--rock-type <rockType>").option("--team-id <teamId>").option("--member-id <memberId>").option("--meeting-id <meetingId>").option("--annual-objective-id <annualObjectiveId>").option("--quarterly-objective-id <quarterlyObjectiveId>").action(async (opts, cmd) => {
1720
2679
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1721
2680
  const organizationId = resolveOrganizationId(context.organizationId);
1722
2681
  const rockCollectionId = opts.rockCollectionId ? rockCollectionIdSchema.parse(opts.rockCollectionId) : void 0;
1723
- const extra = parseQueryJson(opts.queryJson ? String(opts.queryJson) : void 0);
1724
2682
  await runGraphqlQueryCommand({
1725
2683
  command: "rocks.list",
1726
2684
  runtimeOptions: context.runtimeOptions,
@@ -1730,18 +2688,13 @@ function registerRockCommands(program) {
1730
2688
  page: opts.page,
1731
2689
  per: opts.per,
1732
2690
  rock_collection_id: rockCollectionId,
2691
+ start_date: opts.startDate,
2692
+ rock_type: opts.rockType,
1733
2693
  team_id: opts.teamId,
1734
- team_ids: opts.teamIds,
1735
2694
  member_id: opts.memberId,
1736
2695
  meeting_id: opts.meetingId,
1737
2696
  annual_objective_id: opts.annualObjectiveId,
1738
- quarterly_objective_id: opts.quarterlyObjectiveId,
1739
- field_name: opts.fieldName,
1740
- field_value: opts.fieldValue,
1741
- field_blank: opts.fieldBlank,
1742
- rank_direction: opts.rankDirection,
1743
- include_archived: opts.includeArchived,
1744
- ...extra
2697
+ quarterly_objective_id: opts.quarterlyObjectiveId
1745
2698
  }),
1746
2699
  isList: true
1747
2700
  });
@@ -1814,28 +2767,161 @@ function registerRockCommands(program) {
1814
2767
  var import_zod6 = require("zod");
1815
2768
  var idSchema5 = import_zod6.z.string().min(1);
1816
2769
  var notesSchema = import_zod6.z.string().min(1);
2770
+ var MEETING_TYPES = /* @__PURE__ */ new Set(["TeamMeeting", "OneOnOneMeeting"]);
2771
+ var MEETING_STATUSES = /* @__PURE__ */ new Set(["upcoming", "active", "completed"]);
2772
+ var MEETING_REPEATS = /* @__PURE__ */ new Set(["never", "weekly", "biweekly", "monthly", "quarterly"]);
1817
2773
  var createHelp2 = buildDataJsonHelp("meeting", "create") ?? 'JSON object for meeting or {"meeting": {...}}';
1818
2774
  var updateHelp2 = buildDataJsonHelp("meeting", "update") ?? 'JSON object for meeting or {"meeting": {...}}';
2775
+ function asNonEmptyString2(value) {
2776
+ if (typeof value !== "string") {
2777
+ return void 0;
2778
+ }
2779
+ const trimmed = value.trim();
2780
+ return trimmed.length > 0 ? trimmed : void 0;
2781
+ }
2782
+ function toFiniteNumber(value, field) {
2783
+ if (value === void 0 || value === null) {
2784
+ return void 0;
2785
+ }
2786
+ if (typeof value === "number" && Number.isFinite(value)) {
2787
+ return value;
2788
+ }
2789
+ if (typeof value === "string") {
2790
+ const trimmed = value.trim();
2791
+ if (trimmed.length === 0) {
2792
+ return void 0;
2793
+ }
2794
+ const parsed = Number(trimmed);
2795
+ if (Number.isFinite(parsed)) {
2796
+ return parsed;
2797
+ }
2798
+ }
2799
+ throw new CliError({
2800
+ message: `Invalid ${field}. Expected a numeric value.`,
2801
+ kind: "invalid_args",
2802
+ status: 400,
2803
+ exitCode: EXIT_CODES.invalidArgs
2804
+ });
2805
+ }
2806
+ function toStringArray(value, field) {
2807
+ if (value === void 0 || value === null) {
2808
+ return void 0;
2809
+ }
2810
+ const items = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : null;
2811
+ if (!items) {
2812
+ throw new CliError({
2813
+ message: `Invalid ${field}. Expected an array or comma-separated string.`,
2814
+ kind: "invalid_args",
2815
+ status: 400,
2816
+ exitCode: EXIT_CODES.invalidArgs
2817
+ });
2818
+ }
2819
+ const normalized = items.map((item) => String(item).trim()).filter((item) => item.length > 0);
2820
+ return normalized.length > 0 ? normalized : void 0;
2821
+ }
2822
+ function normalizeMeetingCreateBody(body) {
2823
+ const entity = body.meeting;
2824
+ if (!entity || typeof entity !== "object" || Array.isArray(entity)) {
2825
+ throw new CliError({
2826
+ message: 'Invalid payload. Expected object at "meeting".',
2827
+ kind: "invalid_args",
2828
+ status: 400,
2829
+ exitCode: EXIT_CODES.invalidArgs
2830
+ });
2831
+ }
2832
+ const meeting = { ...entity };
2833
+ const type = asNonEmptyString2(meeting.type);
2834
+ if (!type || !MEETING_TYPES.has(type)) {
2835
+ throw new CliError({
2836
+ message: "Invalid meeting.type. Use one of: TeamMeeting, OneOnOneMeeting.",
2837
+ kind: "invalid_args",
2838
+ status: 400,
2839
+ exitCode: EXIT_CODES.invalidArgs,
2840
+ details: { field: "meeting.type", allowed: Array.from(MEETING_TYPES) }
2841
+ });
2842
+ }
2843
+ const memberId = asNonEmptyString2(meeting.member_id);
2844
+ const date = asNonEmptyString2(meeting.date);
2845
+ const startTime = toFiniteNumber(meeting.start_time, "meeting.start_time");
2846
+ const missingRequired = [];
2847
+ if (!memberId) missingRequired.push("member_id");
2848
+ if (!date) missingRequired.push("date");
2849
+ if (startTime === void 0) missingRequired.push("start_time");
2850
+ if (missingRequired.length > 0) {
2851
+ throw new CliError({
2852
+ message: `Missing required create fields for meeting: ${missingRequired.join(", ")}.`,
2853
+ kind: "invalid_args",
2854
+ status: 400,
2855
+ exitCode: EXIT_CODES.invalidArgs,
2856
+ details: { requiredFields: ["member_id", "date", "start_time"], rootKey: "meeting" }
2857
+ });
2858
+ }
2859
+ const status = asNonEmptyString2(meeting.status);
2860
+ if (status && !MEETING_STATUSES.has(status)) {
2861
+ throw new CliError({
2862
+ message: "Invalid meeting.status. Use one of: upcoming, active, completed.",
2863
+ kind: "invalid_args",
2864
+ status: 400,
2865
+ exitCode: EXIT_CODES.invalidArgs,
2866
+ details: { field: "meeting.status", allowed: Array.from(MEETING_STATUSES) }
2867
+ });
2868
+ }
2869
+ const repeats = asNonEmptyString2(meeting.repeats) ?? "never";
2870
+ if (!MEETING_REPEATS.has(repeats)) {
2871
+ throw new CliError({
2872
+ message: "Invalid meeting.repeats. Use one of: never, weekly, biweekly, monthly, quarterly.",
2873
+ kind: "invalid_args",
2874
+ status: 400,
2875
+ exitCode: EXIT_CODES.invalidArgs,
2876
+ details: { field: "meeting.repeats", allowed: Array.from(MEETING_REPEATS) }
2877
+ });
2878
+ }
2879
+ const teamsIds = toStringArray(meeting.teams_ids, "meeting.teams_ids");
2880
+ if (type === "TeamMeeting" && (!teamsIds || teamsIds.length === 0)) {
2881
+ throw new CliError({
2882
+ message: "Missing required create fields for meeting: teams_ids.",
2883
+ kind: "invalid_args",
2884
+ status: 400,
2885
+ exitCode: EXIT_CODES.invalidArgs,
2886
+ details: { requiredFields: ["teams_ids"], rootKey: "meeting" }
2887
+ });
2888
+ }
2889
+ const endTime = toFiniteNumber(meeting.end_time, "meeting.end_time");
2890
+ meeting.type = type;
2891
+ meeting.member_id = memberId;
2892
+ meeting.date = date;
2893
+ meeting.start_time = startTime;
2894
+ meeting.repeats = repeats;
2895
+ if (status) {
2896
+ meeting.status = status;
2897
+ }
2898
+ if (endTime !== void 0) {
2899
+ meeting.end_time = endTime;
2900
+ }
2901
+ if (teamsIds) {
2902
+ meeting.teams_ids = teamsIds;
2903
+ }
2904
+ return { ...body, meeting };
2905
+ }
1819
2906
  function registerMeetingCommands(program) {
1820
2907
  const meetings = program.command("meetings").description("Meeting operations");
1821
- 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) => {
2908
+ meetings.command("list").option("--page <page>").option("--per <per>").option("--date <date>").option("--occurrence-date <occurrenceDate>").option("--past <past>").option("--start-time <startTime>").option("--today-and-active <todayAndActive>").option("--type <type>").action(async (opts, cmd) => {
1822
2909
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1823
2910
  const organizationId = resolveOrganizationId(context.organizationId);
1824
- const extra = parseQueryJson(opts.queryJson ? String(opts.queryJson) : void 0);
1825
2911
  await runGraphqlQueryCommand({
1826
2912
  command: "meetings.list",
1827
2913
  runtimeOptions: context.runtimeOptions,
1828
2914
  field: "meetings",
1829
2915
  variables: normalizeGraphqlVariables2({
1830
2916
  organization_id: organizationId,
2917
+ page: opts.page,
1831
2918
  per: opts.per,
1832
2919
  date: opts.date,
1833
2920
  occurrence_date: opts.occurrenceDate,
1834
2921
  past: opts.past,
1835
2922
  start_time: opts.startTime,
1836
2923
  today_and_active: opts.todayAndActive,
1837
- upcoming: opts.upcoming,
1838
- ...extra
2924
+ type: opts.type
1839
2925
  }),
1840
2926
  isList: true
1841
2927
  });
@@ -1878,7 +2964,8 @@ function registerMeetingCommands(program) {
1878
2964
  meetings.command("create").requiredOption("--data-json <dataJson>", createHelp2).action(async (opts, cmd) => {
1879
2965
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1880
2966
  const organizationId = resolveOrganizationId(context.organizationId);
1881
- const body = __testables.normalizeBody(String(opts.dataJson), "meeting");
2967
+ const rawBody = __testables.normalizeBody(String(opts.dataJson), "meeting");
2968
+ const body = normalizeMeetingCreateBody(rawBody);
1882
2969
  await runGraphqlMutationCommand({
1883
2970
  command: "meetings.create",
1884
2971
  runtimeOptions: context.runtimeOptions,
@@ -1914,10 +3001,9 @@ var createHelp3 = buildDataJsonHelp("member", "create") ?? 'JSON object for memb
1914
3001
  var updateHelp3 = buildDataJsonHelp("member", "update") ?? 'JSON object for member or {"member": {...}}';
1915
3002
  function registerMemberCommands(program) {
1916
3003
  const members = program.command("members").description("Member operations");
1917
- members.command("list").option("--page <page>").option("--per <per>").option("--query-json <queryJson>").action(async (opts, cmd) => {
3004
+ members.command("list").option("--page <page>").option("--per <per>").action(async (opts, cmd) => {
1918
3005
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1919
3006
  const organizationId = resolveOrganizationId(context.organizationId);
1920
- const extra = parseQueryJson(opts.queryJson ? String(opts.queryJson) : void 0);
1921
3007
  await runGraphqlQueryCommand({
1922
3008
  command: "members.list",
1923
3009
  runtimeOptions: context.runtimeOptions,
@@ -1925,8 +3011,7 @@ function registerMemberCommands(program) {
1925
3011
  variables: normalizeGraphqlVariables2({
1926
3012
  organization_id: organizationId,
1927
3013
  page: opts.page,
1928
- per: opts.per,
1929
- ...extra
3014
+ per: opts.per
1930
3015
  }),
1931
3016
  isList: true
1932
3017
  });
@@ -1983,14 +3068,15 @@ var import_zod8 = require("zod");
1983
3068
  var issueGroupIdSchema = import_zod8.z.string().min(1);
1984
3069
  var idSchema7 = import_zod8.z.string().min(1);
1985
3070
  var nameSchema = import_zod8.z.string().min(1);
1986
- var issueTypeSchema = import_zod8.z.string().min(1);
3071
+ var issueTypeSchema = import_zod8.z.string().min(1).refine((value) => value === "short_term" || value === "long_term", {
3072
+ message: "Invalid issue type. Use one of: short_term, long_term."
3073
+ });
1987
3074
  var updateHelp4 = buildDataJsonHelp("issue", "update") ?? 'JSON object for issue or {"issue": {...}}';
1988
3075
  function registerIssueCommands(program) {
1989
3076
  const issues = program.command("issues").description("Issue operations");
1990
- issues.command("list").option("--page <page>").option("--per <per>").option("--issue-group-id <issueGroupId>").option("--team-id <teamId>").option("--team-ids <teamIds>").option("--member-id <memberId>").option("--meeting-id <meetingId>").option("--rank-direction <rankDirection>").option("--include-archived <includeArchived>").option("--query-json <queryJson>").action(async (opts, cmd) => {
3077
+ issues.command("list").option("--page <page>").option("--per <per>").option("--issue-group-id <issueGroupId>").option("--start-date <startDate>").option("--issue-type <issueType>").option("--team-id <teamId>").option("--member-id <memberId>").option("--meeting-id <meetingId>").action(async (opts, cmd) => {
1991
3078
  const context = await resolveCommandContext(cmd.optsWithGlobals());
1992
3079
  const organizationId = resolveOrganizationId(context.organizationId);
1993
- const extra = parseQueryJson(opts.queryJson ? String(opts.queryJson) : void 0);
1994
3080
  await runGraphqlQueryCommand({
1995
3081
  command: "issues.list",
1996
3082
  runtimeOptions: context.runtimeOptions,
@@ -2000,13 +3086,11 @@ function registerIssueCommands(program) {
2000
3086
  page: opts.page,
2001
3087
  per: opts.per,
2002
3088
  issue_group_id: opts.issueGroupId,
3089
+ start_date: opts.startDate,
3090
+ issue_type: opts.issueType,
2003
3091
  team_id: opts.teamId,
2004
- team_ids: opts.teamIds,
2005
3092
  member_id: opts.memberId,
2006
- meeting_id: opts.meetingId,
2007
- rank_direction: opts.rankDirection,
2008
- include_archived: opts.includeArchived,
2009
- ...extra
3093
+ meeting_id: opts.meetingId
2010
3094
  }),
2011
3095
  isList: true
2012
3096
  });
@@ -2026,7 +3110,7 @@ function registerIssueCommands(program) {
2026
3110
  isShow: true
2027
3111
  });
2028
3112
  });
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) => {
3113
+ 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
3114
  const issueGroupId = issueGroupIdSchema.parse(opts.issueGroupId);
2031
3115
  const name = nameSchema.parse(opts.name);
2032
3116
  const issueType = issueTypeSchema.parse(opts.issueType);
@@ -2071,86 +3155,733 @@ function registerIssueCommands(program) {
2071
3155
  });
2072
3156
  }
2073
3157
 
3158
+ // src/commands/smartKpiNames.ts
3159
+ var SMART_KPI_NAMES = [
3160
+ "total_active_users",
3161
+ "total_new_users",
3162
+ "total_return_users",
3163
+ "total_engaged_sessions",
3164
+ "total_sessions",
3165
+ "engagement_rate",
3166
+ "bounce_rate",
3167
+ "page_call_phone_clicks_logged_in_unique",
3168
+ "page_cta_clicks_logged_in_unique",
3169
+ "page_engaged_users",
3170
+ "page_fan_adds_unique",
3171
+ "page_fan_adds",
3172
+ "page_fan_removes",
3173
+ "page_fans",
3174
+ "page_get_directions_clicks_logged_in_unique",
3175
+ "page_impressions_unique",
3176
+ "page_impressions",
3177
+ "page_negative_feedback",
3178
+ "page_positive_feedback_comment",
3179
+ "page_positive_feedback_like",
3180
+ "page_positive_feedback_other",
3181
+ "page_positive_feedback_share",
3182
+ "page_post_engagements",
3183
+ "page_total_actions",
3184
+ "page_views_logged_in_unique",
3185
+ "page_views_total",
3186
+ "page_website_clicks_logged_in_unique",
3187
+ "post_clicks_by_type_unique",
3188
+ "post_engaged_users",
3189
+ "post_impressions_fan_paid",
3190
+ "post_impressions_fan",
3191
+ "post_impressions_organic",
3192
+ "post_impressions_unique",
3193
+ "post_impressions",
3194
+ "post_reactions_like_total",
3195
+ "get_directions_clicks",
3196
+ "phone_call_clicks",
3197
+ "profile_views",
3198
+ "reach",
3199
+ "text_message_clicks",
3200
+ "website_clicks",
3201
+ "online_followers",
3202
+ "total_interactions",
3203
+ "accounts_engaged",
3204
+ "likes",
3205
+ "comments",
3206
+ "saves",
3207
+ "shares",
3208
+ "replies",
3209
+ "impressions",
3210
+ "email_contacts",
3211
+ "follower_count",
3212
+ "total_new_conversations",
3213
+ "total_unassigned_conversations",
3214
+ "total_closed_conversations",
3215
+ "total_new_contacts",
3216
+ "total_contacts",
3217
+ "total_revenue",
3218
+ "total_expenses",
3219
+ "cash_flow",
3220
+ "paid_invoices",
3221
+ "unpaid_invoices",
3222
+ "total_new_payments",
3223
+ "total_new_invoices",
3224
+ "total_paid_invoices",
3225
+ "total_refunds",
3226
+ "total_disputes",
3227
+ "calls",
3228
+ "sms",
3229
+ "mms",
3230
+ "verify_push",
3231
+ "verify_totp",
3232
+ "recordings",
3233
+ "transcriptions",
3234
+ "programmable_voice",
3235
+ "authy_phone_verifications",
3236
+ "authy_authentications",
3237
+ "twilio_errors",
3238
+ "twilio_warnings",
3239
+ "twilio_notices",
3240
+ "total_subscribers",
3241
+ "total_subscribers_gained",
3242
+ "total_subscribers_lost",
3243
+ "total_engagement",
3244
+ "total_views",
3245
+ "total_comments",
3246
+ "total_likes",
3247
+ "total_dislikes",
3248
+ "total_shares",
3249
+ "total_card_impressions",
3250
+ "total_card_clicks",
3251
+ "total_card_click_rate",
3252
+ "rock_total_new_rock_groups",
3253
+ "rock_total_rock_groups",
3254
+ "rock_total_new_rocks",
3255
+ "rock_total_new_milestones",
3256
+ "rock_total_completed_milestones",
3257
+ "rock_total_incomplete_milestones",
3258
+ "project_total_projects",
3259
+ "project_total_new_projects",
3260
+ "project_total_new_tasks",
3261
+ "project_total_completed_tasks",
3262
+ "project_total_incomplete_tasks",
3263
+ "project_total_new_sub_tasks",
3264
+ "project_total_completed_sub_tasks",
3265
+ "project_total_incomplete_sub_tasks",
3266
+ "list_total_list",
3267
+ "list_total_new_list",
3268
+ "list_total_new_list_items",
3269
+ "list_total_completed_list_items",
3270
+ "list_total_incomplete_list_items",
3271
+ "list_total_new_sub_items",
3272
+ "list_total_completed_sub_items",
3273
+ "list_total_incomplete_sub_items",
3274
+ "issue_total_issue_groups",
3275
+ "issue_total_new_issue_groups",
3276
+ "issue_total_new_issues",
3277
+ "issue_total_completed_issues",
3278
+ "issue_total_incomplete_issues",
3279
+ "issue_total_new_sub_issues",
3280
+ "issue_total_completed_sub_issues",
3281
+ "issue_total_incomplete_sub_issues",
3282
+ "todo_total_todo_groups",
3283
+ "todo_total_new_todo_groups",
3284
+ "todo_total_new_todos",
3285
+ "todo_total_completed_todos",
3286
+ "todo_total_incomplete_todos",
3287
+ "todo_total_new_sub_todos",
3288
+ "todo_total_completed_sub_todos",
3289
+ "todo_total_incomplete_sub_todos",
3290
+ "measurable_total_scorecards",
3291
+ "measurable_total_new_scorecards",
3292
+ "measurable_total_new_measurables",
3293
+ "stand_up_daily_stand_up_completion_rate",
3294
+ "stand_up_total_stand_ups_complete",
3295
+ "stand_up_daily_stand_up_block_rate",
3296
+ "stand_up_total_blocked_stand_ups",
3297
+ "headline_total_new_headlines",
3298
+ "content_total_content",
3299
+ "content_total_new_content",
3300
+ "question_total_questions",
3301
+ "question_total_new_questions",
3302
+ "question_total_questions_answered",
3303
+ "survey_new_surveys_sent",
3304
+ "member_total_new_members",
3305
+ "member_total_members",
3306
+ "responsibility_total_new_responsibilities_added",
3307
+ "responsibility_total_responsibilities",
3308
+ "customer_total_customers",
3309
+ "customer_total_new_customers",
3310
+ "customer_total_new_customer_logs",
3311
+ "contact_total_contacts",
3312
+ "contact_total_new_contacts",
3313
+ "contact_total_new_contact_logs"
3314
+ ];
3315
+ var SMART_KPI_NAME_SET = new Set(SMART_KPI_NAMES);
3316
+
2074
3317
  // 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"]
3318
+ var TODO_STATUSES = /* @__PURE__ */ new Set(["open", "completed"]);
3319
+ var KNOWLEDGE_CONTENT_TYPES = /* @__PURE__ */ new Set(["company", "policy", "process"]);
3320
+ var KNOWLEDGE_STATUSES = /* @__PURE__ */ new Set(["draft", "published"]);
3321
+ var NEWS_STATUSES = /* @__PURE__ */ new Set(["active", "completed"]);
3322
+ var NEWS_HEADLINE_TYPES = /* @__PURE__ */ new Set(["team", "org_wide"]);
3323
+ var QUESTION_STATUSES = /* @__PURE__ */ new Set(["asked", "answered"]);
3324
+ var PULSE_STATUSES = /* @__PURE__ */ new Set(["on_track", "at_risk", "off_track"]);
3325
+ var SURVEY_RECIPIENT_TYPES = /* @__PURE__ */ new Set(["member", "team", "org_wide"]);
3326
+ var SURVEY_NAMES = /* @__PURE__ */ new Set([
3327
+ "employee_net_promoter_score",
3328
+ "continuous_performance_review",
3329
+ "core_value_alignment",
3330
+ "engagement",
3331
+ "wellness_and_mental_health",
3332
+ "workspace_culture",
3333
+ "peer_review",
3334
+ "manager_review",
3335
+ "onboarding"
3336
+ ]);
3337
+ var FEEDBACK_QUARTERS = /* @__PURE__ */ new Set(["q1", "q2", "q3", "q4"]);
3338
+ var FEEDBACK_NAMES = /* @__PURE__ */ new Set([
3339
+ "productivity_and_focus",
3340
+ "company_collaboration",
3341
+ "project_management",
3342
+ "employee_engagement",
3343
+ "training_and_development",
3344
+ "innovation_and_creativity",
3345
+ "customer_insights",
3346
+ "process_improvement",
3347
+ "leadership_and_management",
3348
+ "company_culture",
3349
+ "roadmap_and_strategy",
3350
+ "customer_testing_and_feedback"
3351
+ ]);
3352
+ var SCORECARD_INTERVALS = /* @__PURE__ */ new Set([
3353
+ "daily",
3354
+ "weekly",
3355
+ "monthly",
3356
+ "quarterly",
3357
+ "yearly"
3358
+ ]);
3359
+ var SCORECARD_TRENDS = /* @__PURE__ */ new Set(["average", "total"]);
3360
+ function isRecord2(value) {
3361
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3362
+ }
3363
+ function ensureEntityObject(body, rootKey) {
3364
+ const entity = body[rootKey];
3365
+ if (!isRecord2(entity)) {
3366
+ throw new CliError({
3367
+ message: `Invalid payload. Expected object at "${rootKey}".`,
3368
+ kind: "invalid_args",
3369
+ status: 400,
3370
+ exitCode: EXIT_CODES.invalidArgs
3371
+ });
3372
+ }
3373
+ return { ...entity };
3374
+ }
3375
+ function throwMissingRequiredCreateFields(rootKey, fields) {
3376
+ throw new CliError({
3377
+ message: `Missing required create fields for ${rootKey}: ${fields.join(", ")}.`,
3378
+ kind: "invalid_args",
3379
+ status: 400,
3380
+ exitCode: EXIT_CODES.invalidArgs,
3381
+ details: { requiredFields: fields, rootKey }
2115
3382
  });
2116
- registerEntityCrudCommands(program, {
2117
- command: "todos",
2118
- description: "To-do operations",
2119
- resourcePath: "todos",
2120
- rootKey: "todo",
2121
- requiredCreateFields: ["todo_group_id"],
2122
- listParams: [
2123
- "include_archived",
2124
- "meeting_id",
2125
- "member_id",
2126
- "rank_direction",
2127
- "team_id",
2128
- "team_ids",
2129
- "todo_group_id"
2130
- ]
3383
+ }
3384
+ function normalizeTodosCreateBody(body) {
3385
+ const todo = ensureEntityObject(body, "todo");
3386
+ const rawStatus = todo.status;
3387
+ if (rawStatus === void 0 || rawStatus === null || String(rawStatus).trim().length === 0) {
3388
+ todo.status = "open";
3389
+ return { ...body, todo };
3390
+ }
3391
+ if (typeof rawStatus !== "string" || !TODO_STATUSES.has(rawStatus)) {
3392
+ throw new CliError({
3393
+ message: "Invalid todo status. Use one of: open, completed.",
3394
+ kind: "invalid_args",
3395
+ status: 400,
3396
+ exitCode: EXIT_CODES.invalidArgs,
3397
+ details: { allowed: Array.from(TODO_STATUSES) }
3398
+ });
3399
+ }
3400
+ return { ...body, todo };
3401
+ }
3402
+ function asNonEmptyString3(value) {
3403
+ if (typeof value !== "string") {
3404
+ return void 0;
3405
+ }
3406
+ const trimmed = value.trim();
3407
+ return trimmed.length > 0 ? trimmed : void 0;
3408
+ }
3409
+ function validateEnumField(params) {
3410
+ const value = asNonEmptyString3(params.rawValue);
3411
+ if (!value) {
3412
+ return void 0;
3413
+ }
3414
+ if (!params.allowed.has(value)) {
3415
+ throw new CliError({
3416
+ message: params.message,
3417
+ kind: "invalid_args",
3418
+ status: 400,
3419
+ exitCode: EXIT_CODES.invalidArgs,
3420
+ details: { field: params.field, allowed: Array.from(params.allowed) }
3421
+ });
3422
+ }
3423
+ return value;
3424
+ }
3425
+ function normalizeKnowledgeCreateBody(body) {
3426
+ const content = ensureEntityObject(body, "content");
3427
+ const contentType = validateEnumField({
3428
+ rawValue: content.content_type,
3429
+ field: "content.content_type",
3430
+ allowed: KNOWLEDGE_CONTENT_TYPES,
3431
+ message: "Invalid content.content_type. Use one of: company, policy, process."
3432
+ });
3433
+ if (!contentType) {
3434
+ throwMissingRequiredCreateFields("content", ["content_type"]);
3435
+ }
3436
+ content.content_type = contentType;
3437
+ const status = validateEnumField({
3438
+ rawValue: content.status,
3439
+ field: "content.status",
3440
+ allowed: KNOWLEDGE_STATUSES,
3441
+ message: "Invalid content.status. Use one of: draft, published."
3442
+ });
3443
+ content.status = status ?? "draft";
3444
+ const memberId = asNonEmptyString3(content.member_id);
3445
+ if (!memberId) {
3446
+ throwMissingRequiredCreateFields("content", ["member_id"]);
3447
+ }
3448
+ content.member_id = memberId;
3449
+ return { ...body, content };
3450
+ }
3451
+ function normalizeNewsCreateBody(body) {
3452
+ const headline = ensureEntityObject(body, "headline");
3453
+ const memberId = asNonEmptyString3(headline.member_id);
3454
+ if (!memberId) {
3455
+ throwMissingRequiredCreateFields("headline", ["member_id"]);
3456
+ }
3457
+ headline.member_id = memberId;
3458
+ const status = validateEnumField({
3459
+ rawValue: headline.status,
3460
+ field: "headline.status",
3461
+ allowed: NEWS_STATUSES,
3462
+ message: "Invalid headline.status. Use one of: active, completed."
3463
+ });
3464
+ if (!status) {
3465
+ throwMissingRequiredCreateFields("headline", ["status"]);
3466
+ }
3467
+ headline.status = status;
3468
+ const headlineType = validateEnumField({
3469
+ rawValue: headline.headline_type,
3470
+ field: "headline.headline_type",
3471
+ allowed: NEWS_HEADLINE_TYPES,
3472
+ message: "Invalid headline.headline_type. Use one of: team, org_wide."
3473
+ });
3474
+ if (!headlineType) {
3475
+ throwMissingRequiredCreateFields("headline", ["headline_type"]);
3476
+ }
3477
+ headline.headline_type = headlineType;
3478
+ return { ...body, headline };
3479
+ }
3480
+ function normalizeQuestionsCreateBody(body) {
3481
+ const question = ensureEntityObject(body, "question");
3482
+ const summary = asNonEmptyString3(question.summary);
3483
+ const currentName = asNonEmptyString3(question.name);
3484
+ if (!currentName && summary) {
3485
+ question.name = summary;
3486
+ }
3487
+ delete question.summary;
3488
+ const name = asNonEmptyString3(question.name);
3489
+ const memberId = asNonEmptyString3(question.member_id);
3490
+ const missing = [];
3491
+ if (!name) missing.push("name");
3492
+ if (!memberId) missing.push("member_id");
3493
+ if (missing.length > 0) {
3494
+ throwMissingRequiredCreateFields("question", missing);
3495
+ }
3496
+ question.name = name;
3497
+ question.member_id = memberId;
3498
+ const status = validateEnumField({
3499
+ rawValue: question.status,
3500
+ field: "question.status",
3501
+ allowed: QUESTION_STATUSES,
3502
+ message: "Invalid question.status. Use one of: asked, answered."
3503
+ });
3504
+ if (status) {
3505
+ question.status = status;
3506
+ }
3507
+ return { ...body, question };
3508
+ }
3509
+ function normalizeQuestionsUpdateBody(body) {
3510
+ const question = ensureEntityObject(body, "question");
3511
+ const summary = asNonEmptyString3(question.summary);
3512
+ const currentName = asNonEmptyString3(question.name);
3513
+ if (!currentName && summary) {
3514
+ question.name = summary;
3515
+ }
3516
+ delete question.summary;
3517
+ const name = asNonEmptyString3(question.name);
3518
+ if (name) {
3519
+ question.name = name;
3520
+ }
3521
+ const status = validateEnumField({
3522
+ rawValue: question.status,
3523
+ field: "question.status",
3524
+ allowed: QUESTION_STATUSES,
3525
+ message: "Invalid question.status. Use one of: asked, answered."
3526
+ });
3527
+ if (status) {
3528
+ question.status = status;
3529
+ }
3530
+ return { ...body, question };
3531
+ }
3532
+ function normalizePulseCreateBody(body) {
3533
+ const healthUpdate = ensureEntityObject(body, "health_update");
3534
+ const healthUpdatableId = asNonEmptyString3(healthUpdate.health_updatable_id) ?? asNonEmptyString3(healthUpdate.updatable_id);
3535
+ const healthUpdatableType = asNonEmptyString3(healthUpdate.health_updatable_type) ?? asNonEmptyString3(healthUpdate.updatable_type);
3536
+ const memberId = asNonEmptyString3(healthUpdate.member_id);
3537
+ const status = validateEnumField({
3538
+ rawValue: healthUpdate.status,
3539
+ field: "health_update.status",
3540
+ allowed: PULSE_STATUSES,
3541
+ message: "Invalid health_update.status. Use one of: on_track, at_risk, off_track."
3542
+ });
3543
+ const missing = [];
3544
+ if (!healthUpdatableId) missing.push("health_updatable_id");
3545
+ if (!healthUpdatableType) missing.push("health_updatable_type");
3546
+ if (!memberId) missing.push("member_id");
3547
+ if (!status) missing.push("status");
3548
+ if (missing.length > 0) {
3549
+ throwMissingRequiredCreateFields("health_update", missing);
3550
+ }
3551
+ healthUpdate.health_updatable_id = healthUpdatableId;
3552
+ healthUpdate.health_updatable_type = healthUpdatableType;
3553
+ healthUpdate.member_id = memberId;
3554
+ healthUpdate.status = status;
3555
+ delete healthUpdate.updatable_id;
3556
+ delete healthUpdate.updatable_type;
3557
+ return { ...body, health_update: healthUpdate };
3558
+ }
3559
+ function normalizeSurveysCreateBody(body) {
3560
+ const survey = ensureEntityObject(body, "survey");
3561
+ const title = asNonEmptyString3(survey.title);
3562
+ const currentName = asNonEmptyString3(survey.name);
3563
+ if (!currentName && title) {
3564
+ survey.name = title;
3565
+ }
3566
+ delete survey.title;
3567
+ const name = validateEnumField({
3568
+ rawValue: survey.name,
3569
+ field: "survey.name",
3570
+ allowed: SURVEY_NAMES,
3571
+ 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."
3572
+ });
3573
+ const recipientType = validateEnumField({
3574
+ rawValue: survey.recipient_type,
3575
+ field: "survey.recipient_type",
3576
+ allowed: SURVEY_RECIPIENT_TYPES,
3577
+ message: "Invalid survey.recipient_type. Use one of: member, team, org_wide."
3578
+ });
3579
+ const missing = [];
3580
+ if (!name) missing.push("name");
3581
+ if (!recipientType) missing.push("recipient_type");
3582
+ if (missing.length > 0) {
3583
+ throwMissingRequiredCreateFields("survey", missing);
3584
+ }
3585
+ survey.name = name;
3586
+ survey.recipient_type = recipientType;
3587
+ return { ...body, survey };
3588
+ }
3589
+ function normalizeSurveysUpdateBody(body) {
3590
+ const survey = ensureEntityObject(body, "survey");
3591
+ const title = asNonEmptyString3(survey.title);
3592
+ const currentName = asNonEmptyString3(survey.name);
3593
+ if (!currentName && title) {
3594
+ survey.name = title;
3595
+ }
3596
+ delete survey.title;
3597
+ const name = validateEnumField({
3598
+ rawValue: survey.name,
3599
+ field: "survey.name",
3600
+ allowed: SURVEY_NAMES,
3601
+ 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."
3602
+ });
3603
+ if (name) {
3604
+ survey.name = name;
3605
+ }
3606
+ const recipientType = validateEnumField({
3607
+ rawValue: survey.recipient_type,
3608
+ field: "survey.recipient_type",
3609
+ allowed: SURVEY_RECIPIENT_TYPES,
3610
+ message: "Invalid survey.recipient_type. Use one of: member, team, org_wide."
3611
+ });
3612
+ if (recipientType) {
3613
+ survey.recipient_type = recipientType;
3614
+ }
3615
+ return { ...body, survey };
3616
+ }
3617
+ function normalizeFeedbacksCreateBody(body) {
3618
+ const feedback = ensureEntityObject(body, "feedback");
3619
+ const title = asNonEmptyString3(feedback.title);
3620
+ const currentName = asNonEmptyString3(feedback.name);
3621
+ if (!currentName && title) {
3622
+ feedback.name = title;
3623
+ }
3624
+ delete feedback.title;
3625
+ const name = validateEnumField({
3626
+ rawValue: feedback.name,
3627
+ field: "feedback.name",
3628
+ allowed: FEEDBACK_NAMES,
3629
+ 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."
3630
+ });
3631
+ const quarter = validateEnumField({
3632
+ rawValue: feedback.quarter,
3633
+ field: "feedback.quarter",
3634
+ allowed: FEEDBACK_QUARTERS,
3635
+ message: "Invalid feedback.quarter. Use one of: q1, q2, q3, q4."
3636
+ });
3637
+ const year = asNonEmptyString3(feedback.year);
3638
+ const missing = [];
3639
+ if (!name) missing.push("name");
3640
+ if (!quarter) missing.push("quarter");
3641
+ if (!year) missing.push("year");
3642
+ if (missing.length > 0) {
3643
+ throwMissingRequiredCreateFields("feedback", missing);
3644
+ }
3645
+ feedback.name = name;
3646
+ feedback.quarter = quarter;
3647
+ feedback.year = year;
3648
+ return { ...body, feedback };
3649
+ }
3650
+ function normalizeFeedbacksUpdateBody(body) {
3651
+ const feedback = ensureEntityObject(body, "feedback");
3652
+ const title = asNonEmptyString3(feedback.title);
3653
+ const currentName = asNonEmptyString3(feedback.name);
3654
+ if (!currentName && title) {
3655
+ feedback.name = title;
3656
+ }
3657
+ delete feedback.title;
3658
+ const name = validateEnumField({
3659
+ rawValue: feedback.name,
3660
+ field: "feedback.name",
3661
+ allowed: FEEDBACK_NAMES,
3662
+ 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."
3663
+ });
3664
+ if (name) {
3665
+ feedback.name = name;
3666
+ }
3667
+ const quarter = validateEnumField({
3668
+ rawValue: feedback.quarter,
3669
+ field: "feedback.quarter",
3670
+ allowed: FEEDBACK_QUARTERS,
3671
+ message: "Invalid feedback.quarter. Use one of: q1, q2, q3, q4."
3672
+ });
3673
+ if (quarter) {
3674
+ feedback.quarter = quarter;
3675
+ }
3676
+ return { ...body, feedback };
3677
+ }
3678
+ function normalizeAccountabilityCreateBody(body) {
3679
+ const responsibility = ensureEntityObject(body, "responsibility");
3680
+ const summary = asNonEmptyString3(responsibility.summary);
3681
+ const currentName = asNonEmptyString3(responsibility.name);
3682
+ if (!currentName && summary) {
3683
+ responsibility.name = summary;
3684
+ }
3685
+ delete responsibility.summary;
3686
+ const name = asNonEmptyString3(responsibility.name);
3687
+ const memberId = asNonEmptyString3(responsibility.member_id);
3688
+ const missing = [];
3689
+ if (!name) missing.push("name");
3690
+ if (!memberId) missing.push("member_id");
3691
+ if (missing.length > 0) {
3692
+ throwMissingRequiredCreateFields("responsibility", missing);
3693
+ }
3694
+ responsibility.name = name;
3695
+ responsibility.member_id = memberId;
3696
+ return { ...body, responsibility };
3697
+ }
3698
+ function normalizeAccountabilityUpdateBody(body) {
3699
+ const responsibility = ensureEntityObject(body, "responsibility");
3700
+ const summary = asNonEmptyString3(responsibility.summary);
3701
+ const currentName = asNonEmptyString3(responsibility.name);
3702
+ if (!currentName && summary) {
3703
+ responsibility.name = summary;
3704
+ }
3705
+ delete responsibility.summary;
3706
+ return { ...body, responsibility };
3707
+ }
3708
+ function normalizeScorecardsCreateBody(body) {
3709
+ const measurable = ensureEntityObject(body, "measurable");
3710
+ const interval = validateEnumField({
3711
+ rawValue: measurable.interval,
3712
+ field: "measurable.interval",
3713
+ allowed: SCORECARD_INTERVALS,
3714
+ message: "Invalid measurable.interval. Use one of: daily, weekly, monthly, quarterly, yearly."
3715
+ });
3716
+ measurable.interval = interval ?? "weekly";
3717
+ const trend = validateEnumField({
3718
+ rawValue: measurable.trend,
3719
+ field: "measurable.trend",
3720
+ allowed: SCORECARD_TRENDS,
3721
+ message: "Invalid measurable.trend. Use one of: average, total."
3722
+ });
3723
+ measurable.trend = trend ?? "average";
3724
+ return { ...body, measurable };
3725
+ }
3726
+ function buildKpisCreateMutation(params) {
3727
+ const entity = params.body.smart_kpi;
3728
+ if (!entity || typeof entity !== "object" || Array.isArray(entity)) {
3729
+ throw new CliError({
3730
+ message: 'Invalid payload. Expected object at "smart_kpi".',
3731
+ kind: "invalid_args",
3732
+ status: 400,
3733
+ exitCode: EXIT_CODES.invalidArgs
3734
+ });
3735
+ }
3736
+ const smartKpi = { ...entity };
3737
+ const name = asNonEmptyString3(smartKpi.name);
3738
+ const smartKpiViewId = asNonEmptyString3(smartKpi.smart_kpi_view_id);
3739
+ const measurableGroupId = asNonEmptyString3(smartKpi.measurable_group_id);
3740
+ const hasAllowedName = typeof name === "string" && SMART_KPI_NAME_SET.has(name);
3741
+ if (!name) {
3742
+ throw new CliError({
3743
+ message: "Missing required create fields for smart_kpi: name.",
3744
+ kind: "invalid_args",
3745
+ status: 400,
3746
+ exitCode: EXIT_CODES.invalidArgs,
3747
+ details: { requiredFields: ["name"], rootKey: "smart_kpi" }
3748
+ });
3749
+ }
3750
+ if (measurableGroupId && !hasAllowedName) {
3751
+ const measurable = {
3752
+ measurable_group_id: measurableGroupId,
3753
+ name,
3754
+ interval: "daily",
3755
+ trend: "average",
3756
+ measurable_type: "number",
3757
+ condition: "greater_than_or_equal_to"
3758
+ };
3759
+ const notes = asNonEmptyString3(smartKpi.notes);
3760
+ if (notes) {
3761
+ measurable.notes = notes;
3762
+ }
3763
+ return {
3764
+ command: "measurables.create",
3765
+ field: "create_measurable",
3766
+ variables: {
3767
+ organization_id: params.organizationId,
3768
+ params: { measurable }
3769
+ }
3770
+ };
3771
+ }
3772
+ if (!smartKpiViewId) {
3773
+ throw new CliError({
3774
+ message: "Missing required create fields for smart_kpi: smart_kpi_view_id.",
3775
+ kind: "invalid_args",
3776
+ status: 400,
3777
+ exitCode: EXIT_CODES.invalidArgs,
3778
+ details: { requiredFields: ["smart_kpi_view_id"], rootKey: "smart_kpi" }
3779
+ });
3780
+ }
3781
+ if (!hasAllowedName) {
3782
+ throw new CliError({
3783
+ message: "Invalid smart_kpi.name for kpis.create. Use an allowed enum value or route free-text KPI names to measurable create.",
3784
+ kind: "invalid_args",
3785
+ status: 400,
3786
+ exitCode: EXIT_CODES.invalidArgs,
3787
+ details: {
3788
+ field: "smart_kpi.name",
3789
+ allowedValues: SMART_KPI_NAMES
3790
+ }
3791
+ });
3792
+ }
3793
+ delete smartKpi.measurable_group_id;
3794
+ smartKpi.name = name;
3795
+ smartKpi.smart_kpi_view_id = smartKpiViewId;
3796
+ return {
3797
+ command: "kpis.create",
3798
+ field: "create_smart_kpi",
3799
+ variables: {
3800
+ organization_id: params.organizationId,
3801
+ params: { smart_kpi: smartKpi }
3802
+ }
3803
+ };
3804
+ }
3805
+ function registerSystemToolCommands(program) {
3806
+ registerEntityCrudCommands(program, {
3807
+ command: "lists",
3808
+ description: "List operations",
3809
+ resourcePath: "lists",
3810
+ rootKey: "list",
3811
+ listParams: ["member_id", "team_ids"],
3812
+ showParams: ["current_member_id"],
3813
+ allowQueryJson: false
3814
+ });
3815
+ registerEntityCrudCommands(program, {
3816
+ command: "list-items",
3817
+ description: "List item operations",
3818
+ resourcePath: "list_items",
3819
+ rootKey: "list_item",
3820
+ requiredCreateFields: ["list_id"],
3821
+ listParams: ["list_id", "meeting_id", "open", "team_id", "member_id", "include_archived"],
3822
+ allowQueryJson: false
3823
+ });
3824
+ registerEntityCrudCommands(program, {
3825
+ command: "issue-groups",
3826
+ description: "Issue group operations",
3827
+ resourcePath: "issue_groups",
3828
+ rootKey: "issue_group",
3829
+ listParams: ["member_id", "team_ids"],
3830
+ showParams: ["current_member_id"],
3831
+ allowQueryJson: false
3832
+ });
3833
+ registerEntityCrudCommands(program, {
3834
+ command: "todo-groups",
3835
+ description: "To-do group operations",
3836
+ resourcePath: "todo_groups",
3837
+ rootKey: "todo_group",
3838
+ listParams: ["member_id", "team_ids"],
3839
+ showParams: ["current_member_id"],
3840
+ allowQueryJson: false
3841
+ });
3842
+ registerEntityCrudCommands(program, {
3843
+ command: "todos",
3844
+ description: "To-do operations",
3845
+ resourcePath: "todos",
3846
+ rootKey: "todo",
3847
+ requiredCreateFields: ["todo_group_id"],
3848
+ normalizeCreateBody: normalizeTodosCreateBody,
3849
+ listParams: ["todo_group_id", "start_date", "team_id", "member_id"],
3850
+ allowQueryJson: false
2131
3851
  });
2132
3852
  registerEntityCrudCommands(program, {
2133
3853
  command: "rock-collections",
2134
3854
  description: "Rock collection operations",
2135
3855
  resourcePath: "rock_collections",
2136
3856
  rootKey: "rock_collection",
2137
- listParams: ["include_archived", "member_id", "sort", "team_ids", "term"]
3857
+ listParams: ["member_id", "team_ids"],
3858
+ showParams: ["current_member_id"],
3859
+ allowQueryJson: false
2138
3860
  });
2139
3861
  registerEntityCrudCommands(program, {
2140
3862
  command: "knowledge",
2141
3863
  description: "Knowledge content operations",
2142
3864
  resourcePath: "contents",
2143
3865
  rootKey: "content",
3866
+ normalizeCreateBody: normalizeKnowledgeCreateBody,
2144
3867
  listParams: [
2145
3868
  "assigned",
2146
3869
  "contentable_id",
3870
+ "contentable_ids",
3871
+ "content_type",
2147
3872
  "contentable_type",
2148
- "include_all_rollups",
2149
- "include_completed",
3873
+ "focus_member_id",
3874
+ "focus_team_id",
2150
3875
  "member_id",
2151
3876
  "parent_content_id",
2152
- "team_id"
2153
- ]
3877
+ "sort",
3878
+ "status",
3879
+ "team_id",
3880
+ "term",
3881
+ "type"
3882
+ ],
3883
+ showParams: ["include_all_rollups"],
3884
+ allowQueryJson: false
2154
3885
  });
2155
3886
  registerEntityCrudCommands(program, {
2156
3887
  command: "stand-ups",
@@ -2163,74 +3894,118 @@ function registerSystemToolCommands(program) {
2163
3894
  "date",
2164
3895
  "end_date",
2165
3896
  "start_date",
3897
+ "team_id",
2166
3898
  "use_week_range"
2167
- ]
3899
+ ],
3900
+ allowQueryJson: false
2168
3901
  });
2169
3902
  registerEntityCrudCommands(program, {
2170
3903
  command: "news",
2171
3904
  description: "News operations",
2172
3905
  resourcePath: "headlines",
2173
3906
  rootKey: "headline",
2174
- listParams: ["meeting_id", "unread"]
3907
+ requiredCreateFields: ["member_id", "status", "headline_type"],
3908
+ normalizeCreateBody: normalizeNewsCreateBody,
3909
+ listParams: ["meeting_id", "team_id", "unread"],
3910
+ allowQueryJson: false,
3911
+ showQueryFactory: ({ id, organizationId }) => ({
3912
+ field: "headlines",
3913
+ variables: {
3914
+ organization_id: organizationId,
3915
+ page: 1,
3916
+ per: 200
3917
+ },
3918
+ selectionSet: "{ data { id type slug summary description memberId status rank createdAt updatedAt headlineType teamIds meetingId labelIds attributes } count currentPage totalPages }",
3919
+ transformData: (value) => {
3920
+ if (!value || typeof value !== "object") {
3921
+ return null;
3922
+ }
3923
+ const payload = value;
3924
+ const rows = Array.isArray(payload.data) ? payload.data : [];
3925
+ return rows.find((row) => {
3926
+ if (!row || typeof row !== "object") {
3927
+ return false;
3928
+ }
3929
+ return String(row.id ?? "") === id;
3930
+ }) ?? null;
3931
+ }
3932
+ })
2175
3933
  });
2176
3934
  registerEntityCrudCommands(program, {
2177
3935
  command: "questions",
2178
3936
  description: "Q&A forum operations",
2179
3937
  resourcePath: "questions",
2180
3938
  rootKey: "question",
2181
- listParams: ["answered", "asked", "member_id", "team_id", "term"]
3939
+ requiredCreateFields: ["member_id", "name"],
3940
+ normalizeCreateBody: normalizeQuestionsCreateBody,
3941
+ normalizeUpdateBody: normalizeQuestionsUpdateBody,
3942
+ listParams: ["answered", "asked"],
3943
+ allowQueryJson: false
2182
3944
  });
2183
3945
  registerEntityCrudCommands(program, {
2184
3946
  command: "pulse",
2185
3947
  description: "Pulse operations",
2186
3948
  resourcePath: "health_updates",
2187
3949
  rootKey: "health_update",
2188
- listParams: ["health_updatable_id", "health_updatable_type"]
3950
+ listField: "feedbacks",
3951
+ showField: "feedback",
3952
+ requiredCreateFields: ["health_updatable_id", "health_updatable_type", "member_id", "status"],
3953
+ normalizeCreateBody: normalizePulseCreateBody,
3954
+ listParams: ["last", "latest", "start_date", "name", "quarter", "year"],
3955
+ allowQueryJson: false
2189
3956
  });
2190
3957
  registerEntityCrudCommands(program, {
2191
3958
  command: "surveys",
2192
3959
  description: "Survey operations",
2193
3960
  resourcePath: "surveys",
2194
3961
  rootKey: "survey",
2195
- listParams: ["completed", "current_member", "due", "exclude_completed"]
3962
+ requiredCreateFields: ["name", "recipient_type"],
3963
+ normalizeCreateBody: normalizeSurveysCreateBody,
3964
+ normalizeUpdateBody: normalizeSurveysUpdateBody,
3965
+ listParams: ["completed", "current_member", "due", "exclude_completed", "sent"],
3966
+ allowQueryJson: false
2196
3967
  });
2197
3968
  registerEntityCrudCommands(program, {
2198
3969
  command: "feedbacks",
2199
3970
  description: "Feedback operations",
2200
3971
  resourcePath: "feedback",
2201
3972
  rootKey: "feedback",
2202
- listParams: ["last", "latest", "start_date"]
3973
+ requiredCreateFields: ["name", "quarter", "year"],
3974
+ normalizeCreateBody: normalizeFeedbacksCreateBody,
3975
+ normalizeUpdateBody: normalizeFeedbacksUpdateBody,
3976
+ listParams: ["last", "latest", "start_date"],
3977
+ allowQueryJson: false
2203
3978
  });
2204
3979
  registerEntityCrudCommands(program, {
2205
3980
  command: "accountability",
2206
3981
  description: "Accountability operations",
2207
3982
  resourcePath: "responsibilities",
2208
3983
  rootKey: "responsibility",
2209
- listParams: ["meeting_id", "term"]
3984
+ requiredCreateFields: ["name", "member_id"],
3985
+ normalizeCreateBody: normalizeAccountabilityCreateBody,
3986
+ normalizeUpdateBody: normalizeAccountabilityUpdateBody,
3987
+ listParams: [],
3988
+ allowQueryJson: false
2210
3989
  });
2211
3990
  registerEntityCrudCommands(program, {
2212
3991
  command: "kpis",
2213
3992
  description: "KPI operations",
2214
3993
  resourcePath: "smart_kpis",
2215
3994
  rootKey: "smart_kpi",
2216
- listParams: [
2217
- "annual_objective_id",
2218
- "include_archived",
2219
- "interval",
2220
- "meeting_id",
2221
- "member_id",
2222
- "quarterly_objective_id",
2223
- "smart_kpi_view_id",
2224
- "team_id",
2225
- "team_ids"
2226
- ]
3995
+ createMutationFactory: ({ body, organizationId }) => buildKpisCreateMutation({
3996
+ body,
3997
+ organizationId
3998
+ }),
3999
+ listParams: ["team_id", "member_id", "smart_kpi_view_id", "quarterly_objective_id"],
4000
+ allowQueryJson: false
2227
4001
  });
2228
4002
  registerEntityCrudCommands(program, {
2229
4003
  command: "scorecard-groups",
2230
4004
  description: "Scorecard group operations",
2231
4005
  resourcePath: "measurable_groups",
2232
4006
  rootKey: "measurable_group",
2233
- listParams: ["include_archived", "member_id", "name", "sort", "team_ids", "term"]
4007
+ listParams: ["include_archived", "member_id", "name", "sort", "team_ids", "term"],
4008
+ allowQueryJson: false
2234
4009
  });
2235
4010
  registerEntityCrudCommands(program, {
2236
4011
  command: "scorecards",
@@ -2238,6 +4013,7 @@ function registerSystemToolCommands(program) {
2238
4013
  resourcePath: "measurables",
2239
4014
  rootKey: "measurable",
2240
4015
  requiredCreateFields: ["measurable_group_id"],
4016
+ normalizeCreateBody: normalizeScorecardsCreateBody,
2241
4017
  listParams: [
2242
4018
  "annual_objective_id",
2243
4019
  "include_archived",
@@ -2249,21 +4025,24 @@ function registerSystemToolCommands(program) {
2249
4025
  "sort",
2250
4026
  "team_id",
2251
4027
  "team_ids"
2252
- ]
4028
+ ],
4029
+ allowQueryJson: false
2253
4030
  });
2254
4031
  registerEntityCrudCommands(program, {
2255
4032
  command: "customers",
2256
4033
  description: "CRM customer operations",
2257
4034
  resourcePath: "customers",
2258
4035
  rootKey: "customer",
2259
- listParams: ["member_id", "status", "term"]
4036
+ listParams: ["project_id", "meeting_id", "open", "team_id", "member_id"],
4037
+ allowQueryJson: false
2260
4038
  });
2261
4039
  registerEntityCrudCommands(program, {
2262
4040
  command: "contacts",
2263
4041
  description: "CRM contact operations",
2264
4042
  resourcePath: "contacts",
2265
4043
  rootKey: "contact",
2266
- listParams: ["customer_id", "member_id", "status", "term"]
4044
+ listParams: ["customer_id", "member_id"],
4045
+ allowQueryJson: false
2267
4046
  });
2268
4047
  }
2269
4048
 
@@ -2272,10 +4051,9 @@ var import_zod9 = require("zod");
2272
4051
  var idSchema8 = import_zod9.z.string().min(1);
2273
4052
  function registerTeamCommands(program) {
2274
4053
  const teams = program.command("teams").description("Team operations");
2275
- teams.command("list").option("--page <page>").option("--per <per>").option("--query-json <queryJson>").action(async (opts, cmd) => {
4054
+ teams.command("list").option("--page <page>").option("--per <per>").action(async (opts, cmd) => {
2276
4055
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2277
4056
  const organizationId = resolveOrganizationId(context.organizationId);
2278
- const extra = parseQueryJson(opts.queryJson ? String(opts.queryJson) : void 0);
2279
4057
  await runGraphqlQueryCommand({
2280
4058
  command: "teams.list",
2281
4059
  runtimeOptions: context.runtimeOptions,
@@ -2283,8 +4061,7 @@ function registerTeamCommands(program) {
2283
4061
  variables: normalizeGraphqlVariables2({
2284
4062
  organization_id: organizationId,
2285
4063
  page: opts.page,
2286
- per: opts.per,
2287
- ...extra
4064
+ per: opts.per
2288
4065
  }),
2289
4066
  isList: true
2290
4067
  });
@@ -2339,6 +4116,103 @@ function registerTeamCommands(program) {
2339
4116
  // src/commands/organizations.ts
2340
4117
  var import_zod10 = require("zod");
2341
4118
  var idSchema9 = import_zod10.z.string().min(1);
4119
+ function isRecord3(value) {
4120
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4121
+ }
4122
+ function ensureRootObject(body, rootKey) {
4123
+ const root = body[rootKey];
4124
+ if (!isRecord3(root)) {
4125
+ throw new CliError({
4126
+ message: `Invalid payload. Expected object at "${rootKey}".`,
4127
+ kind: "invalid_args",
4128
+ status: 400,
4129
+ exitCode: EXIT_CODES.invalidArgs
4130
+ });
4131
+ }
4132
+ return { ...root };
4133
+ }
4134
+ function asNonEmptyString4(value) {
4135
+ if (typeof value !== "string") {
4136
+ return void 0;
4137
+ }
4138
+ const trimmed = value.trim();
4139
+ return trimmed.length > 0 ? trimmed : void 0;
4140
+ }
4141
+ function normalizeOrganizationUpdateBody(body) {
4142
+ const organization = ensureRootObject(body, "organization");
4143
+ const detail = isRecord3(organization.organization_detail_attributes) ? { ...organization.organization_detail_attributes } : {};
4144
+ const workspaceName = asNonEmptyString4(organization.workspace_name);
4145
+ if (workspaceName) {
4146
+ detail.workspace_name = workspaceName;
4147
+ }
4148
+ delete organization.workspace_name;
4149
+ if (Object.keys(detail).length > 0) {
4150
+ organization.organization_detail_attributes = detail;
4151
+ }
4152
+ return { organization };
4153
+ }
4154
+ function normalizeOrganizationMetaProfileUpdateBody(body) {
4155
+ const root = ensureRootObject(body, "organization_meta_profile");
4156
+ const profile = isRecord3(root.profile) ? { ...root.profile } : {};
4157
+ const title = asNonEmptyString4(root.title);
4158
+ if (title) {
4159
+ const companyIdentity = isRecord3(profile.company_identity) ? { ...profile.company_identity } : {};
4160
+ companyIdentity.one_sentence_summary = title;
4161
+ profile.company_identity = companyIdentity;
4162
+ }
4163
+ const unsupported = Object.keys(root).filter((key) => key !== "profile" && key !== "title");
4164
+ if (unsupported.length > 0) {
4165
+ throw new CliError({
4166
+ message: "Invalid organization_meta_profile update payload. Use organization_meta_profile.profile.<section>.<field>.",
4167
+ kind: "invalid_args",
4168
+ status: 400,
4169
+ exitCode: EXIT_CODES.invalidArgs,
4170
+ details: { unsupportedKeys: unsupported, expectedRootKey: "profile" }
4171
+ });
4172
+ }
4173
+ if (Object.keys(profile).length === 0) {
4174
+ throw new CliError({
4175
+ message: "Missing required update fields for organization_meta_profile: profile.",
4176
+ kind: "invalid_args",
4177
+ status: 400,
4178
+ exitCode: EXIT_CODES.invalidArgs,
4179
+ details: { requiredFields: ["profile"], rootKey: "organization_meta_profile" }
4180
+ });
4181
+ }
4182
+ return { organization_meta_profile: { profile } };
4183
+ }
4184
+ function normalizeKeyMetricMetaProfileUpdateBody(body) {
4185
+ const root = ensureRootObject(body, "key_metric_meta_profile");
4186
+ const profile = isRecord3(root.profile) ? { ...root.profile } : {};
4187
+ const annualRevenue = asNonEmptyString4(root.annual_revenue);
4188
+ if (annualRevenue) {
4189
+ const financial = isRecord3(profile.financial) ? { ...profile.financial } : {};
4190
+ financial.revenue = annualRevenue;
4191
+ profile.financial = financial;
4192
+ }
4193
+ const unsupported = Object.keys(root).filter(
4194
+ (key) => key !== "profile" && key !== "annual_revenue"
4195
+ );
4196
+ if (unsupported.length > 0) {
4197
+ throw new CliError({
4198
+ message: "Invalid key_metric_meta_profile update payload. Use key_metric_meta_profile.profile.<section>.<field>.",
4199
+ kind: "invalid_args",
4200
+ status: 400,
4201
+ exitCode: EXIT_CODES.invalidArgs,
4202
+ details: { unsupportedKeys: unsupported, expectedRootKey: "profile" }
4203
+ });
4204
+ }
4205
+ if (Object.keys(profile).length === 0) {
4206
+ throw new CliError({
4207
+ message: "Missing required update fields for key_metric_meta_profile: profile.",
4208
+ kind: "invalid_args",
4209
+ status: 400,
4210
+ exitCode: EXIT_CODES.invalidArgs,
4211
+ details: { requiredFields: ["profile"], rootKey: "key_metric_meta_profile" }
4212
+ });
4213
+ }
4214
+ return { key_metric_meta_profile: { profile } };
4215
+ }
2342
4216
  function registerOrganizationCommands(program) {
2343
4217
  const organizations = program.command("organizations").description("Organization operations");
2344
4218
  organizations.command("show").option("--id <id>", "Organization ID (defaults to resolved organization context)").action(async (opts, cmd) => {
@@ -2360,7 +4234,8 @@ function registerOrganizationCommands(program) {
2360
4234
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2361
4235
  const fallbackId = resolveOrganizationId(context.organizationId);
2362
4236
  const id = idSchema9.parse(opts.id ?? fallbackId);
2363
- const body = __testables.normalizeBody(String(opts.dataJson), "organization");
4237
+ const rawBody = __testables.normalizeBody(String(opts.dataJson), "organization");
4238
+ const body = normalizeOrganizationUpdateBody(rawBody);
2364
4239
  await runGraphqlMutationCommand({
2365
4240
  command: "organizations.update",
2366
4241
  runtimeOptions: context.runtimeOptions,
@@ -2394,10 +4269,11 @@ function registerOrganizationCommands(program) {
2394
4269
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2395
4270
  const organizationId = resolveOrganizationId(context.organizationId);
2396
4271
  const id = idSchema9.parse(opts.id ?? organizationId);
2397
- const body = __testables.normalizeBody(
4272
+ const rawBody = __testables.normalizeBody(
2398
4273
  String(opts.dataJson),
2399
4274
  "organization_meta_profile"
2400
4275
  );
4276
+ const body = normalizeOrganizationMetaProfileUpdateBody(rawBody);
2401
4277
  await runGraphqlMutationCommand({
2402
4278
  command: "organizations.meta-profile.update",
2403
4279
  runtimeOptions: context.runtimeOptions,
@@ -2432,10 +4308,11 @@ function registerOrganizationCommands(program) {
2432
4308
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2433
4309
  const organizationId = resolveOrganizationId(context.organizationId);
2434
4310
  const id = idSchema9.parse(opts.id ?? organizationId);
2435
- const body = __testables.normalizeBody(
4311
+ const rawBody = __testables.normalizeBody(
2436
4312
  String(opts.dataJson),
2437
4313
  "key_metric_meta_profile"
2438
4314
  );
4315
+ const body = normalizeKeyMetricMetaProfileUpdateBody(rawBody);
2439
4316
  await runGraphqlMutationCommand({
2440
4317
  command: "organizations.key-metric-meta-profile.update",
2441
4318
  runtimeOptions: context.runtimeOptions,
@@ -2452,36 +4329,131 @@ function registerOrganizationCommands(program) {
2452
4329
  // src/commands/foundation.ts
2453
4330
  var import_zod11 = require("zod");
2454
4331
  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
2475
- });
2476
- });
2477
- strategicPlans.command("update").option("--id <id>", "Strategic plan ID (defaults to organization context)").requiredOption(
2478
- "--data-json <dataJson>",
4332
+ var STRATEGIC_PLAN_ALLOWED_UPDATE_KEYS = /* @__PURE__ */ new Set([
4333
+ "published_at",
4334
+ "profile",
4335
+ "strategic_plan_reads_attributes"
4336
+ ]);
4337
+ var STRATEGIC_OBJECTIVE_ALLOWED_UPDATE_KEYS = /* @__PURE__ */ new Set([
4338
+ "summary",
4339
+ "alignment_score",
4340
+ "published_at",
4341
+ "strategic_objective_reads_attributes"
4342
+ ]);
4343
+ function isRecord4(value) {
4344
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4345
+ }
4346
+ function ensureRootObject2(body, rootKey) {
4347
+ const root = body[rootKey];
4348
+ if (!isRecord4(root)) {
4349
+ throw new CliError({
4350
+ message: `Invalid payload. Expected object at "${rootKey}".`,
4351
+ kind: "invalid_args",
4352
+ status: 400,
4353
+ exitCode: EXIT_CODES.invalidArgs
4354
+ });
4355
+ }
4356
+ return { ...root };
4357
+ }
4358
+ function asNonEmptyString5(value) {
4359
+ if (typeof value !== "string") {
4360
+ return void 0;
4361
+ }
4362
+ const trimmed = value.trim();
4363
+ return trimmed.length > 0 ? trimmed : void 0;
4364
+ }
4365
+ function normalizeStrategicPlanUpdateBody(body) {
4366
+ const strategicPlan = ensureRootObject2(body, "strategic_plan");
4367
+ const unsupported = Object.keys(strategicPlan).filter(
4368
+ (key) => !STRATEGIC_PLAN_ALLOWED_UPDATE_KEYS.has(key)
4369
+ );
4370
+ if (unsupported.length > 0) {
4371
+ throw new CliError({
4372
+ message: "Invalid strategic_plan update payload. Allowed keys: published_at, profile, strategic_plan_reads_attributes.",
4373
+ kind: "invalid_args",
4374
+ status: 400,
4375
+ exitCode: EXIT_CODES.invalidArgs,
4376
+ details: {
4377
+ unsupportedKeys: unsupported,
4378
+ allowedKeys: Array.from(STRATEGIC_PLAN_ALLOWED_UPDATE_KEYS)
4379
+ }
4380
+ });
4381
+ }
4382
+ return { strategic_plan: strategicPlan };
4383
+ }
4384
+ function normalizeStrategicObjectiveUpdateBody(body) {
4385
+ const strategicObjective = ensureRootObject2(body, "strategic_objective");
4386
+ const title = asNonEmptyString5(strategicObjective.title);
4387
+ if (!asNonEmptyString5(strategicObjective.summary) && title) {
4388
+ strategicObjective.summary = title;
4389
+ }
4390
+ delete strategicObjective.title;
4391
+ const unsupported = Object.keys(strategicObjective).filter(
4392
+ (key) => !STRATEGIC_OBJECTIVE_ALLOWED_UPDATE_KEYS.has(key)
4393
+ );
4394
+ if (unsupported.length > 0) {
4395
+ throw new CliError({
4396
+ message: "Invalid strategic_objective update payload. Allowed keys: summary, alignment_score, published_at, strategic_objective_reads_attributes.",
4397
+ kind: "invalid_args",
4398
+ status: 400,
4399
+ exitCode: EXIT_CODES.invalidArgs,
4400
+ details: {
4401
+ unsupportedKeys: unsupported,
4402
+ allowedKeys: Array.from(STRATEGIC_OBJECTIVE_ALLOWED_UPDATE_KEYS)
4403
+ }
4404
+ });
4405
+ }
4406
+ return { strategic_objective: strategicObjective };
4407
+ }
4408
+ function normalizeAnnualObjectiveCreateBody(body) {
4409
+ const annualObjective = ensureRootObject2(body, "annual_objective");
4410
+ const title = asNonEmptyString5(annualObjective.title);
4411
+ if (!asNonEmptyString5(annualObjective.name) && title) {
4412
+ annualObjective.name = title;
4413
+ }
4414
+ delete annualObjective.title;
4415
+ return { annual_objective: annualObjective };
4416
+ }
4417
+ function normalizeQuarterlyObjectiveCreateBody(body) {
4418
+ const quarterlyObjective = ensureRootObject2(body, "quarterly_objective");
4419
+ const title = asNonEmptyString5(quarterlyObjective.title);
4420
+ if (!asNonEmptyString5(quarterlyObjective.name) && title) {
4421
+ quarterlyObjective.name = title;
4422
+ }
4423
+ delete quarterlyObjective.title;
4424
+ return { quarterly_objective: quarterlyObjective };
4425
+ }
4426
+ function registerFoundationCommands(program) {
4427
+ const foundation = program.command("foundation").description("Foundation operations");
4428
+ const strategicPlans = foundation.command("strategic-plans").description("Strategic plan operations");
4429
+ const strategicObjectives = foundation.command("strategic-objectives").description("Strategic objective operations");
4430
+ 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) => {
4431
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
4432
+ const organizationId = resolveOrganizationId(context.organizationId);
4433
+ const id = idSchema10.parse(opts.id ?? organizationId);
4434
+ await runGraphqlQueryCommand({
4435
+ command: "foundation.strategic-plans.show",
4436
+ runtimeOptions: context.runtimeOptions,
4437
+ field: "strategic_plan",
4438
+ variables: normalizeGraphqlVariables2({
4439
+ organization_id: organizationId,
4440
+ id,
4441
+ progress_scope: opts.progressScope,
4442
+ all_progress: opts.allProgress,
4443
+ all: opts.all
4444
+ }),
4445
+ isShow: true
4446
+ });
4447
+ });
4448
+ strategicPlans.command("update").option("--id <id>", "Strategic plan ID (defaults to organization context)").requiredOption(
4449
+ "--data-json <dataJson>",
2479
4450
  'JSON object for strategic_plan or {"strategic_plan": {...}}'
2480
4451
  ).action(async (opts, cmd) => {
2481
4452
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2482
4453
  const organizationId = resolveOrganizationId(context.organizationId);
2483
4454
  const id = idSchema10.parse(opts.id ?? organizationId);
2484
- const body = __testables.normalizeBody(String(opts.dataJson), "strategic_plan");
4455
+ const rawBody = __testables.normalizeBody(String(opts.dataJson), "strategic_plan");
4456
+ const body = normalizeStrategicPlanUpdateBody(rawBody);
2485
4457
  await runGraphqlMutationCommand({
2486
4458
  command: "foundation.strategic-plans.update",
2487
4459
  runtimeOptions: context.runtimeOptions,
@@ -2518,10 +4490,11 @@ function registerFoundationCommands(program) {
2518
4490
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2519
4491
  const organizationId = resolveOrganizationId(context.organizationId);
2520
4492
  const id = idSchema10.parse(opts.id ?? organizationId);
2521
- const body = __testables.normalizeBody(
4493
+ const rawBody = __testables.normalizeBody(
2522
4494
  String(opts.dataJson),
2523
4495
  "strategic_objective"
2524
4496
  );
4497
+ const body = normalizeStrategicObjectiveUpdateBody(rawBody);
2525
4498
  await runGraphqlMutationCommand({
2526
4499
  command: "foundation.strategic-objectives.update",
2527
4500
  runtimeOptions: context.runtimeOptions,
@@ -2538,16 +4511,20 @@ function registerFoundationCommands(program) {
2538
4511
  description: "Foundation annual objective operations",
2539
4512
  resourcePath: "annual_objectives",
2540
4513
  rootKey: "annual_objective",
2541
- requiredCreateFields: ["strategic_objective_id"],
2542
- listParams: []
4514
+ requiredCreateFields: ["strategic_objective_id", "name"],
4515
+ normalizeCreateBody: normalizeAnnualObjectiveCreateBody,
4516
+ listParams: [],
4517
+ allowQueryJson: false
2543
4518
  });
2544
4519
  registerEntityCrudCommands(foundation, {
2545
4520
  command: "quarterly-objectives",
2546
4521
  description: "Foundation quarterly objective operations",
2547
4522
  resourcePath: "quarterly_objectives",
2548
4523
  rootKey: "quarterly_objective",
2549
- requiredCreateFields: ["strategic_objective_id", "annual_objective_id"],
2550
- listParams: ["annual_objective_id"]
4524
+ requiredCreateFields: ["strategic_objective_id", "annual_objective_id", "name"],
4525
+ normalizeCreateBody: normalizeQuarterlyObjectiveCreateBody,
4526
+ listParams: [],
4527
+ allowQueryJson: false
2551
4528
  });
2552
4529
  }
2553
4530
 
@@ -2650,6 +4627,20 @@ function normalizeListPayload(payload, parentKind, parentIdFallback, parentTyped
2650
4627
  totalPages: record.totalPages ?? 1
2651
4628
  };
2652
4629
  }
4630
+ function normalizeSubtaskCreateBody(body) {
4631
+ const subtask = body.subtask;
4632
+ if (!subtask || typeof subtask !== "object" || Array.isArray(subtask)) {
4633
+ return body;
4634
+ }
4635
+ const subtaskRecord = subtask;
4636
+ const summary = typeof subtaskRecord.summary === "string" ? subtaskRecord.summary.trim() : void 0;
4637
+ const hasName = typeof subtaskRecord.name === "string" && subtaskRecord.name.trim().length > 0;
4638
+ if (!hasName && summary && summary.length > 0) {
4639
+ subtaskRecord.name = summary;
4640
+ }
4641
+ delete subtaskRecord.summary;
4642
+ return body;
4643
+ }
2653
4644
  function registerChildCommands(program, config) {
2654
4645
  const command = program.command(config.command).description(config.description);
2655
4646
  command.command("list").requiredOption(`--${config.parentFlag} <${config.parentFlag}>`).option("--page <page>").option("--per <per>").action(async (opts, cmd) => {
@@ -2680,7 +4671,10 @@ function registerChildCommands(program, config) {
2680
4671
  command.command("create").requiredOption("--data-json <dataJson>").action(async (opts, cmd) => {
2681
4672
  const context = await resolveCommandContext(cmd.optsWithGlobals());
2682
4673
  const organizationId = resolveOrganizationId(context.organizationId);
2683
- const body = normalizeBody2(String(opts.dataJson), config.rootKey);
4674
+ let body = normalizeBody2(String(opts.dataJson), config.rootKey);
4675
+ if (config.normalizeCreateBody) {
4676
+ body = config.normalizeCreateBody(body);
4677
+ }
2684
4678
  assertRequiredParent(body, config.rootKey, config.parentFlag.replace(/-/g, "_"));
2685
4679
  await runGraphqlMutationCommand({
2686
4680
  command: `${config.command}.create`,
@@ -2743,7 +4737,8 @@ function registerChildEntityCommands(program) {
2743
4737
  updateOperationName: "UpdateSubtask",
2744
4738
  destroyOperationName: "DestroySubtask",
2745
4739
  listSelectionSet: "{ data { id type name status taskId attributes } count currentPage totalPages }",
2746
- listParentTypedField: "taskId"
4740
+ listParentTypedField: "taskId",
4741
+ normalizeCreateBody: normalizeSubtaskCreateBody
2747
4742
  });
2748
4743
  registerChildCommands(program, {
2749
4744
  command: "milestones",
@@ -2887,7 +4882,7 @@ function registerNoteCommands(program) {
2887
4882
  per: opts.per
2888
4883
  }),
2889
4884
  isList: true,
2890
- selectionSet: "{ count currentPage totalPages data { id type name contentableType contentableId memberId focusMemberId focusTeamId attributes } }"
4885
+ selectionSet: "{ count currentPage totalPages data { id type name slug firstChildSlug rootParentSlug status contentType lastEdited organizationId memberId focusMemberId focusTeamId teamId creatorId createdAt updatedAt childCount assignmentType contentableId contentableSlug contentableType votesTotal labelIds rootContentId parentContentId attributes } }"
2891
4886
  });
2892
4887
  });
2893
4888
  notes.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
@@ -2904,7 +4899,7 @@ function registerNoteCommands(program) {
2904
4899
  id
2905
4900
  }),
2906
4901
  isShow: true,
2907
- selectionSet: "{ id type name contentableType contentableId memberId focusMemberId focusTeamId attributes }"
4902
+ selectionSet: "{ id type name slug firstChildSlug rootParentSlug status contentType lastEdited organizationId memberId focusMemberId focusTeamId teamId creatorId createdAt updatedAt childCount assignmentType contentableId contentableSlug contentableType votesTotal labelIds rootContentId parentContentId attributes }"
2908
4903
  });
2909
4904
  });
2910
4905
  notes.command("update").requiredOption("--id <id>").option("--name <name>").option("--body <body>").option("--status <status>").action(async (opts, cmd) => {
@@ -3025,8 +5020,980 @@ function registerNoteCommands(program) {
3025
5020
  });
3026
5021
  }
3027
5022
 
5023
+ // src/commands/markdownTree.ts
5024
+ var import_zod14 = require("zod");
5025
+ var nonEmptyString2 = import_zod14.z.string().min(1);
5026
+ var nonNegativeInt = import_zod14.z.coerce.number().int().min(0);
5027
+ function addScopeOptions(command) {
5028
+ 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");
5029
+ }
5030
+ function parseScopeOptions(raw) {
5031
+ const parsed = {
5032
+ toolKey: nonEmptyString2.parse(raw.toolKey),
5033
+ nodeKey: nonEmptyString2.parse(raw.nodeKey)
5034
+ };
5035
+ if (typeof raw.parentId === "string" && raw.parentId.trim() !== "") {
5036
+ parsed.parentId = raw.parentId.trim();
5037
+ }
5038
+ if (typeof raw.recordId === "string" && raw.recordId.trim() !== "") {
5039
+ parsed.recordId = raw.recordId.trim();
5040
+ }
5041
+ if (typeof raw.memberId === "string" && raw.memberId.trim() !== "") {
5042
+ parsed.memberId = raw.memberId.trim();
5043
+ }
5044
+ if (typeof raw.teamId === "string" && raw.teamId.trim() !== "") {
5045
+ parsed.teamId = raw.teamId.trim();
5046
+ }
5047
+ if (typeof raw.contentType === "string" && raw.contentType.trim() !== "") {
5048
+ parsed.contentType = raw.contentType.trim();
5049
+ }
5050
+ if (raw.treeView === true) {
5051
+ parsed.treeView = true;
5052
+ }
5053
+ return parsed;
5054
+ }
5055
+ function baseNodeFields() {
5056
+ return [
5057
+ "toolKey",
5058
+ "nodeKey",
5059
+ "nodeKind",
5060
+ "runtimeLabel",
5061
+ "resolvedScope { parentId recordId memberId teamId contentType }",
5062
+ "isLeaf",
5063
+ "treeView",
5064
+ "details"
5065
+ ].join(" ");
5066
+ }
5067
+ function buildChildSelection(depth) {
5068
+ if (depth <= 0) return "";
5069
+ const nested = buildChildSelection(depth - 1);
5070
+ return nested.length > 0 ? `children { ${baseNodeFields()} ${nested} }` : `children { ${baseNodeFields()} }`;
5071
+ }
5072
+ function buildNodeSelectionSet(depth) {
5073
+ const nested = buildChildSelection(depth);
5074
+ return nested.length > 0 ? `{ ${baseNodeFields()} ${nested} }` : `{ ${baseNodeFields()} }`;
5075
+ }
5076
+ function requireExplicitDepth(rawDepth) {
5077
+ if (rawDepth === void 0 || rawDepth === null || rawDepth === "") {
5078
+ throw new CliError({
5079
+ message: "Missing required --depth for markdown-tree subtree.",
5080
+ kind: "invalid_args",
5081
+ status: 400,
5082
+ exitCode: EXIT_CODES.invalidArgs
5083
+ });
5084
+ }
5085
+ return nonNegativeInt.parse(rawDepth);
5086
+ }
5087
+ function registerMarkdownTreeCommands(program) {
5088
+ const markdownTree = program.command("markdown-tree").description("Markdown tree traversal operations");
5089
+ markdownTree.command("root").option("--tree-view").action(async (opts, cmd) => {
5090
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5091
+ const organizationId = resolveOrganizationId(context.organizationId);
5092
+ await runGraphqlQueryCommand({
5093
+ command: "markdown-tree.root",
5094
+ operationName: "MarkdownTreeRoot",
5095
+ runtimeOptions: context.runtimeOptions,
5096
+ field: "markdown_tree_root",
5097
+ variables: {
5098
+ organization_id: organizationId,
5099
+ tree_view: opts.treeView === true ? true : void 0
5100
+ },
5101
+ selectionSet: buildNodeSelectionSet(1),
5102
+ isShow: true
5103
+ });
5104
+ });
5105
+ addScopeOptions(markdownTree.command("resolve")).action(async (opts, cmd) => {
5106
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5107
+ const organizationId = resolveOrganizationId(context.organizationId);
5108
+ const scope = parseScopeOptions(opts);
5109
+ await runGraphqlQueryCommand({
5110
+ command: "markdown-tree.resolve",
5111
+ operationName: "MarkdownTreeNode",
5112
+ runtimeOptions: context.runtimeOptions,
5113
+ field: "markdown_tree_node",
5114
+ variables: {
5115
+ organization_id: organizationId,
5116
+ tool_key: scope.toolKey,
5117
+ node_key: scope.nodeKey,
5118
+ parent_id: scope.parentId,
5119
+ record_id: scope.recordId,
5120
+ member_id: scope.memberId,
5121
+ team_id: scope.teamId,
5122
+ content_type: scope.contentType,
5123
+ tree_view: scope.treeView
5124
+ },
5125
+ selectionSet: buildNodeSelectionSet(1),
5126
+ isShow: true
5127
+ });
5128
+ });
5129
+ addScopeOptions(markdownTree.command("children")).action(async (opts, cmd) => {
5130
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5131
+ const organizationId = resolveOrganizationId(context.organizationId);
5132
+ const scope = parseScopeOptions(opts);
5133
+ await runGraphqlQueryCommand({
5134
+ command: "markdown-tree.children",
5135
+ operationName: "MarkdownTreeChildren",
5136
+ runtimeOptions: context.runtimeOptions,
5137
+ field: "markdown_tree_children",
5138
+ variables: {
5139
+ organization_id: organizationId,
5140
+ tool_key: scope.toolKey,
5141
+ node_key: scope.nodeKey,
5142
+ parent_id: scope.parentId,
5143
+ record_id: scope.recordId,
5144
+ member_id: scope.memberId,
5145
+ team_id: scope.teamId,
5146
+ content_type: scope.contentType,
5147
+ tree_view: scope.treeView
5148
+ },
5149
+ selectionSet: buildNodeSelectionSet(1),
5150
+ isShow: true
5151
+ });
5152
+ });
5153
+ addScopeOptions(
5154
+ markdownTree.command("subtree").requiredOption("--depth <depth>")
5155
+ ).action(async (opts, cmd) => {
5156
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5157
+ const organizationId = resolveOrganizationId(context.organizationId);
5158
+ const scope = parseScopeOptions(opts);
5159
+ const depth = requireExplicitDepth(opts.depth);
5160
+ await runGraphqlQueryCommand({
5161
+ command: "markdown-tree.subtree",
5162
+ operationName: "MarkdownTreeSubtree",
5163
+ runtimeOptions: context.runtimeOptions,
5164
+ field: "markdown_tree_subtree",
5165
+ variables: {
5166
+ organization_id: organizationId,
5167
+ tool_key: scope.toolKey,
5168
+ node_key: scope.nodeKey,
5169
+ parent_id: scope.parentId,
5170
+ record_id: scope.recordId,
5171
+ member_id: scope.memberId,
5172
+ team_id: scope.teamId,
5173
+ content_type: scope.contentType,
5174
+ tree_view: scope.treeView,
5175
+ depth
5176
+ },
5177
+ selectionSet: buildNodeSelectionSet(depth + 1),
5178
+ isShow: true
5179
+ });
5180
+ });
5181
+ }
5182
+
5183
+ // src/commands/navigation.ts
5184
+ var import_zod15 = require("zod");
5185
+
5186
+ // src/internalOptions.ts
5187
+ var INTERNAL_OPTIONS_KEY = "__waveInternalOptions";
5188
+ function asRecord3(value) {
5189
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
5190
+ return null;
5191
+ }
5192
+ return value;
5193
+ }
5194
+ function setInternalCliOptions(program, options) {
5195
+ if (!options) return;
5196
+ const target = program;
5197
+ target[INTERNAL_OPTIONS_KEY] = { ...options };
5198
+ }
5199
+ function getInternalCliOptions(command) {
5200
+ let current = command;
5201
+ while (current) {
5202
+ const record = asRecord3(current[INTERNAL_OPTIONS_KEY]);
5203
+ if (record) {
5204
+ return {
5205
+ enableRetryOnEmptyPhrase: record.enableRetryOnEmptyPhrase === true
5206
+ };
5207
+ }
5208
+ current = current.parent ?? null;
5209
+ }
5210
+ return {};
5211
+ }
5212
+
5213
+ // src/commands/navigation.ts
5214
+ var nonEmpty = import_zod15.z.string().min(1);
5215
+ var nonNegativeInt2 = import_zod15.z.coerce.number().int().min(0);
5216
+ var MIGRATED_BRANCHES = ["directory", "projects", "knowledge"];
5217
+ function normalizeText(input) {
5218
+ if (typeof input !== "string") return "";
5219
+ return input.trim().toLowerCase().replace(/\s+/g, " ");
5220
+ }
5221
+ function toDisplay(input) {
5222
+ if (typeof input !== "string") return "";
5223
+ const value = input.trim();
5224
+ return value.length > 0 ? value : "";
5225
+ }
5226
+ function asObject(value) {
5227
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
5228
+ }
5229
+ function asArray(value) {
5230
+ return Array.isArray(value) ? value : [];
5231
+ }
5232
+ function parseScopeFromOptions(raw) {
5233
+ const scope = {
5234
+ toolKey: nonEmpty.parse(raw.toolKey),
5235
+ nodeKey: nonEmpty.parse(raw.nodeKey)
5236
+ };
5237
+ if (typeof raw.parentId === "string" && raw.parentId.trim() !== "") {
5238
+ scope.parentId = raw.parentId.trim();
5239
+ }
5240
+ if (typeof raw.recordId === "string" && raw.recordId.trim() !== "") {
5241
+ scope.recordId = raw.recordId.trim();
5242
+ }
5243
+ if (typeof raw.memberId === "string" && raw.memberId.trim() !== "") {
5244
+ scope.memberId = raw.memberId.trim();
5245
+ }
5246
+ if (typeof raw.teamId === "string" && raw.teamId.trim() !== "") {
5247
+ scope.teamId = raw.teamId.trim();
5248
+ }
5249
+ if (typeof raw.contentType === "string" && raw.contentType.trim() !== "") {
5250
+ scope.contentType = raw.contentType.trim();
5251
+ }
5252
+ if (raw.treeView === true) {
5253
+ scope.treeView = true;
5254
+ }
5255
+ return scope;
5256
+ }
5257
+ function parseOptionalScopeFromOptions(raw) {
5258
+ if (typeof raw.toolKey !== "string" || raw.toolKey.trim() === "") {
5259
+ return null;
5260
+ }
5261
+ if (typeof raw.nodeKey !== "string" || raw.nodeKey.trim() === "") {
5262
+ return null;
5263
+ }
5264
+ return parseScopeFromOptions(raw);
5265
+ }
5266
+ function scopeFromCandidate(candidate, treeView) {
5267
+ const scopeObj = asObject(candidate.scope);
5268
+ const resolvedScopeObj = asObject(candidate.resolvedScope);
5269
+ const normalizedScope = Object.keys(scopeObj).length > 0 ? scopeObj : resolvedScopeObj;
5270
+ const toolKey = toDisplay(candidate.toolKey);
5271
+ const nodeKey = toDisplay(candidate.nodeKey);
5272
+ return {
5273
+ toolKey,
5274
+ nodeKey,
5275
+ parentId: toDisplay(normalizedScope.parentId) || void 0,
5276
+ recordId: toDisplay(normalizedScope.recordId) || void 0,
5277
+ memberId: toDisplay(normalizedScope.memberId) || void 0,
5278
+ teamId: toDisplay(normalizedScope.teamId) || void 0,
5279
+ contentType: toDisplay(normalizedScope.contentType) || void 0,
5280
+ treeView
5281
+ };
5282
+ }
5283
+ function notFoundEnvelope(params) {
5284
+ return {
5285
+ ok: false,
5286
+ command: params.command,
5287
+ status: 404,
5288
+ data: null,
5289
+ error: {
5290
+ code: "not_found",
5291
+ message: params.message,
5292
+ details: {}
5293
+ },
5294
+ meta: {
5295
+ requestId: params.requestId ?? "local_error"
5296
+ }
5297
+ };
5298
+ }
5299
+ function ambiguityEnvelope(params) {
5300
+ return {
5301
+ ok: false,
5302
+ command: params.command,
5303
+ status: 409,
5304
+ data: null,
5305
+ error: {
5306
+ code: "ambiguous_match",
5307
+ message: params.message,
5308
+ details: {
5309
+ candidates: params.candidates
5310
+ }
5311
+ },
5312
+ meta: {
5313
+ requestId: params.requestId ?? "local_error"
5314
+ }
5315
+ };
5316
+ }
5317
+ function unsupportedBranchEnvelope(params) {
5318
+ const tool = params.tool ?? "unknown";
5319
+ return {
5320
+ ok: false,
5321
+ command: params.command,
5322
+ status: 400,
5323
+ data: null,
5324
+ error: {
5325
+ code: "unsupported_branch",
5326
+ message: `This branch isn't migrated to markdown-tree yet: ${tool}. Try directory/projects/knowledge.`,
5327
+ details: {
5328
+ tool,
5329
+ migratedBranches: [...MIGRATED_BRANCHES],
5330
+ originalError: params.originalError ?? null
5331
+ }
5332
+ },
5333
+ meta: {
5334
+ requestId: params.requestId ?? "local_error"
5335
+ }
5336
+ };
5337
+ }
5338
+ function parseToolFromGraphqlError(errorBody) {
5339
+ const errorObj = asObject(errorBody);
5340
+ const details = asObject(errorObj.details);
5341
+ const errors = asArray(details.errors);
5342
+ for (const item of errors) {
5343
+ const message = toDisplay(item.message);
5344
+ if (message === "") continue;
5345
+ const match = message.match(/tool_key=([a-zA-Z0-9_]+)/);
5346
+ if (match?.[1]) {
5347
+ return match[1];
5348
+ }
5349
+ }
5350
+ return null;
5351
+ }
5352
+ function toolHintFromPathLike(value) {
5353
+ const text = toDisplay(value);
5354
+ if (text === "") return null;
5355
+ const [first] = text.split("/");
5356
+ return first ? first.trim() : null;
5357
+ }
5358
+ function unsupportedToolFromHints(params) {
5359
+ const fromError = parseToolFromGraphqlError(params.envelopeError);
5360
+ if (fromError) return fromError;
5361
+ return toDisplay(params.explicitTool) || toolHintFromPathLike(params.underPath) || toolHintFromPathLike(params.queryLike) || "unknown";
5362
+ }
5363
+ async function requestTraversal(params) {
5364
+ const config = getConfig(params.runtimeOptions);
5365
+ const result = await graphqlRequest({
5366
+ config,
5367
+ command: params.command,
5368
+ operationName: params.operationName,
5369
+ operationType: "query",
5370
+ field: params.field,
5371
+ variables: params.variables,
5372
+ selectionSet: buildNodeSelectionSet(params.depth),
5373
+ isShow: true
5374
+ });
5375
+ if (!result.envelope.ok) {
5376
+ if (result.envelope.error?.code === "unsupported_branch") {
5377
+ printEnvelopeAndExit({
5378
+ envelope: unsupportedBranchEnvelope({
5379
+ command: params.command,
5380
+ requestId: result.envelope.meta.requestId,
5381
+ tool: unsupportedToolFromHints({
5382
+ explicitTool: params.variables.tool_key,
5383
+ envelopeError: result.envelope.error
5384
+ }),
5385
+ originalError: asObject(result.envelope.error)
5386
+ }),
5387
+ exitCode: result.exitCode
5388
+ });
5389
+ }
5390
+ printEnvelopeAndExit({
5391
+ envelope: result.envelope,
5392
+ exitCode: result.exitCode
5393
+ });
5394
+ }
5395
+ const data = asObject(result.envelope.data);
5396
+ return asObject(data[params.field]);
5397
+ }
5398
+ function findSelectionSet() {
5399
+ return `{
5400
+ query
5401
+ underPath
5402
+ candidates {
5403
+ label
5404
+ canonicalPath
5405
+ toolKey
5406
+ nodeKey
5407
+ nodeKind
5408
+ isLeaf
5409
+ scope { parentId recordId memberId teamId contentType }
5410
+ resolvedScope { parentId recordId memberId teamId contentType }
5411
+ matchType
5412
+ rank
5413
+ aliasMatched
5414
+ breadcrumb
5415
+ }
5416
+ }`;
5417
+ }
5418
+ async function requestFind(params) {
5419
+ const config = getConfig(params.runtimeOptions);
5420
+ const result = await graphqlRequest({
5421
+ config,
5422
+ command: params.command,
5423
+ operationName: "MarkdownTreeFind",
5424
+ operationType: "query",
5425
+ field: "markdown_tree_find",
5426
+ variables: {
5427
+ organization_id: params.organizationId,
5428
+ query: params.query,
5429
+ under_path: params.underPath,
5430
+ tool_key: params.toolKey,
5431
+ node_key: params.nodeKey,
5432
+ limit: params.limit
5433
+ },
5434
+ selectionSet: findSelectionSet(),
5435
+ isShow: true
5436
+ });
5437
+ if (!result.envelope.ok) {
5438
+ if (result.envelope.error?.code === "unsupported_branch") {
5439
+ printEnvelopeAndExit({
5440
+ envelope: unsupportedBranchEnvelope({
5441
+ command: params.command,
5442
+ requestId: result.envelope.meta.requestId,
5443
+ tool: unsupportedToolFromHints({
5444
+ explicitTool: params.toolKey,
5445
+ underPath: params.underPath,
5446
+ queryLike: params.query,
5447
+ envelopeError: result.envelope.error
5448
+ }),
5449
+ originalError: asObject(result.envelope.error)
5450
+ }),
5451
+ exitCode: result.exitCode
5452
+ });
5453
+ }
5454
+ printEnvelopeAndExit({
5455
+ envelope: result.envelope,
5456
+ exitCode: result.exitCode
5457
+ });
5458
+ }
5459
+ const data = asObject(result.envelope.data);
5460
+ const payload = asObject(data.markdown_tree_find);
5461
+ return {
5462
+ ...payload,
5463
+ candidates: asArray(payload.candidates)
5464
+ };
5465
+ }
5466
+ function matchTypePrecedence(candidate) {
5467
+ const matchType = toDisplay(candidate.matchType).toLowerCase();
5468
+ const order = {
5469
+ exact_label: 0,
5470
+ exact_path: 1,
5471
+ prefix_label: 2,
5472
+ path_prefix: 3,
5473
+ path_fragment: 4,
5474
+ alias_match: 5,
5475
+ fuzzy: 6
5476
+ };
5477
+ return order[matchType] ?? Number.POSITIVE_INFINITY;
5478
+ }
5479
+ function isTopCandidateDominant(candidates) {
5480
+ if (candidates.length <= 1) {
5481
+ return true;
5482
+ }
5483
+ const first = candidates[0];
5484
+ const second = candidates[1];
5485
+ if (typeof first.rank === "number" && typeof second.rank === "number") {
5486
+ return first.rank < second.rank;
5487
+ }
5488
+ const firstMatch = matchTypePrecedence(first);
5489
+ const secondMatch = matchTypePrecedence(second);
5490
+ if (Number.isFinite(firstMatch) || Number.isFinite(secondMatch)) {
5491
+ return firstMatch < secondMatch;
5492
+ }
5493
+ return false;
5494
+ }
5495
+ function findExactPathMatches(candidates, path) {
5496
+ const target = normalizeText(path);
5497
+ if (target === "") return [];
5498
+ return candidates.filter((candidate) => {
5499
+ const canonicalPath = toDisplay(candidate.canonicalPath);
5500
+ return normalizeText(canonicalPath) === target;
5501
+ });
5502
+ }
5503
+ async function resolvePathScope(params) {
5504
+ const findPayload = await requestFind({
5505
+ command: params.command,
5506
+ runtimeOptions: params.runtimeOptions,
5507
+ organizationId: params.organizationId,
5508
+ query: params.path,
5509
+ underPath: params.underPath,
5510
+ limit: 25
5511
+ });
5512
+ const exactMatches = findExactPathMatches(findPayload.candidates, params.path);
5513
+ if (exactMatches.length === 1) {
5514
+ return {
5515
+ scope: scopeFromCandidate(exactMatches[0], params.treeView),
5516
+ match: exactMatches[0],
5517
+ ambiguous: []
5518
+ };
5519
+ }
5520
+ if (exactMatches.length > 1) {
5521
+ return {
5522
+ ambiguous: exactMatches.slice(0, 10)
5523
+ };
5524
+ }
5525
+ return {
5526
+ ambiguous: []
5527
+ };
5528
+ }
5529
+ function isMultiWordQuery(query) {
5530
+ const parts = query.trim().split(/\s+/).filter((part) => part.length > 0);
5531
+ return parts.length > 1;
5532
+ }
5533
+ function reduceMultiWordQuery(query) {
5534
+ const tokens = query.trim().split(/\s+/).map((token) => token.replace(/^[^a-zA-Z0-9]+|[^a-zA-Z0-9]+$/g, "")).filter((token) => token.length > 0);
5535
+ if (tokens.length <= 1) return null;
5536
+ const meaningful = tokens.filter((token) => token.length >= 3);
5537
+ const selected = meaningful.length > 0 ? meaningful[meaningful.length - 1] : tokens[tokens.length - 1];
5538
+ return selected ?? null;
5539
+ }
5540
+ function registerNavigationCommands(program) {
5541
+ 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) => {
5542
+ const globals = cmd.optsWithGlobals();
5543
+ const context = await resolveCommandContext(globals);
5544
+ const organizationId = resolveOrganizationId(context.organizationId);
5545
+ const internalOptions = getInternalCliOptions(cmd);
5546
+ const limit = typeof opts.limit === "string" && opts.limit.trim() !== "" ? Math.max(1, Number.parseInt(opts.limit, 10) || 20) : 20;
5547
+ const underPath = typeof opts.under === "string" && opts.under.trim() !== "" ? opts.under.trim() : typeof opts.path === "string" && opts.path.trim() !== "" ? opts.path.trim() : void 0;
5548
+ const payload = await requestFind({
5549
+ command: "find",
5550
+ runtimeOptions: context.runtimeOptions,
5551
+ organizationId,
5552
+ query,
5553
+ underPath,
5554
+ toolKey: typeof opts.toolKey === "string" ? opts.toolKey : void 0,
5555
+ nodeKey: typeof opts.nodeKey === "string" ? opts.nodeKey : void 0,
5556
+ limit
5557
+ });
5558
+ let finalPayload = payload;
5559
+ let assistantRecovery;
5560
+ if (internalOptions.enableRetryOnEmptyPhrase === true && payload.candidates.length === 0 && isMultiWordQuery(query)) {
5561
+ const retryQuery = reduceMultiWordQuery(query);
5562
+ if (retryQuery && normalizeText(retryQuery) !== normalizeText(query)) {
5563
+ finalPayload = await requestFind({
5564
+ command: "find",
5565
+ runtimeOptions: context.runtimeOptions,
5566
+ organizationId,
5567
+ query: retryQuery,
5568
+ underPath,
5569
+ toolKey: typeof opts.toolKey === "string" ? opts.toolKey : void 0,
5570
+ nodeKey: typeof opts.nodeKey === "string" ? opts.nodeKey : void 0,
5571
+ limit
5572
+ });
5573
+ assistantRecovery = {
5574
+ triggered: true,
5575
+ originalQuery: query,
5576
+ retryQuery,
5577
+ reason: "empty_multi_word_query"
5578
+ };
5579
+ }
5580
+ }
5581
+ printEnvelopeAndExit({
5582
+ envelope: {
5583
+ ok: true,
5584
+ command: "find",
5585
+ status: 200,
5586
+ data: assistantRecovery ? {
5587
+ ...finalPayload,
5588
+ assistantRecovery
5589
+ } : finalPayload,
5590
+ error: null,
5591
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
5592
+ }
5593
+ });
5594
+ });
5595
+ 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) => {
5596
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5597
+ const organizationId = resolveOrganizationId(context.organizationId);
5598
+ const limit = typeof opts.limit === "string" && opts.limit.trim() !== "" ? Math.max(1, Number.parseInt(opts.limit, 10) || 10) : 10;
5599
+ const underPath = typeof opts.under === "string" && opts.under.trim() !== "" ? opts.under.trim() : typeof opts.path === "string" && opts.path.trim() !== "" ? opts.path.trim() : void 0;
5600
+ const payload = await requestFind({
5601
+ command: "open",
5602
+ runtimeOptions: context.runtimeOptions,
5603
+ organizationId,
5604
+ query: name,
5605
+ underPath,
5606
+ toolKey: typeof opts.toolKey === "string" ? opts.toolKey : void 0,
5607
+ nodeKey: typeof opts.nodeKey === "string" ? opts.nodeKey : void 0,
5608
+ limit
5609
+ });
5610
+ const candidates = payload.candidates;
5611
+ if (candidates.length === 0) {
5612
+ printEnvelopeAndExit({
5613
+ envelope: notFoundEnvelope({
5614
+ command: "open",
5615
+ message: `No node matched "${name}".`
5616
+ }),
5617
+ exitCode: EXIT_CODES.notFound
5618
+ });
5619
+ }
5620
+ if (candidates.length > 1 && !isTopCandidateDominant(candidates)) {
5621
+ printEnvelopeAndExit({
5622
+ envelope: ambiguityEnvelope({
5623
+ command: "open",
5624
+ message: `Multiple nodes matched "${name}".`,
5625
+ candidates: candidates.slice(0, 10)
5626
+ }),
5627
+ exitCode: EXIT_CODES.generic
5628
+ });
5629
+ }
5630
+ const selected = candidates[0];
5631
+ const scope = scopeFromCandidate(selected, opts.treeView === true);
5632
+ const node = await requestTraversal({
5633
+ command: "open",
5634
+ runtimeOptions: context.runtimeOptions,
5635
+ operationName: "MarkdownTreeNode",
5636
+ field: "markdown_tree_node",
5637
+ variables: {
5638
+ organization_id: organizationId,
5639
+ tool_key: scope.toolKey,
5640
+ node_key: scope.nodeKey,
5641
+ parent_id: scope.parentId,
5642
+ record_id: scope.recordId,
5643
+ member_id: scope.memberId,
5644
+ team_id: scope.teamId,
5645
+ content_type: scope.contentType,
5646
+ tree_view: scope.treeView
5647
+ },
5648
+ depth: 1
5649
+ });
5650
+ printEnvelopeAndExit({
5651
+ envelope: {
5652
+ ok: true,
5653
+ command: "open",
5654
+ status: 200,
5655
+ data: {
5656
+ match: selected,
5657
+ node
5658
+ },
5659
+ error: null,
5660
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
5661
+ }
5662
+ });
5663
+ });
5664
+ 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) => {
5665
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5666
+ const organizationId = resolveOrganizationId(context.organizationId);
5667
+ let scope = null;
5668
+ let pathMatch = null;
5669
+ if (typeof opts.path === "string" && opts.path.trim() !== "") {
5670
+ const resolved = await resolvePathScope({
5671
+ command: "ls",
5672
+ runtimeOptions: context.runtimeOptions,
5673
+ organizationId,
5674
+ path: opts.path,
5675
+ underPath: typeof opts.under === "string" ? opts.under : void 0,
5676
+ treeView: opts.treeView === true
5677
+ });
5678
+ if (!resolved.scope) {
5679
+ if (resolved.ambiguous.length > 0) {
5680
+ printEnvelopeAndExit({
5681
+ envelope: ambiguityEnvelope({
5682
+ command: "ls",
5683
+ message: `Path "${opts.path}" is ambiguous.`,
5684
+ candidates: resolved.ambiguous
5685
+ }),
5686
+ exitCode: EXIT_CODES.generic
5687
+ });
5688
+ }
5689
+ printEnvelopeAndExit({
5690
+ envelope: notFoundEnvelope({
5691
+ command: "ls",
5692
+ message: `Path "${opts.path}" was not found.`
5693
+ }),
5694
+ exitCode: EXIT_CODES.notFound
5695
+ });
5696
+ }
5697
+ scope = resolved.scope;
5698
+ pathMatch = resolved.match ?? null;
5699
+ } else {
5700
+ scope = parseOptionalScopeFromOptions(opts);
5701
+ }
5702
+ if (!scope) {
5703
+ printEnvelopeAndExit({
5704
+ envelope: {
5705
+ ok: false,
5706
+ command: "ls",
5707
+ status: 400,
5708
+ data: null,
5709
+ error: {
5710
+ code: "invalid_args",
5711
+ message: "Provide either --path or full scope args (--tool-key and --node-key).",
5712
+ details: {}
5713
+ },
5714
+ meta: { requestId: context.runtimeOptions.requestId ?? "local_error" }
5715
+ },
5716
+ exitCode: EXIT_CODES.invalidArgs
5717
+ });
5718
+ }
5719
+ const node = await requestTraversal({
5720
+ command: "ls",
5721
+ runtimeOptions: context.runtimeOptions,
5722
+ operationName: "MarkdownTreeChildren",
5723
+ field: "markdown_tree_children",
5724
+ variables: {
5725
+ organization_id: organizationId,
5726
+ tool_key: scope.toolKey,
5727
+ node_key: scope.nodeKey,
5728
+ parent_id: scope.parentId,
5729
+ record_id: scope.recordId,
5730
+ member_id: scope.memberId,
5731
+ team_id: scope.teamId,
5732
+ content_type: scope.contentType,
5733
+ tree_view: scope.treeView
5734
+ },
5735
+ depth: 1
5736
+ });
5737
+ const children = asArray(node.children);
5738
+ const filtered = typeof query === "string" && query.trim() !== "" ? children.filter(
5739
+ (child) => normalizeText(child.runtimeLabel).includes(normalizeText(query))
5740
+ ) : children;
5741
+ printEnvelopeAndExit({
5742
+ envelope: {
5743
+ ok: true,
5744
+ command: "ls",
5745
+ status: 200,
5746
+ data: {
5747
+ target: pathMatch,
5748
+ children: filtered
5749
+ },
5750
+ error: null,
5751
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
5752
+ }
5753
+ });
5754
+ });
5755
+ 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) => {
5756
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5757
+ const organizationId = resolveOrganizationId(context.organizationId);
5758
+ let scope = null;
5759
+ let pathMatch = null;
5760
+ if (typeof opts.path === "string" && opts.path.trim() !== "") {
5761
+ const resolved = await resolvePathScope({
5762
+ command: "cat",
5763
+ runtimeOptions: context.runtimeOptions,
5764
+ organizationId,
5765
+ path: opts.path,
5766
+ underPath: typeof opts.under === "string" ? opts.under : void 0,
5767
+ treeView: opts.treeView === true
5768
+ });
5769
+ if (!resolved.scope) {
5770
+ if (resolved.ambiguous.length > 0) {
5771
+ printEnvelopeAndExit({
5772
+ envelope: ambiguityEnvelope({
5773
+ command: "cat",
5774
+ message: `Path "${opts.path}" is ambiguous.`,
5775
+ candidates: resolved.ambiguous
5776
+ }),
5777
+ exitCode: EXIT_CODES.generic
5778
+ });
5779
+ }
5780
+ printEnvelopeAndExit({
5781
+ envelope: notFoundEnvelope({
5782
+ command: "cat",
5783
+ message: `Path "${opts.path}" was not found.`
5784
+ }),
5785
+ exitCode: EXIT_CODES.notFound
5786
+ });
5787
+ }
5788
+ scope = resolved.scope;
5789
+ pathMatch = resolved.match ?? null;
5790
+ } else {
5791
+ scope = parseOptionalScopeFromOptions(opts);
5792
+ }
5793
+ if (!scope) {
5794
+ printEnvelopeAndExit({
5795
+ envelope: {
5796
+ ok: false,
5797
+ command: "cat",
5798
+ status: 400,
5799
+ data: null,
5800
+ error: {
5801
+ code: "invalid_args",
5802
+ message: "Provide either --path or full scope args (--tool-key and --node-key).",
5803
+ details: {}
5804
+ },
5805
+ meta: { requestId: context.runtimeOptions.requestId ?? "local_error" }
5806
+ },
5807
+ exitCode: EXIT_CODES.invalidArgs
5808
+ });
5809
+ }
5810
+ const node = await requestTraversal({
5811
+ command: "cat",
5812
+ runtimeOptions: context.runtimeOptions,
5813
+ operationName: "MarkdownTreeNode",
5814
+ field: "markdown_tree_node",
5815
+ variables: {
5816
+ organization_id: organizationId,
5817
+ tool_key: scope.toolKey,
5818
+ node_key: scope.nodeKey,
5819
+ parent_id: scope.parentId,
5820
+ record_id: scope.recordId,
5821
+ member_id: scope.memberId,
5822
+ team_id: scope.teamId,
5823
+ content_type: scope.contentType,
5824
+ tree_view: scope.treeView
5825
+ },
5826
+ depth: 1
5827
+ });
5828
+ printEnvelopeAndExit({
5829
+ envelope: {
5830
+ ok: true,
5831
+ command: "cat",
5832
+ status: 200,
5833
+ data: {
5834
+ target: pathMatch,
5835
+ node
5836
+ },
5837
+ error: null,
5838
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
5839
+ }
5840
+ });
5841
+ });
5842
+ 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) => {
5843
+ const context = await resolveCommandContext(cmd.optsWithGlobals());
5844
+ const organizationId = resolveOrganizationId(context.organizationId);
5845
+ const depth = nonNegativeInt2.parse(opts.depth);
5846
+ let scope = null;
5847
+ let pathMatch = null;
5848
+ if (typeof opts.path === "string" && opts.path.trim() !== "") {
5849
+ const resolved = await resolvePathScope({
5850
+ command: "tree",
5851
+ runtimeOptions: context.runtimeOptions,
5852
+ organizationId,
5853
+ path: opts.path,
5854
+ underPath: typeof opts.under === "string" ? opts.under : void 0,
5855
+ treeView: opts.treeView === true
5856
+ });
5857
+ if (!resolved.scope) {
5858
+ if (resolved.ambiguous.length > 0) {
5859
+ printEnvelopeAndExit({
5860
+ envelope: ambiguityEnvelope({
5861
+ command: "tree",
5862
+ message: `Path "${opts.path}" is ambiguous.`,
5863
+ candidates: resolved.ambiguous
5864
+ }),
5865
+ exitCode: EXIT_CODES.generic
5866
+ });
5867
+ }
5868
+ printEnvelopeAndExit({
5869
+ envelope: notFoundEnvelope({
5870
+ command: "tree",
5871
+ message: `Path "${opts.path}" was not found.`
5872
+ }),
5873
+ exitCode: EXIT_CODES.notFound
5874
+ });
5875
+ }
5876
+ scope = resolved.scope;
5877
+ pathMatch = resolved.match ?? null;
5878
+ } else {
5879
+ scope = parseOptionalScopeFromOptions(opts);
5880
+ }
5881
+ if (!scope) {
5882
+ printEnvelopeAndExit({
5883
+ envelope: {
5884
+ ok: false,
5885
+ command: "tree",
5886
+ status: 400,
5887
+ data: null,
5888
+ error: {
5889
+ code: "invalid_args",
5890
+ message: "Provide either --path or full scope args (--tool-key and --node-key).",
5891
+ details: {}
5892
+ },
5893
+ meta: { requestId: context.runtimeOptions.requestId ?? "local_error" }
5894
+ },
5895
+ exitCode: EXIT_CODES.invalidArgs
5896
+ });
5897
+ }
5898
+ const node = await requestTraversal({
5899
+ command: "tree",
5900
+ runtimeOptions: context.runtimeOptions,
5901
+ operationName: "MarkdownTreeSubtree",
5902
+ field: "markdown_tree_subtree",
5903
+ variables: {
5904
+ organization_id: organizationId,
5905
+ tool_key: scope.toolKey,
5906
+ node_key: scope.nodeKey,
5907
+ parent_id: scope.parentId,
5908
+ record_id: scope.recordId,
5909
+ member_id: scope.memberId,
5910
+ team_id: scope.teamId,
5911
+ content_type: scope.contentType,
5912
+ tree_view: scope.treeView,
5913
+ depth
5914
+ },
5915
+ depth: depth + 1
5916
+ });
5917
+ printEnvelopeAndExit({
5918
+ envelope: {
5919
+ ok: true,
5920
+ command: "tree",
5921
+ status: 200,
5922
+ data: {
5923
+ target: pathMatch,
5924
+ depth,
5925
+ node
5926
+ },
5927
+ error: null,
5928
+ meta: { requestId: context.runtimeOptions.requestId ?? "local" }
5929
+ }
5930
+ });
5931
+ });
5932
+ }
5933
+
5934
+ // src/commands/mutationCapability.ts
5935
+ function unsupportedMutationEnvelope(params) {
5936
+ return {
5937
+ ok: false,
5938
+ command: params.command,
5939
+ status: 400,
5940
+ data: null,
5941
+ error: {
5942
+ code: "mutation_unsupported",
5943
+ message: "No mutation command is supported for this node type.",
5944
+ details: {
5945
+ node: params.node
5946
+ }
5947
+ },
5948
+ meta: {
5949
+ requestId: "local_error"
5950
+ }
5951
+ };
5952
+ }
5953
+ function emitUnsupportedMutation(params) {
5954
+ const canonicalPath = typeof params.canonicalPath === "string" && params.canonicalPath.trim().length > 0 ? params.canonicalPath.trim() : null;
5955
+ printEnvelopeAndExit({
5956
+ envelope: unsupportedMutationEnvelope({
5957
+ command: params.command,
5958
+ node: {
5959
+ toolKey: params.toolKey,
5960
+ nodeKey: params.nodeKey,
5961
+ canonicalPath
5962
+ }
5963
+ }),
5964
+ exitCode: EXIT_CODES.invalidArgs
5965
+ });
5966
+ }
5967
+ function registerMutationCapabilityCommands(program) {
5968
+ const projectNotes = program.command("project-notes").description("Project notes node (read-only in CLI mutation surface)");
5969
+ projectNotes.command("create").option("--path <path>", "Canonical path for the selected node").action((opts) => {
5970
+ emitUnsupportedMutation({
5971
+ command: "project-notes.create",
5972
+ toolKey: "projects",
5973
+ nodeKey: "project_notes",
5974
+ canonicalPath: opts.path
5975
+ });
5976
+ });
5977
+ projectNotes.command("update").option("--path <path>", "Canonical path for the selected node").action((opts) => {
5978
+ emitUnsupportedMutation({
5979
+ command: "project-notes.update",
5980
+ toolKey: "projects",
5981
+ nodeKey: "project_notes",
5982
+ canonicalPath: opts.path
5983
+ });
5984
+ });
5985
+ projectNotes.command("destroy").option("--path <path>", "Canonical path for the selected node").action((opts) => {
5986
+ emitUnsupportedMutation({
5987
+ command: "project-notes.destroy",
5988
+ toolKey: "projects",
5989
+ nodeKey: "project_notes",
5990
+ canonicalPath: opts.path
5991
+ });
5992
+ });
5993
+ }
5994
+
3028
5995
  // src/cli.ts
3029
- function buildCli() {
5996
+ function buildCli(options) {
3030
5997
  const program = new import_commander.Command();
3031
5998
  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
5999
  "--auth-json-stdin",
@@ -3047,6 +6014,7 @@ function buildCli() {
3047
6014
  "--openapi-version <openapiVersion>",
3048
6015
  "Optional pinned OpenAPI version/hash"
3049
6016
  ).exitOverride();
6017
+ setInternalCliOptions(program, options?.internal);
3050
6018
  registerTaskCommands(program);
3051
6019
  registerProjectCommands(program);
3052
6020
  registerRockCommands(program);
@@ -3059,6 +6027,9 @@ function buildCli() {
3059
6027
  registerFoundationCommands(program);
3060
6028
  registerChildEntityCommands(program);
3061
6029
  registerNoteCommands(program);
6030
+ registerMutationCapabilityCommands(program);
6031
+ registerMarkdownTreeCommands(program);
6032
+ registerNavigationCommands(program);
3062
6033
  return program;
3063
6034
  }
3064
6035
 
@@ -3107,13 +6078,13 @@ main().catch((error) => {
3107
6078
  exitCode: EXIT_CODES.invalidArgs
3108
6079
  });
3109
6080
  }
3110
- if (error instanceof import_zod14.ZodError || error instanceof import_commander2.InvalidArgumentError) {
6081
+ if (error instanceof import_zod16.ZodError || error instanceof import_commander2.InvalidArgumentError) {
3111
6082
  printCliFailure({
3112
6083
  status: 400,
3113
6084
  code: "invalid_args",
3114
6085
  message: "Invalid command arguments.",
3115
6086
  details: {
3116
- issues: error instanceof import_zod14.ZodError ? error.issues : [{ message: error.message, code: "invalid_argument" }]
6087
+ issues: error instanceof import_zod16.ZodError ? error.issues : [{ message: error.message, code: "invalid_argument" }]
3117
6088
  },
3118
6089
  exitCode: EXIT_CODES.invalidArgs
3119
6090
  });