exponential-cli 1.12.0 → 1.13.0
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 +25 -0
- package/dist/index.js +408 -58
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command23 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/auth.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -1358,6 +1358,157 @@ Pages (${pages.length} total)`));
|
|
|
1358
1358
|
}
|
|
1359
1359
|
console.log();
|
|
1360
1360
|
}
|
|
1361
|
+
function meetingWhen(meeting) {
|
|
1362
|
+
return new Date(meeting.meetingDate ?? meeting.createdAt);
|
|
1363
|
+
}
|
|
1364
|
+
function renderMeetingSummary(summary) {
|
|
1365
|
+
if (!summary.trimStart().startsWith("{")) return summary;
|
|
1366
|
+
try {
|
|
1367
|
+
const parsed = JSON.parse(summary);
|
|
1368
|
+
if (parsed && typeof parsed === "object") {
|
|
1369
|
+
const obj = parsed;
|
|
1370
|
+
const parts = [obj.overview, obj.detailed_breakdown].filter(
|
|
1371
|
+
(v) => typeof v === "string" && v.length > 0
|
|
1372
|
+
);
|
|
1373
|
+
if (parts.length > 0) return parts.join("\n\n");
|
|
1374
|
+
}
|
|
1375
|
+
} catch {
|
|
1376
|
+
}
|
|
1377
|
+
return summary;
|
|
1378
|
+
}
|
|
1379
|
+
function transformMeeting(m) {
|
|
1380
|
+
return {
|
|
1381
|
+
id: m.id,
|
|
1382
|
+
sessionId: m.sessionId,
|
|
1383
|
+
title: m.title,
|
|
1384
|
+
description: m.description,
|
|
1385
|
+
notes: m.notes,
|
|
1386
|
+
summary: m.summary,
|
|
1387
|
+
transcription: m.transcription,
|
|
1388
|
+
meetingDate: m.meetingDate,
|
|
1389
|
+
createdAt: m.createdAt,
|
|
1390
|
+
updatedAt: m.updatedAt,
|
|
1391
|
+
userId: m.userId,
|
|
1392
|
+
projectId: m.projectId,
|
|
1393
|
+
workspaceId: m.workspaceId,
|
|
1394
|
+
archivedAt: m.archivedAt,
|
|
1395
|
+
durationSeconds: m.durationSeconds ?? null,
|
|
1396
|
+
participantCount: m.participantCount ?? null,
|
|
1397
|
+
videoUrl: m.videoUrl ?? null,
|
|
1398
|
+
project: m.project ?? null,
|
|
1399
|
+
workspace: m.workspace ?? null,
|
|
1400
|
+
sourceIntegration: m.sourceIntegration ?? null,
|
|
1401
|
+
participants: m.participants ?? [],
|
|
1402
|
+
actions: m.actions ?? []
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1405
|
+
function transformMeetingListRow(m) {
|
|
1406
|
+
const { notes, summary, transcription, ...rest } = transformMeeting(m);
|
|
1407
|
+
return {
|
|
1408
|
+
...rest,
|
|
1409
|
+
hasNotes: Boolean(notes),
|
|
1410
|
+
hasSummary: Boolean(summary),
|
|
1411
|
+
hasTranscript: Boolean(transcription)
|
|
1412
|
+
};
|
|
1413
|
+
}
|
|
1414
|
+
function outputMeetingJson(meeting) {
|
|
1415
|
+
console.log(JSON.stringify(transformMeeting(meeting), null, 2));
|
|
1416
|
+
}
|
|
1417
|
+
function outputMeetingPretty(meeting, options = {}) {
|
|
1418
|
+
console.log(chalk3.gray("\u2500".repeat(50)));
|
|
1419
|
+
console.log(`
|
|
1420
|
+
${chalk3.bold(meeting.title ?? "Untitled meeting")}`);
|
|
1421
|
+
console.log(chalk3.gray(` ID: ${meeting.id}`));
|
|
1422
|
+
console.log(` ${chalk3.gray("Date:")} ${meetingWhen(meeting).toLocaleString()}`);
|
|
1423
|
+
if (meeting.workspace) {
|
|
1424
|
+
console.log(` ${chalk3.gray("Workspace:")} ${meeting.workspace.name}`);
|
|
1425
|
+
}
|
|
1426
|
+
if (meeting.project) {
|
|
1427
|
+
console.log(` ${chalk3.gray("Project:")} ${meeting.project.name}`);
|
|
1428
|
+
}
|
|
1429
|
+
if (meeting.sourceIntegration) {
|
|
1430
|
+
console.log(` ${chalk3.gray("Source:")} ${meeting.sourceIntegration.provider}`);
|
|
1431
|
+
}
|
|
1432
|
+
if (meeting.durationSeconds) {
|
|
1433
|
+
console.log(` ${chalk3.gray("Duration:")} ${Math.round(meeting.durationSeconds / 60)} min`);
|
|
1434
|
+
}
|
|
1435
|
+
if (meeting.archivedAt) {
|
|
1436
|
+
console.log(` ${chalk3.yellow("Archived")}`);
|
|
1437
|
+
}
|
|
1438
|
+
if (meeting.participants && meeting.participants.length > 0) {
|
|
1439
|
+
const people = meeting.participants.map((p) => p.name ?? p.email).join(", ");
|
|
1440
|
+
console.log(` ${chalk3.gray("Participants:")} ${people}`);
|
|
1441
|
+
}
|
|
1442
|
+
if (meeting.description) {
|
|
1443
|
+
console.log(`
|
|
1444
|
+
${meeting.description}`);
|
|
1445
|
+
}
|
|
1446
|
+
if (meeting.summary) {
|
|
1447
|
+
console.log(`
|
|
1448
|
+
${chalk3.bold("Summary")}`);
|
|
1449
|
+
console.log(renderMeetingSummary(meeting.summary));
|
|
1450
|
+
}
|
|
1451
|
+
if (meeting.notes) {
|
|
1452
|
+
console.log(`
|
|
1453
|
+
${chalk3.bold("Notes")}`);
|
|
1454
|
+
console.log(meeting.notes);
|
|
1455
|
+
} else {
|
|
1456
|
+
console.log(chalk3.gray("\nNo notes yet."));
|
|
1457
|
+
}
|
|
1458
|
+
if (options.transcript) {
|
|
1459
|
+
if (meeting.transcription) {
|
|
1460
|
+
console.log(`
|
|
1461
|
+
${chalk3.bold("Transcript")}`);
|
|
1462
|
+
console.log(meeting.transcription);
|
|
1463
|
+
} else {
|
|
1464
|
+
console.log(chalk3.gray("\nNo transcript."));
|
|
1465
|
+
}
|
|
1466
|
+
} else if (meeting.transcription) {
|
|
1467
|
+
console.log(chalk3.gray("\n(transcript available \u2014 pass --transcript to print it)"));
|
|
1468
|
+
}
|
|
1469
|
+
console.log();
|
|
1470
|
+
}
|
|
1471
|
+
function outputMeetingsJson(meetings) {
|
|
1472
|
+
console.log(
|
|
1473
|
+
JSON.stringify(
|
|
1474
|
+
{ meetings: meetings.map(transformMeetingListRow), total: meetings.length },
|
|
1475
|
+
null,
|
|
1476
|
+
2
|
|
1477
|
+
)
|
|
1478
|
+
);
|
|
1479
|
+
}
|
|
1480
|
+
function outputMeetingsPretty(meetings) {
|
|
1481
|
+
if (meetings.length === 0) {
|
|
1482
|
+
console.log(chalk3.gray("No meetings found."));
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
console.log(chalk3.bold(`
|
|
1486
|
+
Meetings (${meetings.length} total)`));
|
|
1487
|
+
console.log(chalk3.gray("\u2500".repeat(50)));
|
|
1488
|
+
for (const m of meetings) {
|
|
1489
|
+
const flags = [
|
|
1490
|
+
m.notes ? "notes" : null,
|
|
1491
|
+
m.summary ? "summary" : null,
|
|
1492
|
+
m.transcription ? "transcript" : null
|
|
1493
|
+
].filter(Boolean);
|
|
1494
|
+
const archived = m.archivedAt ? chalk3.yellow(" [archived]") : "";
|
|
1495
|
+
console.log(
|
|
1496
|
+
` ${chalk3.bold(m.title ?? "Untitled meeting")}${archived} ${chalk3.gray(
|
|
1497
|
+
meetingWhen(m).toLocaleDateString()
|
|
1498
|
+
)}`
|
|
1499
|
+
);
|
|
1500
|
+
console.log(chalk3.gray(` ID: ${m.id}`));
|
|
1501
|
+
const context = [
|
|
1502
|
+
m.project ? `Project: ${m.project.name}` : null,
|
|
1503
|
+
m.participantCount ? `${m.participantCount} participants` : null,
|
|
1504
|
+
flags.length > 0 ? flags.join(", ") : null
|
|
1505
|
+
].filter(Boolean);
|
|
1506
|
+
if (context.length > 0) {
|
|
1507
|
+
console.log(chalk3.gray(` ${context.join(" \xB7 ")}`));
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
console.log();
|
|
1511
|
+
}
|
|
1361
1512
|
function outputRequirementJson(requirement) {
|
|
1362
1513
|
console.log(JSON.stringify(requirement, null, 2));
|
|
1363
1514
|
}
|
|
@@ -3804,8 +3955,211 @@ function createLabelsCommand() {
|
|
|
3804
3955
|
return labels;
|
|
3805
3956
|
}
|
|
3806
3957
|
|
|
3807
|
-
// src/commands/
|
|
3958
|
+
// src/commands/meetings.ts
|
|
3808
3959
|
import { Command as Command13 } from "commander";
|
|
3960
|
+
import chalk6 from "chalk";
|
|
3961
|
+
|
|
3962
|
+
// src/utils/input.ts
|
|
3963
|
+
import { readFileSync } from "fs";
|
|
3964
|
+
var stdinConsumed = false;
|
|
3965
|
+
function readText(inline, file) {
|
|
3966
|
+
if (inline !== void 0) return inline;
|
|
3967
|
+
if (file === void 0) return void 0;
|
|
3968
|
+
if (file === "-") {
|
|
3969
|
+
if (stdinConsumed) {
|
|
3970
|
+
throw new Error('stdin ("-") can only back one option per invocation.');
|
|
3971
|
+
}
|
|
3972
|
+
stdinConsumed = true;
|
|
3973
|
+
return readFileSync(0, "utf-8");
|
|
3974
|
+
}
|
|
3975
|
+
return readFileSync(file, "utf-8");
|
|
3976
|
+
}
|
|
3977
|
+
function parseDate2(value) {
|
|
3978
|
+
if (value === void 0 || value === "") return void 0;
|
|
3979
|
+
const date = /^\d{4}-\d{2}-\d{2}$/.test(value) ? /* @__PURE__ */ new Date(`${value}T00:00:00`) : new Date(value);
|
|
3980
|
+
if (Number.isNaN(date.getTime())) {
|
|
3981
|
+
throw new Error(
|
|
3982
|
+
`Invalid date: "${value}". Use ISO format, e.g. 2026-08-25 or 2026-08-25T14:00.`
|
|
3983
|
+
);
|
|
3984
|
+
}
|
|
3985
|
+
return date;
|
|
3986
|
+
}
|
|
3987
|
+
|
|
3988
|
+
// src/commands/meetings.ts
|
|
3989
|
+
function createMeetingsCommand() {
|
|
3990
|
+
const meetings = new Command13("meetings").description(
|
|
3991
|
+
"Manage meetings and their notes (recorded, imported, or manually created)"
|
|
3992
|
+
);
|
|
3993
|
+
meetings.command("list").description(
|
|
3994
|
+
'List meetings you can see (owned, attended, or shared via project/workspace). JSON rows carry hasNotes/hasSummary/hasTranscript flags instead of the bodies \u2014 use "get" for content.'
|
|
3995
|
+
).option("--workspace <slug|id>", "Restrict to one workspace").option("--mine", "Only meetings you own or attended").option("--archived", "Include archived meetings").action(
|
|
3996
|
+
async (options, cmd) => {
|
|
3997
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
3998
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
3999
|
+
try {
|
|
4000
|
+
const client = getClient();
|
|
4001
|
+
const workspaceId = options.workspace ? await resolveWorkspaceId(client, options.workspace) : void 0;
|
|
4002
|
+
const list = await client.meetings.list({
|
|
4003
|
+
workspaceId,
|
|
4004
|
+
includeArchived: options.archived,
|
|
4005
|
+
meetingType: options.mine ? "mine" : void 0
|
|
4006
|
+
});
|
|
4007
|
+
if (useJson) outputMeetingsJson(list);
|
|
4008
|
+
else outputMeetingsPretty(list);
|
|
4009
|
+
} catch (error) {
|
|
4010
|
+
handleError(error, useJson);
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
);
|
|
4014
|
+
meetings.command("get <id>").description("Get a meeting: details, summary, and notes").option("--transcript", "Also print the raw transcript (pretty mode; JSON always includes it)").action(
|
|
4015
|
+
async (id, options, cmd) => {
|
|
4016
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
4017
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
4018
|
+
try {
|
|
4019
|
+
const client = getClient();
|
|
4020
|
+
const meeting = await client.meetings.get(id);
|
|
4021
|
+
if (useJson) outputMeetingJson(meeting);
|
|
4022
|
+
else outputMeetingPretty(meeting, { transcript: options.transcript });
|
|
4023
|
+
} catch (error) {
|
|
4024
|
+
handleError(error, useJson);
|
|
4025
|
+
}
|
|
4026
|
+
}
|
|
4027
|
+
);
|
|
4028
|
+
meetings.command("create").description(
|
|
4029
|
+
"Create a meeting manually. Transcript: --transcript text, --transcript-file <path>, or --transcript-file - for stdin."
|
|
4030
|
+
).requiredOption("-t, --title <title>", "Meeting title").option("--transcript <text>", "Transcript text (required by the API)").option("--transcript-file <path>", 'Read the transcript from a file ("-" = stdin)').option("--notes <markdown>", "Meeting notes").option("--notes-file <path>", 'Read the notes from a file ("-" = stdin)').option("--description <text>", "Short description").option("--date <iso>", "When the meeting occurred (e.g. 2026-08-25T14:00; a bare date is local midnight)").option("--project <id>", "Link to a project (the meeting inherits its workspace)").option("--workspace <slug|id>", "Workspace (omit for a personal meeting)").action(
|
|
4031
|
+
async (options, cmd) => {
|
|
4032
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
4033
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
4034
|
+
try {
|
|
4035
|
+
const client = getClient();
|
|
4036
|
+
const transcription = readText(options.transcript, options.transcriptFile);
|
|
4037
|
+
if (transcription === void 0) {
|
|
4038
|
+
throw new Error(
|
|
4039
|
+
"A transcript is required: pass --transcript <text> or --transcript-file <path|->."
|
|
4040
|
+
);
|
|
4041
|
+
}
|
|
4042
|
+
if (transcription.trim() === "") {
|
|
4043
|
+
throw new Error("The transcript is empty. The API requires a non-empty transcript.");
|
|
4044
|
+
}
|
|
4045
|
+
const workspaceId = options.workspace ? await resolveWorkspaceId(client, options.workspace) : void 0;
|
|
4046
|
+
const meeting = await client.meetings.create({
|
|
4047
|
+
title: options.title,
|
|
4048
|
+
transcription,
|
|
4049
|
+
notes: readText(options.notes, options.notesFile),
|
|
4050
|
+
description: options.description,
|
|
4051
|
+
meetingDate: parseDate2(options.date),
|
|
4052
|
+
projectId: options.project,
|
|
4053
|
+
workspaceId
|
|
4054
|
+
});
|
|
4055
|
+
if (useJson) outputMeetingJson(meeting);
|
|
4056
|
+
else {
|
|
4057
|
+
console.log("\n\u2713 Meeting created");
|
|
4058
|
+
outputMeetingPretty(meeting);
|
|
4059
|
+
}
|
|
4060
|
+
} catch (error) {
|
|
4061
|
+
handleError(error, useJson);
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
);
|
|
4065
|
+
meetings.command("update").description(
|
|
4066
|
+
"Update a meeting; only the fields you pass are written. Title and other fields are two API calls \u2014 on a mid-flight failure the title may already be saved."
|
|
4067
|
+
).requiredOption("--id <id>", "Meeting CUID").option("-t, --title <title>", "New title").option("--notes <markdown>", "Replace the meeting notes").option("--notes-file <path>", 'Read the new notes from a file ("-" = stdin)').option("--summary <text>", "Replace the summary").option("--description <text>", "Replace the description").option("--date <iso>", "When the meeting occurred").action(
|
|
4068
|
+
async (options, cmd) => {
|
|
4069
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
4070
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
4071
|
+
try {
|
|
4072
|
+
const notes2 = readText(options.notes, options.notesFile);
|
|
4073
|
+
if (options.title === void 0 && notes2 === void 0 && options.summary === void 0 && options.description === void 0 && options.date === void 0) {
|
|
4074
|
+
throw new Error(
|
|
4075
|
+
"Nothing to update. Pass at least one of --title, --notes, --notes-file, --summary, --description, --date."
|
|
4076
|
+
);
|
|
4077
|
+
}
|
|
4078
|
+
const client = getClient();
|
|
4079
|
+
const meeting = await client.meetings.update({
|
|
4080
|
+
id: options.id,
|
|
4081
|
+
title: options.title,
|
|
4082
|
+
notes: notes2,
|
|
4083
|
+
summary: options.summary,
|
|
4084
|
+
description: options.description,
|
|
4085
|
+
meetingDate: parseDate2(options.date)
|
|
4086
|
+
});
|
|
4087
|
+
if (useJson) outputMeetingJson(meeting);
|
|
4088
|
+
else {
|
|
4089
|
+
console.log("\n\u2713 Meeting updated");
|
|
4090
|
+
outputMeetingPretty(meeting);
|
|
4091
|
+
}
|
|
4092
|
+
} catch (error) {
|
|
4093
|
+
handleError(error, useJson);
|
|
4094
|
+
}
|
|
4095
|
+
}
|
|
4096
|
+
);
|
|
4097
|
+
const notes = new Command13("notes").description(
|
|
4098
|
+
"Read and write a meeting's notes"
|
|
4099
|
+
);
|
|
4100
|
+
notes.command("get <id>").description(
|
|
4101
|
+
"Print the meeting notes as raw Markdown (safe to redirect to a file); pass --json for a {id, notes} envelope"
|
|
4102
|
+
).action(async (id, _options, cmd) => {
|
|
4103
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
4104
|
+
try {
|
|
4105
|
+
const client = getClient();
|
|
4106
|
+
const body = await client.meetings.getNotes(id);
|
|
4107
|
+
if (globalOpts.json) {
|
|
4108
|
+
console.log(JSON.stringify({ id, notes: body }, null, 2));
|
|
4109
|
+
} else if (body !== null) {
|
|
4110
|
+
process.stdout.write(body.endsWith("\n") ? body : `${body}
|
|
4111
|
+
`);
|
|
4112
|
+
} else if (process.stdout.isTTY) {
|
|
4113
|
+
console.log(chalk6.gray("No notes yet."));
|
|
4114
|
+
}
|
|
4115
|
+
} catch (error) {
|
|
4116
|
+
handleError(error, shouldUseJson(globalOpts.json, globalOpts.pretty));
|
|
4117
|
+
}
|
|
4118
|
+
});
|
|
4119
|
+
notes.command("set <id> [notes]").description("Replace the meeting notes. Body: inline, --file <path>, or --file - for stdin.").option("--file <path>", 'Read the notes from a file ("-" = stdin)').action(
|
|
4120
|
+
async (id, inline, options, cmd) => {
|
|
4121
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
4122
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
4123
|
+
try {
|
|
4124
|
+
const body = readText(inline, options.file);
|
|
4125
|
+
if (body === void 0) {
|
|
4126
|
+
throw new Error("Pass the notes inline or via --file <path|->.");
|
|
4127
|
+
}
|
|
4128
|
+
const client = getClient();
|
|
4129
|
+
const meeting = await client.meetings.setNotes(id, body);
|
|
4130
|
+
if (useJson) outputMeetingJson(meeting);
|
|
4131
|
+
else console.log("\u2713 Notes saved");
|
|
4132
|
+
} catch (error) {
|
|
4133
|
+
handleError(error, useJson);
|
|
4134
|
+
}
|
|
4135
|
+
}
|
|
4136
|
+
);
|
|
4137
|
+
notes.command("append <id> [notes]").description(
|
|
4138
|
+
"Append a block to the meeting notes (separated by a blank line). Read-modify-write: concurrent appends can lose one side."
|
|
4139
|
+
).option("--file <path>", 'Read the block from a file ("-" = stdin)').action(
|
|
4140
|
+
async (id, inline, options, cmd) => {
|
|
4141
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
4142
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
4143
|
+
try {
|
|
4144
|
+
const body = readText(inline, options.file);
|
|
4145
|
+
if (body === void 0) {
|
|
4146
|
+
throw new Error("Pass the notes inline or via --file <path|->.");
|
|
4147
|
+
}
|
|
4148
|
+
const client = getClient();
|
|
4149
|
+
const meeting = await client.meetings.appendNotes(id, body);
|
|
4150
|
+
if (useJson) outputMeetingJson(meeting);
|
|
4151
|
+
else console.log("\u2713 Notes appended");
|
|
4152
|
+
} catch (error) {
|
|
4153
|
+
handleError(error, useJson);
|
|
4154
|
+
}
|
|
4155
|
+
}
|
|
4156
|
+
);
|
|
4157
|
+
meetings.addCommand(notes);
|
|
4158
|
+
return meetings;
|
|
4159
|
+
}
|
|
4160
|
+
|
|
4161
|
+
// src/commands/organizations.ts
|
|
4162
|
+
import { Command as Command14 } from "commander";
|
|
3809
4163
|
var VALID_SIZES = [
|
|
3810
4164
|
"1-10",
|
|
3811
4165
|
"11-50",
|
|
@@ -3815,7 +4169,7 @@ var VALID_SIZES = [
|
|
|
3815
4169
|
"1000+"
|
|
3816
4170
|
];
|
|
3817
4171
|
function createOrganizationsCommand() {
|
|
3818
|
-
const organizations = new
|
|
4172
|
+
const organizations = new Command14("organizations").alias("orgs").description("Manage CRM organizations");
|
|
3819
4173
|
organizations.command("list").description("List organizations").requiredOption("--workspace <id>", "Workspace ID").option("--search <query>", "Search by name or description").option("--industry <industry>", "Filter by industry").option("--limit <n>", "Max results to return", parseInt).option("--cursor <cursor>", "Pagination cursor").action(async (options, cmd) => {
|
|
3820
4174
|
const globalOpts = cmd.optsWithGlobals();
|
|
3821
4175
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -3883,13 +4237,12 @@ function createOrganizationsCommand() {
|
|
|
3883
4237
|
}
|
|
3884
4238
|
|
|
3885
4239
|
// src/commands/pages.ts
|
|
3886
|
-
import {
|
|
3887
|
-
import { Command as Command15 } from "commander";
|
|
4240
|
+
import { Command as Command16 } from "commander";
|
|
3888
4241
|
|
|
3889
4242
|
// src/commands/pageComments.ts
|
|
3890
|
-
import { Command as
|
|
4243
|
+
import { Command as Command15 } from "commander";
|
|
3891
4244
|
function createPageCommentsCommand() {
|
|
3892
|
-
const comment = new
|
|
4245
|
+
const comment = new Command15("comment").description(
|
|
3893
4246
|
"Read and post comments on a page. Mention teammates with --mention."
|
|
3894
4247
|
);
|
|
3895
4248
|
comment.command("list").description("List comments on a page").requiredOption("--page <id>", "Page ID").action(async (options, cmd) => {
|
|
@@ -3983,14 +4336,8 @@ function createPageCommentsCommand() {
|
|
|
3983
4336
|
}
|
|
3984
4337
|
|
|
3985
4338
|
// src/commands/pages.ts
|
|
3986
|
-
function readBody(body, bodyFile) {
|
|
3987
|
-
if (body !== void 0) return body;
|
|
3988
|
-
if (bodyFile === void 0) return void 0;
|
|
3989
|
-
if (bodyFile === "-") return readFileSync(0, "utf-8");
|
|
3990
|
-
return readFileSync(bodyFile, "utf-8");
|
|
3991
|
-
}
|
|
3992
4339
|
function createPagesCommand() {
|
|
3993
|
-
const pages = new
|
|
4340
|
+
const pages = new Command16("pages").description(
|
|
3994
4341
|
'Manage Knowledge pages (PRDs, research, technical specs). Link one to a feature with "features link-page".'
|
|
3995
4342
|
);
|
|
3996
4343
|
pages.command("list").description("List pages in a workspace").option("--workspace <slug|id>", "Workspace (defaults to the configured default)").option("--search <text>", "Filter by title/content").action(
|
|
@@ -4033,7 +4380,7 @@ function createPagesCommand() {
|
|
|
4033
4380
|
const page = await client.pages.create({
|
|
4034
4381
|
workspaceId,
|
|
4035
4382
|
title: options.title,
|
|
4036
|
-
body:
|
|
4383
|
+
body: readText(options.body, options.bodyFile)
|
|
4037
4384
|
});
|
|
4038
4385
|
if (useJson) outputPageJson(page);
|
|
4039
4386
|
else {
|
|
@@ -4056,7 +4403,7 @@ function createPagesCommand() {
|
|
|
4056
4403
|
const page = await client.pages.update({
|
|
4057
4404
|
id: options.id,
|
|
4058
4405
|
title: options.title,
|
|
4059
|
-
body:
|
|
4406
|
+
body: readText(options.body, options.bodyFile)
|
|
4060
4407
|
});
|
|
4061
4408
|
if (useJson) outputPageJson(page);
|
|
4062
4409
|
else {
|
|
@@ -4073,9 +4420,9 @@ function createPagesCommand() {
|
|
|
4073
4420
|
}
|
|
4074
4421
|
|
|
4075
4422
|
// src/commands/products.ts
|
|
4076
|
-
import { Command as
|
|
4423
|
+
import { Command as Command17 } from "commander";
|
|
4077
4424
|
function createProductsCommand() {
|
|
4078
|
-
const products = new
|
|
4425
|
+
const products = new Command17("products").description(
|
|
4079
4426
|
"Manage products. A workspace contains products; a product holds features and tickets."
|
|
4080
4427
|
);
|
|
4081
4428
|
products.command("list").description("List products in a workspace").option("--workspace <slug|id>", "Workspace slug or CUID (defaults to configured workspace)").action(async (options, cmd) => {
|
|
@@ -4138,7 +4485,7 @@ function createProductsCommand() {
|
|
|
4138
4485
|
}
|
|
4139
4486
|
|
|
4140
4487
|
// src/commands/projects.ts
|
|
4141
|
-
import { Command as
|
|
4488
|
+
import { Command as Command18 } from "commander";
|
|
4142
4489
|
var PROJECT_STATUSES = [
|
|
4143
4490
|
"ACTIVE",
|
|
4144
4491
|
"ON_HOLD",
|
|
@@ -4165,7 +4512,7 @@ function validateProjectPriority(value) {
|
|
|
4165
4512
|
return value;
|
|
4166
4513
|
}
|
|
4167
4514
|
function createProjectsCommand() {
|
|
4168
|
-
const projects = new
|
|
4515
|
+
const projects = new Command18("projects").description("Manage projects");
|
|
4169
4516
|
projects.command("list").description("List all projects").option("--workspace <slug|id>", "Workspace slug or CUID").option("--include-actions", "Include actions in output").action(async (options, cmd) => {
|
|
4170
4517
|
const globalOpts = cmd.optsWithGlobals();
|
|
4171
4518
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -4284,8 +4631,8 @@ Re-run with --force to delete it anyway.`
|
|
|
4284
4631
|
}
|
|
4285
4632
|
|
|
4286
4633
|
// src/commands/search.ts
|
|
4287
|
-
import { Command as
|
|
4288
|
-
import
|
|
4634
|
+
import { Command as Command19 } from "commander";
|
|
4635
|
+
import chalk7 from "chalk";
|
|
4289
4636
|
var TYPE_LABELS = {
|
|
4290
4637
|
workspace: "Workspaces",
|
|
4291
4638
|
project: "Projects",
|
|
@@ -4303,7 +4650,7 @@ var TYPE_LABELS = {
|
|
|
4303
4650
|
product: "Products"
|
|
4304
4651
|
};
|
|
4305
4652
|
function createSearchCommand() {
|
|
4306
|
-
const search = new
|
|
4653
|
+
const search = new Command19("search").description(
|
|
4307
4654
|
"Global search across projects, actions, goals, workspaces and more \u2014 same coverage as the app's Cmd+K palette"
|
|
4308
4655
|
).argument("<query>", "Text to search for").option("-w, --workspace <slug>", "Restrict results to one workspace (slug or ID)").option("-l, --limit <n>", "Max results per entity type (1-25, default 10)").action(async (query, options, cmd) => {
|
|
4309
4656
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -4317,10 +4664,10 @@ function createSearchCommand() {
|
|
|
4317
4664
|
(w) => w.slug === options.workspace || w.id === options.workspace
|
|
4318
4665
|
);
|
|
4319
4666
|
if (!match) {
|
|
4320
|
-
console.error(
|
|
4321
|
-
console.log(
|
|
4667
|
+
console.error(chalk7.red(`Workspace "${options.workspace}" not found.`));
|
|
4668
|
+
console.log(chalk7.gray("Available workspaces:"));
|
|
4322
4669
|
workspaces.forEach((w) => {
|
|
4323
|
-
console.log(
|
|
4670
|
+
console.log(chalk7.gray(` - ${w.slug} (${w.name})`));
|
|
4324
4671
|
});
|
|
4325
4672
|
process.exit(1);
|
|
4326
4673
|
}
|
|
@@ -4333,7 +4680,7 @@ function createSearchCommand() {
|
|
|
4333
4680
|
return;
|
|
4334
4681
|
}
|
|
4335
4682
|
if (result.results.length === 0) {
|
|
4336
|
-
console.log(
|
|
4683
|
+
console.log(chalk7.gray(`No matches for "${result.query}".`));
|
|
4337
4684
|
return;
|
|
4338
4685
|
}
|
|
4339
4686
|
const byType = /* @__PURE__ */ new Map();
|
|
@@ -4343,14 +4690,14 @@ function createSearchCommand() {
|
|
|
4343
4690
|
byType.set(r.type, bucket);
|
|
4344
4691
|
}
|
|
4345
4692
|
for (const [type, rows] of byType) {
|
|
4346
|
-
console.log(
|
|
4693
|
+
console.log(chalk7.bold(`
|
|
4347
4694
|
${TYPE_LABELS[type] ?? type}`));
|
|
4348
4695
|
for (const row of rows) {
|
|
4349
|
-
const parts = [
|
|
4350
|
-
if (row.subtitle) parts.push(
|
|
4351
|
-
if (row.workspace) parts.push(
|
|
4352
|
-
console.log(` ${parts.join(
|
|
4353
|
-
console.log(
|
|
4696
|
+
const parts = [chalk7.white(row.title)];
|
|
4697
|
+
if (row.subtitle) parts.push(chalk7.gray(row.subtitle));
|
|
4698
|
+
if (row.workspace) parts.push(chalk7.cyan(`@${row.workspace.slug}`));
|
|
4699
|
+
console.log(` ${parts.join(chalk7.gray(" \xB7 "))}`);
|
|
4700
|
+
console.log(chalk7.gray(` ${row.id}${row.url ? ` ${row.url}` : ""}`));
|
|
4354
4701
|
}
|
|
4355
4702
|
}
|
|
4356
4703
|
console.log();
|
|
@@ -4362,7 +4709,7 @@ ${TYPE_LABELS[type] ?? type}`));
|
|
|
4362
4709
|
}
|
|
4363
4710
|
|
|
4364
4711
|
// src/commands/tickets.ts
|
|
4365
|
-
import { Command as
|
|
4712
|
+
import { Command as Command20 } from "commander";
|
|
4366
4713
|
function collectRepeatable(value, previous) {
|
|
4367
4714
|
return [...previous, value];
|
|
4368
4715
|
}
|
|
@@ -4405,7 +4752,7 @@ function validateTicketType(value) {
|
|
|
4405
4752
|
return value;
|
|
4406
4753
|
}
|
|
4407
4754
|
function createTicketsCommand() {
|
|
4408
|
-
const tickets = new
|
|
4755
|
+
const tickets = new Command20("tickets").description(
|
|
4409
4756
|
"Manage product backlog tickets. Tickets live under a product, link to features/epics, depend on each other, and can be implemented via actions."
|
|
4410
4757
|
);
|
|
4411
4758
|
tickets.command("list").description(
|
|
@@ -4518,7 +4865,7 @@ function createTicketsCommand() {
|
|
|
4518
4865
|
handleError(error, useJson);
|
|
4519
4866
|
}
|
|
4520
4867
|
});
|
|
4521
|
-
tickets.command("create").description("Create a new ticket in a product").requiredOption("--product <slug|id>", "Product slug or CUID").requiredOption("-t, --title <title>", "Ticket title").option("-b, --body <text>", "Body (markdown supported)").option("--type <type>", `Ticket type: ${TICKET_TYPES.join(", ")}`).option("--status <status>", `Initial status: ${TICKET_STATUSES.join(", ")}`).option("--priority <n>", "Priority 0-4 (lower = higher)", parseInt).option("--points <n>", "Story points", parseFloat).option("--feature <id>", "Feature CUID to attach to").option("--scope <id>", "Feature scope CUID to attach to (requires --feature)").option("--epic <id>", "Epic CUID to attach to").option("--assignee <id>", "Assignee user ID").option("--branch <name>", "Branch name").option("--pr <url>", "Pull request URL").option("--workspace <slug|id>", "Workspace (required when --product is a slug)").option(
|
|
4868
|
+
tickets.command("create").description("Create a new ticket in a product").requiredOption("--product <slug|id>", "Product slug or CUID").requiredOption("-t, --title <title>", "Ticket title").option("-b, --body <text>", "Body (markdown supported)").option("--type <type>", `Ticket type: ${TICKET_TYPES.join(", ")}`).option("--status <status>", `Initial status: ${TICKET_STATUSES.join(", ")}`).option("--priority <n>", "Priority 0-4 (lower = higher)", parseInt).option("--points <n>", "Story points", parseFloat).option("--feature <id>", "Feature CUID to attach to").option("--scope <id>", "Feature scope CUID to attach to (requires --feature)").option("--epic <id>", "Epic CUID to attach to").option("--cycle <id>", "Cycle CUID to assign to").option("--assignee <id>", "Assignee user ID").option("--branch <name>", "Branch name").option("--pr <url>", "Pull request URL").option("--workspace <slug|id>", "Workspace (required when --product is a slug)").option(
|
|
4522
4869
|
"--label <slug-or-id>",
|
|
4523
4870
|
"Label to attach (repeatable)",
|
|
4524
4871
|
collectRepeatable,
|
|
@@ -4548,6 +4895,7 @@ function createTicketsCommand() {
|
|
|
4548
4895
|
featureId: options.feature,
|
|
4549
4896
|
scopeId: options.scope,
|
|
4550
4897
|
epicId: options.epic,
|
|
4898
|
+
cycleId: options.cycle,
|
|
4551
4899
|
assigneeId: options.assignee,
|
|
4552
4900
|
branchName: options.branch,
|
|
4553
4901
|
prUrl: options.pr
|
|
@@ -4570,7 +4918,7 @@ function createTicketsCommand() {
|
|
|
4570
4918
|
}
|
|
4571
4919
|
}
|
|
4572
4920
|
);
|
|
4573
|
-
tickets.command("update").description("Update an existing ticket").requiredOption("--id <id>", "Ticket CUID").option("-t, --title <title>", "New title").option("-b, --body <text>", "New body").option("--type <type>", `Type: ${TICKET_TYPES.join(", ")}`).option("--status <status>", `Status: ${TICKET_STATUSES.join(", ")}`).option("--priority <n>", 'Priority 0-4 (or "null" to clear)').option("--points <n>", 'Story points (or "null" to clear)').option("--feature <id>", 'Feature CUID (or "null" to detach)').option("--epic <id>", 'Epic CUID (or "null" to detach)').option("--assignee <id>", 'Assignee user ID (or "null" to unassign)').option("--branch <name>", 'Branch name (or "null")').option("--pr <url>", 'PR URL (or "null")').option(
|
|
4921
|
+
tickets.command("update").description("Update an existing ticket").requiredOption("--id <id>", "Ticket CUID").option("-t, --title <title>", "New title").option("-b, --body <text>", "New body").option("--type <type>", `Type: ${TICKET_TYPES.join(", ")}`).option("--status <status>", `Status: ${TICKET_STATUSES.join(", ")}`).option("--priority <n>", 'Priority 0-4 (or "null" to clear)').option("--points <n>", 'Story points (or "null" to clear)').option("--feature <id>", 'Feature CUID (or "null" to detach)').option("--epic <id>", 'Epic CUID (or "null" to detach)').option("--cycle <id>", 'Cycle CUID (or "null" to detach)').option("--assignee <id>", 'Assignee user ID (or "null" to unassign)').option("--branch <name>", 'Branch name (or "null")').option("--pr <url>", 'PR URL (or "null")').option(
|
|
4574
4922
|
"--add-label <slug-or-id>",
|
|
4575
4923
|
"Label to attach to this ticket (repeatable)",
|
|
4576
4924
|
collectRepeatable,
|
|
@@ -4617,6 +4965,7 @@ function createTicketsCommand() {
|
|
|
4617
4965
|
points: parseNullableFloat(options.points),
|
|
4618
4966
|
featureId: parseNullableString(options.feature),
|
|
4619
4967
|
epicId: parseNullableString(options.epic),
|
|
4968
|
+
cycleId: parseNullableString(options.cycle),
|
|
4620
4969
|
assigneeId: parseNullableString(options.assignee),
|
|
4621
4970
|
branchName: parseNullableString(options.branch),
|
|
4622
4971
|
prUrl: parseNullableString(options.pr)
|
|
@@ -4729,7 +5078,7 @@ function createTicketsCommand() {
|
|
|
4729
5078
|
handleError(error, useJson);
|
|
4730
5079
|
}
|
|
4731
5080
|
});
|
|
4732
|
-
const comment = new
|
|
5081
|
+
const comment = new Command20("comment").description("Manage comments on a ticket");
|
|
4733
5082
|
comment.command("list").description("List comments on a ticket").requiredOption("--id <id>", "Ticket CUID").action(async (options, cmd) => {
|
|
4734
5083
|
const globalOpts = cmd.optsWithGlobals();
|
|
4735
5084
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -4821,10 +5170,10 @@ function createTicketsCommand() {
|
|
|
4821
5170
|
}
|
|
4822
5171
|
|
|
4823
5172
|
// src/commands/workspaces.ts
|
|
4824
|
-
import { Command as
|
|
4825
|
-
import
|
|
5173
|
+
import { Command as Command21 } from "commander";
|
|
5174
|
+
import chalk8 from "chalk";
|
|
4826
5175
|
function createWorkspacesCommand() {
|
|
4827
|
-
const workspaces = new
|
|
5176
|
+
const workspaces = new Command21("workspaces").description("Manage workspaces");
|
|
4828
5177
|
workspaces.command("list").description("List all workspaces").action(async (_options, cmd) => {
|
|
4829
5178
|
const globalOpts = cmd.optsWithGlobals();
|
|
4830
5179
|
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
@@ -4837,7 +5186,7 @@ function createWorkspacesCommand() {
|
|
|
4837
5186
|
const config = getConfig();
|
|
4838
5187
|
outputWorkspacesPretty(workspaces2);
|
|
4839
5188
|
if (config.defaultWorkspaceSlug) {
|
|
4840
|
-
console.log(
|
|
5189
|
+
console.log(chalk8.gray(`Default workspace: ${config.defaultWorkspaceSlug}`));
|
|
4841
5190
|
}
|
|
4842
5191
|
}
|
|
4843
5192
|
} catch (error) {
|
|
@@ -4850,10 +5199,10 @@ function createWorkspacesCommand() {
|
|
|
4850
5199
|
const workspaces2 = await client.workspaces.list();
|
|
4851
5200
|
const workspace = workspaces2.find((w) => w.slug === slug);
|
|
4852
5201
|
if (!workspace) {
|
|
4853
|
-
console.error(
|
|
4854
|
-
console.log(
|
|
5202
|
+
console.error(chalk8.red(`Workspace with slug "${slug}" not found.`));
|
|
5203
|
+
console.log(chalk8.gray("Available workspaces:"));
|
|
4855
5204
|
workspaces2.forEach((w) => {
|
|
4856
|
-
console.log(
|
|
5205
|
+
console.log(chalk8.gray(` - ${w.slug} (${w.name})`));
|
|
4857
5206
|
});
|
|
4858
5207
|
process.exit(1);
|
|
4859
5208
|
}
|
|
@@ -4861,7 +5210,7 @@ function createWorkspacesCommand() {
|
|
|
4861
5210
|
defaultWorkspaceId: workspace.id,
|
|
4862
5211
|
defaultWorkspaceSlug: workspace.slug
|
|
4863
5212
|
});
|
|
4864
|
-
console.log(
|
|
5213
|
+
console.log(chalk8.green(`Default workspace set to: ${workspace.name} (${workspace.slug})`));
|
|
4865
5214
|
} catch (error) {
|
|
4866
5215
|
handleError(error);
|
|
4867
5216
|
}
|
|
@@ -4889,20 +5238,20 @@ function createWorkspacesCommand() {
|
|
|
4889
5238
|
return;
|
|
4890
5239
|
}
|
|
4891
5240
|
if (members.length === 0) {
|
|
4892
|
-
console.log(
|
|
5241
|
+
console.log(chalk8.gray("No members found."));
|
|
4893
5242
|
return;
|
|
4894
5243
|
}
|
|
4895
|
-
console.log(
|
|
5244
|
+
console.log(chalk8.bold(`
|
|
4896
5245
|
Members (${members.length})
|
|
4897
5246
|
`));
|
|
4898
5247
|
for (const m of members) {
|
|
4899
5248
|
const label = m.name ?? m.email ?? m.id;
|
|
4900
|
-
const via = m.source === "team" ?
|
|
5249
|
+
const via = m.source === "team" ? chalk8.gray(
|
|
4901
5250
|
` via team${m.teams.length ? `: ${m.teams.map((t) => t.name).join(", ")}` : ""}` + (m.teamRole ? ` [team ${m.teamRole}]` : "")
|
|
4902
5251
|
) : "";
|
|
4903
|
-
console.log(`${
|
|
4904
|
-
if (m.email) console.log(
|
|
4905
|
-
console.log(
|
|
5252
|
+
console.log(`${chalk8.bold(label)} ${chalk8.gray(`(${m.role})`)}${via}`);
|
|
5253
|
+
if (m.email) console.log(chalk8.gray(` ${m.email}`));
|
|
5254
|
+
console.log(chalk8.gray(` mention: ${m.mentionSyntax}`));
|
|
4906
5255
|
console.log();
|
|
4907
5256
|
}
|
|
4908
5257
|
} catch (error) {
|
|
@@ -4914,7 +5263,7 @@ Members (${members.length})
|
|
|
4914
5263
|
}
|
|
4915
5264
|
|
|
4916
5265
|
// src/commands/goals.ts
|
|
4917
|
-
import { Command as
|
|
5266
|
+
import { Command as Command22 } from "commander";
|
|
4918
5267
|
var GOAL_STATUSES = [
|
|
4919
5268
|
"planned",
|
|
4920
5269
|
"active",
|
|
@@ -5026,7 +5375,7 @@ function validateKeyResultUnit(value) {
|
|
|
5026
5375
|
return value;
|
|
5027
5376
|
}
|
|
5028
5377
|
function createKeyResultsCommand() {
|
|
5029
|
-
const kr = new
|
|
5378
|
+
const kr = new Command22("kr").description(
|
|
5030
5379
|
"Key results on an objective. Ids are CUIDs; --goal takes the objective's integer id."
|
|
5031
5380
|
);
|
|
5032
5381
|
kr.command("list").description("List key results").option("--goal <id>", "Objective ID (a number)").option("-w, --workspace <slug|id>", "Workspace (workspace-wide: every member's KRs)").option("--period <period>", "Period, e.g. Q3-2026").option("--status <status>", `Filter by status: ${KEY_RESULT_STATUSES.join(", ")}`).option("--mine", "Narrow a workspace list to key results you own").action(
|
|
@@ -5229,7 +5578,7 @@ function createKeyResultsCommand() {
|
|
|
5229
5578
|
return kr;
|
|
5230
5579
|
}
|
|
5231
5580
|
function createGoalCommentsCommand() {
|
|
5232
|
-
const comment = new
|
|
5581
|
+
const comment = new Command22("comment").description(
|
|
5233
5582
|
"Read and post comments on a goal. Mention teammates with --mention."
|
|
5234
5583
|
);
|
|
5235
5584
|
comment.command("list").description("List comments on a goal").requiredOption("--goal <id>", "Goal ID (a number)").action(async (options, cmd) => {
|
|
@@ -5324,7 +5673,7 @@ function createGoalCommentsCommand() {
|
|
|
5324
5673
|
return comment;
|
|
5325
5674
|
}
|
|
5326
5675
|
function createGoalsCommand() {
|
|
5327
|
-
const goals = new
|
|
5676
|
+
const goals = new Command22("goals").description(
|
|
5328
5677
|
"Manage goals (objectives) and their key results. Objectives have integer ids; key results are CUIDs."
|
|
5329
5678
|
);
|
|
5330
5679
|
goals.command("list").description(
|
|
@@ -5590,7 +5939,7 @@ Re-run with --with-key-results to go ahead, or move them with \`goals kr update
|
|
|
5590
5939
|
return goals;
|
|
5591
5940
|
}
|
|
5592
5941
|
function createOkrsCommand() {
|
|
5593
|
-
const okrs = new
|
|
5942
|
+
const okrs = new Command22("okrs").description(
|
|
5594
5943
|
"OKRs \u2014 objectives with their key results nested. Manage the parts with `goals` and `goals kr`."
|
|
5595
5944
|
);
|
|
5596
5945
|
okrs.command("list").description(
|
|
@@ -5674,7 +6023,7 @@ import { fileURLToPath } from "url";
|
|
|
5674
6023
|
var PKG_VERSION = JSON.parse(
|
|
5675
6024
|
readFileSync2(join(dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf-8")
|
|
5676
6025
|
).version;
|
|
5677
|
-
var program = new
|
|
6026
|
+
var program = new Command23();
|
|
5678
6027
|
program.name("exponential").description(
|
|
5679
6028
|
[
|
|
5680
6029
|
"CLI to interact with Exponential productivity app.",
|
|
@@ -5691,6 +6040,7 @@ program.addCommand(createDealsCommand());
|
|
|
5691
6040
|
program.addCommand(createEpicsCommand());
|
|
5692
6041
|
program.addCommand(createFeaturesCommand());
|
|
5693
6042
|
program.addCommand(createLabelsCommand());
|
|
6043
|
+
program.addCommand(createMeetingsCommand());
|
|
5694
6044
|
program.addCommand(createOrganizationsCommand());
|
|
5695
6045
|
program.addCommand(createPagesCommand());
|
|
5696
6046
|
program.addCommand(createProductsCommand());
|