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