epismo 0.3.0 → 0.4.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 +7 -2
- package/dist/auth.js +2 -2
- package/dist/auth.js.map +1 -1
- package/dist/context.js +2 -2
- package/dist/context.js.map +1 -1
- package/dist/packs.js +2 -9
- package/dist/packs.js.map +1 -1
- package/dist/program.js +115 -233
- package/dist/program.js.map +1 -1
- package/dist/projects.js +2 -9
- package/dist/projects.js.map +1 -1
- package/dist/tracks.js +16 -30
- package/dist/tracks.js.map +1 -1
- package/dist/workspace.js +6 -4
- package/dist/workspace.js.map +1 -1
- package/dist/workspaces.js +2 -15
- package/dist/workspaces.js.map +1 -1
- package/package.json +1 -1
- package/dist/token.js +0 -10
- package/dist/token.js.map +0 -1
package/dist/program.js
CHANGED
|
@@ -3,19 +3,21 @@ 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 {
|
|
7
|
-
import {
|
|
6
|
+
import { deleteTrack, getTrack, searchTracks, upsertTrack } from "./tracks.js";
|
|
7
|
+
import { deletePack, getPack, likePack, searchPacks, upsertPack } 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 {
|
|
13
|
-
import { addProjectMember,
|
|
14
|
-
import { createToken } from "./token.js";
|
|
12
|
+
import { deleteWorkspaceMember, listWorkspaceMembers, upsertWorkspace, upsertWorkspaceMember } from "./workspaces.js";
|
|
13
|
+
import { addProjectMember, deleteProject, deleteProjectMember, listProjectMembers, listProjects, upsertProject } from "./projects.js";
|
|
15
14
|
const TRACK_TYPES = ["task", "goal"];
|
|
16
15
|
const PACK_TYPES = ["workflow", "context"];
|
|
17
16
|
const PACK_VISIBILITIES = ["public", "private"];
|
|
18
|
-
// centralize
|
|
17
|
+
// #1: centralize --workspace-id option so description is defined once
|
|
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
|
|
19
21
|
const WARNING_ENV_TOKEN_WORKSPACE_IGNORED = "EPISMO_TOKEN_WORKSPACE_IGNORED";
|
|
20
22
|
async function resolveInput(options, overrides) {
|
|
21
23
|
const base = await readJsonObjectInput(options.input);
|
|
@@ -28,8 +30,8 @@ function getExplicitOptionOverride(command, optionName, value) {
|
|
|
28
30
|
}
|
|
29
31
|
return value;
|
|
30
32
|
}
|
|
31
|
-
async function resolveContext() {
|
|
32
|
-
const context = await resolveExecutionContext();
|
|
33
|
+
async function resolveContext(options) {
|
|
34
|
+
const context = await resolveExecutionContext(options);
|
|
33
35
|
if (context.warning) {
|
|
34
36
|
printWarning({
|
|
35
37
|
warning: { code: WARNING_ENV_TOKEN_WORKSPACE_IGNORED, message: context.warning }
|
|
@@ -49,12 +51,11 @@ export function buildProgram(version) {
|
|
|
49
51
|
.exitOverride();
|
|
50
52
|
program.addHelpText("after", `
|
|
51
53
|
Workspace resolution:
|
|
52
|
-
|
|
53
|
-
1.
|
|
54
|
-
2.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
issue a workspace-scoped token for CI/CD.
|
|
54
|
+
Commands that accept --workspace-id resolve the workspace in this order:
|
|
55
|
+
1. --workspace-id flag
|
|
56
|
+
2. Saved default (epismo workspace use)
|
|
57
|
+
3. Personal space (fallback)
|
|
58
|
+
When EPISMO_TOKEN is set, the saved default is skipped.
|
|
58
59
|
|
|
59
60
|
Examples:
|
|
60
61
|
epismo login
|
|
@@ -107,14 +108,16 @@ Examples:
|
|
|
107
108
|
program
|
|
108
109
|
.command("whoami")
|
|
109
110
|
.description("show the currently authenticated user")
|
|
110
|
-
.
|
|
111
|
-
|
|
111
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
112
|
+
.action(async (options) => {
|
|
113
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
112
114
|
printJson(await whoami({ workspaceId: context.workspaceId, auth: context.auth }));
|
|
113
115
|
});
|
|
114
116
|
program.commands.at(-1)?.addHelpText("after", `
|
|
115
117
|
Examples:
|
|
116
118
|
epismo whoami
|
|
117
|
-
EPISMO_TOKEN=<access-token> epismo whoami
|
|
119
|
+
EPISMO_TOKEN=<access-token> epismo whoami
|
|
120
|
+
epismo whoami --workspace-id <workspace-id>`);
|
|
118
121
|
const workspace = program
|
|
119
122
|
.command("workspace")
|
|
120
123
|
.description("manage workspaces and the saved default workspace");
|
|
@@ -156,63 +159,33 @@ Example:
|
|
|
156
159
|
Example:
|
|
157
160
|
epismo workspace clear`);
|
|
158
161
|
workspace
|
|
159
|
-
.command("
|
|
160
|
-
.description("create a new workspace")
|
|
162
|
+
.command("upsert")
|
|
163
|
+
.description("create a new workspace or update one you can access")
|
|
161
164
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
165
|
+
.option("--id <id>", "existing workspace id")
|
|
162
166
|
.option("--name <name>", "workspace name")
|
|
163
167
|
.addOption(new Option("--plan <plan>", "basic | pro").choices(["basic", "pro"]))
|
|
164
168
|
.action(async (options) => {
|
|
165
|
-
const payload = await resolveInput({ input: options.input }, { name: options.name, plan: options.plan });
|
|
166
|
-
const context = await resolveContext();
|
|
167
|
-
|
|
168
|
-
const workspaceId = created.workspace?.id;
|
|
169
|
-
if (workspaceId) {
|
|
170
|
-
const checkout = await getWorkspaceCheckout(context, workspaceId);
|
|
171
|
-
printJson({ ...created, ...checkout });
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
printJson(created);
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
workspace.commands.at(-1)?.addHelpText("after", `
|
|
178
|
-
Examples:
|
|
179
|
-
epismo workspace create --name my-team --plan basic
|
|
180
|
-
epismo workspace create --input @workspace.json`);
|
|
181
|
-
workspace
|
|
182
|
-
.command("checkout")
|
|
183
|
-
.description("get the billing URL for a workspace (to complete or retry payment)")
|
|
184
|
-
.requiredOption("--id <id>", "workspace id")
|
|
185
|
-
.action(async (options) => {
|
|
186
|
-
const context = await resolveContext();
|
|
187
|
-
printJson(await getWorkspaceCheckout(context, options.id));
|
|
188
|
-
});
|
|
189
|
-
workspace.commands.at(-1)?.addHelpText("after", `
|
|
190
|
-
Examples:
|
|
191
|
-
epismo workspace checkout --id <workspace-id>`);
|
|
192
|
-
workspace
|
|
193
|
-
.command("update")
|
|
194
|
-
.description("update a workspace you own (PATCH — omitted fields are unchanged)")
|
|
195
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
196
|
-
.requiredOption("--id <id>", "workspace id to update")
|
|
197
|
-
.option("--name <name>", "updated workspace name")
|
|
198
|
-
.addOption(new Option("--plan <plan>", "basic | pro").choices(["basic", "pro"]))
|
|
199
|
-
.action(async (options) => {
|
|
200
|
-
const payload = await resolveInput({ input: options.input }, { name: options.name, plan: options.plan });
|
|
201
|
-
const context = await resolveContext();
|
|
202
|
-
printJson(await updateWorkspace(context, options.id, payload));
|
|
169
|
+
const payload = await resolveInput({ input: options.input }, { id: options.id, name: options.name, plan: options.plan });
|
|
170
|
+
const context = await resolveContext({});
|
|
171
|
+
printJson(await upsertWorkspace(context, payload));
|
|
203
172
|
});
|
|
204
173
|
const workspaceMember = workspace.command("member").description("manage workspace members");
|
|
205
174
|
workspaceMember
|
|
206
175
|
.command("list")
|
|
207
176
|
.description("list members in a workspace")
|
|
208
|
-
.
|
|
209
|
-
|
|
210
|
-
|
|
177
|
+
.option("--workspace-id <workspaceId>", "workspace id")
|
|
178
|
+
.action(async (options) => {
|
|
179
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
180
|
+
printJson(await listWorkspaceMembers(context, {
|
|
181
|
+
workspaceId: options.workspaceId ?? context.workspaceId
|
|
182
|
+
}));
|
|
211
183
|
});
|
|
212
184
|
workspaceMember
|
|
213
185
|
.command("upsert")
|
|
214
186
|
.description("add a workspace member or update the member role")
|
|
215
187
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
188
|
+
.option("--workspace-id <workspaceId>", "workspace id")
|
|
216
189
|
.option("--user-id <userId>", "user id")
|
|
217
190
|
.addOption(new Option("--role <role>", "owner | admin | member").choices([
|
|
218
191
|
"owner",
|
|
@@ -220,74 +193,65 @@ Examples:
|
|
|
220
193
|
"member"
|
|
221
194
|
]))
|
|
222
195
|
.action(async (options) => {
|
|
223
|
-
const context = await resolveContext();
|
|
224
196
|
const payload = await resolveInput({ input: options.input }, {
|
|
225
|
-
workspaceId:
|
|
197
|
+
workspaceId: options.workspaceId,
|
|
226
198
|
userId: options.userId,
|
|
227
199
|
role: options.role
|
|
228
200
|
});
|
|
201
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
229
202
|
printJson(await upsertWorkspaceMember(context, payload));
|
|
230
203
|
});
|
|
231
204
|
workspaceMember
|
|
232
205
|
.command("delete")
|
|
233
206
|
.description("remove a workspace member")
|
|
234
207
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
208
|
+
.option("--workspace-id <workspaceId>", "workspace id")
|
|
235
209
|
.option("--user-id <userId>", "user id")
|
|
236
210
|
.action(async (options) => {
|
|
237
|
-
const context = await resolveContext();
|
|
238
211
|
const payload = await resolveInput({ input: options.input }, {
|
|
239
|
-
workspaceId:
|
|
212
|
+
workspaceId: options.workspaceId,
|
|
240
213
|
userId: options.userId
|
|
241
214
|
});
|
|
215
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
242
216
|
printJson(await deleteWorkspaceMember(context, payload));
|
|
243
217
|
});
|
|
244
218
|
const project = program.command("project").description("manage workspace projects");
|
|
245
219
|
project
|
|
246
220
|
.command("list")
|
|
247
221
|
.description("list projects visible in the selected workspace")
|
|
248
|
-
.
|
|
249
|
-
|
|
222
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
223
|
+
.action(async (options) => {
|
|
224
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
250
225
|
printJson(await listProjects(context));
|
|
251
226
|
});
|
|
252
227
|
project
|
|
253
|
-
.command("
|
|
254
|
-
.description("create a project in the selected workspace")
|
|
228
|
+
.command("upsert")
|
|
229
|
+
.description("create a project in the selected workspace or update one you can access")
|
|
255
230
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
231
|
+
.option("--id <id>", "existing project id")
|
|
256
232
|
.option("--name <name>", "project name")
|
|
257
233
|
.option("--description <description>", "project description")
|
|
234
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
258
235
|
.action(async (options) => {
|
|
259
236
|
const payload = await resolveInput(options, {
|
|
237
|
+
id: options.id,
|
|
260
238
|
name: options.name,
|
|
261
239
|
description: options.description
|
|
262
240
|
});
|
|
263
|
-
const context = await resolveContext();
|
|
264
|
-
printJson(await
|
|
265
|
-
});
|
|
266
|
-
project
|
|
267
|
-
.command("update")
|
|
268
|
-
.description("update a project you can access (PATCH — omitted fields are unchanged)")
|
|
269
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
270
|
-
.requiredOption("--id <id>", "project id to update")
|
|
271
|
-
.option("--name <name>", "updated project name")
|
|
272
|
-
.option("--description <description>", "updated project description")
|
|
273
|
-
.action(async (options) => {
|
|
274
|
-
const payload = await resolveInput(options, {
|
|
275
|
-
name: options.name,
|
|
276
|
-
description: options.description
|
|
277
|
-
});
|
|
278
|
-
const context = await resolveContext();
|
|
279
|
-
printJson(await updateProject(context, options.id, payload));
|
|
241
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
242
|
+
printJson(await upsertProject(context, payload));
|
|
280
243
|
});
|
|
281
244
|
project
|
|
282
245
|
.command("delete")
|
|
283
246
|
.description("delete a project you can access in the selected workspace")
|
|
284
247
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
285
248
|
.option("--id <id>", "project id")
|
|
249
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
286
250
|
.action(async (options) => {
|
|
287
251
|
const payload = await resolveInput(options, {
|
|
288
252
|
id: options.id
|
|
289
253
|
});
|
|
290
|
-
const context = await resolveContext();
|
|
254
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
291
255
|
printJson(await deleteProject(context, payload));
|
|
292
256
|
});
|
|
293
257
|
const projectMember = project.command("member").description("manage project members");
|
|
@@ -296,11 +260,12 @@ Examples:
|
|
|
296
260
|
.description("list members across one or more projects")
|
|
297
261
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
298
262
|
.option("--project-ids <projectIds>", "JSON array or comma-separated project ids")
|
|
263
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
299
264
|
.action(async (options) => {
|
|
300
265
|
const payload = await resolveInput(options, {
|
|
301
266
|
projectIds: parseStringArrayInput(options.projectIds, "--project-ids")
|
|
302
267
|
});
|
|
303
|
-
const context = await resolveContext();
|
|
268
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
304
269
|
printJson(await listProjectMembers(context, payload));
|
|
305
270
|
});
|
|
306
271
|
projectMember
|
|
@@ -309,12 +274,13 @@ Examples:
|
|
|
309
274
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
310
275
|
.option("--project-id <projectId>", "project id")
|
|
311
276
|
.option("--user-id <userId>", "user id")
|
|
277
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
312
278
|
.action(async (options) => {
|
|
313
279
|
const payload = await resolveInput(options, {
|
|
314
280
|
projectId: options.projectId,
|
|
315
281
|
userId: options.userId
|
|
316
282
|
});
|
|
317
|
-
const context = await resolveContext();
|
|
283
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
318
284
|
printJson(await addProjectMember(context, payload));
|
|
319
285
|
});
|
|
320
286
|
projectMember
|
|
@@ -323,84 +289,60 @@ Examples:
|
|
|
323
289
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
324
290
|
.option("--project-id <projectId>", "project id")
|
|
325
291
|
.option("--user-id <userId>", "user id")
|
|
292
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
326
293
|
.action(async (options) => {
|
|
327
294
|
const payload = await resolveInput(options, {
|
|
328
295
|
projectId: options.projectId,
|
|
329
296
|
userId: options.userId
|
|
330
297
|
});
|
|
331
|
-
const context = await resolveContext();
|
|
298
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
332
299
|
printJson(await deleteProjectMember(context, payload));
|
|
333
300
|
});
|
|
334
301
|
const track = program.command("track").description("manage project tracks (tasks and goals)");
|
|
335
302
|
track
|
|
336
|
-
.command("
|
|
337
|
-
.description("create a
|
|
303
|
+
.command("upsert")
|
|
304
|
+
.description("create or update a project track (task or goal)")
|
|
338
305
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
339
306
|
.addOption(new Option("--type <type>", "task | goal").choices(TRACK_TYPES))
|
|
307
|
+
.option("--id <id>", "existing item id")
|
|
340
308
|
.option("--title <title>", "title")
|
|
341
309
|
.option("--content <content>", "markdown content")
|
|
342
310
|
.option("--projects <projects>", "JSON array or comma-separated project ids")
|
|
343
311
|
.option("--task <task>", 'task-specific fields as JSON object e.g. \'{"status":"todo","dueDate":"2025-12-31"}\'')
|
|
344
312
|
.option("--goal <goal>", 'goal-specific fields as JSON object e.g. \'{"status":"on_track","dueDate":"2025-12-31"}\'')
|
|
313
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
345
314
|
.action(async (options) => {
|
|
346
315
|
const payload = await resolveInput(options, {
|
|
347
316
|
type: options.type,
|
|
317
|
+
id: options.id,
|
|
348
318
|
title: options.title,
|
|
349
319
|
content: options.content,
|
|
350
320
|
projects: parseStringArrayInput(options.projects, "--projects"),
|
|
351
321
|
task: parseJsonObjectOption(options.task, "--task"),
|
|
352
322
|
goal: parseJsonObjectOption(options.goal, "--goal")
|
|
353
323
|
});
|
|
354
|
-
const context = await resolveContext();
|
|
355
|
-
printJson(await
|
|
324
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
325
|
+
printJson(await upsertTrack(context, payload));
|
|
356
326
|
});
|
|
357
327
|
track.commands.at(-1)?.addHelpText("after", `
|
|
358
328
|
Notes:
|
|
359
329
|
Use --task or --goal to pass type-specific fields.
|
|
360
330
|
|
|
361
331
|
Examples:
|
|
362
|
-
epismo track
|
|
363
|
-
epismo track
|
|
364
|
-
epismo track
|
|
365
|
-
track
|
|
366
|
-
.command("update")
|
|
367
|
-
.description("update an existing project track (PATCH — omitted fields are unchanged)")
|
|
368
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
369
|
-
.requiredOption("--id <id>", "track id to update")
|
|
370
|
-
.option("--title <title>", "updated title")
|
|
371
|
-
.option("--content <content>", "updated markdown content")
|
|
372
|
-
.option("--projects <projects>", "JSON array or comma-separated project ids")
|
|
373
|
-
.option("--task <task>", 'task-specific fields as partial JSON object e.g. \'{"status":"done"}\'')
|
|
374
|
-
.option("--goal <goal>", 'goal-specific fields as partial JSON object e.g. \'{"progress":50}\'')
|
|
375
|
-
.action(async (options) => {
|
|
376
|
-
const payload = await resolveInput(options, {
|
|
377
|
-
title: options.title,
|
|
378
|
-
content: options.content,
|
|
379
|
-
projects: parseStringArrayInput(options.projects, "--projects"),
|
|
380
|
-
task: parseJsonObjectOption(options.task, "--task"),
|
|
381
|
-
goal: parseJsonObjectOption(options.goal, "--goal")
|
|
382
|
-
});
|
|
383
|
-
const context = await resolveContext();
|
|
384
|
-
printJson(await updateTrack(context, options.id, payload));
|
|
385
|
-
});
|
|
386
|
-
track.commands.at(-1)?.addHelpText("after", `
|
|
387
|
-
Notes:
|
|
388
|
-
Omitted fields keep their existing value.
|
|
389
|
-
|
|
390
|
-
Examples:
|
|
391
|
-
epismo track update --id <id> --title "Updated title"
|
|
392
|
-
epismo track update --id <id> --task '{"status":"done"}'
|
|
393
|
-
epismo track update --id <id> --goal '{"progress":75}'`);
|
|
332
|
+
epismo track upsert --type task --title "Fix bug" --content "Details..."
|
|
333
|
+
epismo track upsert --input @task.json
|
|
334
|
+
epismo track upsert --type goal --title "Launch" --goal '{"status":"on_track"}'`);
|
|
394
335
|
track
|
|
395
336
|
.command("get")
|
|
396
337
|
.description("fetch one project track")
|
|
397
338
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
398
339
|
.option("--id <id>", "item id")
|
|
340
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
399
341
|
.action(async (options) => {
|
|
400
342
|
const payload = await resolveInput(options, {
|
|
401
343
|
id: options.id
|
|
402
344
|
});
|
|
403
|
-
const context = await resolveContext();
|
|
345
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
404
346
|
printJson(await getTrack(context, payload));
|
|
405
347
|
});
|
|
406
348
|
track.commands.at(-1)?.addHelpText("after", `
|
|
@@ -415,6 +357,7 @@ Example:
|
|
|
415
357
|
.option("--page <page>", "1-based page number")
|
|
416
358
|
.option("--projects <projects>", "JSON array or comma-separated project ids")
|
|
417
359
|
.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)
|
|
418
361
|
.action(async (options, command) => {
|
|
419
362
|
const payload = await resolveInput(options, {
|
|
420
363
|
type: getExplicitOptionOverride(command, "type", options.type),
|
|
@@ -423,7 +366,7 @@ Example:
|
|
|
423
366
|
projects: getExplicitOptionOverride(command, "projects", parseStringArrayInput(options.projects, "--projects")),
|
|
424
367
|
filter: getExplicitOptionOverride(command, "filter", parseJsonObjectOption(options.filter, "--filter"))
|
|
425
368
|
});
|
|
426
|
-
const context = await resolveContext();
|
|
369
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
427
370
|
printJson(await searchTracks(context, payload));
|
|
428
371
|
});
|
|
429
372
|
track.commands.at(-1)?.addHelpText("after", `
|
|
@@ -436,43 +379,23 @@ Examples:
|
|
|
436
379
|
.description("delete one project track")
|
|
437
380
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
438
381
|
.option("--id <id>", "item id")
|
|
382
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
439
383
|
.action(async (options) => {
|
|
440
384
|
const payload = await resolveInput(options, {
|
|
441
385
|
id: options.id
|
|
442
386
|
});
|
|
443
|
-
const context = await resolveContext();
|
|
387
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
444
388
|
printJson(await deleteTrack(context, payload));
|
|
445
389
|
});
|
|
446
390
|
track.commands.at(-1)?.addHelpText("after", `
|
|
447
391
|
Example:
|
|
448
392
|
epismo track delete --id <id>`);
|
|
449
|
-
track
|
|
450
|
-
.command("apply")
|
|
451
|
-
.description("create, update, and delete multiple tracks in a single request")
|
|
452
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
453
|
-
.option("--projects <projects>", "JSON array or comma-separated project ids")
|
|
454
|
-
.action(async (options) => {
|
|
455
|
-
const payload = await resolveInput(options, {
|
|
456
|
-
projects: parseStringArrayInput(options.projects, "--projects")
|
|
457
|
-
});
|
|
458
|
-
const context = await resolveContext();
|
|
459
|
-
printJson(await applyTracks(context, payload));
|
|
460
|
-
});
|
|
461
|
-
track.commands.at(-1)?.addHelpText("after", `
|
|
462
|
-
Notes:
|
|
463
|
-
updateDrafts: use a non-UUID string as id (e.g. "t001") to create a new track, or a UUID to update an existing one.
|
|
464
|
-
Labels in task.parentId, task.dependsOn, and task.goalId are resolved by the server, so you can wire
|
|
465
|
-
up dependencies between new entries in the same request.
|
|
466
|
-
deleteDrafts: provide UUIDs of tracks to delete.
|
|
467
|
-
|
|
468
|
-
Examples:
|
|
469
|
-
epismo track apply --input @batch.json
|
|
470
|
-
epismo track apply --input '{"updateDrafts":[{"id":"t001","title":"Task A","task":{"status":"todo"}},{"id":"t002","title":"Task B","task":{"status":"todo","dependsOn":["t001"]}}]}'`);
|
|
471
393
|
const pack = program.command("pack").description("manage agent packs (workflows and contexts)");
|
|
472
|
-
pack.command("
|
|
473
|
-
.description("create
|
|
394
|
+
pack.command("upsert")
|
|
395
|
+
.description("create or update an agent pack")
|
|
474
396
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
475
397
|
.addOption(new Option("--type <type>", "workflow | context").choices(PACK_TYPES))
|
|
398
|
+
.option("--id <id>", "existing pack id")
|
|
476
399
|
.option("--title <title>", "title")
|
|
477
400
|
.option("--content <content>", "markdown content")
|
|
478
401
|
.option("--category <category>", "pack category")
|
|
@@ -480,9 +403,11 @@ Examples:
|
|
|
480
403
|
.option("--projects <projects>", "JSON array or comma-separated project ids")
|
|
481
404
|
.option("--steps <steps>", "workflow steps as JSON array (use --input @file.json for complex payloads)")
|
|
482
405
|
.option("--blocks <blocks>", "context blocks as JSON array (for type=context; use --input @file.json for complex payloads)")
|
|
406
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
483
407
|
.action(async (options) => {
|
|
484
408
|
const payload = await resolveInput(options, {
|
|
485
409
|
type: options.type,
|
|
410
|
+
id: options.id,
|
|
486
411
|
title: options.title,
|
|
487
412
|
content: options.content,
|
|
488
413
|
category: options.category,
|
|
@@ -491,53 +416,15 @@ Examples:
|
|
|
491
416
|
steps: parseJsonArrayOption(options.steps, "--steps"),
|
|
492
417
|
blocks: parseJsonArrayOption(options.blocks, "--blocks")
|
|
493
418
|
});
|
|
494
|
-
const context = await resolveContext();
|
|
495
|
-
printJson(await
|
|
496
|
-
});
|
|
497
|
-
pack.commands.at(-1)?.addHelpText("after", `
|
|
498
|
-
Examples:
|
|
499
|
-
epismo pack create --type workflow --title "My workflow" --input @workflow.json
|
|
500
|
-
epismo pack create --type workflow --title "My workflow" --steps '[{"title":"Step 1","content":"..."}]'
|
|
501
|
-
epismo pack create --type context --title "My context" --input @context.json
|
|
502
|
-
epismo pack create --type context --title "My context" --blocks '[{"title":"Block 1","content":"..."}]'`);
|
|
503
|
-
pack.command("update")
|
|
504
|
-
.description("update an existing agent pack (PATCH semantics — omitted fields are unchanged)")
|
|
505
|
-
.requiredOption("--id <id>", "pack id to update")
|
|
506
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
507
|
-
.option("--title <title>", "updated title")
|
|
508
|
-
.option("--content <content>", "updated markdown content")
|
|
509
|
-
.option("--category <category>", "updated pack category")
|
|
510
|
-
.addOption(new Option("--visibility <visibility>", "public | private").choices(PACK_VISIBILITIES))
|
|
511
|
-
.option("--projects <projects>", "JSON array or comma-separated project ids")
|
|
512
|
-
.option("--steps <steps>", 'step operations as JSON array with op field: [{"op":"add","title":"..."},{"op":"update","id":"s001","content":"..."},{"op":"remove","id":"s002"}]')
|
|
513
|
-
.option("--blocks <blocks>", 'block operations as JSON array with op field: [{"op":"add","title":"..."},{"op":"update","id":"b001","content":"..."},{"op":"remove","id":"b002"}]')
|
|
514
|
-
.action(async (options) => {
|
|
515
|
-
const payload = await resolveInput(options, {
|
|
516
|
-
title: options.title,
|
|
517
|
-
content: options.content,
|
|
518
|
-
category: options.category,
|
|
519
|
-
visibility: options.visibility,
|
|
520
|
-
projects: parseStringArrayInput(options.projects, "--projects"),
|
|
521
|
-
steps: parseJsonArrayOption(options.steps, "--steps"),
|
|
522
|
-
blocks: parseJsonArrayOption(options.blocks, "--blocks")
|
|
523
|
-
});
|
|
524
|
-
const context = await resolveContext();
|
|
525
|
-
printJson(await updatePack(context, options.id, payload));
|
|
419
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
420
|
+
printJson(await upsertPack(context, payload));
|
|
526
421
|
});
|
|
527
422
|
pack.commands.at(-1)?.addHelpText("after", `
|
|
528
|
-
Notes:
|
|
529
|
-
Omitted fields keep their existing value.
|
|
530
|
-
steps/blocks use operation objects with an "op" field (add | update | remove).
|
|
531
|
-
Omitting steps/blocks keeps them unchanged. Passing an empty array [] is a no-op.
|
|
532
|
-
To remove all items, send a remove op for each existing item ID.
|
|
533
|
-
|
|
534
423
|
Examples:
|
|
535
|
-
epismo pack
|
|
536
|
-
epismo pack
|
|
537
|
-
epismo pack
|
|
538
|
-
epismo pack
|
|
539
|
-
epismo pack update --id <id> --blocks '[{"op":"remove","id":"b002"}]'
|
|
540
|
-
epismo pack update --id <id> --input @changes.json`);
|
|
424
|
+
epismo pack upsert --type workflow --title "My workflow" --input @workflow.json
|
|
425
|
+
epismo pack upsert --type workflow --title "My workflow" --steps '[{"title":"Step 1","content":"..."}]'
|
|
426
|
+
epismo pack upsert --type context --title "My context" --input @context.json
|
|
427
|
+
epismo pack upsert --type context --title "My context" --blocks '[{"title":"Block 1","content":"..."}]'`);
|
|
541
428
|
pack.command("get")
|
|
542
429
|
.description("fetch one agent pack")
|
|
543
430
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
@@ -546,13 +433,14 @@ Examples:
|
|
|
546
433
|
.option("--full", "include nested item content")
|
|
547
434
|
.option("--block-id <blockId>", "context block id to extract (type=context only)")
|
|
548
435
|
.option("--step-id <stepId>", "workflow step id to extract (type=workflow only)")
|
|
436
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
549
437
|
.action(async (options) => {
|
|
550
438
|
const payload = await resolveInput(options, {
|
|
551
439
|
id: options.id,
|
|
552
440
|
alias: options.alias,
|
|
553
441
|
full: options.full ? true : undefined
|
|
554
442
|
});
|
|
555
|
-
const context = await resolveContext();
|
|
443
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
556
444
|
printJson(await getPack(context, payload, {
|
|
557
445
|
blockId: options.blockId,
|
|
558
446
|
stepId: options.stepId
|
|
@@ -574,6 +462,7 @@ Examples:
|
|
|
574
462
|
.option("--page <page>", "1-based page number")
|
|
575
463
|
.option("--projects <projects>", "JSON array or comma-separated project ids")
|
|
576
464
|
.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)
|
|
577
466
|
.action(async (options, command) => {
|
|
578
467
|
const payload = await resolveInput(options, {
|
|
579
468
|
type: getExplicitOptionOverride(command, "type", options.type),
|
|
@@ -582,7 +471,7 @@ Examples:
|
|
|
582
471
|
projects: getExplicitOptionOverride(command, "projects", parseStringArrayInput(options.projects, "--projects")),
|
|
583
472
|
filter: getExplicitOptionOverride(command, "filter", parseJsonObjectOption(options.filter, "--filter"))
|
|
584
473
|
});
|
|
585
|
-
const context = await resolveContext();
|
|
474
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
586
475
|
printJson(await searchPacks(context, payload));
|
|
587
476
|
});
|
|
588
477
|
pack.commands.at(-1)?.addHelpText("after", `
|
|
@@ -596,6 +485,7 @@ Examples:
|
|
|
596
485
|
.option("--id <id>", "pack id")
|
|
597
486
|
.option("--liked", "mark as liked")
|
|
598
487
|
.option("--no-liked", "remove like")
|
|
488
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
599
489
|
.action(async (options) => {
|
|
600
490
|
const payload = await resolveInput(options, {
|
|
601
491
|
id: options.id,
|
|
@@ -608,7 +498,7 @@ Examples:
|
|
|
608
498
|
hint: "Use --liked to add a like, or --no-liked to remove one."
|
|
609
499
|
});
|
|
610
500
|
}
|
|
611
|
-
const context = await resolveContext();
|
|
501
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
612
502
|
printJson(await likePack(context, payload));
|
|
613
503
|
});
|
|
614
504
|
pack.commands.at(-1)?.addHelpText("after", `
|
|
@@ -619,11 +509,12 @@ Examples:
|
|
|
619
509
|
.description("delete one agent pack and any of your aliases that point to it")
|
|
620
510
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
621
511
|
.option("--id <id>", "pack id")
|
|
512
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
622
513
|
.action(async (options) => {
|
|
623
514
|
const payload = await resolveInput(options, {
|
|
624
515
|
id: options.id
|
|
625
516
|
});
|
|
626
|
-
const context = await resolveContext();
|
|
517
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
627
518
|
printJson(await deletePack(context, payload));
|
|
628
519
|
});
|
|
629
520
|
pack.commands.at(-1)?.addHelpText("after", `
|
|
@@ -633,23 +524,26 @@ Examples:
|
|
|
633
524
|
agent
|
|
634
525
|
.command("list")
|
|
635
526
|
.description("list AI teammates and whether they appear in the assignee roster")
|
|
636
|
-
.
|
|
637
|
-
|
|
527
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
528
|
+
.action(async (options) => {
|
|
529
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
638
530
|
printJson(await listAgents(context));
|
|
639
531
|
});
|
|
640
532
|
agent.commands.at(-1)?.addHelpText("after", `
|
|
641
533
|
Examples:
|
|
642
|
-
epismo agent list
|
|
534
|
+
epismo agent list
|
|
535
|
+
epismo agent list --workspace-id <workspace-id>`);
|
|
643
536
|
agent
|
|
644
537
|
.command("add")
|
|
645
538
|
.description("add AI teammates to the assignee roster")
|
|
646
539
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
647
540
|
.option("--agent-ids <agentIds>", "JSON array or comma-separated agent ids")
|
|
541
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
648
542
|
.action(async (options) => {
|
|
649
543
|
const payload = await resolveInput(options, {
|
|
650
544
|
agentIds: parseStringArrayInput(options.agentIds, "--agent-ids")
|
|
651
545
|
});
|
|
652
|
-
const context = await resolveContext();
|
|
546
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
653
547
|
printJson(await addAgents(context, payload));
|
|
654
548
|
});
|
|
655
549
|
agent.commands.at(-1)?.addHelpText("after", `
|
|
@@ -661,11 +555,12 @@ Examples:
|
|
|
661
555
|
.description("remove AI teammates from the assignee roster")
|
|
662
556
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
663
557
|
.option("--agent-ids <agentIds>", "JSON array or comma-separated agent ids")
|
|
558
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
664
559
|
.action(async (options) => {
|
|
665
560
|
const payload = await resolveInput(options, {
|
|
666
561
|
agentIds: parseStringArrayInput(options.agentIds, "--agent-ids")
|
|
667
562
|
});
|
|
668
|
-
const context = await resolveContext();
|
|
563
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
669
564
|
printJson(await removeAgents(context, payload));
|
|
670
565
|
});
|
|
671
566
|
agent.commands.at(-1)?.addHelpText("after", `
|
|
@@ -676,23 +571,26 @@ Examples:
|
|
|
676
571
|
credit
|
|
677
572
|
.command("balance")
|
|
678
573
|
.description("show current credit balance")
|
|
679
|
-
.
|
|
680
|
-
|
|
574
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
575
|
+
.action(async (options) => {
|
|
576
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
681
577
|
printJson(await creditBalance(context));
|
|
682
578
|
});
|
|
683
579
|
credit.commands.at(-1)?.addHelpText("after", `
|
|
684
580
|
Examples:
|
|
685
|
-
epismo credit balance
|
|
581
|
+
epismo credit balance
|
|
582
|
+
epismo credit balance --workspace-id <workspace-id>`);
|
|
686
583
|
credit
|
|
687
584
|
.command("checkout")
|
|
688
585
|
.description("start a credit purchase and get a checkout URL")
|
|
689
586
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
690
587
|
.option("--allocations <allocations>", 'JSON array of { userId, quantity } e.g. \'[{"userId":"u_1","quantity":10}]\'')
|
|
588
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
691
589
|
.action(async (options) => {
|
|
692
590
|
const payload = await resolveInput(options, {
|
|
693
591
|
allocations: parseJsonArrayOption(options.allocations, "--allocations")
|
|
694
592
|
});
|
|
695
|
-
const context = await resolveContext();
|
|
593
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
696
594
|
printJson(await creditCheckout(context, payload));
|
|
697
595
|
});
|
|
698
596
|
credit.commands.at(-1)?.addHelpText("after", `
|
|
@@ -706,13 +604,14 @@ Example:
|
|
|
706
604
|
.addOption(new Option("--type <type>", "workflow | context").choices(PACK_TYPES))
|
|
707
605
|
.option("--id <id>", "target pack id")
|
|
708
606
|
.option("--alias <alias>", "alias name")
|
|
607
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
709
608
|
.action(async (options) => {
|
|
710
609
|
const payload = await resolveInput(options, {
|
|
711
610
|
type: options.type,
|
|
712
611
|
id: options.id,
|
|
713
612
|
alias: options.alias
|
|
714
613
|
});
|
|
715
|
-
const context = await resolveContext();
|
|
614
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
716
615
|
printJson(await upsertAlias(context, payload));
|
|
717
616
|
});
|
|
718
617
|
alias.commands.at(-1)?.addHelpText("after", `
|
|
@@ -724,11 +623,12 @@ Examples:
|
|
|
724
623
|
.description("resolve one alias")
|
|
725
624
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
726
625
|
.option("--alias <alias>", "alias reference (`alias` or `@handle/alias`)")
|
|
626
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
727
627
|
.action(async (options) => {
|
|
728
628
|
const payload = await resolveInput(options, {
|
|
729
629
|
alias: options.alias
|
|
730
630
|
});
|
|
731
|
-
const context = await resolveContext();
|
|
631
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
732
632
|
printJson(await getAlias(context, payload));
|
|
733
633
|
});
|
|
734
634
|
alias.commands.at(-1)?.addHelpText("after", `
|
|
@@ -739,8 +639,9 @@ Examples:
|
|
|
739
639
|
.command("list")
|
|
740
640
|
.description("list your aliases")
|
|
741
641
|
.addOption(new Option("--type <type>", "workflow | context").choices(PACK_TYPES))
|
|
642
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
742
643
|
.action(async (options) => {
|
|
743
|
-
const context = await resolveContext();
|
|
644
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
744
645
|
printJson(await listAliases(context, { type: options.type }));
|
|
745
646
|
});
|
|
746
647
|
alias.commands.at(-1)?.addHelpText("after", `
|
|
@@ -752,36 +653,17 @@ Example:
|
|
|
752
653
|
.description("delete one alias")
|
|
753
654
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
754
655
|
.option("--alias <alias>", "alias name")
|
|
656
|
+
.option(WORKSPACE_ID_OPT, WORKSPACE_ID_DESC)
|
|
755
657
|
.action(async (options) => {
|
|
756
658
|
const payload = await resolveInput(options, {
|
|
757
659
|
alias: options.alias
|
|
758
660
|
});
|
|
759
|
-
const context = await resolveContext();
|
|
661
|
+
const context = await resolveContext({ workspaceId: options.workspaceId });
|
|
760
662
|
printJson(await deleteAlias(context, payload));
|
|
761
663
|
});
|
|
762
664
|
alias.commands.at(-1)?.addHelpText("after", `
|
|
763
665
|
Example:
|
|
764
666
|
epismo alias delete --alias myproject`);
|
|
765
|
-
const token = program.command("token").description("manage CLI tokens for CI/CD");
|
|
766
|
-
token
|
|
767
|
-
.command("create")
|
|
768
|
-
.description("issue a workspace-scoped CLI token for use in CI/CD pipelines")
|
|
769
|
-
.option("--workspace-id <workspaceId>", "workspace to scope the token to (omit for personal space)")
|
|
770
|
-
.action(async (options) => {
|
|
771
|
-
const context = await resolveContext();
|
|
772
|
-
printJson(await createToken(context, options.workspaceId ?? context.workspaceId));
|
|
773
|
-
});
|
|
774
|
-
token.commands.at(-1)?.addHelpText("after", `
|
|
775
|
-
Notes:
|
|
776
|
-
The issued token has the same scopes as a normal CLI token (read, write, offline_access)
|
|
777
|
-
but carries the workspace ID embedded. Use it via the EPISMO_TOKEN environment variable
|
|
778
|
-
in CI/CD so no --workspace-id flag is needed at runtime.
|
|
779
|
-
If --workspace-id is omitted, the saved default workspace is used (epismo workspace use),
|
|
780
|
-
falling back to personal space when no default is set.
|
|
781
|
-
|
|
782
|
-
Examples:
|
|
783
|
-
epismo token create --workspace-id <workspace-id>
|
|
784
|
-
epismo token create # uses saved default workspace, or personal space if none`);
|
|
785
667
|
return program;
|
|
786
668
|
}
|
|
787
669
|
//# sourceMappingURL=program.js.map
|