@ted-galago/wave-cli 0.1.4 → 0.1.5
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/README.md +65 -0
- package/dist/index.cjs +490 -4
- package/dist/index.js +487 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -84,7 +84,25 @@ wave lists create --data-json '{"name":"Weekly List"}'
|
|
|
84
84
|
wave list-items create --data-json '{"list_id":"123","summary":"Follow up"}'
|
|
85
85
|
wave todos create --data-json '{"todo_group_id":"55","name":"Send update"}'
|
|
86
86
|
wave knowledge create --data-json '{"title":"Runbook","content":"..."}'
|
|
87
|
+
wave notes create-member --target-member-id 67 --name "1:1 Note" --body "Strong progress"
|
|
88
|
+
wave notes create-manager --actor-member-id 67 --target-member-id 68 --name "Manager Note" --body "Coaching plan"
|
|
89
|
+
wave notes create-team --actor-member-id 67 --team-id 9 --name "Team Note" --body "Team context"
|
|
90
|
+
wave notes create-project --actor-member-id 67 --project-id 80 --name "Project Note" --body "Project context"
|
|
91
|
+
wave notes create-customer --actor-member-id 67 --customer-id 30 --name "Customer Note" --body "Customer context"
|
|
92
|
+
wave notes create-contact --actor-member-id 67 --contact-id 31 --name "Contact Note" --body "Contact context"
|
|
93
|
+
wave notes list --contentable-type Member --contentable-id 67 --member-id 67 --page 1 --per 20
|
|
94
|
+
wave notes show --id 1001
|
|
95
|
+
wave notes update --id 1001 --name "Updated Note" --body "Updated body" --status published
|
|
96
|
+
wave notes destroy --id 1001
|
|
87
97
|
wave pulse update --id 12 --data-json '{"status":"on_track"}'
|
|
98
|
+
wave subtasks list --task-id 123 --page 1 --per 20
|
|
99
|
+
wave milestones list --rock-id 234 --page 1 --per 20
|
|
100
|
+
wave subitems list --list-item-id 345 --page 1 --per 20
|
|
101
|
+
wave subtodos list --todo-id 456 --page 1 --per 20
|
|
102
|
+
wave subissues list --issue-id 567 --page 1 --per 20
|
|
103
|
+
wave talking-points list --meeting-id 678 --page 1 --per 20
|
|
104
|
+
wave subtasks create --data-json '{"subtask":{"task_id":"123","member_id":"67","name":"Subtask name","description":"Subtask description"}}'
|
|
105
|
+
wave subissues destroy --id 999
|
|
88
106
|
```
|
|
89
107
|
|
|
90
108
|
All commands require organization context via `--organization-id` or `WAVE_ORGANIZATION_ID`.
|
|
@@ -99,9 +117,56 @@ These child resources enforce parent IDs at CLI validation time:
|
|
|
99
117
|
- `todos.create` requires `todo_group_id`
|
|
100
118
|
- `rocks.create` requires `rock_collection_id`
|
|
101
119
|
- `scorecards.create` requires `measurable_group_id`
|
|
120
|
+
- `subtasks.create` requires `task_id`
|
|
121
|
+
- `milestones.create` requires `rock_id`
|
|
122
|
+
- `subitems.create` requires `list_item_id`
|
|
123
|
+
- `subtodos.create` requires `todo_id`
|
|
124
|
+
- `subissues.create` requires `issue_id`
|
|
125
|
+
- `talking-points.create` requires `meeting_id`
|
|
102
126
|
|
|
103
127
|
If a required parent field is missing, CLI returns JSON error with exit code `2`.
|
|
104
128
|
|
|
129
|
+
## Notes Contract
|
|
130
|
+
|
|
131
|
+
The `notes` command uses exact GraphQL operation names:
|
|
132
|
+
|
|
133
|
+
- `CreateContent`
|
|
134
|
+
- `UpdateContent`
|
|
135
|
+
- `DestroyContent`
|
|
136
|
+
- `ContentShow`
|
|
137
|
+
- `ContentsIndex`
|
|
138
|
+
|
|
139
|
+
Placement rules enforced by command shape:
|
|
140
|
+
|
|
141
|
+
- `notes create-member`
|
|
142
|
+
- `contentable_type: "Member"`
|
|
143
|
+
- `contentable_id: TARGET_MEMBER_ID`
|
|
144
|
+
- `member_id: TARGET_MEMBER_ID`
|
|
145
|
+
- `focus_member_id: null`
|
|
146
|
+
- `focus_team_id: null`
|
|
147
|
+
- `notes create-manager`
|
|
148
|
+
- `contentable_type: "Member"`
|
|
149
|
+
- `contentable_id: ACTOR_MEMBER_ID`
|
|
150
|
+
- `member_id: ACTOR_MEMBER_ID`
|
|
151
|
+
- `focus_member_id: TARGET_MEMBER_ID`
|
|
152
|
+
- `notes create-team`
|
|
153
|
+
- `contentable_type: "Team"`
|
|
154
|
+
- `contentable_id: TEAM_ID`
|
|
155
|
+
- `member_id: ACTOR_MEMBER_ID`
|
|
156
|
+
- `focus_team_id: TEAM_ID`
|
|
157
|
+
- `notes create-project`
|
|
158
|
+
- `contentable_type: "Project"`
|
|
159
|
+
- `contentable_id: PROJECT_ID`
|
|
160
|
+
- `member_id: ACTOR_MEMBER_ID`
|
|
161
|
+
- `notes create-customer`
|
|
162
|
+
- `contentable_type: "Customer"`
|
|
163
|
+
- `contentable_id: CUSTOMER_ID`
|
|
164
|
+
- `member_id: ACTOR_MEMBER_ID`
|
|
165
|
+
- `notes create-contact`
|
|
166
|
+
- `contentable_type: "Contact"`
|
|
167
|
+
- `contentable_id: CONTACT_ID`
|
|
168
|
+
- `member_id: ACTOR_MEMBER_ID`
|
|
169
|
+
|
|
105
170
|
## JSON Envelope
|
|
106
171
|
|
|
107
172
|
Success:
|
package/dist/index.cjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
5
5
|
var import_commander2 = require("commander");
|
|
6
|
-
var
|
|
6
|
+
var import_zod14 = require("zod");
|
|
7
7
|
|
|
8
8
|
// src/cli.ts
|
|
9
9
|
var import_commander = require("commander");
|
|
@@ -252,7 +252,7 @@ function normalizeGraphqlVariables(variables) {
|
|
|
252
252
|
function buildGraphqlBody(input) {
|
|
253
253
|
const graphqlField = toCamelCase(input.field);
|
|
254
254
|
const graphqlVariables = normalizeGraphqlVariables(input.variables);
|
|
255
|
-
const operationName = graphqlOperationName(input.command);
|
|
255
|
+
const operationName = input.operationName ?? graphqlOperationName(input.command);
|
|
256
256
|
const variableEntries = Object.entries(graphqlVariables).filter(([, value]) => value !== void 0);
|
|
257
257
|
const variableDecl = variableEntries.map(([name, value]) => `$${name}: ${withNonNull(graphqlTypeForVariable(name, value))}`).join(", ");
|
|
258
258
|
const fieldArgs = variableEntries.map(([name]) => `${name}: $${name}`).join(", ");
|
|
@@ -490,12 +490,21 @@ async function runGraphqlQueryCommand(input) {
|
|
|
490
490
|
const result = await graphqlRequest({
|
|
491
491
|
config,
|
|
492
492
|
command: input.command,
|
|
493
|
+
operationName: input.operationName,
|
|
493
494
|
operationType: "query",
|
|
494
495
|
field: input.field,
|
|
495
496
|
variables: input.variables ?? {},
|
|
496
497
|
selectionSet: input.selectionSet ?? defaultQuerySelectionSet(input.field, Boolean(input.isList)),
|
|
497
498
|
isShow: input.isShow
|
|
498
499
|
});
|
|
500
|
+
if (result.envelope.ok && input.transformData && result.envelope.data) {
|
|
501
|
+
const dataRecord = result.envelope.data;
|
|
502
|
+
const transformed = input.transformData(dataRecord[input.field]);
|
|
503
|
+
result.envelope.data = {
|
|
504
|
+
...dataRecord,
|
|
505
|
+
[input.field]: transformed
|
|
506
|
+
};
|
|
507
|
+
}
|
|
499
508
|
printEnvelopeAndExit(result);
|
|
500
509
|
} catch (error) {
|
|
501
510
|
if (error instanceof CliError) {
|
|
@@ -528,6 +537,7 @@ async function runGraphqlMutationCommand(input) {
|
|
|
528
537
|
const result = await graphqlRequest({
|
|
529
538
|
config,
|
|
530
539
|
command: input.command,
|
|
540
|
+
operationName: input.operationName,
|
|
531
541
|
operationType: "mutation",
|
|
532
542
|
field: input.field,
|
|
533
543
|
variables: input.variables ?? {},
|
|
@@ -2541,6 +2551,480 @@ function registerFoundationCommands(program) {
|
|
|
2541
2551
|
});
|
|
2542
2552
|
}
|
|
2543
2553
|
|
|
2554
|
+
// src/commands/childEntities.ts
|
|
2555
|
+
var import_zod12 = require("zod");
|
|
2556
|
+
var idSchema11 = import_zod12.z.string().min(1);
|
|
2557
|
+
var jsonObjectSchema = import_zod12.z.record(import_zod12.z.string(), import_zod12.z.unknown());
|
|
2558
|
+
function parseJsonObject2(raw) {
|
|
2559
|
+
try {
|
|
2560
|
+
const parsed = JSON.parse(raw);
|
|
2561
|
+
return jsonObjectSchema.parse(parsed);
|
|
2562
|
+
} catch (error) {
|
|
2563
|
+
throw new CliError({
|
|
2564
|
+
message: error instanceof Error ? `Invalid --data-json: ${error.message}` : "Invalid --data-json.",
|
|
2565
|
+
kind: "invalid_args",
|
|
2566
|
+
status: 400,
|
|
2567
|
+
exitCode: EXIT_CODES.invalidArgs
|
|
2568
|
+
});
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
function normalizeBody2(raw, rootKey) {
|
|
2572
|
+
const payload = parseJsonObject2(raw);
|
|
2573
|
+
const rooted = payload[rootKey];
|
|
2574
|
+
if (rooted && typeof rooted === "object" && !Array.isArray(rooted)) {
|
|
2575
|
+
return payload;
|
|
2576
|
+
}
|
|
2577
|
+
return { [rootKey]: payload };
|
|
2578
|
+
}
|
|
2579
|
+
function assertRequiredParent(body, rootKey, parentKey) {
|
|
2580
|
+
const entity = body[rootKey];
|
|
2581
|
+
if (!entity || typeof entity !== "object" || Array.isArray(entity)) {
|
|
2582
|
+
throw new CliError({
|
|
2583
|
+
message: `Invalid payload. Expected object at "${rootKey}".`,
|
|
2584
|
+
kind: "invalid_args",
|
|
2585
|
+
status: 400,
|
|
2586
|
+
exitCode: EXIT_CODES.invalidArgs
|
|
2587
|
+
});
|
|
2588
|
+
}
|
|
2589
|
+
const value = entity[parentKey];
|
|
2590
|
+
if (!(typeof value === "string" && value.trim().length > 0)) {
|
|
2591
|
+
throw new CliError({
|
|
2592
|
+
message: `Missing required create field for ${rootKey}: ${parentKey}.`,
|
|
2593
|
+
kind: "invalid_args",
|
|
2594
|
+
status: 400,
|
|
2595
|
+
exitCode: EXIT_CODES.invalidArgs
|
|
2596
|
+
});
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
function attrValue(attrs, keys) {
|
|
2600
|
+
if (!attrs || typeof attrs !== "object" || Array.isArray(attrs)) {
|
|
2601
|
+
return void 0;
|
|
2602
|
+
}
|
|
2603
|
+
const record = attrs;
|
|
2604
|
+
for (const key of keys) {
|
|
2605
|
+
if (record[key] !== void 0 && record[key] !== null && `${record[key]}`.trim() !== "") {
|
|
2606
|
+
return record[key];
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
return void 0;
|
|
2610
|
+
}
|
|
2611
|
+
function normalizePlacementRow(row, parentKind, parentIdFallback, parentTypedField) {
|
|
2612
|
+
const typedParent = parentTypedField ? row[parentTypedField] : void 0;
|
|
2613
|
+
const parentId = (typeof typedParent === "string" && typedParent.trim().length > 0 ? typedParent : void 0) ?? parentIdFallback ?? null;
|
|
2614
|
+
const attrs = row.attributes;
|
|
2615
|
+
const memberId = (typeof row.memberId === "string" ? row.memberId : void 0) ?? attrValue(attrs, ["memberId", "member_id"]) ?? null;
|
|
2616
|
+
const creatorId = (typeof row.creatorId === "string" ? row.creatorId : void 0) ?? attrValue(attrs, ["creatorId", "creator_id"]) ?? null;
|
|
2617
|
+
const ownerRaw = attrValue(attrs, ["memberId", "member_id", "creatorId", "creator_id"]) ?? null;
|
|
2618
|
+
const description = (typeof row.description === "string" && row.description.length > 0 ? row.description : attrValue(attrs, ["description"])) ?? null;
|
|
2619
|
+
return {
|
|
2620
|
+
id: row.id ?? null,
|
|
2621
|
+
type: row.type ?? null,
|
|
2622
|
+
parent: {
|
|
2623
|
+
kind: parentKind,
|
|
2624
|
+
id: parentId
|
|
2625
|
+
},
|
|
2626
|
+
owner: {
|
|
2627
|
+
memberId,
|
|
2628
|
+
creatorId,
|
|
2629
|
+
raw: ownerRaw
|
|
2630
|
+
},
|
|
2631
|
+
description,
|
|
2632
|
+
attributes: attrs ?? {}
|
|
2633
|
+
};
|
|
2634
|
+
}
|
|
2635
|
+
function normalizeListPayload(payload, parentKind, parentIdFallback, parentTypedField) {
|
|
2636
|
+
const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
2637
|
+
const rows = Array.isArray(record.data) ? record.data : [];
|
|
2638
|
+
const normalizedRows = rows.map(
|
|
2639
|
+
(row) => normalizePlacementRow(
|
|
2640
|
+
row,
|
|
2641
|
+
parentKind,
|
|
2642
|
+
parentIdFallback,
|
|
2643
|
+
parentTypedField
|
|
2644
|
+
)
|
|
2645
|
+
);
|
|
2646
|
+
return {
|
|
2647
|
+
data: normalizedRows,
|
|
2648
|
+
count: record.count ?? normalizedRows.length,
|
|
2649
|
+
currentPage: record.currentPage ?? 1,
|
|
2650
|
+
totalPages: record.totalPages ?? 1
|
|
2651
|
+
};
|
|
2652
|
+
}
|
|
2653
|
+
function registerChildCommands(program, config) {
|
|
2654
|
+
const command = program.command(config.command).description(config.description);
|
|
2655
|
+
command.command("list").requiredOption(`--${config.parentFlag} <${config.parentFlag}>`).option("--page <page>").option("--per <per>").action(async (opts, cmd) => {
|
|
2656
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2657
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2658
|
+
const parentId = idSchema11.parse(opts[config.parentFlag.replace(/-([a-z])/g, (_, c) => c.toUpperCase())]);
|
|
2659
|
+
await runGraphqlQueryCommand({
|
|
2660
|
+
command: `${config.command}.list`,
|
|
2661
|
+
operationName: config.listOperationName,
|
|
2662
|
+
runtimeOptions: context.runtimeOptions,
|
|
2663
|
+
field: config.listField,
|
|
2664
|
+
variables: {
|
|
2665
|
+
organization_id: organizationId,
|
|
2666
|
+
[config.parentFlag.replace(/-/g, "_")]: parentId,
|
|
2667
|
+
page: opts.page,
|
|
2668
|
+
per: opts.per
|
|
2669
|
+
},
|
|
2670
|
+
isList: true,
|
|
2671
|
+
selectionSet: config.listSelectionSet,
|
|
2672
|
+
transformData: (payload) => normalizeListPayload(
|
|
2673
|
+
payload,
|
|
2674
|
+
config.parentKind,
|
|
2675
|
+
parentId,
|
|
2676
|
+
config.listParentTypedField
|
|
2677
|
+
)
|
|
2678
|
+
});
|
|
2679
|
+
});
|
|
2680
|
+
command.command("create").requiredOption("--data-json <dataJson>").action(async (opts, cmd) => {
|
|
2681
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2682
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2683
|
+
const body = normalizeBody2(String(opts.dataJson), config.rootKey);
|
|
2684
|
+
assertRequiredParent(body, config.rootKey, config.parentFlag.replace(/-/g, "_"));
|
|
2685
|
+
await runGraphqlMutationCommand({
|
|
2686
|
+
command: `${config.command}.create`,
|
|
2687
|
+
operationName: config.createOperationName,
|
|
2688
|
+
runtimeOptions: context.runtimeOptions,
|
|
2689
|
+
field: config.createField,
|
|
2690
|
+
variables: {
|
|
2691
|
+
organization_id: organizationId,
|
|
2692
|
+
params: body
|
|
2693
|
+
}
|
|
2694
|
+
});
|
|
2695
|
+
});
|
|
2696
|
+
command.command("update").requiredOption("--id <id>").requiredOption("--data-json <dataJson>").action(async (opts, cmd) => {
|
|
2697
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2698
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2699
|
+
const id = idSchema11.parse(opts.id);
|
|
2700
|
+
const body = normalizeBody2(String(opts.dataJson), config.rootKey);
|
|
2701
|
+
await runGraphqlMutationCommand({
|
|
2702
|
+
command: `${config.command}.update`,
|
|
2703
|
+
operationName: config.updateOperationName,
|
|
2704
|
+
runtimeOptions: context.runtimeOptions,
|
|
2705
|
+
field: config.updateField,
|
|
2706
|
+
variables: {
|
|
2707
|
+
organization_id: organizationId,
|
|
2708
|
+
[config.idVariable]: id,
|
|
2709
|
+
params: body
|
|
2710
|
+
}
|
|
2711
|
+
});
|
|
2712
|
+
});
|
|
2713
|
+
command.command("destroy").requiredOption("--id <id>").action(async (opts, cmd) => {
|
|
2714
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2715
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2716
|
+
const id = idSchema11.parse(opts.id);
|
|
2717
|
+
await runGraphqlMutationCommand({
|
|
2718
|
+
command: `${config.command}.destroy`,
|
|
2719
|
+
operationName: config.destroyOperationName,
|
|
2720
|
+
runtimeOptions: context.runtimeOptions,
|
|
2721
|
+
field: config.destroyField,
|
|
2722
|
+
variables: {
|
|
2723
|
+
organization_id: organizationId,
|
|
2724
|
+
[config.idVariable]: id
|
|
2725
|
+
}
|
|
2726
|
+
});
|
|
2727
|
+
});
|
|
2728
|
+
}
|
|
2729
|
+
function registerChildEntityCommands(program) {
|
|
2730
|
+
registerChildCommands(program, {
|
|
2731
|
+
command: "subtasks",
|
|
2732
|
+
description: "Subtask operations",
|
|
2733
|
+
parentFlag: "task-id",
|
|
2734
|
+
parentKind: "task",
|
|
2735
|
+
rootKey: "subtask",
|
|
2736
|
+
listField: "subtasks",
|
|
2737
|
+
createField: "create_subtask",
|
|
2738
|
+
updateField: "update_subtask",
|
|
2739
|
+
destroyField: "destroy_subtask",
|
|
2740
|
+
idVariable: "subtask_id",
|
|
2741
|
+
listOperationName: "SubtasksForTask",
|
|
2742
|
+
createOperationName: "CreateSubtask",
|
|
2743
|
+
updateOperationName: "UpdateSubtask",
|
|
2744
|
+
destroyOperationName: "DestroySubtask",
|
|
2745
|
+
listSelectionSet: "{ data { id type name status taskId attributes } count currentPage totalPages }",
|
|
2746
|
+
listParentTypedField: "taskId"
|
|
2747
|
+
});
|
|
2748
|
+
registerChildCommands(program, {
|
|
2749
|
+
command: "milestones",
|
|
2750
|
+
description: "Milestone operations",
|
|
2751
|
+
parentFlag: "rock-id",
|
|
2752
|
+
parentKind: "rock",
|
|
2753
|
+
rootKey: "milestone",
|
|
2754
|
+
listField: "milestones",
|
|
2755
|
+
createField: "create_milestone",
|
|
2756
|
+
updateField: "update_milestone",
|
|
2757
|
+
destroyField: "destroy_milestone",
|
|
2758
|
+
idVariable: "milestone_id",
|
|
2759
|
+
listOperationName: "MilestonesForRock",
|
|
2760
|
+
createOperationName: "CreateMilestone",
|
|
2761
|
+
updateOperationName: "UpdateMilestone",
|
|
2762
|
+
destroyOperationName: "DestroyMilestone",
|
|
2763
|
+
listSelectionSet: "{ data { id type name slug status attributes } count currentPage totalPages }"
|
|
2764
|
+
});
|
|
2765
|
+
registerChildCommands(program, {
|
|
2766
|
+
command: "subitems",
|
|
2767
|
+
description: "Subitem operations",
|
|
2768
|
+
parentFlag: "list-item-id",
|
|
2769
|
+
parentKind: "listItem",
|
|
2770
|
+
rootKey: "subitem",
|
|
2771
|
+
listField: "subitems",
|
|
2772
|
+
createField: "create_subitem",
|
|
2773
|
+
updateField: "update_subitem",
|
|
2774
|
+
destroyField: "destroy_subitem",
|
|
2775
|
+
idVariable: "subitem_id",
|
|
2776
|
+
listOperationName: "SubitemsForListItem",
|
|
2777
|
+
createOperationName: "CreateSubitem",
|
|
2778
|
+
updateOperationName: "UpdateSubitem",
|
|
2779
|
+
destroyOperationName: "DestroySubitem",
|
|
2780
|
+
listSelectionSet: "{ data { id type name status listItemId attributes } count currentPage totalPages }",
|
|
2781
|
+
listParentTypedField: "listItemId"
|
|
2782
|
+
});
|
|
2783
|
+
registerChildCommands(program, {
|
|
2784
|
+
command: "subtodos",
|
|
2785
|
+
description: "Subtodo operations",
|
|
2786
|
+
parentFlag: "todo-id",
|
|
2787
|
+
parentKind: "todo",
|
|
2788
|
+
rootKey: "sub_todo",
|
|
2789
|
+
listField: "sub_todos",
|
|
2790
|
+
createField: "create_sub_todo",
|
|
2791
|
+
updateField: "update_sub_todo",
|
|
2792
|
+
destroyField: "destroy_sub_todo",
|
|
2793
|
+
idVariable: "sub_todo_id",
|
|
2794
|
+
listOperationName: "SubtodosForTodo",
|
|
2795
|
+
createOperationName: "CreateSubTodo",
|
|
2796
|
+
updateOperationName: "UpdateSubTodo",
|
|
2797
|
+
destroyOperationName: "DestroySubTodo",
|
|
2798
|
+
listSelectionSet: "{ data { id type name status todoId attributes } count currentPage totalPages }",
|
|
2799
|
+
listParentTypedField: "todoId"
|
|
2800
|
+
});
|
|
2801
|
+
registerChildCommands(program, {
|
|
2802
|
+
command: "subissues",
|
|
2803
|
+
description: "Subissue operations",
|
|
2804
|
+
parentFlag: "issue-id",
|
|
2805
|
+
parentKind: "issue",
|
|
2806
|
+
rootKey: "sub_issue",
|
|
2807
|
+
listField: "sub_issues",
|
|
2808
|
+
createField: "create_sub_issue",
|
|
2809
|
+
updateField: "update_sub_issue",
|
|
2810
|
+
destroyField: "destroy_sub_issue",
|
|
2811
|
+
idVariable: "sub_issue_id",
|
|
2812
|
+
listOperationName: "SubissuesForIssue",
|
|
2813
|
+
createOperationName: "CreateSubIssue",
|
|
2814
|
+
updateOperationName: "UpdateSubIssue",
|
|
2815
|
+
destroyOperationName: "DestroySubIssue",
|
|
2816
|
+
listSelectionSet: "{ data { id type name status issueId attributes } count currentPage totalPages }",
|
|
2817
|
+
listParentTypedField: "issueId"
|
|
2818
|
+
});
|
|
2819
|
+
registerChildCommands(program, {
|
|
2820
|
+
command: "talking-points",
|
|
2821
|
+
description: "Talking point operations",
|
|
2822
|
+
parentFlag: "meeting-id",
|
|
2823
|
+
parentKind: "meeting",
|
|
2824
|
+
rootKey: "talking_point",
|
|
2825
|
+
listField: "talking_points",
|
|
2826
|
+
createField: "create_talking_point",
|
|
2827
|
+
updateField: "update_talking_point",
|
|
2828
|
+
destroyField: "destroy_talking_point",
|
|
2829
|
+
idVariable: "talking_point_id",
|
|
2830
|
+
listOperationName: "TalkingPointsForMeeting",
|
|
2831
|
+
createOperationName: "CreateTalkingPoint",
|
|
2832
|
+
updateOperationName: "UpdateTalkingPoint",
|
|
2833
|
+
destroyOperationName: "DestroyTalkingPoint",
|
|
2834
|
+
listSelectionSet: "{ data { id type name description status priority rank dueDate memberId creatorId meetingId attributes } count currentPage totalPages }",
|
|
2835
|
+
listParentTypedField: "meetingId"
|
|
2836
|
+
});
|
|
2837
|
+
}
|
|
2838
|
+
|
|
2839
|
+
// src/commands/notes.ts
|
|
2840
|
+
var import_zod13 = require("zod");
|
|
2841
|
+
var idSchema12 = import_zod13.z.string().min(1);
|
|
2842
|
+
var nonEmptyString = import_zod13.z.string().min(1);
|
|
2843
|
+
function assertUpdateFields(params) {
|
|
2844
|
+
if (!params.name && !params.content && !params.status) {
|
|
2845
|
+
throw new CliError({
|
|
2846
|
+
message: "notes update requires at least one of --name, --body, or --status.",
|
|
2847
|
+
kind: "invalid_args",
|
|
2848
|
+
status: 400,
|
|
2849
|
+
exitCode: EXIT_CODES.invalidArgs
|
|
2850
|
+
});
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
async function createContent(command, cmd, payload) {
|
|
2854
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2855
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2856
|
+
return runGraphqlMutationCommand({
|
|
2857
|
+
command,
|
|
2858
|
+
operationName: "CreateContent",
|
|
2859
|
+
runtimeOptions: context.runtimeOptions,
|
|
2860
|
+
field: "create_content",
|
|
2861
|
+
variables: normalizeGraphqlVariables2({
|
|
2862
|
+
organization_id: organizationId,
|
|
2863
|
+
params: {
|
|
2864
|
+
content: payload
|
|
2865
|
+
}
|
|
2866
|
+
})
|
|
2867
|
+
});
|
|
2868
|
+
}
|
|
2869
|
+
function registerNoteCommands(program) {
|
|
2870
|
+
const notes = program.command("notes").description("Content note operations");
|
|
2871
|
+
notes.command("list").option("--contentable-type <contentableType>").option("--contentable-id <contentableId>").option("--member-id <memberId>").option("--focus-member-id <focusMemberId>").option("--focus-team-id <focusTeamId>").option("--page <page>").option("--per <per>").action(async (opts, cmd) => {
|
|
2872
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2873
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2874
|
+
await runGraphqlQueryCommand({
|
|
2875
|
+
command: "notes.list",
|
|
2876
|
+
operationName: "ContentsIndex",
|
|
2877
|
+
runtimeOptions: context.runtimeOptions,
|
|
2878
|
+
field: "contents",
|
|
2879
|
+
variables: normalizeGraphqlVariables2({
|
|
2880
|
+
organization_id: organizationId,
|
|
2881
|
+
contentable_type: opts.contentableType,
|
|
2882
|
+
contentable_id: opts.contentableId,
|
|
2883
|
+
member_id: opts.memberId,
|
|
2884
|
+
focus_member_id: opts.focusMemberId,
|
|
2885
|
+
focus_team_id: opts.focusTeamId,
|
|
2886
|
+
page: opts.page,
|
|
2887
|
+
per: opts.per
|
|
2888
|
+
}),
|
|
2889
|
+
isList: true,
|
|
2890
|
+
selectionSet: "{ count currentPage totalPages data { id type name contentableType contentableId memberId focusMemberId focusTeamId attributes } }"
|
|
2891
|
+
});
|
|
2892
|
+
});
|
|
2893
|
+
notes.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
|
|
2894
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2895
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2896
|
+
const id = idSchema12.parse(opts.id);
|
|
2897
|
+
await runGraphqlQueryCommand({
|
|
2898
|
+
command: "notes.show",
|
|
2899
|
+
operationName: "ContentShow",
|
|
2900
|
+
runtimeOptions: context.runtimeOptions,
|
|
2901
|
+
field: "content",
|
|
2902
|
+
variables: normalizeGraphqlVariables2({
|
|
2903
|
+
organization_id: organizationId,
|
|
2904
|
+
id
|
|
2905
|
+
}),
|
|
2906
|
+
isShow: true,
|
|
2907
|
+
selectionSet: "{ id type name contentableType contentableId memberId focusMemberId focusTeamId attributes }"
|
|
2908
|
+
});
|
|
2909
|
+
});
|
|
2910
|
+
notes.command("update").requiredOption("--id <id>").option("--name <name>").option("--body <body>").option("--status <status>").action(async (opts, cmd) => {
|
|
2911
|
+
assertUpdateFields({
|
|
2912
|
+
name: opts.name,
|
|
2913
|
+
content: opts.body,
|
|
2914
|
+
status: opts.status
|
|
2915
|
+
});
|
|
2916
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2917
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2918
|
+
const contentId = idSchema12.parse(opts.id);
|
|
2919
|
+
await runGraphqlMutationCommand({
|
|
2920
|
+
command: "notes.update",
|
|
2921
|
+
operationName: "UpdateContent",
|
|
2922
|
+
runtimeOptions: context.runtimeOptions,
|
|
2923
|
+
field: "update_content",
|
|
2924
|
+
variables: normalizeGraphqlVariables2({
|
|
2925
|
+
organization_id: organizationId,
|
|
2926
|
+
content_id: contentId,
|
|
2927
|
+
params: {
|
|
2928
|
+
content: normalizeGraphqlVariables2({
|
|
2929
|
+
name: opts.name,
|
|
2930
|
+
content: opts.body,
|
|
2931
|
+
status: opts.status
|
|
2932
|
+
})
|
|
2933
|
+
}
|
|
2934
|
+
})
|
|
2935
|
+
});
|
|
2936
|
+
});
|
|
2937
|
+
notes.command("destroy").requiredOption("--id <id>").action(async (opts, cmd) => {
|
|
2938
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2939
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2940
|
+
const contentId = idSchema12.parse(opts.id);
|
|
2941
|
+
await runGraphqlMutationCommand({
|
|
2942
|
+
command: "notes.destroy",
|
|
2943
|
+
operationName: "DestroyContent",
|
|
2944
|
+
runtimeOptions: context.runtimeOptions,
|
|
2945
|
+
field: "destroy_content",
|
|
2946
|
+
variables: normalizeGraphqlVariables2({
|
|
2947
|
+
organization_id: organizationId,
|
|
2948
|
+
content_id: contentId
|
|
2949
|
+
})
|
|
2950
|
+
});
|
|
2951
|
+
});
|
|
2952
|
+
notes.command("create-member").requiredOption("--target-member-id <targetMemberId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
|
|
2953
|
+
const targetMemberId = nonEmptyString.parse(opts.targetMemberId);
|
|
2954
|
+
await createContent("notes.create-member", cmd, {
|
|
2955
|
+
type: "WrittenContent",
|
|
2956
|
+
name: nonEmptyString.parse(opts.name),
|
|
2957
|
+
content: nonEmptyString.parse(opts.body),
|
|
2958
|
+
status: String(opts.status ?? "draft"),
|
|
2959
|
+
contentable_type: "Member",
|
|
2960
|
+
contentable_id: targetMemberId,
|
|
2961
|
+
member_id: targetMemberId,
|
|
2962
|
+
focus_member_id: null,
|
|
2963
|
+
focus_team_id: null
|
|
2964
|
+
});
|
|
2965
|
+
});
|
|
2966
|
+
notes.command("create-manager").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--target-member-id <targetMemberId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
|
|
2967
|
+
const actorMemberId = nonEmptyString.parse(opts.actorMemberId);
|
|
2968
|
+
await createContent("notes.create-manager", cmd, {
|
|
2969
|
+
type: "WrittenContent",
|
|
2970
|
+
name: nonEmptyString.parse(opts.name),
|
|
2971
|
+
content: nonEmptyString.parse(opts.body),
|
|
2972
|
+
status: String(opts.status ?? "draft"),
|
|
2973
|
+
contentable_type: "Member",
|
|
2974
|
+
contentable_id: actorMemberId,
|
|
2975
|
+
member_id: actorMemberId,
|
|
2976
|
+
focus_member_id: nonEmptyString.parse(opts.targetMemberId)
|
|
2977
|
+
});
|
|
2978
|
+
});
|
|
2979
|
+
notes.command("create-team").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--team-id <teamId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
|
|
2980
|
+
const actorMemberId = nonEmptyString.parse(opts.actorMemberId);
|
|
2981
|
+
const teamId = nonEmptyString.parse(opts.teamId);
|
|
2982
|
+
await createContent("notes.create-team", cmd, {
|
|
2983
|
+
type: "WrittenContent",
|
|
2984
|
+
name: nonEmptyString.parse(opts.name),
|
|
2985
|
+
content: nonEmptyString.parse(opts.body),
|
|
2986
|
+
status: String(opts.status ?? "draft"),
|
|
2987
|
+
contentable_type: "Team",
|
|
2988
|
+
contentable_id: teamId,
|
|
2989
|
+
member_id: actorMemberId,
|
|
2990
|
+
focus_team_id: teamId
|
|
2991
|
+
});
|
|
2992
|
+
});
|
|
2993
|
+
notes.command("create-project").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--project-id <projectId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
|
|
2994
|
+
await createContent("notes.create-project", cmd, {
|
|
2995
|
+
type: "WrittenContent",
|
|
2996
|
+
name: nonEmptyString.parse(opts.name),
|
|
2997
|
+
content: nonEmptyString.parse(opts.body),
|
|
2998
|
+
status: String(opts.status ?? "draft"),
|
|
2999
|
+
contentable_type: "Project",
|
|
3000
|
+
contentable_id: nonEmptyString.parse(opts.projectId),
|
|
3001
|
+
member_id: nonEmptyString.parse(opts.actorMemberId)
|
|
3002
|
+
});
|
|
3003
|
+
});
|
|
3004
|
+
notes.command("create-customer").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--customer-id <customerId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
|
|
3005
|
+
await createContent("notes.create-customer", cmd, {
|
|
3006
|
+
type: "WrittenContent",
|
|
3007
|
+
name: nonEmptyString.parse(opts.name),
|
|
3008
|
+
content: nonEmptyString.parse(opts.body),
|
|
3009
|
+
status: String(opts.status ?? "draft"),
|
|
3010
|
+
contentable_type: "Customer",
|
|
3011
|
+
contentable_id: nonEmptyString.parse(opts.customerId),
|
|
3012
|
+
member_id: nonEmptyString.parse(opts.actorMemberId)
|
|
3013
|
+
});
|
|
3014
|
+
});
|
|
3015
|
+
notes.command("create-contact").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--contact-id <contactId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
|
|
3016
|
+
await createContent("notes.create-contact", cmd, {
|
|
3017
|
+
type: "WrittenContent",
|
|
3018
|
+
name: nonEmptyString.parse(opts.name),
|
|
3019
|
+
content: nonEmptyString.parse(opts.body),
|
|
3020
|
+
status: String(opts.status ?? "draft"),
|
|
3021
|
+
contentable_type: "Contact",
|
|
3022
|
+
contentable_id: nonEmptyString.parse(opts.contactId),
|
|
3023
|
+
member_id: nonEmptyString.parse(opts.actorMemberId)
|
|
3024
|
+
});
|
|
3025
|
+
});
|
|
3026
|
+
}
|
|
3027
|
+
|
|
2544
3028
|
// src/cli.ts
|
|
2545
3029
|
function buildCli() {
|
|
2546
3030
|
const program = new import_commander.Command();
|
|
@@ -2573,6 +3057,8 @@ function buildCli() {
|
|
|
2573
3057
|
registerIssueCommands(program);
|
|
2574
3058
|
registerSystemToolCommands(program);
|
|
2575
3059
|
registerFoundationCommands(program);
|
|
3060
|
+
registerChildEntityCommands(program);
|
|
3061
|
+
registerNoteCommands(program);
|
|
2576
3062
|
return program;
|
|
2577
3063
|
}
|
|
2578
3064
|
|
|
@@ -2621,13 +3107,13 @@ main().catch((error) => {
|
|
|
2621
3107
|
exitCode: EXIT_CODES.invalidArgs
|
|
2622
3108
|
});
|
|
2623
3109
|
}
|
|
2624
|
-
if (error instanceof
|
|
3110
|
+
if (error instanceof import_zod14.ZodError || error instanceof import_commander2.InvalidArgumentError) {
|
|
2625
3111
|
printCliFailure({
|
|
2626
3112
|
status: 400,
|
|
2627
3113
|
code: "invalid_args",
|
|
2628
3114
|
message: "Invalid command arguments.",
|
|
2629
3115
|
details: {
|
|
2630
|
-
issues: error instanceof
|
|
3116
|
+
issues: error instanceof import_zod14.ZodError ? error.issues : [{ message: error.message, code: "invalid_argument" }]
|
|
2631
3117
|
},
|
|
2632
3118
|
exitCode: EXIT_CODES.invalidArgs
|
|
2633
3119
|
});
|
package/dist/index.js
CHANGED
|
@@ -251,7 +251,7 @@ function normalizeGraphqlVariables(variables) {
|
|
|
251
251
|
function buildGraphqlBody(input) {
|
|
252
252
|
const graphqlField = toCamelCase(input.field);
|
|
253
253
|
const graphqlVariables = normalizeGraphqlVariables(input.variables);
|
|
254
|
-
const operationName = graphqlOperationName(input.command);
|
|
254
|
+
const operationName = input.operationName ?? graphqlOperationName(input.command);
|
|
255
255
|
const variableEntries = Object.entries(graphqlVariables).filter(([, value]) => value !== void 0);
|
|
256
256
|
const variableDecl = variableEntries.map(([name, value]) => `$${name}: ${withNonNull(graphqlTypeForVariable(name, value))}`).join(", ");
|
|
257
257
|
const fieldArgs = variableEntries.map(([name]) => `${name}: $${name}`).join(", ");
|
|
@@ -489,12 +489,21 @@ async function runGraphqlQueryCommand(input) {
|
|
|
489
489
|
const result = await graphqlRequest({
|
|
490
490
|
config,
|
|
491
491
|
command: input.command,
|
|
492
|
+
operationName: input.operationName,
|
|
492
493
|
operationType: "query",
|
|
493
494
|
field: input.field,
|
|
494
495
|
variables: input.variables ?? {},
|
|
495
496
|
selectionSet: input.selectionSet ?? defaultQuerySelectionSet(input.field, Boolean(input.isList)),
|
|
496
497
|
isShow: input.isShow
|
|
497
498
|
});
|
|
499
|
+
if (result.envelope.ok && input.transformData && result.envelope.data) {
|
|
500
|
+
const dataRecord = result.envelope.data;
|
|
501
|
+
const transformed = input.transformData(dataRecord[input.field]);
|
|
502
|
+
result.envelope.data = {
|
|
503
|
+
...dataRecord,
|
|
504
|
+
[input.field]: transformed
|
|
505
|
+
};
|
|
506
|
+
}
|
|
498
507
|
printEnvelopeAndExit(result);
|
|
499
508
|
} catch (error) {
|
|
500
509
|
if (error instanceof CliError) {
|
|
@@ -527,6 +536,7 @@ async function runGraphqlMutationCommand(input) {
|
|
|
527
536
|
const result = await graphqlRequest({
|
|
528
537
|
config,
|
|
529
538
|
command: input.command,
|
|
539
|
+
operationName: input.operationName,
|
|
530
540
|
operationType: "mutation",
|
|
531
541
|
field: input.field,
|
|
532
542
|
variables: input.variables ?? {},
|
|
@@ -2540,6 +2550,480 @@ function registerFoundationCommands(program) {
|
|
|
2540
2550
|
});
|
|
2541
2551
|
}
|
|
2542
2552
|
|
|
2553
|
+
// src/commands/childEntities.ts
|
|
2554
|
+
import { z as z12 } from "zod";
|
|
2555
|
+
var idSchema11 = z12.string().min(1);
|
|
2556
|
+
var jsonObjectSchema = z12.record(z12.string(), z12.unknown());
|
|
2557
|
+
function parseJsonObject2(raw) {
|
|
2558
|
+
try {
|
|
2559
|
+
const parsed = JSON.parse(raw);
|
|
2560
|
+
return jsonObjectSchema.parse(parsed);
|
|
2561
|
+
} catch (error) {
|
|
2562
|
+
throw new CliError({
|
|
2563
|
+
message: error instanceof Error ? `Invalid --data-json: ${error.message}` : "Invalid --data-json.",
|
|
2564
|
+
kind: "invalid_args",
|
|
2565
|
+
status: 400,
|
|
2566
|
+
exitCode: EXIT_CODES.invalidArgs
|
|
2567
|
+
});
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
function normalizeBody2(raw, rootKey) {
|
|
2571
|
+
const payload = parseJsonObject2(raw);
|
|
2572
|
+
const rooted = payload[rootKey];
|
|
2573
|
+
if (rooted && typeof rooted === "object" && !Array.isArray(rooted)) {
|
|
2574
|
+
return payload;
|
|
2575
|
+
}
|
|
2576
|
+
return { [rootKey]: payload };
|
|
2577
|
+
}
|
|
2578
|
+
function assertRequiredParent(body, rootKey, parentKey) {
|
|
2579
|
+
const entity = body[rootKey];
|
|
2580
|
+
if (!entity || typeof entity !== "object" || Array.isArray(entity)) {
|
|
2581
|
+
throw new CliError({
|
|
2582
|
+
message: `Invalid payload. Expected object at "${rootKey}".`,
|
|
2583
|
+
kind: "invalid_args",
|
|
2584
|
+
status: 400,
|
|
2585
|
+
exitCode: EXIT_CODES.invalidArgs
|
|
2586
|
+
});
|
|
2587
|
+
}
|
|
2588
|
+
const value = entity[parentKey];
|
|
2589
|
+
if (!(typeof value === "string" && value.trim().length > 0)) {
|
|
2590
|
+
throw new CliError({
|
|
2591
|
+
message: `Missing required create field for ${rootKey}: ${parentKey}.`,
|
|
2592
|
+
kind: "invalid_args",
|
|
2593
|
+
status: 400,
|
|
2594
|
+
exitCode: EXIT_CODES.invalidArgs
|
|
2595
|
+
});
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
function attrValue(attrs, keys) {
|
|
2599
|
+
if (!attrs || typeof attrs !== "object" || Array.isArray(attrs)) {
|
|
2600
|
+
return void 0;
|
|
2601
|
+
}
|
|
2602
|
+
const record = attrs;
|
|
2603
|
+
for (const key of keys) {
|
|
2604
|
+
if (record[key] !== void 0 && record[key] !== null && `${record[key]}`.trim() !== "") {
|
|
2605
|
+
return record[key];
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
return void 0;
|
|
2609
|
+
}
|
|
2610
|
+
function normalizePlacementRow(row, parentKind, parentIdFallback, parentTypedField) {
|
|
2611
|
+
const typedParent = parentTypedField ? row[parentTypedField] : void 0;
|
|
2612
|
+
const parentId = (typeof typedParent === "string" && typedParent.trim().length > 0 ? typedParent : void 0) ?? parentIdFallback ?? null;
|
|
2613
|
+
const attrs = row.attributes;
|
|
2614
|
+
const memberId = (typeof row.memberId === "string" ? row.memberId : void 0) ?? attrValue(attrs, ["memberId", "member_id"]) ?? null;
|
|
2615
|
+
const creatorId = (typeof row.creatorId === "string" ? row.creatorId : void 0) ?? attrValue(attrs, ["creatorId", "creator_id"]) ?? null;
|
|
2616
|
+
const ownerRaw = attrValue(attrs, ["memberId", "member_id", "creatorId", "creator_id"]) ?? null;
|
|
2617
|
+
const description = (typeof row.description === "string" && row.description.length > 0 ? row.description : attrValue(attrs, ["description"])) ?? null;
|
|
2618
|
+
return {
|
|
2619
|
+
id: row.id ?? null,
|
|
2620
|
+
type: row.type ?? null,
|
|
2621
|
+
parent: {
|
|
2622
|
+
kind: parentKind,
|
|
2623
|
+
id: parentId
|
|
2624
|
+
},
|
|
2625
|
+
owner: {
|
|
2626
|
+
memberId,
|
|
2627
|
+
creatorId,
|
|
2628
|
+
raw: ownerRaw
|
|
2629
|
+
},
|
|
2630
|
+
description,
|
|
2631
|
+
attributes: attrs ?? {}
|
|
2632
|
+
};
|
|
2633
|
+
}
|
|
2634
|
+
function normalizeListPayload(payload, parentKind, parentIdFallback, parentTypedField) {
|
|
2635
|
+
const record = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
2636
|
+
const rows = Array.isArray(record.data) ? record.data : [];
|
|
2637
|
+
const normalizedRows = rows.map(
|
|
2638
|
+
(row) => normalizePlacementRow(
|
|
2639
|
+
row,
|
|
2640
|
+
parentKind,
|
|
2641
|
+
parentIdFallback,
|
|
2642
|
+
parentTypedField
|
|
2643
|
+
)
|
|
2644
|
+
);
|
|
2645
|
+
return {
|
|
2646
|
+
data: normalizedRows,
|
|
2647
|
+
count: record.count ?? normalizedRows.length,
|
|
2648
|
+
currentPage: record.currentPage ?? 1,
|
|
2649
|
+
totalPages: record.totalPages ?? 1
|
|
2650
|
+
};
|
|
2651
|
+
}
|
|
2652
|
+
function registerChildCommands(program, config) {
|
|
2653
|
+
const command = program.command(config.command).description(config.description);
|
|
2654
|
+
command.command("list").requiredOption(`--${config.parentFlag} <${config.parentFlag}>`).option("--page <page>").option("--per <per>").action(async (opts, cmd) => {
|
|
2655
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2656
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2657
|
+
const parentId = idSchema11.parse(opts[config.parentFlag.replace(/-([a-z])/g, (_, c) => c.toUpperCase())]);
|
|
2658
|
+
await runGraphqlQueryCommand({
|
|
2659
|
+
command: `${config.command}.list`,
|
|
2660
|
+
operationName: config.listOperationName,
|
|
2661
|
+
runtimeOptions: context.runtimeOptions,
|
|
2662
|
+
field: config.listField,
|
|
2663
|
+
variables: {
|
|
2664
|
+
organization_id: organizationId,
|
|
2665
|
+
[config.parentFlag.replace(/-/g, "_")]: parentId,
|
|
2666
|
+
page: opts.page,
|
|
2667
|
+
per: opts.per
|
|
2668
|
+
},
|
|
2669
|
+
isList: true,
|
|
2670
|
+
selectionSet: config.listSelectionSet,
|
|
2671
|
+
transformData: (payload) => normalizeListPayload(
|
|
2672
|
+
payload,
|
|
2673
|
+
config.parentKind,
|
|
2674
|
+
parentId,
|
|
2675
|
+
config.listParentTypedField
|
|
2676
|
+
)
|
|
2677
|
+
});
|
|
2678
|
+
});
|
|
2679
|
+
command.command("create").requiredOption("--data-json <dataJson>").action(async (opts, cmd) => {
|
|
2680
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2681
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2682
|
+
const body = normalizeBody2(String(opts.dataJson), config.rootKey);
|
|
2683
|
+
assertRequiredParent(body, config.rootKey, config.parentFlag.replace(/-/g, "_"));
|
|
2684
|
+
await runGraphqlMutationCommand({
|
|
2685
|
+
command: `${config.command}.create`,
|
|
2686
|
+
operationName: config.createOperationName,
|
|
2687
|
+
runtimeOptions: context.runtimeOptions,
|
|
2688
|
+
field: config.createField,
|
|
2689
|
+
variables: {
|
|
2690
|
+
organization_id: organizationId,
|
|
2691
|
+
params: body
|
|
2692
|
+
}
|
|
2693
|
+
});
|
|
2694
|
+
});
|
|
2695
|
+
command.command("update").requiredOption("--id <id>").requiredOption("--data-json <dataJson>").action(async (opts, cmd) => {
|
|
2696
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2697
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2698
|
+
const id = idSchema11.parse(opts.id);
|
|
2699
|
+
const body = normalizeBody2(String(opts.dataJson), config.rootKey);
|
|
2700
|
+
await runGraphqlMutationCommand({
|
|
2701
|
+
command: `${config.command}.update`,
|
|
2702
|
+
operationName: config.updateOperationName,
|
|
2703
|
+
runtimeOptions: context.runtimeOptions,
|
|
2704
|
+
field: config.updateField,
|
|
2705
|
+
variables: {
|
|
2706
|
+
organization_id: organizationId,
|
|
2707
|
+
[config.idVariable]: id,
|
|
2708
|
+
params: body
|
|
2709
|
+
}
|
|
2710
|
+
});
|
|
2711
|
+
});
|
|
2712
|
+
command.command("destroy").requiredOption("--id <id>").action(async (opts, cmd) => {
|
|
2713
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2714
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2715
|
+
const id = idSchema11.parse(opts.id);
|
|
2716
|
+
await runGraphqlMutationCommand({
|
|
2717
|
+
command: `${config.command}.destroy`,
|
|
2718
|
+
operationName: config.destroyOperationName,
|
|
2719
|
+
runtimeOptions: context.runtimeOptions,
|
|
2720
|
+
field: config.destroyField,
|
|
2721
|
+
variables: {
|
|
2722
|
+
organization_id: organizationId,
|
|
2723
|
+
[config.idVariable]: id
|
|
2724
|
+
}
|
|
2725
|
+
});
|
|
2726
|
+
});
|
|
2727
|
+
}
|
|
2728
|
+
function registerChildEntityCommands(program) {
|
|
2729
|
+
registerChildCommands(program, {
|
|
2730
|
+
command: "subtasks",
|
|
2731
|
+
description: "Subtask operations",
|
|
2732
|
+
parentFlag: "task-id",
|
|
2733
|
+
parentKind: "task",
|
|
2734
|
+
rootKey: "subtask",
|
|
2735
|
+
listField: "subtasks",
|
|
2736
|
+
createField: "create_subtask",
|
|
2737
|
+
updateField: "update_subtask",
|
|
2738
|
+
destroyField: "destroy_subtask",
|
|
2739
|
+
idVariable: "subtask_id",
|
|
2740
|
+
listOperationName: "SubtasksForTask",
|
|
2741
|
+
createOperationName: "CreateSubtask",
|
|
2742
|
+
updateOperationName: "UpdateSubtask",
|
|
2743
|
+
destroyOperationName: "DestroySubtask",
|
|
2744
|
+
listSelectionSet: "{ data { id type name status taskId attributes } count currentPage totalPages }",
|
|
2745
|
+
listParentTypedField: "taskId"
|
|
2746
|
+
});
|
|
2747
|
+
registerChildCommands(program, {
|
|
2748
|
+
command: "milestones",
|
|
2749
|
+
description: "Milestone operations",
|
|
2750
|
+
parentFlag: "rock-id",
|
|
2751
|
+
parentKind: "rock",
|
|
2752
|
+
rootKey: "milestone",
|
|
2753
|
+
listField: "milestones",
|
|
2754
|
+
createField: "create_milestone",
|
|
2755
|
+
updateField: "update_milestone",
|
|
2756
|
+
destroyField: "destroy_milestone",
|
|
2757
|
+
idVariable: "milestone_id",
|
|
2758
|
+
listOperationName: "MilestonesForRock",
|
|
2759
|
+
createOperationName: "CreateMilestone",
|
|
2760
|
+
updateOperationName: "UpdateMilestone",
|
|
2761
|
+
destroyOperationName: "DestroyMilestone",
|
|
2762
|
+
listSelectionSet: "{ data { id type name slug status attributes } count currentPage totalPages }"
|
|
2763
|
+
});
|
|
2764
|
+
registerChildCommands(program, {
|
|
2765
|
+
command: "subitems",
|
|
2766
|
+
description: "Subitem operations",
|
|
2767
|
+
parentFlag: "list-item-id",
|
|
2768
|
+
parentKind: "listItem",
|
|
2769
|
+
rootKey: "subitem",
|
|
2770
|
+
listField: "subitems",
|
|
2771
|
+
createField: "create_subitem",
|
|
2772
|
+
updateField: "update_subitem",
|
|
2773
|
+
destroyField: "destroy_subitem",
|
|
2774
|
+
idVariable: "subitem_id",
|
|
2775
|
+
listOperationName: "SubitemsForListItem",
|
|
2776
|
+
createOperationName: "CreateSubitem",
|
|
2777
|
+
updateOperationName: "UpdateSubitem",
|
|
2778
|
+
destroyOperationName: "DestroySubitem",
|
|
2779
|
+
listSelectionSet: "{ data { id type name status listItemId attributes } count currentPage totalPages }",
|
|
2780
|
+
listParentTypedField: "listItemId"
|
|
2781
|
+
});
|
|
2782
|
+
registerChildCommands(program, {
|
|
2783
|
+
command: "subtodos",
|
|
2784
|
+
description: "Subtodo operations",
|
|
2785
|
+
parentFlag: "todo-id",
|
|
2786
|
+
parentKind: "todo",
|
|
2787
|
+
rootKey: "sub_todo",
|
|
2788
|
+
listField: "sub_todos",
|
|
2789
|
+
createField: "create_sub_todo",
|
|
2790
|
+
updateField: "update_sub_todo",
|
|
2791
|
+
destroyField: "destroy_sub_todo",
|
|
2792
|
+
idVariable: "sub_todo_id",
|
|
2793
|
+
listOperationName: "SubtodosForTodo",
|
|
2794
|
+
createOperationName: "CreateSubTodo",
|
|
2795
|
+
updateOperationName: "UpdateSubTodo",
|
|
2796
|
+
destroyOperationName: "DestroySubTodo",
|
|
2797
|
+
listSelectionSet: "{ data { id type name status todoId attributes } count currentPage totalPages }",
|
|
2798
|
+
listParentTypedField: "todoId"
|
|
2799
|
+
});
|
|
2800
|
+
registerChildCommands(program, {
|
|
2801
|
+
command: "subissues",
|
|
2802
|
+
description: "Subissue operations",
|
|
2803
|
+
parentFlag: "issue-id",
|
|
2804
|
+
parentKind: "issue",
|
|
2805
|
+
rootKey: "sub_issue",
|
|
2806
|
+
listField: "sub_issues",
|
|
2807
|
+
createField: "create_sub_issue",
|
|
2808
|
+
updateField: "update_sub_issue",
|
|
2809
|
+
destroyField: "destroy_sub_issue",
|
|
2810
|
+
idVariable: "sub_issue_id",
|
|
2811
|
+
listOperationName: "SubissuesForIssue",
|
|
2812
|
+
createOperationName: "CreateSubIssue",
|
|
2813
|
+
updateOperationName: "UpdateSubIssue",
|
|
2814
|
+
destroyOperationName: "DestroySubIssue",
|
|
2815
|
+
listSelectionSet: "{ data { id type name status issueId attributes } count currentPage totalPages }",
|
|
2816
|
+
listParentTypedField: "issueId"
|
|
2817
|
+
});
|
|
2818
|
+
registerChildCommands(program, {
|
|
2819
|
+
command: "talking-points",
|
|
2820
|
+
description: "Talking point operations",
|
|
2821
|
+
parentFlag: "meeting-id",
|
|
2822
|
+
parentKind: "meeting",
|
|
2823
|
+
rootKey: "talking_point",
|
|
2824
|
+
listField: "talking_points",
|
|
2825
|
+
createField: "create_talking_point",
|
|
2826
|
+
updateField: "update_talking_point",
|
|
2827
|
+
destroyField: "destroy_talking_point",
|
|
2828
|
+
idVariable: "talking_point_id",
|
|
2829
|
+
listOperationName: "TalkingPointsForMeeting",
|
|
2830
|
+
createOperationName: "CreateTalkingPoint",
|
|
2831
|
+
updateOperationName: "UpdateTalkingPoint",
|
|
2832
|
+
destroyOperationName: "DestroyTalkingPoint",
|
|
2833
|
+
listSelectionSet: "{ data { id type name description status priority rank dueDate memberId creatorId meetingId attributes } count currentPage totalPages }",
|
|
2834
|
+
listParentTypedField: "meetingId"
|
|
2835
|
+
});
|
|
2836
|
+
}
|
|
2837
|
+
|
|
2838
|
+
// src/commands/notes.ts
|
|
2839
|
+
import { z as z13 } from "zod";
|
|
2840
|
+
var idSchema12 = z13.string().min(1);
|
|
2841
|
+
var nonEmptyString = z13.string().min(1);
|
|
2842
|
+
function assertUpdateFields(params) {
|
|
2843
|
+
if (!params.name && !params.content && !params.status) {
|
|
2844
|
+
throw new CliError({
|
|
2845
|
+
message: "notes update requires at least one of --name, --body, or --status.",
|
|
2846
|
+
kind: "invalid_args",
|
|
2847
|
+
status: 400,
|
|
2848
|
+
exitCode: EXIT_CODES.invalidArgs
|
|
2849
|
+
});
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
async function createContent(command, cmd, payload) {
|
|
2853
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2854
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2855
|
+
return runGraphqlMutationCommand({
|
|
2856
|
+
command,
|
|
2857
|
+
operationName: "CreateContent",
|
|
2858
|
+
runtimeOptions: context.runtimeOptions,
|
|
2859
|
+
field: "create_content",
|
|
2860
|
+
variables: normalizeGraphqlVariables2({
|
|
2861
|
+
organization_id: organizationId,
|
|
2862
|
+
params: {
|
|
2863
|
+
content: payload
|
|
2864
|
+
}
|
|
2865
|
+
})
|
|
2866
|
+
});
|
|
2867
|
+
}
|
|
2868
|
+
function registerNoteCommands(program) {
|
|
2869
|
+
const notes = program.command("notes").description("Content note operations");
|
|
2870
|
+
notes.command("list").option("--contentable-type <contentableType>").option("--contentable-id <contentableId>").option("--member-id <memberId>").option("--focus-member-id <focusMemberId>").option("--focus-team-id <focusTeamId>").option("--page <page>").option("--per <per>").action(async (opts, cmd) => {
|
|
2871
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2872
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2873
|
+
await runGraphqlQueryCommand({
|
|
2874
|
+
command: "notes.list",
|
|
2875
|
+
operationName: "ContentsIndex",
|
|
2876
|
+
runtimeOptions: context.runtimeOptions,
|
|
2877
|
+
field: "contents",
|
|
2878
|
+
variables: normalizeGraphqlVariables2({
|
|
2879
|
+
organization_id: organizationId,
|
|
2880
|
+
contentable_type: opts.contentableType,
|
|
2881
|
+
contentable_id: opts.contentableId,
|
|
2882
|
+
member_id: opts.memberId,
|
|
2883
|
+
focus_member_id: opts.focusMemberId,
|
|
2884
|
+
focus_team_id: opts.focusTeamId,
|
|
2885
|
+
page: opts.page,
|
|
2886
|
+
per: opts.per
|
|
2887
|
+
}),
|
|
2888
|
+
isList: true,
|
|
2889
|
+
selectionSet: "{ count currentPage totalPages data { id type name contentableType contentableId memberId focusMemberId focusTeamId attributes } }"
|
|
2890
|
+
});
|
|
2891
|
+
});
|
|
2892
|
+
notes.command("show").requiredOption("--id <id>").action(async (opts, cmd) => {
|
|
2893
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2894
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2895
|
+
const id = idSchema12.parse(opts.id);
|
|
2896
|
+
await runGraphqlQueryCommand({
|
|
2897
|
+
command: "notes.show",
|
|
2898
|
+
operationName: "ContentShow",
|
|
2899
|
+
runtimeOptions: context.runtimeOptions,
|
|
2900
|
+
field: "content",
|
|
2901
|
+
variables: normalizeGraphqlVariables2({
|
|
2902
|
+
organization_id: organizationId,
|
|
2903
|
+
id
|
|
2904
|
+
}),
|
|
2905
|
+
isShow: true,
|
|
2906
|
+
selectionSet: "{ id type name contentableType contentableId memberId focusMemberId focusTeamId attributes }"
|
|
2907
|
+
});
|
|
2908
|
+
});
|
|
2909
|
+
notes.command("update").requiredOption("--id <id>").option("--name <name>").option("--body <body>").option("--status <status>").action(async (opts, cmd) => {
|
|
2910
|
+
assertUpdateFields({
|
|
2911
|
+
name: opts.name,
|
|
2912
|
+
content: opts.body,
|
|
2913
|
+
status: opts.status
|
|
2914
|
+
});
|
|
2915
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2916
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2917
|
+
const contentId = idSchema12.parse(opts.id);
|
|
2918
|
+
await runGraphqlMutationCommand({
|
|
2919
|
+
command: "notes.update",
|
|
2920
|
+
operationName: "UpdateContent",
|
|
2921
|
+
runtimeOptions: context.runtimeOptions,
|
|
2922
|
+
field: "update_content",
|
|
2923
|
+
variables: normalizeGraphqlVariables2({
|
|
2924
|
+
organization_id: organizationId,
|
|
2925
|
+
content_id: contentId,
|
|
2926
|
+
params: {
|
|
2927
|
+
content: normalizeGraphqlVariables2({
|
|
2928
|
+
name: opts.name,
|
|
2929
|
+
content: opts.body,
|
|
2930
|
+
status: opts.status
|
|
2931
|
+
})
|
|
2932
|
+
}
|
|
2933
|
+
})
|
|
2934
|
+
});
|
|
2935
|
+
});
|
|
2936
|
+
notes.command("destroy").requiredOption("--id <id>").action(async (opts, cmd) => {
|
|
2937
|
+
const context = await resolveCommandContext(cmd.optsWithGlobals());
|
|
2938
|
+
const organizationId = resolveOrganizationId(context.organizationId);
|
|
2939
|
+
const contentId = idSchema12.parse(opts.id);
|
|
2940
|
+
await runGraphqlMutationCommand({
|
|
2941
|
+
command: "notes.destroy",
|
|
2942
|
+
operationName: "DestroyContent",
|
|
2943
|
+
runtimeOptions: context.runtimeOptions,
|
|
2944
|
+
field: "destroy_content",
|
|
2945
|
+
variables: normalizeGraphqlVariables2({
|
|
2946
|
+
organization_id: organizationId,
|
|
2947
|
+
content_id: contentId
|
|
2948
|
+
})
|
|
2949
|
+
});
|
|
2950
|
+
});
|
|
2951
|
+
notes.command("create-member").requiredOption("--target-member-id <targetMemberId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
|
|
2952
|
+
const targetMemberId = nonEmptyString.parse(opts.targetMemberId);
|
|
2953
|
+
await createContent("notes.create-member", cmd, {
|
|
2954
|
+
type: "WrittenContent",
|
|
2955
|
+
name: nonEmptyString.parse(opts.name),
|
|
2956
|
+
content: nonEmptyString.parse(opts.body),
|
|
2957
|
+
status: String(opts.status ?? "draft"),
|
|
2958
|
+
contentable_type: "Member",
|
|
2959
|
+
contentable_id: targetMemberId,
|
|
2960
|
+
member_id: targetMemberId,
|
|
2961
|
+
focus_member_id: null,
|
|
2962
|
+
focus_team_id: null
|
|
2963
|
+
});
|
|
2964
|
+
});
|
|
2965
|
+
notes.command("create-manager").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--target-member-id <targetMemberId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
|
|
2966
|
+
const actorMemberId = nonEmptyString.parse(opts.actorMemberId);
|
|
2967
|
+
await createContent("notes.create-manager", cmd, {
|
|
2968
|
+
type: "WrittenContent",
|
|
2969
|
+
name: nonEmptyString.parse(opts.name),
|
|
2970
|
+
content: nonEmptyString.parse(opts.body),
|
|
2971
|
+
status: String(opts.status ?? "draft"),
|
|
2972
|
+
contentable_type: "Member",
|
|
2973
|
+
contentable_id: actorMemberId,
|
|
2974
|
+
member_id: actorMemberId,
|
|
2975
|
+
focus_member_id: nonEmptyString.parse(opts.targetMemberId)
|
|
2976
|
+
});
|
|
2977
|
+
});
|
|
2978
|
+
notes.command("create-team").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--team-id <teamId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
|
|
2979
|
+
const actorMemberId = nonEmptyString.parse(opts.actorMemberId);
|
|
2980
|
+
const teamId = nonEmptyString.parse(opts.teamId);
|
|
2981
|
+
await createContent("notes.create-team", cmd, {
|
|
2982
|
+
type: "WrittenContent",
|
|
2983
|
+
name: nonEmptyString.parse(opts.name),
|
|
2984
|
+
content: nonEmptyString.parse(opts.body),
|
|
2985
|
+
status: String(opts.status ?? "draft"),
|
|
2986
|
+
contentable_type: "Team",
|
|
2987
|
+
contentable_id: teamId,
|
|
2988
|
+
member_id: actorMemberId,
|
|
2989
|
+
focus_team_id: teamId
|
|
2990
|
+
});
|
|
2991
|
+
});
|
|
2992
|
+
notes.command("create-project").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--project-id <projectId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
|
|
2993
|
+
await createContent("notes.create-project", cmd, {
|
|
2994
|
+
type: "WrittenContent",
|
|
2995
|
+
name: nonEmptyString.parse(opts.name),
|
|
2996
|
+
content: nonEmptyString.parse(opts.body),
|
|
2997
|
+
status: String(opts.status ?? "draft"),
|
|
2998
|
+
contentable_type: "Project",
|
|
2999
|
+
contentable_id: nonEmptyString.parse(opts.projectId),
|
|
3000
|
+
member_id: nonEmptyString.parse(opts.actorMemberId)
|
|
3001
|
+
});
|
|
3002
|
+
});
|
|
3003
|
+
notes.command("create-customer").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--customer-id <customerId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
|
|
3004
|
+
await createContent("notes.create-customer", cmd, {
|
|
3005
|
+
type: "WrittenContent",
|
|
3006
|
+
name: nonEmptyString.parse(opts.name),
|
|
3007
|
+
content: nonEmptyString.parse(opts.body),
|
|
3008
|
+
status: String(opts.status ?? "draft"),
|
|
3009
|
+
contentable_type: "Customer",
|
|
3010
|
+
contentable_id: nonEmptyString.parse(opts.customerId),
|
|
3011
|
+
member_id: nonEmptyString.parse(opts.actorMemberId)
|
|
3012
|
+
});
|
|
3013
|
+
});
|
|
3014
|
+
notes.command("create-contact").requiredOption("--actor-member-id <actorMemberId>").requiredOption("--contact-id <contactId>").requiredOption("--name <name>").requiredOption("--body <body>").option("--status <status>", "draft").action(async (opts, cmd) => {
|
|
3015
|
+
await createContent("notes.create-contact", cmd, {
|
|
3016
|
+
type: "WrittenContent",
|
|
3017
|
+
name: nonEmptyString.parse(opts.name),
|
|
3018
|
+
content: nonEmptyString.parse(opts.body),
|
|
3019
|
+
status: String(opts.status ?? "draft"),
|
|
3020
|
+
contentable_type: "Contact",
|
|
3021
|
+
contentable_id: nonEmptyString.parse(opts.contactId),
|
|
3022
|
+
member_id: nonEmptyString.parse(opts.actorMemberId)
|
|
3023
|
+
});
|
|
3024
|
+
});
|
|
3025
|
+
}
|
|
3026
|
+
|
|
2543
3027
|
// src/cli.ts
|
|
2544
3028
|
function buildCli() {
|
|
2545
3029
|
const program = new Command();
|
|
@@ -2572,6 +3056,8 @@ function buildCli() {
|
|
|
2572
3056
|
registerIssueCommands(program);
|
|
2573
3057
|
registerSystemToolCommands(program);
|
|
2574
3058
|
registerFoundationCommands(program);
|
|
3059
|
+
registerChildEntityCommands(program);
|
|
3060
|
+
registerNoteCommands(program);
|
|
2575
3061
|
return program;
|
|
2576
3062
|
}
|
|
2577
3063
|
|