epismo 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth.js +32 -4
- package/dist/auth.js.map +1 -1
- package/dist/context.js +2 -2
- package/dist/context.js.map +1 -1
- package/dist/packs.js +9 -2
- package/dist/packs.js.map +1 -1
- package/dist/program.js +301 -126
- package/dist/program.js.map +1 -1
- package/dist/projects.js +9 -2
- package/dist/projects.js.map +1 -1
- package/dist/token.js +10 -0
- package/dist/token.js.map +1 -0
- package/dist/tracks.js +30 -16
- package/dist/tracks.js.map +1 -1
- package/dist/workspace.js +4 -6
- package/dist/workspace.js.map +1 -1
- package/dist/workspaces.js +15 -2
- package/dist/workspaces.js.map +1 -1
- package/package.json +1 -1
package/dist/program.js
CHANGED
|
@@ -3,21 +3,19 @@ import { clearWorkspace, getCurrentWorkspace, listAvailableWorkspaces, login, lo
|
|
|
3
3
|
import { resolveExecutionContext } from "./context.js";
|
|
4
4
|
import { mergeDefined, parseJsonArrayOption, parseJsonObjectOption, parseOptionalPositiveInteger, parseStringArrayInput, readJsonObjectInput } from "./input.js";
|
|
5
5
|
import { printJson, printWarning } from "./output.js";
|
|
6
|
-
import { deleteTrack, getTrack, searchTracks,
|
|
7
|
-
import { deletePack, getPack, likePack, searchPacks,
|
|
6
|
+
import { applyTracks, createTrack, deleteTrack, getTrack, searchTracks, updateTrack } from "./tracks.js";
|
|
7
|
+
import { createPack, deletePack, getPack, likePack, searchPacks, updatePack } from "./packs.js";
|
|
8
8
|
import { deleteAlias, getAlias, listAliases, upsertAlias } from "./aliases.js";
|
|
9
9
|
import { creditBalance, creditCheckout } from "./credits.js";
|
|
10
10
|
import { CliError } from "./errors.js";
|
|
11
11
|
import { addAgents, listAgents, removeAgents } from "./agents.js";
|
|
12
|
-
import { deleteWorkspaceMember, listWorkspaceMembers,
|
|
13
|
-
import { addProjectMember, deleteProject, deleteProjectMember, listProjectMembers, listProjects,
|
|
12
|
+
import { createWorkspace, deleteWorkspaceMember, getWorkspaceCheckout, listWorkspaceMembers, updateWorkspace, upsertWorkspaceMember } from "./workspaces.js";
|
|
13
|
+
import { addProjectMember, createProject, deleteProject, deleteProjectMember, listProjectMembers, listProjects, updateProject } from "./projects.js";
|
|
14
|
+
import { createToken } from "./token.js";
|
|
14
15
|
const TRACK_TYPES = ["task", "goal"];
|
|
15
16
|
const PACK_TYPES = ["workflow", "context"];
|
|
16
17
|
const PACK_VISIBILITIES = ["public", "private"];
|
|
17
|
-
//
|
|
18
|
-
const WORKSPACE_ID_OPT = "--workspace-id <workspaceId>";
|
|
19
|
-
const WORKSPACE_ID_DESC = "workspace to use; resolved in order: CLI arg → saved default → personal space";
|
|
20
|
-
// #2: centralize warning codes so wording is consistent everywhere
|
|
18
|
+
// centralize warning codes so wording is consistent everywhere
|
|
21
19
|
const WARNING_ENV_TOKEN_WORKSPACE_IGNORED = "EPISMO_TOKEN_WORKSPACE_IGNORED";
|
|
22
20
|
async function resolveInput(options, overrides) {
|
|
23
21
|
const base = await readJsonObjectInput(options.input);
|
|
@@ -30,8 +28,42 @@ function getExplicitOptionOverride(command, optionName, value) {
|
|
|
30
28
|
}
|
|
31
29
|
return value;
|
|
32
30
|
}
|
|
33
|
-
|
|
34
|
-
const
|
|
31
|
+
function buildSharingTargets(command, options) {
|
|
32
|
+
const targets = mergeDefined({}, {
|
|
33
|
+
projectIds: getExplicitOptionOverride(command, "projectIds", parseStringArrayInput(options.projectIds, "--project-ids")),
|
|
34
|
+
userIds: getExplicitOptionOverride(command, "userIds", parseStringArrayInput(options.userIds, "--user-ids")),
|
|
35
|
+
emails: getExplicitOptionOverride(command, "emails", parseStringArrayInput(options.emails, "--emails"))
|
|
36
|
+
});
|
|
37
|
+
return Object.keys(targets).length > 0 ? targets : undefined;
|
|
38
|
+
}
|
|
39
|
+
function buildSearchTargets(command, options) {
|
|
40
|
+
const targets = mergeDefined({}, {
|
|
41
|
+
projectIds: getExplicitOptionOverride(command, "projectIds", parseStringArrayInput(options.projectIds, "--project-ids")),
|
|
42
|
+
self: getExplicitOptionOverride(command, "self", parseOptionalBooleanText(options.self, "--self"))
|
|
43
|
+
});
|
|
44
|
+
return Object.keys(targets).length > 0 ? targets : undefined;
|
|
45
|
+
}
|
|
46
|
+
function parseOptionalBooleanText(value, optionName) {
|
|
47
|
+
if (value === undefined) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
if (typeof value === "boolean") {
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
if (typeof value === "string") {
|
|
54
|
+
const normalized = value.trim().toLowerCase();
|
|
55
|
+
if (normalized === "true")
|
|
56
|
+
return true;
|
|
57
|
+
if (normalized === "false")
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
throw new CliError({
|
|
61
|
+
code: "INVALID_INPUT",
|
|
62
|
+
message: `Invalid ${optionName}: expected true or false.`
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async function resolveContext() {
|
|
66
|
+
const context = await resolveExecutionContext();
|
|
35
67
|
if (context.warning) {
|
|
36
68
|
printWarning({
|
|
37
69
|
warning: { code: WARNING_ENV_TOKEN_WORKSPACE_IGNORED, message: context.warning }
|
|
@@ -51,11 +83,12 @@ export function buildProgram(version) {
|
|
|
51
83
|
.exitOverride();
|
|
52
84
|
program.addHelpText("after", `
|
|
53
85
|
Workspace resolution:
|
|
54
|
-
|
|
55
|
-
1.
|
|
56
|
-
2.
|
|
57
|
-
|
|
58
|
-
|
|
86
|
+
All commands resolve workspace in this order:
|
|
87
|
+
1. Saved default (epismo workspace use)
|
|
88
|
+
2. Personal space (fallback)
|
|
89
|
+
When EPISMO_TOKEN is set, the saved default is skipped — the workspace is
|
|
90
|
+
resolved from the token itself. Use epismo token create --workspace-id to
|
|
91
|
+
issue a workspace-scoped token for CI/CD.
|
|
59
92
|
|
|
60
93
|
Examples:
|
|
61
94
|
epismo login
|
|
@@ -108,16 +141,14 @@ Examples:
|
|
|
108
141
|
program
|
|
109
142
|
.command("whoami")
|
|
110
143
|
.description("show the currently authenticated user")
|
|
111
|
-
.
|
|
112
|
-
|
|
113
|
-
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
144
|
+
.action(async () => {
|
|
145
|
+
const context = await resolveContext();
|
|
114
146
|
printJson(await whoami({ workspaceId: context.workspaceId, auth: context.auth }));
|
|
115
147
|
});
|
|
116
148
|
program.commands.at(-1)?.addHelpText("after", `
|
|
117
149
|
Examples:
|
|
118
150
|
epismo whoami
|
|
119
|
-
EPISMO_TOKEN=<access-token> epismo whoami
|
|
120
|
-
epismo whoami --workspace-id <workspace-id>`);
|
|
151
|
+
EPISMO_TOKEN=<access-token> epismo whoami`);
|
|
121
152
|
const workspace = program
|
|
122
153
|
.command("workspace")
|
|
123
154
|
.description("manage workspaces and the saved default workspace");
|
|
@@ -159,33 +190,63 @@ Example:
|
|
|
159
190
|
Example:
|
|
160
191
|
epismo workspace clear`);
|
|
161
192
|
workspace
|
|
162
|
-
.command("
|
|
163
|
-
.description("create a new workspace
|
|
193
|
+
.command("create")
|
|
194
|
+
.description("create a new workspace")
|
|
164
195
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
165
|
-
.option("--id <id>", "existing workspace id")
|
|
166
196
|
.option("--name <name>", "workspace name")
|
|
167
197
|
.addOption(new Option("--plan <plan>", "basic | pro").choices(["basic", "pro"]))
|
|
168
198
|
.action(async (options) => {
|
|
169
|
-
const payload = await resolveInput({ input: options.input }, {
|
|
170
|
-
const context = await resolveContext(
|
|
171
|
-
|
|
199
|
+
const payload = await resolveInput({ input: options.input }, { name: options.name, plan: options.plan });
|
|
200
|
+
const context = await resolveContext();
|
|
201
|
+
const created = await createWorkspace(context, payload);
|
|
202
|
+
const workspaceId = created.workspace?.id;
|
|
203
|
+
if (workspaceId) {
|
|
204
|
+
const checkout = await getWorkspaceCheckout(context, workspaceId);
|
|
205
|
+
printJson({ ...created, ...checkout });
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
printJson(created);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
workspace.commands.at(-1)?.addHelpText("after", `
|
|
212
|
+
Examples:
|
|
213
|
+
epismo workspace create --name my-team --plan basic
|
|
214
|
+
epismo workspace create --input @workspace.json`);
|
|
215
|
+
workspace
|
|
216
|
+
.command("checkout")
|
|
217
|
+
.description("get the billing URL for a workspace (to complete or retry payment)")
|
|
218
|
+
.requiredOption("--id <id>", "workspace id")
|
|
219
|
+
.action(async (options) => {
|
|
220
|
+
const context = await resolveContext();
|
|
221
|
+
printJson(await getWorkspaceCheckout(context, options.id));
|
|
222
|
+
});
|
|
223
|
+
workspace.commands.at(-1)?.addHelpText("after", `
|
|
224
|
+
Examples:
|
|
225
|
+
epismo workspace checkout --id <workspace-id>`);
|
|
226
|
+
workspace
|
|
227
|
+
.command("update")
|
|
228
|
+
.description("update a workspace you own (PATCH — omitted fields are unchanged)")
|
|
229
|
+
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
230
|
+
.requiredOption("--id <id>", "workspace id to update")
|
|
231
|
+
.option("--name <name>", "updated workspace name")
|
|
232
|
+
.addOption(new Option("--plan <plan>", "basic | pro").choices(["basic", "pro"]))
|
|
233
|
+
.action(async (options) => {
|
|
234
|
+
const payload = await resolveInput({ input: options.input }, { name: options.name, plan: options.plan });
|
|
235
|
+
const context = await resolveContext();
|
|
236
|
+
printJson(await updateWorkspace(context, options.id, payload));
|
|
172
237
|
});
|
|
173
238
|
const workspaceMember = workspace.command("member").description("manage workspace members");
|
|
174
239
|
workspaceMember
|
|
175
240
|
.command("list")
|
|
176
241
|
.description("list members in a workspace")
|
|
177
|
-
.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
printJson(await listWorkspaceMembers(context, {
|
|
181
|
-
workspaceId: options.workspaceId ?? context.workspaceId
|
|
182
|
-
}));
|
|
242
|
+
.action(async () => {
|
|
243
|
+
const context = await resolveContext();
|
|
244
|
+
printJson(await listWorkspaceMembers(context, { workspaceId: context.workspaceId }));
|
|
183
245
|
});
|
|
184
246
|
workspaceMember
|
|
185
247
|
.command("upsert")
|
|
186
248
|
.description("add a workspace member or update the member role")
|
|
187
249
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
188
|
-
.option("--workspace-id <workspaceId>", "workspace id")
|
|
189
250
|
.option("--user-id <userId>", "user id")
|
|
190
251
|
.addOption(new Option("--role <role>", "owner | admin | member").choices([
|
|
191
252
|
"owner",
|
|
@@ -193,65 +254,74 @@ Example:
|
|
|
193
254
|
"member"
|
|
194
255
|
]))
|
|
195
256
|
.action(async (options) => {
|
|
257
|
+
const context = await resolveContext();
|
|
196
258
|
const payload = await resolveInput({ input: options.input }, {
|
|
197
|
-
workspaceId:
|
|
259
|
+
workspaceId: context.workspaceId,
|
|
198
260
|
userId: options.userId,
|
|
199
261
|
role: options.role
|
|
200
262
|
});
|
|
201
|
-
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
202
263
|
printJson(await upsertWorkspaceMember(context, payload));
|
|
203
264
|
});
|
|
204
265
|
workspaceMember
|
|
205
266
|
.command("delete")
|
|
206
267
|
.description("remove a workspace member")
|
|
207
268
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
208
|
-
.option("--workspace-id <workspaceId>", "workspace id")
|
|
209
269
|
.option("--user-id <userId>", "user id")
|
|
210
270
|
.action(async (options) => {
|
|
271
|
+
const context = await resolveContext();
|
|
211
272
|
const payload = await resolveInput({ input: options.input }, {
|
|
212
|
-
workspaceId:
|
|
273
|
+
workspaceId: context.workspaceId,
|
|
213
274
|
userId: options.userId
|
|
214
275
|
});
|
|
215
|
-
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
216
276
|
printJson(await deleteWorkspaceMember(context, payload));
|
|
217
277
|
});
|
|
218
278
|
const project = program.command("project").description("manage workspace projects");
|
|
219
279
|
project
|
|
220
280
|
.command("list")
|
|
221
281
|
.description("list projects visible in the selected workspace")
|
|
222
|
-
.
|
|
223
|
-
|
|
224
|
-
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
282
|
+
.action(async () => {
|
|
283
|
+
const context = await resolveContext();
|
|
225
284
|
printJson(await listProjects(context));
|
|
226
285
|
});
|
|
227
286
|
project
|
|
228
|
-
.command("
|
|
229
|
-
.description("create a project in the selected workspace
|
|
287
|
+
.command("create")
|
|
288
|
+
.description("create a project in the selected workspace")
|
|
230
289
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
231
|
-
.option("--id <id>", "existing project id")
|
|
232
290
|
.option("--name <name>", "project name")
|
|
233
291
|
.option("--description <description>", "project description")
|
|
234
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
235
292
|
.action(async (options) => {
|
|
236
293
|
const payload = await resolveInput(options, {
|
|
237
|
-
id: options.id,
|
|
238
294
|
name: options.name,
|
|
239
295
|
description: options.description
|
|
240
296
|
});
|
|
241
|
-
const context = await resolveContext(
|
|
242
|
-
printJson(await
|
|
297
|
+
const context = await resolveContext();
|
|
298
|
+
printJson(await createProject(context, payload));
|
|
299
|
+
});
|
|
300
|
+
project
|
|
301
|
+
.command("update")
|
|
302
|
+
.description("update a project you can access (PATCH — omitted fields are unchanged)")
|
|
303
|
+
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
304
|
+
.requiredOption("--id <id>", "project id to update")
|
|
305
|
+
.option("--name <name>", "updated project name")
|
|
306
|
+
.option("--description <description>", "updated project description")
|
|
307
|
+
.action(async (options) => {
|
|
308
|
+
const payload = await resolveInput(options, {
|
|
309
|
+
name: options.name,
|
|
310
|
+
description: options.description
|
|
311
|
+
});
|
|
312
|
+
const context = await resolveContext();
|
|
313
|
+
printJson(await updateProject(context, options.id, payload));
|
|
243
314
|
});
|
|
244
315
|
project
|
|
245
316
|
.command("delete")
|
|
246
317
|
.description("delete a project you can access in the selected workspace")
|
|
247
318
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
248
319
|
.option("--id <id>", "project id")
|
|
249
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
250
320
|
.action(async (options) => {
|
|
251
321
|
const payload = await resolveInput(options, {
|
|
252
322
|
id: options.id
|
|
253
323
|
});
|
|
254
|
-
const context = await resolveContext(
|
|
324
|
+
const context = await resolveContext();
|
|
255
325
|
printJson(await deleteProject(context, payload));
|
|
256
326
|
});
|
|
257
327
|
const projectMember = project.command("member").description("manage project members");
|
|
@@ -260,12 +330,11 @@ Example:
|
|
|
260
330
|
.description("list members across one or more projects")
|
|
261
331
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
262
332
|
.option("--project-ids <projectIds>", "JSON array or comma-separated project ids")
|
|
263
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
264
333
|
.action(async (options) => {
|
|
265
334
|
const payload = await resolveInput(options, {
|
|
266
335
|
projectIds: parseStringArrayInput(options.projectIds, "--project-ids")
|
|
267
336
|
});
|
|
268
|
-
const context = await resolveContext(
|
|
337
|
+
const context = await resolveContext();
|
|
269
338
|
printJson(await listProjectMembers(context, payload));
|
|
270
339
|
});
|
|
271
340
|
projectMember
|
|
@@ -274,13 +343,12 @@ Example:
|
|
|
274
343
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
275
344
|
.option("--project-id <projectId>", "project id")
|
|
276
345
|
.option("--user-id <userId>", "user id")
|
|
277
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
278
346
|
.action(async (options) => {
|
|
279
347
|
const payload = await resolveInput(options, {
|
|
280
348
|
projectId: options.projectId,
|
|
281
349
|
userId: options.userId
|
|
282
350
|
});
|
|
283
|
-
const context = await resolveContext(
|
|
351
|
+
const context = await resolveContext();
|
|
284
352
|
printJson(await addProjectMember(context, payload));
|
|
285
353
|
});
|
|
286
354
|
projectMember
|
|
@@ -289,60 +357,88 @@ Example:
|
|
|
289
357
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
290
358
|
.option("--project-id <projectId>", "project id")
|
|
291
359
|
.option("--user-id <userId>", "user id")
|
|
292
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
293
360
|
.action(async (options) => {
|
|
294
361
|
const payload = await resolveInput(options, {
|
|
295
362
|
projectId: options.projectId,
|
|
296
363
|
userId: options.userId
|
|
297
364
|
});
|
|
298
|
-
const context = await resolveContext(
|
|
365
|
+
const context = await resolveContext();
|
|
299
366
|
printJson(await deleteProjectMember(context, payload));
|
|
300
367
|
});
|
|
301
368
|
const track = program.command("track").description("manage project tracks (tasks and goals)");
|
|
302
369
|
track
|
|
303
|
-
.command("
|
|
304
|
-
.description("create
|
|
370
|
+
.command("create")
|
|
371
|
+
.description("create a new project track (task or goal)")
|
|
305
372
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
306
373
|
.addOption(new Option("--type <type>", "task | goal").choices(TRACK_TYPES))
|
|
307
|
-
.option("--id <id>", "existing item id")
|
|
308
374
|
.option("--title <title>", "title")
|
|
309
375
|
.option("--content <content>", "markdown content")
|
|
310
|
-
.option("--
|
|
376
|
+
.option("--project-ids <projectIds>", "JSON array or comma-separated project ids")
|
|
377
|
+
.option("--user-ids <userIds>", "JSON array or comma-separated user ids")
|
|
378
|
+
.option("--emails <emails>", "JSON array or comma-separated email addresses")
|
|
311
379
|
.option("--task <task>", 'task-specific fields as JSON object e.g. \'{"status":"todo","dueDate":"2025-12-31"}\'')
|
|
312
380
|
.option("--goal <goal>", 'goal-specific fields as JSON object e.g. \'{"status":"on_track","dueDate":"2025-12-31"}\'')
|
|
313
|
-
.
|
|
314
|
-
.action(async (options) => {
|
|
381
|
+
.action(async (options, command) => {
|
|
315
382
|
const payload = await resolveInput(options, {
|
|
316
383
|
type: options.type,
|
|
317
|
-
id: options.id,
|
|
318
384
|
title: options.title,
|
|
319
385
|
content: options.content,
|
|
320
|
-
|
|
386
|
+
targets: buildSharingTargets(command, options),
|
|
321
387
|
task: parseJsonObjectOption(options.task, "--task"),
|
|
322
388
|
goal: parseJsonObjectOption(options.goal, "--goal")
|
|
323
389
|
});
|
|
324
|
-
const context = await resolveContext(
|
|
325
|
-
printJson(await
|
|
390
|
+
const context = await resolveContext();
|
|
391
|
+
printJson(await createTrack(context, payload));
|
|
326
392
|
});
|
|
327
393
|
track.commands.at(-1)?.addHelpText("after", `
|
|
328
394
|
Notes:
|
|
329
395
|
Use --task or --goal to pass type-specific fields.
|
|
330
396
|
|
|
331
397
|
Examples:
|
|
332
|
-
epismo track
|
|
333
|
-
epismo track
|
|
334
|
-
epismo track
|
|
398
|
+
epismo track create --type task --title "Fix bug" --content "Details..."
|
|
399
|
+
epismo track create --input @task.json
|
|
400
|
+
epismo track create --type goal --title "Launch" --goal '{"status":"on_track"}'`);
|
|
401
|
+
track
|
|
402
|
+
.command("update")
|
|
403
|
+
.description("update an existing project track (PATCH — omitted fields are unchanged)")
|
|
404
|
+
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
405
|
+
.requiredOption("--id <id>", "track id to update")
|
|
406
|
+
.option("--title <title>", "updated title")
|
|
407
|
+
.option("--content <content>", "updated markdown content")
|
|
408
|
+
.option("--project-ids <projectIds>", "JSON array or comma-separated project ids")
|
|
409
|
+
.option("--user-ids <userIds>", "JSON array or comma-separated user ids")
|
|
410
|
+
.option("--emails <emails>", "JSON array or comma-separated email addresses")
|
|
411
|
+
.option("--task <task>", 'task-specific fields as partial JSON object e.g. \'{"status":"done"}\'')
|
|
412
|
+
.option("--goal <goal>", 'goal-specific fields as partial JSON object e.g. \'{"progress":50}\'')
|
|
413
|
+
.action(async (options, command) => {
|
|
414
|
+
const payload = await resolveInput(options, {
|
|
415
|
+
title: options.title,
|
|
416
|
+
content: options.content,
|
|
417
|
+
targets: buildSharingTargets(command, options),
|
|
418
|
+
task: parseJsonObjectOption(options.task, "--task"),
|
|
419
|
+
goal: parseJsonObjectOption(options.goal, "--goal")
|
|
420
|
+
});
|
|
421
|
+
const context = await resolveContext();
|
|
422
|
+
printJson(await updateTrack(context, options.id, payload));
|
|
423
|
+
});
|
|
424
|
+
track.commands.at(-1)?.addHelpText("after", `
|
|
425
|
+
Notes:
|
|
426
|
+
Omitted fields keep their existing value.
|
|
427
|
+
|
|
428
|
+
Examples:
|
|
429
|
+
epismo track update --id <id> --title "Updated title"
|
|
430
|
+
epismo track update --id <id> --task '{"status":"done"}'
|
|
431
|
+
epismo track update --id <id> --goal '{"progress":75}'`);
|
|
335
432
|
track
|
|
336
433
|
.command("get")
|
|
337
434
|
.description("fetch one project track")
|
|
338
435
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
339
436
|
.option("--id <id>", "item id")
|
|
340
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
341
437
|
.action(async (options) => {
|
|
342
438
|
const payload = await resolveInput(options, {
|
|
343
439
|
id: options.id
|
|
344
440
|
});
|
|
345
|
-
const context = await resolveContext(
|
|
441
|
+
const context = await resolveContext();
|
|
346
442
|
printJson(await getTrack(context, payload));
|
|
347
443
|
});
|
|
348
444
|
track.commands.at(-1)?.addHelpText("after", `
|
|
@@ -355,18 +451,18 @@ Example:
|
|
|
355
451
|
.addOption(new Option("--type <type>", "task | goal").choices(TRACK_TYPES))
|
|
356
452
|
.option("--query <query>", "free-text query")
|
|
357
453
|
.option("--page <page>", "1-based page number")
|
|
358
|
-
.option("--
|
|
454
|
+
.option("--project-ids <projectIds>", "JSON array or comma-separated project ids")
|
|
455
|
+
.option("--self <self>", "whether to include items that target the current user directly")
|
|
359
456
|
.option("--filter <filter>", 'filter as JSON object; each value is an array of accepted values e.g. \'{"status":["todo","in_progress"]}\' (use --input @file.json for complex filters)')
|
|
360
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
361
457
|
.action(async (options, command) => {
|
|
362
458
|
const payload = await resolveInput(options, {
|
|
363
459
|
type: getExplicitOptionOverride(command, "type", options.type),
|
|
364
460
|
query: getExplicitOptionOverride(command, "query", options.query),
|
|
365
461
|
page: getExplicitOptionOverride(command, "page", parseOptionalPositiveInteger(options.page, "--page")),
|
|
366
|
-
|
|
462
|
+
targets: buildSearchTargets(command, options),
|
|
367
463
|
filter: getExplicitOptionOverride(command, "filter", parseJsonObjectOption(options.filter, "--filter"))
|
|
368
464
|
});
|
|
369
|
-
const context = await resolveContext(
|
|
465
|
+
const context = await resolveContext();
|
|
370
466
|
printJson(await searchTracks(context, payload));
|
|
371
467
|
});
|
|
372
468
|
track.commands.at(-1)?.addHelpText("after", `
|
|
@@ -379,52 +475,125 @@ Examples:
|
|
|
379
475
|
.description("delete one project track")
|
|
380
476
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
381
477
|
.option("--id <id>", "item id")
|
|
382
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
383
478
|
.action(async (options) => {
|
|
384
479
|
const payload = await resolveInput(options, {
|
|
385
480
|
id: options.id
|
|
386
481
|
});
|
|
387
|
-
const context = await resolveContext(
|
|
482
|
+
const context = await resolveContext();
|
|
388
483
|
printJson(await deleteTrack(context, payload));
|
|
389
484
|
});
|
|
390
485
|
track.commands.at(-1)?.addHelpText("after", `
|
|
391
486
|
Example:
|
|
392
487
|
epismo track delete --id <id>`);
|
|
488
|
+
track
|
|
489
|
+
.command("apply")
|
|
490
|
+
.description("create, update, and delete multiple tracks in a single request")
|
|
491
|
+
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
492
|
+
.option("--project-ids <projectIds>", "JSON array or comma-separated project ids")
|
|
493
|
+
.option("--user-ids <userIds>", "JSON array or comma-separated user ids")
|
|
494
|
+
.option("--emails <emails>", "JSON array or comma-separated email addresses")
|
|
495
|
+
.action(async (options, command) => {
|
|
496
|
+
const payload = await resolveInput(options, {
|
|
497
|
+
targets: buildSharingTargets(command, options)
|
|
498
|
+
});
|
|
499
|
+
const context = await resolveContext();
|
|
500
|
+
printJson(await applyTracks(context, payload));
|
|
501
|
+
});
|
|
502
|
+
track.commands.at(-1)?.addHelpText("after", `
|
|
503
|
+
Notes:
|
|
504
|
+
updateDrafts: use a non-UUID string as id (e.g. "t001") to create a new track, or a UUID to update an existing one.
|
|
505
|
+
Labels in task.parentId, task.dependsOn, and task.goalId are resolved by the server, so you can wire
|
|
506
|
+
up dependencies between new entries in the same request.
|
|
507
|
+
deleteDrafts: provide UUIDs of tracks to delete.
|
|
508
|
+
|
|
509
|
+
Examples:
|
|
510
|
+
epismo track apply --input @batch.json
|
|
511
|
+
epismo track apply --input '{"updateDrafts":[{"id":"t001","title":"Task A","task":{"status":"todo"}},{"id":"t002","title":"Task B","task":{"status":"todo","dependsOn":["t001"]}}]}'`);
|
|
393
512
|
const pack = program.command("pack").description("manage agent packs (workflows and contexts)");
|
|
394
|
-
pack.command("
|
|
395
|
-
.description("create
|
|
513
|
+
pack.command("create")
|
|
514
|
+
.description("create a new agent pack")
|
|
396
515
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
397
|
-
.addOption(new Option("--type <type>", "workflow | context
|
|
398
|
-
.
|
|
516
|
+
.addOption(new Option("--type <type>", "workflow | context (required unless provided in --input)")
|
|
517
|
+
.choices(PACK_TYPES))
|
|
399
518
|
.option("--title <title>", "title")
|
|
400
519
|
.option("--content <content>", "markdown content")
|
|
401
520
|
.option("--category <category>", "pack category")
|
|
402
521
|
.addOption(new Option("--visibility <visibility>", "public | private").choices(PACK_VISIBILITIES))
|
|
403
|
-
.option("--
|
|
522
|
+
.option("--project-ids <projectIds>", "JSON array or comma-separated project ids")
|
|
523
|
+
.option("--user-ids <userIds>", "JSON array or comma-separated user ids")
|
|
524
|
+
.option("--emails <emails>", "JSON array or comma-separated email addresses")
|
|
404
525
|
.option("--steps <steps>", "workflow steps as JSON array (use --input @file.json for complex payloads)")
|
|
405
526
|
.option("--blocks <blocks>", "context blocks as JSON array (for type=context; use --input @file.json for complex payloads)")
|
|
406
|
-
.
|
|
407
|
-
.action(async (options) => {
|
|
527
|
+
.action(async (options, command) => {
|
|
408
528
|
const payload = await resolveInput(options, {
|
|
409
529
|
type: options.type,
|
|
410
|
-
id: options.id,
|
|
411
530
|
title: options.title,
|
|
412
531
|
content: options.content,
|
|
413
532
|
category: options.category,
|
|
414
533
|
visibility: options.visibility,
|
|
415
|
-
|
|
534
|
+
targets: buildSharingTargets(command, options),
|
|
535
|
+
steps: parseJsonArrayOption(options.steps, "--steps"),
|
|
536
|
+
blocks: parseJsonArrayOption(options.blocks, "--blocks")
|
|
537
|
+
});
|
|
538
|
+
if (payload.type !== "workflow" && payload.type !== "context") {
|
|
539
|
+
throw new CliError({
|
|
540
|
+
code: "INVALID_INPUT",
|
|
541
|
+
message: "Pack type is required.",
|
|
542
|
+
hint: 'Pass --type workflow|context or include {"type":"workflow"} / {"type":"context"} in --input.'
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
const context = await resolveContext();
|
|
546
|
+
printJson(await createPack(context, payload));
|
|
547
|
+
});
|
|
548
|
+
pack.commands.at(-1)?.addHelpText("after", `
|
|
549
|
+
Notes:
|
|
550
|
+
type is required for pack create. Pass --type or include it in --input.
|
|
551
|
+
|
|
552
|
+
Examples:
|
|
553
|
+
epismo pack create --type workflow --title "My workflow" --input @workflow.json
|
|
554
|
+
epismo pack create --type workflow --title "My workflow" --steps '[{"title":"Step 1","content":"..."}]'
|
|
555
|
+
epismo pack create --type context --title "My context" --input @context.json
|
|
556
|
+
epismo pack create --type context --title "My context" --blocks '[{"title":"Block 1","content":"..."}]'`);
|
|
557
|
+
pack.command("update")
|
|
558
|
+
.description("update an existing agent pack (PATCH semantics — omitted fields are unchanged)")
|
|
559
|
+
.requiredOption("--id <id>", "pack id to update")
|
|
560
|
+
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
561
|
+
.option("--title <title>", "updated title")
|
|
562
|
+
.option("--content <content>", "updated markdown content")
|
|
563
|
+
.option("--category <category>", "updated pack category")
|
|
564
|
+
.addOption(new Option("--visibility <visibility>", "public | private").choices(PACK_VISIBILITIES))
|
|
565
|
+
.option("--project-ids <projectIds>", "JSON array or comma-separated project ids")
|
|
566
|
+
.option("--user-ids <userIds>", "JSON array or comma-separated user ids")
|
|
567
|
+
.option("--emails <emails>", "JSON array or comma-separated email addresses")
|
|
568
|
+
.option("--steps <steps>", 'step operations as JSON array with op field: [{"op":"add","title":"..."},{"op":"update","id":"s001","content":"..."},{"op":"remove","id":"s002"}]')
|
|
569
|
+
.option("--blocks <blocks>", 'block operations as JSON array with op field: [{"op":"add","title":"..."},{"op":"update","id":"b001","content":"..."},{"op":"remove","id":"b002"}]')
|
|
570
|
+
.action(async (options, command) => {
|
|
571
|
+
const payload = await resolveInput(options, {
|
|
572
|
+
title: options.title,
|
|
573
|
+
content: options.content,
|
|
574
|
+
category: options.category,
|
|
575
|
+
visibility: options.visibility,
|
|
576
|
+
targets: buildSharingTargets(command, options),
|
|
416
577
|
steps: parseJsonArrayOption(options.steps, "--steps"),
|
|
417
578
|
blocks: parseJsonArrayOption(options.blocks, "--blocks")
|
|
418
579
|
});
|
|
419
|
-
const context = await resolveContext(
|
|
420
|
-
printJson(await
|
|
580
|
+
const context = await resolveContext();
|
|
581
|
+
printJson(await updatePack(context, options.id, payload));
|
|
421
582
|
});
|
|
422
583
|
pack.commands.at(-1)?.addHelpText("after", `
|
|
584
|
+
Notes:
|
|
585
|
+
Omitted fields keep their existing value.
|
|
586
|
+
steps/blocks use operation objects with an "op" field (add | update | remove).
|
|
587
|
+
Omitting steps/blocks keeps them unchanged. Passing an empty array [] is a no-op.
|
|
588
|
+
To remove all items, send a remove op for each existing item ID.
|
|
589
|
+
|
|
423
590
|
Examples:
|
|
424
|
-
epismo pack
|
|
425
|
-
epismo pack
|
|
426
|
-
epismo pack
|
|
427
|
-
epismo pack
|
|
591
|
+
epismo pack update --id <id> --category ""
|
|
592
|
+
epismo pack update --id <id> --visibility public --category productivity
|
|
593
|
+
epismo pack update --id <id> --blocks '[{"op":"add","title":"New Block","content":"..."}]'
|
|
594
|
+
epismo pack update --id <id> --blocks '[{"op":"update","id":"b001","content":"updated..."}]'
|
|
595
|
+
epismo pack update --id <id> --blocks '[{"op":"remove","id":"b002"}]'
|
|
596
|
+
epismo pack update --id <id> --input @changes.json`);
|
|
428
597
|
pack.command("get")
|
|
429
598
|
.description("fetch one agent pack")
|
|
430
599
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
@@ -433,14 +602,13 @@ Examples:
|
|
|
433
602
|
.option("--full", "include nested item content")
|
|
434
603
|
.option("--block-id <blockId>", "context block id to extract (type=context only)")
|
|
435
604
|
.option("--step-id <stepId>", "workflow step id to extract (type=workflow only)")
|
|
436
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
437
605
|
.action(async (options) => {
|
|
438
606
|
const payload = await resolveInput(options, {
|
|
439
607
|
id: options.id,
|
|
440
608
|
alias: options.alias,
|
|
441
609
|
full: options.full ? true : undefined
|
|
442
610
|
});
|
|
443
|
-
const context = await resolveContext(
|
|
611
|
+
const context = await resolveContext();
|
|
444
612
|
printJson(await getPack(context, payload, {
|
|
445
613
|
blockId: options.blockId,
|
|
446
614
|
stepId: options.stepId
|
|
@@ -460,18 +628,18 @@ Examples:
|
|
|
460
628
|
.addOption(new Option("--type <type>", "workflow | context").choices(PACK_TYPES))
|
|
461
629
|
.option("--query <query>", "free-text query")
|
|
462
630
|
.option("--page <page>", "1-based page number")
|
|
463
|
-
.option("--
|
|
631
|
+
.option("--project-ids <projectIds>", "JSON array or comma-separated project ids")
|
|
632
|
+
.option("--self <self>", "whether to include packs that target the current user directly")
|
|
464
633
|
.option("--filter <filter>", 'filter as JSON object; each value is an array of accepted values e.g. \'{"visibility":["public"]}\' (use --input @file.json for complex filters)')
|
|
465
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
466
634
|
.action(async (options, command) => {
|
|
467
635
|
const payload = await resolveInput(options, {
|
|
468
636
|
type: getExplicitOptionOverride(command, "type", options.type),
|
|
469
637
|
query: getExplicitOptionOverride(command, "query", options.query),
|
|
470
638
|
page: getExplicitOptionOverride(command, "page", parseOptionalPositiveInteger(options.page, "--page")),
|
|
471
|
-
|
|
639
|
+
targets: buildSearchTargets(command, options),
|
|
472
640
|
filter: getExplicitOptionOverride(command, "filter", parseJsonObjectOption(options.filter, "--filter"))
|
|
473
641
|
});
|
|
474
|
-
const context = await resolveContext(
|
|
642
|
+
const context = await resolveContext();
|
|
475
643
|
printJson(await searchPacks(context, payload));
|
|
476
644
|
});
|
|
477
645
|
pack.commands.at(-1)?.addHelpText("after", `
|
|
@@ -485,7 +653,6 @@ Examples:
|
|
|
485
653
|
.option("--id <id>", "pack id")
|
|
486
654
|
.option("--liked", "mark as liked")
|
|
487
655
|
.option("--no-liked", "remove like")
|
|
488
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
489
656
|
.action(async (options) => {
|
|
490
657
|
const payload = await resolveInput(options, {
|
|
491
658
|
id: options.id,
|
|
@@ -498,7 +665,7 @@ Examples:
|
|
|
498
665
|
hint: "Use --liked to add a like, or --no-liked to remove one."
|
|
499
666
|
});
|
|
500
667
|
}
|
|
501
|
-
const context = await resolveContext(
|
|
668
|
+
const context = await resolveContext();
|
|
502
669
|
printJson(await likePack(context, payload));
|
|
503
670
|
});
|
|
504
671
|
pack.commands.at(-1)?.addHelpText("after", `
|
|
@@ -509,12 +676,11 @@ Examples:
|
|
|
509
676
|
.description("delete one agent pack and any of your aliases that point to it")
|
|
510
677
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
511
678
|
.option("--id <id>", "pack id")
|
|
512
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
513
679
|
.action(async (options) => {
|
|
514
680
|
const payload = await resolveInput(options, {
|
|
515
681
|
id: options.id
|
|
516
682
|
});
|
|
517
|
-
const context = await resolveContext(
|
|
683
|
+
const context = await resolveContext();
|
|
518
684
|
printJson(await deletePack(context, payload));
|
|
519
685
|
});
|
|
520
686
|
pack.commands.at(-1)?.addHelpText("after", `
|
|
@@ -524,26 +690,23 @@ Examples:
|
|
|
524
690
|
agent
|
|
525
691
|
.command("list")
|
|
526
692
|
.description("list AI teammates and whether they appear in the assignee roster")
|
|
527
|
-
.
|
|
528
|
-
|
|
529
|
-
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
693
|
+
.action(async () => {
|
|
694
|
+
const context = await resolveContext();
|
|
530
695
|
printJson(await listAgents(context));
|
|
531
696
|
});
|
|
532
697
|
agent.commands.at(-1)?.addHelpText("after", `
|
|
533
698
|
Examples:
|
|
534
|
-
epismo agent list
|
|
535
|
-
epismo agent list --workspace-id <workspace-id>`);
|
|
699
|
+
epismo agent list`);
|
|
536
700
|
agent
|
|
537
701
|
.command("add")
|
|
538
702
|
.description("add AI teammates to the assignee roster")
|
|
539
703
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
540
704
|
.option("--agent-ids <agentIds>", "JSON array or comma-separated agent ids")
|
|
541
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
542
705
|
.action(async (options) => {
|
|
543
706
|
const payload = await resolveInput(options, {
|
|
544
707
|
agentIds: parseStringArrayInput(options.agentIds, "--agent-ids")
|
|
545
708
|
});
|
|
546
|
-
const context = await resolveContext(
|
|
709
|
+
const context = await resolveContext();
|
|
547
710
|
printJson(await addAgents(context, payload));
|
|
548
711
|
});
|
|
549
712
|
agent.commands.at(-1)?.addHelpText("after", `
|
|
@@ -555,12 +718,11 @@ Examples:
|
|
|
555
718
|
.description("remove AI teammates from the assignee roster")
|
|
556
719
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
557
720
|
.option("--agent-ids <agentIds>", "JSON array or comma-separated agent ids")
|
|
558
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
559
721
|
.action(async (options) => {
|
|
560
722
|
const payload = await resolveInput(options, {
|
|
561
723
|
agentIds: parseStringArrayInput(options.agentIds, "--agent-ids")
|
|
562
724
|
});
|
|
563
|
-
const context = await resolveContext(
|
|
725
|
+
const context = await resolveContext();
|
|
564
726
|
printJson(await removeAgents(context, payload));
|
|
565
727
|
});
|
|
566
728
|
agent.commands.at(-1)?.addHelpText("after", `
|
|
@@ -571,26 +733,23 @@ Examples:
|
|
|
571
733
|
credit
|
|
572
734
|
.command("balance")
|
|
573
735
|
.description("show current credit balance")
|
|
574
|
-
.
|
|
575
|
-
|
|
576
|
-
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
736
|
+
.action(async () => {
|
|
737
|
+
const context = await resolveContext();
|
|
577
738
|
printJson(await creditBalance(context));
|
|
578
739
|
});
|
|
579
740
|
credit.commands.at(-1)?.addHelpText("after", `
|
|
580
741
|
Examples:
|
|
581
|
-
epismo credit balance
|
|
582
|
-
epismo credit balance --workspace-id <workspace-id>`);
|
|
742
|
+
epismo credit balance`);
|
|
583
743
|
credit
|
|
584
744
|
.command("checkout")
|
|
585
745
|
.description("start a credit purchase and get a checkout URL")
|
|
586
746
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
587
747
|
.option("--allocations <allocations>", 'JSON array of { userId, quantity } e.g. \'[{"userId":"u_1","quantity":10}]\'')
|
|
588
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
589
748
|
.action(async (options) => {
|
|
590
749
|
const payload = await resolveInput(options, {
|
|
591
750
|
allocations: parseJsonArrayOption(options.allocations, "--allocations")
|
|
592
751
|
});
|
|
593
|
-
const context = await resolveContext(
|
|
752
|
+
const context = await resolveContext();
|
|
594
753
|
printJson(await creditCheckout(context, payload));
|
|
595
754
|
});
|
|
596
755
|
credit.commands.at(-1)?.addHelpText("after", `
|
|
@@ -604,14 +763,13 @@ Example:
|
|
|
604
763
|
.addOption(new Option("--type <type>", "workflow | context").choices(PACK_TYPES))
|
|
605
764
|
.option("--id <id>", "target pack id")
|
|
606
765
|
.option("--alias <alias>", "alias name")
|
|
607
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
608
766
|
.action(async (options) => {
|
|
609
767
|
const payload = await resolveInput(options, {
|
|
610
768
|
type: options.type,
|
|
611
769
|
id: options.id,
|
|
612
770
|
alias: options.alias
|
|
613
771
|
});
|
|
614
|
-
const context = await resolveContext(
|
|
772
|
+
const context = await resolveContext();
|
|
615
773
|
printJson(await upsertAlias(context, payload));
|
|
616
774
|
});
|
|
617
775
|
alias.commands.at(-1)?.addHelpText("after", `
|
|
@@ -623,12 +781,11 @@ Examples:
|
|
|
623
781
|
.description("resolve one alias")
|
|
624
782
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
625
783
|
.option("--alias <alias>", "alias reference (`alias` or `@handle/alias`)")
|
|
626
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
627
784
|
.action(async (options) => {
|
|
628
785
|
const payload = await resolveInput(options, {
|
|
629
786
|
alias: options.alias
|
|
630
787
|
});
|
|
631
|
-
const context = await resolveContext(
|
|
788
|
+
const context = await resolveContext();
|
|
632
789
|
printJson(await getAlias(context, payload));
|
|
633
790
|
});
|
|
634
791
|
alias.commands.at(-1)?.addHelpText("after", `
|
|
@@ -639,9 +796,8 @@ Examples:
|
|
|
639
796
|
.command("list")
|
|
640
797
|
.description("list your aliases")
|
|
641
798
|
.addOption(new Option("--type <type>", "workflow | context").choices(PACK_TYPES))
|
|
642
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
643
799
|
.action(async (options) => {
|
|
644
|
-
const context = await resolveContext(
|
|
800
|
+
const context = await resolveContext();
|
|
645
801
|
printJson(await listAliases(context, { type: options.type }));
|
|
646
802
|
});
|
|
647
803
|
alias.commands.at(-1)?.addHelpText("after", `
|
|
@@ -653,17 +809,36 @@ Example:
|
|
|
653
809
|
.description("delete one alias")
|
|
654
810
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
655
811
|
.option("--alias <alias>", "alias name")
|
|
656
|
-
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
657
812
|
.action(async (options) => {
|
|
658
813
|
const payload = await resolveInput(options, {
|
|
659
814
|
alias: options.alias
|
|
660
815
|
});
|
|
661
|
-
const context = await resolveContext(
|
|
816
|
+
const context = await resolveContext();
|
|
662
817
|
printJson(await deleteAlias(context, payload));
|
|
663
818
|
});
|
|
664
819
|
alias.commands.at(-1)?.addHelpText("after", `
|
|
665
820
|
Example:
|
|
666
821
|
epismo alias delete --alias myproject`);
|
|
822
|
+
const token = program.command("token").description("manage CLI tokens for CI/CD");
|
|
823
|
+
token
|
|
824
|
+
.command("create")
|
|
825
|
+
.description("issue a workspace-scoped CLI token for use in CI/CD pipelines")
|
|
826
|
+
.option("--workspace-id <workspaceId>", "workspace to scope the token to (omit for personal space)")
|
|
827
|
+
.action(async (options) => {
|
|
828
|
+
const context = await resolveContext();
|
|
829
|
+
printJson(await createToken(context, options.workspaceId ?? context.workspaceId));
|
|
830
|
+
});
|
|
831
|
+
token.commands.at(-1)?.addHelpText("after", `
|
|
832
|
+
Notes:
|
|
833
|
+
The issued token has the same scopes as a normal CLI token (read, write, offline_access)
|
|
834
|
+
but carries the workspace ID embedded. Use it via the EPISMO_TOKEN environment variable
|
|
835
|
+
in CI/CD so no --workspace-id flag is needed at runtime.
|
|
836
|
+
If --workspace-id is omitted, the saved default workspace is used (epismo workspace use),
|
|
837
|
+
falling back to personal space when no default is set.
|
|
838
|
+
|
|
839
|
+
Examples:
|
|
840
|
+
epismo token create --workspace-id <workspace-id>
|
|
841
|
+
epismo token create # uses saved default workspace, or personal space if none`);
|
|
667
842
|
return program;
|
|
668
843
|
}
|
|
669
844
|
//# sourceMappingURL=program.js.map
|