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