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