epismo 0.20.0 → 1.0.2
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 +74 -67
- package/dist/auth.js +37 -10
- package/dist/auth.js.map +1 -1
- package/dist/cases.js +25 -0
- package/dist/cases.js.map +1 -0
- package/dist/config.js.map +1 -1
- package/dist/playbook-program.js +397 -0
- package/dist/playbook-program.js.map +1 -0
- package/dist/playbooks.js +56 -0
- package/dist/playbooks.js.map +1 -0
- package/dist/program.js +7 -862
- package/dist/program.js.map +1 -1
- package/dist/records.js +12 -0
- package/dist/records.js.map +1 -0
- package/dist/suggestions.js +12 -40
- package/dist/suggestions.js.map +1 -1
- package/package.json +14 -2
- package/dist/agents.js +0 -40
- package/dist/agents.js.map +0 -1
- package/dist/aliases.js +0 -49
- package/dist/aliases.js.map +0 -1
- package/dist/logs.js +0 -43
- package/dist/logs.js.map +0 -1
- package/dist/packs.js +0 -177
- package/dist/packs.js.map +0 -1
- package/dist/track-reference.js +0 -33
- package/dist/track-reference.js.map +0 -1
- package/dist/tracks.js +0 -122
- package/dist/tracks.js.map +0 -1
package/dist/program.js
CHANGED
|
@@ -1,161 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Command, Option } from "commander";
|
|
2
2
|
import { clearWorkspace, getCurrentWorkspace, listAvailableWorkspaces, login, logout, useWorkspace, whoami } from "./auth.js";
|
|
3
3
|
import { resolveExecutionContext } from "./context.js";
|
|
4
|
-
import { mergeDefined,
|
|
4
|
+
import { mergeDefined, parseStringArrayInput, readJsonObjectInput } from "./input.js";
|
|
5
5
|
import { printJson, printWarning } from "./output.js";
|
|
6
|
-
import { applyTracks, createTrack, deleteTrack, getTrack, reviewTracks, searchTracks, updateTrack } from "./tracks.js";
|
|
7
|
-
import { createLogForTrack, deleteLog, listLogs } from "./logs.js";
|
|
8
|
-
import { createPack, deletePack, getPack, likePack, ratePack, runPack, searchPacks, updatePack } from "./packs.js";
|
|
9
|
-
import { createSuggestion, getSuggestion, listSuggestions, resolveSuggestion, updateSuggestion } from "./suggestions.js";
|
|
10
|
-
import { deleteAlias, getAlias, listAliases, upsertAlias } from "./aliases.js";
|
|
11
6
|
import { creditBalance, creditCheckout } from "./credits.js";
|
|
12
7
|
import { CliError } from "./errors.js";
|
|
13
|
-
import { addAgents, listAgents, removeAgents } from "./agents.js";
|
|
14
8
|
import { createWorkspace, deleteWorkspaceMembers, getWorkspaceCheckout, listWorkspaceMembers, updateWorkspace, upsertWorkspaceMembers } from "./workspaces.js";
|
|
15
9
|
import { addProjectMembers, createProject, deleteProjectMembers, listProjectMembers, listProjects, updateProject } from "./projects.js";
|
|
16
10
|
import { createToken } from "./token.js";
|
|
17
|
-
|
|
18
|
-
const LOG_ORDERS = ["asc", "desc"];
|
|
19
|
-
const PACK_TYPES = ["workflow", "context"];
|
|
20
|
-
const ALIAS_NAMESPACES = ["personal", "workspace"];
|
|
21
|
-
const PACK_VISIBILITIES = ["public", "private"];
|
|
22
|
-
const SUGGESTION_STATUSES = ["open", "applied", "declined", "archived"];
|
|
11
|
+
import { registerPlaybookProgram } from "./playbook-program.js";
|
|
23
12
|
// centralize warning codes so wording is consistent everywhere
|
|
24
13
|
const WARNING_ENV_TOKEN_WORKSPACE_IGNORED = "EPISMO_TOKEN_WORKSPACE_IGNORED";
|
|
25
|
-
function collectOption(value, previous = []) {
|
|
26
|
-
return [...previous, value];
|
|
27
|
-
}
|
|
28
14
|
async function resolveInput(options, overrides) {
|
|
29
15
|
const base = await readJsonObjectInput(options.input);
|
|
30
16
|
return mergeDefined(base, overrides);
|
|
31
17
|
}
|
|
32
|
-
function getExplicitOptionOverride(command, optionName, value) {
|
|
33
|
-
const source = command.getOptionValueSource(optionName);
|
|
34
|
-
if (source === undefined || source === "default") {
|
|
35
|
-
return undefined;
|
|
36
|
-
}
|
|
37
|
-
return value;
|
|
38
|
-
}
|
|
39
|
-
function buildScopeOption(command, options) {
|
|
40
|
-
const personalExplicit = getExplicitOptionOverride(command, "personal", options.personal);
|
|
41
|
-
const projectsExplicit = getExplicitOptionOverride(command, "projects", parseStringArrayInput(options.projects, "--projects"));
|
|
42
|
-
if (personalExplicit !== undefined && projectsExplicit !== undefined) {
|
|
43
|
-
throw new CliError({
|
|
44
|
-
code: "INVALID_INPUT",
|
|
45
|
-
message: "--personal and --projects cannot be combined."
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
if (personalExplicit === true) {
|
|
49
|
-
return { type: "personal" };
|
|
50
|
-
}
|
|
51
|
-
if (projectsExplicit !== undefined) {
|
|
52
|
-
const ids = projectsExplicit;
|
|
53
|
-
if (ids.length === 0) {
|
|
54
|
-
throw new CliError({
|
|
55
|
-
code: "INVALID_INPUT",
|
|
56
|
-
message: "--projects requires at least one project id."
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
return { type: "projects", ids };
|
|
60
|
-
}
|
|
61
|
-
return undefined;
|
|
62
|
-
}
|
|
63
|
-
function buildSharedWithOption(command, options) {
|
|
64
|
-
const values = getExplicitOptionOverride(command, "shareWith", parseStringArrayInput(options.shareWith, "--share-with"));
|
|
65
|
-
if (values === undefined) {
|
|
66
|
-
return undefined;
|
|
67
|
-
}
|
|
68
|
-
const emails = [];
|
|
69
|
-
const userIds = [];
|
|
70
|
-
for (const value of values) {
|
|
71
|
-
if (value.includes("@")) {
|
|
72
|
-
emails.push(value);
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
userIds.push(value);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
const result = {};
|
|
79
|
-
if (userIds.length > 0) {
|
|
80
|
-
result.userIds = userIds;
|
|
81
|
-
}
|
|
82
|
-
if (emails.length > 0) {
|
|
83
|
-
result.emails = emails;
|
|
84
|
-
}
|
|
85
|
-
return result;
|
|
86
|
-
}
|
|
87
|
-
function buildSearchScopes(command, options) {
|
|
88
|
-
const personalExplicit = getExplicitOptionOverride(command, "personal", options.personal);
|
|
89
|
-
const projectsExplicit = getExplicitOptionOverride(command, "projects", parseStringArrayInput(options.projects, "--projects"));
|
|
90
|
-
const scopes = [];
|
|
91
|
-
if (personalExplicit === true) {
|
|
92
|
-
scopes.push({ type: "personal" });
|
|
93
|
-
}
|
|
94
|
-
if (projectsExplicit !== undefined) {
|
|
95
|
-
const ids = projectsExplicit;
|
|
96
|
-
if (ids.length === 0) {
|
|
97
|
-
throw new CliError({
|
|
98
|
-
code: "INVALID_INPUT",
|
|
99
|
-
message: "--projects requires at least one project id."
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
scopes.push({ type: "projects", ids });
|
|
103
|
-
}
|
|
104
|
-
return scopes.length > 0 ? scopes : undefined;
|
|
105
|
-
}
|
|
106
|
-
// TODO(remove-legacy-search-targets): delete this helper and the hidden
|
|
107
|
-
// `--project-ids` / `--self` options once users have migrated to `--personal`
|
|
108
|
-
// / `--projects`.
|
|
109
|
-
function buildLegacySearchTargets(command, options) {
|
|
110
|
-
const projectIdsExplicit = getExplicitOptionOverride(command, "projectIds", parseStringArrayInput(options.projectIds, "--project-ids"));
|
|
111
|
-
const selfExplicit = getExplicitOptionOverride(command, "self", parseOptionalBooleanText(options.self, "--self"));
|
|
112
|
-
const targets = {};
|
|
113
|
-
if (projectIdsExplicit !== undefined) {
|
|
114
|
-
targets.projectIds = projectIdsExplicit;
|
|
115
|
-
}
|
|
116
|
-
if (selfExplicit !== undefined) {
|
|
117
|
-
targets.self = selfExplicit;
|
|
118
|
-
}
|
|
119
|
-
return Object.keys(targets).length > 0 ? targets : undefined;
|
|
120
|
-
}
|
|
121
|
-
// TODO(remove-legacy-search-targets): delete with the helpers above.
|
|
122
|
-
function parseOptionalBooleanText(value, optionName) {
|
|
123
|
-
if (value === undefined) {
|
|
124
|
-
return undefined;
|
|
125
|
-
}
|
|
126
|
-
if (typeof value === "boolean") {
|
|
127
|
-
return value;
|
|
128
|
-
}
|
|
129
|
-
if (typeof value === "string") {
|
|
130
|
-
const normalized = value.trim().toLowerCase();
|
|
131
|
-
if (normalized === "true")
|
|
132
|
-
return true;
|
|
133
|
-
if (normalized === "false")
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
throw new CliError({
|
|
137
|
-
code: "INVALID_INPUT",
|
|
138
|
-
message: `Invalid ${optionName}: expected true or false.`
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
// TODO(remove-legacy-search-targets): inline back into action handlers
|
|
142
|
-
// once legacy `--project-ids` / `--self` are removed.
|
|
143
|
-
function buildSearchSelection(command, options) {
|
|
144
|
-
const scopes = buildSearchScopes(command, options);
|
|
145
|
-
const targets = buildLegacySearchTargets(command, options);
|
|
146
|
-
if (scopes !== undefined && targets !== undefined) {
|
|
147
|
-
throw new CliError({
|
|
148
|
-
code: "INVALID_INPUT",
|
|
149
|
-
message: "--personal/--projects cannot be combined with the legacy --self/--project-ids flags."
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
const result = {};
|
|
153
|
-
if (scopes !== undefined)
|
|
154
|
-
result.scopes = scopes;
|
|
155
|
-
if (targets !== undefined)
|
|
156
|
-
result.targets = targets;
|
|
157
|
-
return result;
|
|
158
|
-
}
|
|
159
18
|
async function resolveContext() {
|
|
160
19
|
const context = await resolveExecutionContext();
|
|
161
20
|
if (context.warning) {
|
|
@@ -169,7 +28,7 @@ export function buildProgram(version) {
|
|
|
169
28
|
const program = new Command();
|
|
170
29
|
program
|
|
171
30
|
.name("epismo")
|
|
172
|
-
.description("
|
|
31
|
+
.description("Agent-first CLI for discovering, authoring, and coordinating reusable AI Playbooks.")
|
|
173
32
|
.version(version)
|
|
174
33
|
.showHelpAfterError(false)
|
|
175
34
|
.showSuggestionAfterError(false)
|
|
@@ -187,15 +46,7 @@ Workspace resolution:
|
|
|
187
46
|
Examples:
|
|
188
47
|
epismo login
|
|
189
48
|
epismo whoami
|
|
190
|
-
epismo workspace list
|
|
191
|
-
epismo alias list
|
|
192
|
-
epismo track search --query "bug"
|
|
193
|
-
epismo pack search --query "meeting notes"
|
|
194
|
-
epismo suggestion list --owner --status open
|
|
195
|
-
epismo suggestion create @market-research --title "Add review step" --content "Add a final human review."
|
|
196
|
-
epismo pack get <id> --block-id b001
|
|
197
|
-
epismo pack get @myproject
|
|
198
|
-
epismo pack get @handle/myproject`);
|
|
49
|
+
epismo workspace list`);
|
|
199
50
|
program
|
|
200
51
|
.command("login")
|
|
201
52
|
.description("log in through a browser, or use email with automatic SSO discovery")
|
|
@@ -329,7 +180,7 @@ Examples:
|
|
|
329
180
|
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
330
181
|
.option("--name <name>", "updated workspace name")
|
|
331
182
|
.action(async (workspaceId, options) => {
|
|
332
|
-
const payload = await resolveInput(
|
|
183
|
+
const payload = await resolveInput(options, { name: options.name });
|
|
333
184
|
const context = await resolveContext();
|
|
334
185
|
printJson(await updateWorkspace(context, workspaceId, payload));
|
|
335
186
|
});
|
|
@@ -456,646 +307,6 @@ Examples:
|
|
|
456
307
|
const context = await resolveContext();
|
|
457
308
|
printJson(await deleteProjectMembers(context, options.projectId, userIds));
|
|
458
309
|
});
|
|
459
|
-
const track = program.command("track").description("manage project tracks (tasks and goals)");
|
|
460
|
-
track
|
|
461
|
-
.command("create")
|
|
462
|
-
.description("create a new project track (task or goal)")
|
|
463
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
464
|
-
.addOption(new Option("--type <type>", "task | goal").choices(TRACK_TYPES))
|
|
465
|
-
.option("--title <title>", "title")
|
|
466
|
-
.option("--content <content>", "markdown content")
|
|
467
|
-
.option("--personal", "keep private to the current user (mutually exclusive with --projects)")
|
|
468
|
-
.option("--projects <projects>", "JSON array or comma-separated project ids (mutually exclusive with --personal)")
|
|
469
|
-
.option("--share-with <shareWith>", "JSON array or comma-separated list of user ids and/or emails (values containing '@' are emails)")
|
|
470
|
-
.option("--sources <sources>", 'JSON array or comma-separated source references: bare entry_ids, or pack origins as "workflow:<id>" / "context:<id>"')
|
|
471
|
-
.option("--task <task>", 'task-specific fields as JSON object e.g. \'{"status":"todo","dueDate":"2025-12-31"}\'')
|
|
472
|
-
.option("--goal <goal>", 'goal-specific fields as JSON object e.g. \'{"status":"on_track","dueDate":"2025-12-31"}\'')
|
|
473
|
-
.action(async (options, command) => {
|
|
474
|
-
const payload = await resolveInput(options, {
|
|
475
|
-
type: options.type,
|
|
476
|
-
title: options.title,
|
|
477
|
-
content: options.content,
|
|
478
|
-
scope: buildScopeOption(command, options),
|
|
479
|
-
sharedWith: buildSharedWithOption(command, options),
|
|
480
|
-
sources: parseStringArrayInput(options.sources, "--sources"),
|
|
481
|
-
task: parseJsonObjectOption(options.task, "--task"),
|
|
482
|
-
goal: parseJsonObjectOption(options.goal, "--goal")
|
|
483
|
-
});
|
|
484
|
-
const context = await resolveContext();
|
|
485
|
-
printJson(await createTrack(context, payload));
|
|
486
|
-
});
|
|
487
|
-
track.commands.at(-1)?.addHelpText("after", `
|
|
488
|
-
Notes:
|
|
489
|
-
Use --task or --goal to pass type-specific fields.
|
|
490
|
-
|
|
491
|
-
Examples:
|
|
492
|
-
epismo track create --type task --title "Fix bug" --content "Details..."
|
|
493
|
-
epismo track create --input @task.json
|
|
494
|
-
epismo track create --type goal --title "Launch" --goal '{"status":"on_track"}'`);
|
|
495
|
-
track
|
|
496
|
-
.command("update")
|
|
497
|
-
.description("update an existing project track (PATCH — omitted fields are unchanged)")
|
|
498
|
-
.argument("<reference>", "task/goal UUID or URL containing it")
|
|
499
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
500
|
-
.option("--title <title>", "updated title")
|
|
501
|
-
.option("--content <content>", "updated markdown content")
|
|
502
|
-
.option("--personal", "set scope to personal (mutually exclusive with --projects)")
|
|
503
|
-
.option("--projects <projects>", "JSON array or comma-separated project ids (mutually exclusive with --personal)")
|
|
504
|
-
.option("--share-with <shareWith>", "JSON array or comma-separated list of user ids and/or emails (values containing '@' are emails)")
|
|
505
|
-
.option("--sources <sources>", 'JSON array or comma-separated source references: bare entry_ids, or pack origins as "workflow:<id>" / "context:<id>"')
|
|
506
|
-
.option("--task <task>", 'task-specific fields as partial JSON object e.g. \'{"status":"done"}\'')
|
|
507
|
-
.option("--goal <goal>", "goal-specific fields as partial JSON object e.g. '{\"progress\":50}'")
|
|
508
|
-
.option("--note <note>", 'optional status note as JSON, e.g. \'{"kind":"review","content":"Tests passed"}\'')
|
|
509
|
-
.action(async (reference, options, command) => {
|
|
510
|
-
const payload = await resolveInput(options, {
|
|
511
|
-
title: options.title,
|
|
512
|
-
content: options.content,
|
|
513
|
-
scope: buildScopeOption(command, options),
|
|
514
|
-
sharedWith: buildSharedWithOption(command, options),
|
|
515
|
-
sources: parseStringArrayInput(options.sources, "--sources"),
|
|
516
|
-
task: parseJsonObjectOption(options.task, "--task"),
|
|
517
|
-
goal: parseJsonObjectOption(options.goal, "--goal"),
|
|
518
|
-
note: parseJsonObjectOption(options.note, "--note")
|
|
519
|
-
});
|
|
520
|
-
const context = await resolveContext();
|
|
521
|
-
printJson(await updateTrack(context, reference, payload));
|
|
522
|
-
});
|
|
523
|
-
track.commands.at(-1)?.addHelpText("after", `
|
|
524
|
-
Notes:
|
|
525
|
-
Omitted fields keep their existing value.
|
|
526
|
-
Completing a task or completing/postponing a goal may return review.recommendations
|
|
527
|
-
for an outcome log or a detailed review.
|
|
528
|
-
|
|
529
|
-
Examples:
|
|
530
|
-
epismo track update <track-reference> --title "Updated title"
|
|
531
|
-
epismo track update <track-reference> --task '{"status":"done"}'
|
|
532
|
-
epismo track update <track-reference> --task '{"status":"done"}' --note '{"kind":"review","content":"Tests passed"}'
|
|
533
|
-
epismo track update <track-reference> --goal '{"progress":75}'`);
|
|
534
|
-
track
|
|
535
|
-
.command("get")
|
|
536
|
-
.description("fetch one project track")
|
|
537
|
-
.argument("<reference>", "task/goal UUID or URL containing it")
|
|
538
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
539
|
-
.action(async (reference) => {
|
|
540
|
-
const context = await resolveContext();
|
|
541
|
-
printJson(await getTrack(context, reference));
|
|
542
|
-
});
|
|
543
|
-
track.commands.at(-1)?.addHelpText("after", `
|
|
544
|
-
Example:
|
|
545
|
-
epismo track get <track-reference>`);
|
|
546
|
-
track
|
|
547
|
-
.command("review")
|
|
548
|
-
.description("generate a detailed review for one or more task/goal tracks")
|
|
549
|
-
.argument("<references...>", "one or more task/goal UUIDs or URLs containing them")
|
|
550
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
551
|
-
.option("--instruction <instruction>", "optional instruction to steer the review")
|
|
552
|
-
.action(async (references, options) => {
|
|
553
|
-
const payload = await resolveInput(options, {
|
|
554
|
-
targetIds: references,
|
|
555
|
-
instruction: options.instruction
|
|
556
|
-
});
|
|
557
|
-
const context = await resolveContext();
|
|
558
|
-
printJson(await reviewTracks(context, payload));
|
|
559
|
-
});
|
|
560
|
-
track.commands.at(-1)?.addHelpText("after", `
|
|
561
|
-
Notes:
|
|
562
|
-
Review output is displayed only; it does not create or update packs automatically.
|
|
563
|
-
|
|
564
|
-
Example:
|
|
565
|
-
epismo track review <track-reference>
|
|
566
|
-
epismo track review <track-reference> <related-track-reference>`);
|
|
567
|
-
track
|
|
568
|
-
.command("search")
|
|
569
|
-
.description("search project tracks")
|
|
570
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
571
|
-
.addOption(new Option("--type <type>", "task | goal").choices(TRACK_TYPES))
|
|
572
|
-
.option("--query <query>", "free-text query")
|
|
573
|
-
.addOption(new Option("--search-mode <mode>", "keyword (default) or semantic; semantic blends keyword and vector relevance").choices(["keyword", "semantic"]))
|
|
574
|
-
.option("--page <page>", "1-based page number")
|
|
575
|
-
.option("--personal", "search personal/private-to-user items")
|
|
576
|
-
.option("--projects <projects>", "JSON array or comma-separated project ids to search")
|
|
577
|
-
// TODO(remove-legacy-search-targets): drop these two hidden options.
|
|
578
|
-
.addOption(new Option("--project-ids <projectIds>", "deprecated; use --projects").hideHelp())
|
|
579
|
-
.addOption(new Option("--self <self>", "deprecated; use --personal").hideHelp())
|
|
580
|
-
.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)')
|
|
581
|
-
.action(async (options, command) => {
|
|
582
|
-
const selection = buildSearchSelection(command, options);
|
|
583
|
-
const payload = await resolveInput(options, {
|
|
584
|
-
type: getExplicitOptionOverride(command, "type", options.type),
|
|
585
|
-
query: getExplicitOptionOverride(command, "query", options.query),
|
|
586
|
-
searchMode: getExplicitOptionOverride(command, "searchMode", options.searchMode),
|
|
587
|
-
page: getExplicitOptionOverride(command, "page", parseOptionalPositiveInteger(options.page, "--page")),
|
|
588
|
-
scopes: selection.scopes,
|
|
589
|
-
targets: selection.targets,
|
|
590
|
-
filter: getExplicitOptionOverride(command, "filter", parseJsonObjectOption(options.filter, "--filter"))
|
|
591
|
-
});
|
|
592
|
-
const context = await resolveContext();
|
|
593
|
-
printJson(await searchTracks(context, payload));
|
|
594
|
-
});
|
|
595
|
-
track.commands.at(-1)?.addHelpText("after", `
|
|
596
|
-
Examples:
|
|
597
|
-
epismo track search --query "bug"
|
|
598
|
-
epismo track search --type task --query "bug"
|
|
599
|
-
epismo track search --query "auth rollout plan" --search-mode semantic
|
|
600
|
-
epismo track search --type task --projects proj1
|
|
601
|
-
epismo track search --type task --personal --projects proj1
|
|
602
|
-
epismo track search --type task --filter '{"status":["todo"]}'
|
|
603
|
-
epismo track search --type goal --query "roadmap"`);
|
|
604
|
-
track
|
|
605
|
-
.command("delete")
|
|
606
|
-
.description("delete one project track")
|
|
607
|
-
.argument("<reference>", "task/goal UUID or URL containing it")
|
|
608
|
-
.action(async (reference) => {
|
|
609
|
-
const context = await resolveContext();
|
|
610
|
-
printJson(await deleteTrack(context, reference));
|
|
611
|
-
});
|
|
612
|
-
track.commands.at(-1)?.addHelpText("after", `
|
|
613
|
-
Example:
|
|
614
|
-
epismo track delete <track-reference>`);
|
|
615
|
-
track
|
|
616
|
-
.command("apply")
|
|
617
|
-
.description("create, update, and delete multiple tracks in a single request")
|
|
618
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
619
|
-
.option("--personal", "set scope to personal (mutually exclusive with --projects)")
|
|
620
|
-
.option("--projects <projects>", "JSON array or comma-separated project ids (mutually exclusive with --personal)")
|
|
621
|
-
.option("--share-with <shareWith>", "JSON array or comma-separated list of user ids and/or emails (values containing '@' are emails)")
|
|
622
|
-
.action(async (options, command) => {
|
|
623
|
-
const payload = await resolveInput(options, {
|
|
624
|
-
scope: buildScopeOption(command, options),
|
|
625
|
-
sharedWith: buildSharedWithOption(command, options)
|
|
626
|
-
});
|
|
627
|
-
const context = await resolveContext();
|
|
628
|
-
printJson(await applyTracks(context, payload));
|
|
629
|
-
});
|
|
630
|
-
track.commands.at(-1)?.addHelpText("after", `
|
|
631
|
-
Notes:
|
|
632
|
-
upserts: use a non-UUID string as id (e.g. "t001") to create a new track, or a UUID to update an existing one.
|
|
633
|
-
Labels in task.parentId, task.dependsOn, and task.goalId are resolved by the server, so you can wire
|
|
634
|
-
up dependencies between new entries in the same request.
|
|
635
|
-
deletes: provide UUIDs of tracks to delete.
|
|
636
|
-
|
|
637
|
-
Examples:
|
|
638
|
-
epismo track apply --input @batch.json
|
|
639
|
-
epismo track apply --input '{"upserts":[{"id":"t001","title":"Task A","task":{"status":"todo"}},{"id":"t002","title":"Task B","task":{"status":"todo","dependsOn":["t001"]}}]}'`);
|
|
640
|
-
const log = program.command("log").description("manage track logs");
|
|
641
|
-
log.command("create")
|
|
642
|
-
.description("append a log/comment to a track")
|
|
643
|
-
.argument("<reference>", "task/goal UUID or URL containing it")
|
|
644
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
645
|
-
.option("--kind <kind>", "comment | update | review (default: comment)")
|
|
646
|
-
.option("--content <content>", "log content")
|
|
647
|
-
.option("--metadata <metadata>", "machine-readable metadata as JSON object")
|
|
648
|
-
.option("--idempotency-key <idempotencyKey>", "optional UUID for idempotent retry")
|
|
649
|
-
.action(async (trackId, options, command) => {
|
|
650
|
-
const payload = await resolveInput(options, {
|
|
651
|
-
kind: getExplicitOptionOverride(command, "kind", options.kind),
|
|
652
|
-
content: getExplicitOptionOverride(command, "content", options.content),
|
|
653
|
-
metadata: getExplicitOptionOverride(command, "metadata", parseJsonObjectOption(options.metadata, "--metadata")),
|
|
654
|
-
idempotencyKey: getExplicitOptionOverride(command, "idempotencyKey", options.idempotencyKey)
|
|
655
|
-
});
|
|
656
|
-
const context = await resolveContext();
|
|
657
|
-
printJson(await createLogForTrack(context, trackId, payload));
|
|
658
|
-
});
|
|
659
|
-
log.commands.at(-1)?.addHelpText("after", `
|
|
660
|
-
Examples:
|
|
661
|
-
epismo log create <track-reference> --content "Evaluator failed because tests are missing."
|
|
662
|
-
epismo log create <track-reference> --kind review --content "Tests failed" --metadata '{"verdict":"fail"}'`);
|
|
663
|
-
log.command("list")
|
|
664
|
-
.description("list logs — for one track, or across every track you can see")
|
|
665
|
-
.argument("[reference]", "task/goal UUID or URL containing it (omit for the cross-track activity feed)")
|
|
666
|
-
.option("--author-id <userId>", "narrow to logs authored by this user id")
|
|
667
|
-
.addOption(new Option("--order <order>", "desc = newest first (default), asc = oldest first").choices(LOG_ORDERS))
|
|
668
|
-
.option("--cursor <logId>", "continue past this log id in the chosen order (nextCursor)")
|
|
669
|
-
.action(async (trackId, options) => {
|
|
670
|
-
const context = await resolveContext();
|
|
671
|
-
printJson(await listLogs(context, trackId, {
|
|
672
|
-
authorId: options.authorId,
|
|
673
|
-
order: options.order,
|
|
674
|
-
cursor: options.cursor
|
|
675
|
-
}));
|
|
676
|
-
});
|
|
677
|
-
log.commands.at(-1)?.addHelpText("after", `
|
|
678
|
-
Examples:
|
|
679
|
-
epismo log list <track-reference> # newest logs first for one track
|
|
680
|
-
epismo log list <track-reference> --cursor <logId> # older history
|
|
681
|
-
epismo log list <track-reference> --order asc # chronological from the start
|
|
682
|
-
epismo log list # every log you can see, newest first
|
|
683
|
-
epismo log list --author-id <userId> # only logs one user wrote`);
|
|
684
|
-
log.command("delete")
|
|
685
|
-
.description("delete one log")
|
|
686
|
-
.argument("<logId>", "log id")
|
|
687
|
-
.action(async (logId) => {
|
|
688
|
-
const context = await resolveContext();
|
|
689
|
-
printJson(await deleteLog(context, logId));
|
|
690
|
-
});
|
|
691
|
-
log.commands.at(-1)?.addHelpText("after", `
|
|
692
|
-
Example:
|
|
693
|
-
epismo log delete <logId>`);
|
|
694
|
-
const pack = program.command("pack").description("manage agent packs (workflows and contexts)");
|
|
695
|
-
pack.command("create")
|
|
696
|
-
.description("create a new agent pack")
|
|
697
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
698
|
-
.addOption(new Option("--type <type>", "workflow | context (required unless provided in --input)").choices(PACK_TYPES))
|
|
699
|
-
.option("--title <title>", "title")
|
|
700
|
-
.option("--content <content>", "markdown content")
|
|
701
|
-
.option("--category <category>", "pack category")
|
|
702
|
-
.addOption(new Option("--visibility <visibility>", "public | private").choices(PACK_VISIBILITIES))
|
|
703
|
-
.option("--personal", "keep private to the current user (mutually exclusive with --projects)")
|
|
704
|
-
.option("--projects <projects>", "JSON array or comma-separated project ids (mutually exclusive with --personal)")
|
|
705
|
-
.option("--share-with <shareWith>", "JSON array or comma-separated list of user ids and/or emails (values containing '@' are emails)")
|
|
706
|
-
.option("--steps <steps>", "workflow steps as JSON array (use --input @file.json for complex payloads)")
|
|
707
|
-
.option("--blocks <blocks>", "context blocks as JSON array (for type=context; use --input @file.json for complex payloads)")
|
|
708
|
-
.action(async (options, command) => {
|
|
709
|
-
const payload = await resolveInput(options, {
|
|
710
|
-
type: options.type,
|
|
711
|
-
title: options.title,
|
|
712
|
-
content: options.content,
|
|
713
|
-
category: options.category,
|
|
714
|
-
visibility: options.visibility,
|
|
715
|
-
scope: buildScopeOption(command, options),
|
|
716
|
-
sharedWith: buildSharedWithOption(command, options),
|
|
717
|
-
steps: parseJsonArrayOption(options.steps, "--steps"),
|
|
718
|
-
blocks: parseJsonArrayOption(options.blocks, "--blocks")
|
|
719
|
-
});
|
|
720
|
-
if (payload.type !== "workflow" && payload.type !== "context") {
|
|
721
|
-
throw new CliError({
|
|
722
|
-
code: "INVALID_INPUT",
|
|
723
|
-
message: "Pack type is required.",
|
|
724
|
-
hint: 'Pass --type workflow|context or include {"type":"workflow"} / {"type":"context"} in --input.'
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
const context = await resolveContext();
|
|
728
|
-
printJson(await createPack(context, payload));
|
|
729
|
-
});
|
|
730
|
-
pack.commands.at(-1)?.addHelpText("after", `
|
|
731
|
-
Notes:
|
|
732
|
-
type is required for pack create. Pass --type or include it in --input.
|
|
733
|
-
|
|
734
|
-
Examples:
|
|
735
|
-
epismo pack create --type workflow --title "My workflow" --input @workflow.json
|
|
736
|
-
epismo pack create --type workflow --title "My workflow" --steps '[{"title":"Step 1","content":"..."}]'
|
|
737
|
-
epismo pack create --type context --title "My context" --input @context.json
|
|
738
|
-
epismo pack create --type context --title "My context" --blocks '[{"title":"Block 1","content":"..."}]'`);
|
|
739
|
-
pack.command("update")
|
|
740
|
-
.description("update an existing agent pack (PATCH semantics — omitted fields are unchanged)")
|
|
741
|
-
.argument("<reference>", "pack reference: id, alias, share URL, or hub URL")
|
|
742
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
743
|
-
.option("--title <title>", "updated title")
|
|
744
|
-
.option("--content <content>", "updated markdown content")
|
|
745
|
-
.option("--category <category>", "updated pack category")
|
|
746
|
-
.addOption(new Option("--visibility <visibility>", "public | private").choices(PACK_VISIBILITIES))
|
|
747
|
-
.option("--personal", "set scope to personal (mutually exclusive with --projects)")
|
|
748
|
-
.option("--projects <projects>", "JSON array or comma-separated project ids (mutually exclusive with --personal)")
|
|
749
|
-
.option("--share-with <shareWith>", "JSON array or comma-separated list of user ids and/or emails (values containing '@' are emails)")
|
|
750
|
-
.option("--steps <steps>", 'step operations as JSON array with op field: [{"op":"add","title":"...","beforeId":"s002"},{"op":"move","id":"s003","afterId":"s001"},{"op":"update","id":"s001","content":"..."},{"op":"remove","id":"s002"}]')
|
|
751
|
-
.option("--blocks <blocks>", 'block operations as JSON array with op field: [{"op":"add","title":"...","beforeId":"b002"},{"op":"move","id":"b003","afterId":"b001"},{"op":"update","id":"b001","content":"..."},{"op":"remove","id":"b002"}]')
|
|
752
|
-
.action(async (reference, options, command) => {
|
|
753
|
-
const payload = await resolveInput(options, {
|
|
754
|
-
title: options.title,
|
|
755
|
-
content: options.content,
|
|
756
|
-
category: options.category,
|
|
757
|
-
visibility: options.visibility,
|
|
758
|
-
scope: buildScopeOption(command, options),
|
|
759
|
-
sharedWith: buildSharedWithOption(command, options),
|
|
760
|
-
steps: parseJsonArrayOption(options.steps, "--steps"),
|
|
761
|
-
blocks: parseJsonArrayOption(options.blocks, "--blocks")
|
|
762
|
-
});
|
|
763
|
-
const context = await resolveContext();
|
|
764
|
-
printJson(await updatePack(context, reference, payload));
|
|
765
|
-
});
|
|
766
|
-
pack.commands.at(-1)?.addHelpText("after", `
|
|
767
|
-
Notes:
|
|
768
|
-
Omitted fields keep their existing value.
|
|
769
|
-
steps/blocks use operation objects with an "op" field (add | update | move | remove).
|
|
770
|
-
add/move accept beforeId or afterId. Workflow move keeps dependsOn unchanged.
|
|
771
|
-
Omitting steps/blocks keeps them unchanged. Passing an empty array [] is a no-op.
|
|
772
|
-
To remove all items, send a remove op for each existing item ID.
|
|
773
|
-
|
|
774
|
-
Examples:
|
|
775
|
-
epismo pack update <id> --category ""
|
|
776
|
-
epismo pack update @myproject --visibility public
|
|
777
|
-
epismo pack update <id> --visibility public --category productivity
|
|
778
|
-
epismo pack update <id> --steps '[{"op":"move","id":"s003","afterId":"s001"}]'
|
|
779
|
-
epismo pack update <id> --blocks '[{"op":"add","title":"New Block","content":"..."}]'
|
|
780
|
-
epismo pack update <id> --blocks '[{"op":"move","id":"b003","beforeId":"b001"}]'
|
|
781
|
-
epismo pack update <id> --blocks '[{"op":"update","id":"b001","content":"updated..."}]'
|
|
782
|
-
epismo pack update <id> --blocks '[{"op":"remove","id":"b002"}]'
|
|
783
|
-
epismo pack update <id> --input @changes.json`);
|
|
784
|
-
pack.command("run")
|
|
785
|
-
.description("materialize a workflow pack into a track (a root goal plus one task per step); fetch the run later with track search by goal id")
|
|
786
|
-
.argument("<reference>", "workflow pack reference: id, alias, share URL, or hub URL")
|
|
787
|
-
.option("--title <title>", "objective for the run's root goal (defaults to the pack title)")
|
|
788
|
-
.option("--content <content>", "root goal content in Markdown (defaults to the pack content)")
|
|
789
|
-
.option("--due-date <date>", "YYYY-MM-DD absolute due date for the root goal")
|
|
790
|
-
.option("--context <reference>", "context pack reference (id, alias, share URL, or hub URL) to record as a source on the goal; comma-separated or repeatable", collectOption)
|
|
791
|
-
.option("--assignee <token=id>", "map a pack assignee token to a track assignee id, e.g. human=<user-id>; comma-separated or repeatable", collectOption)
|
|
792
|
-
.option("--personal", "keep created tracks private to the current user (mutually exclusive with --projects)")
|
|
793
|
-
.option("--projects <projects>", "JSON array or comma-separated project ids (mutually exclusive with --personal)")
|
|
794
|
-
.option("--share-with <shareWith>", "JSON array or comma-separated list of user ids and/or emails (values containing '@' are emails)")
|
|
795
|
-
.action(async (reference, options, command) => {
|
|
796
|
-
const body = {
|
|
797
|
-
reference,
|
|
798
|
-
title: options.title,
|
|
799
|
-
content: options.content,
|
|
800
|
-
goalDueDate: options.dueDate,
|
|
801
|
-
context: options.context,
|
|
802
|
-
assignees: options.assignee,
|
|
803
|
-
scope: buildScopeOption(command, options),
|
|
804
|
-
sharedWith: buildSharedWithOption(command, options)
|
|
805
|
-
};
|
|
806
|
-
const context = await resolveContext();
|
|
807
|
-
printJson(await runPack(context, body));
|
|
808
|
-
});
|
|
809
|
-
pack.commands.at(-1)?.addHelpText("after", `
|
|
810
|
-
Notes:
|
|
811
|
-
Creates the track immediately. Review the returned warnings; delete and re-run to fix mistakes.
|
|
812
|
-
--assignee maps pack tokens to track assignees; map human to a user id (agent ids resolve as-is).
|
|
813
|
-
|
|
814
|
-
Examples:
|
|
815
|
-
epismo pack run @small-feature-ship
|
|
816
|
-
epismo pack run @small-feature-ship --assignee human=<user-id>
|
|
817
|
-
epismo pack run @small-feature-ship --title "Ship CSV export" --projects <project-id> --context <context-pack-id>`);
|
|
818
|
-
pack.command("get")
|
|
819
|
-
.description("fetch one agent pack")
|
|
820
|
-
.argument("<reference>", "pack reference: id, alias, share URL, or hub URL")
|
|
821
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
822
|
-
.option("--full", "include nested item content")
|
|
823
|
-
.option("--share-url", "create or return a share URL for this pack")
|
|
824
|
-
.option("--block-id <blockId>", "context block id to extract; comma-separated or repeatable (type=context only)", collectOption)
|
|
825
|
-
.option("--step-id <stepId>", "workflow step id to extract; comma-separated or repeatable (type=workflow only)", collectOption)
|
|
826
|
-
.addOption(new Option("--namespace <namespace>", "resolve a bare/`@alias` reference in personal or workspace (omit to try personal first, then workspace)").choices(ALIAS_NAMESPACES))
|
|
827
|
-
.action(async (reference, options) => {
|
|
828
|
-
const payload = await resolveInput(options, {
|
|
829
|
-
full: options.full ? true : undefined
|
|
830
|
-
});
|
|
831
|
-
const context = await resolveContext();
|
|
832
|
-
printJson(await getPack(context, reference, payload, {
|
|
833
|
-
blockIds: options.blockId,
|
|
834
|
-
stepIds: options.stepId,
|
|
835
|
-
namespace: options.namespace,
|
|
836
|
-
shareUrl: options.shareUrl
|
|
837
|
-
}));
|
|
838
|
-
});
|
|
839
|
-
pack.commands.at(-1)?.addHelpText("after", `
|
|
840
|
-
Examples:
|
|
841
|
-
epismo pack get <id>
|
|
842
|
-
epismo pack get @myproject
|
|
843
|
-
epismo pack get @handle/myproject
|
|
844
|
-
epismo pack get https://epismo.ai/share/<token>
|
|
845
|
-
epismo pack get https://epismo.ai/hub/workflows/<id>
|
|
846
|
-
epismo pack get <id> --share-url
|
|
847
|
-
epismo pack get <id> --full
|
|
848
|
-
epismo pack get <id> --block-id b001
|
|
849
|
-
epismo pack get <id> --block-id b001 --block-id b002
|
|
850
|
-
epismo pack get <id> --step-id s001,s002`);
|
|
851
|
-
pack.command("search")
|
|
852
|
-
.description("search agent packs")
|
|
853
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
854
|
-
.addOption(new Option("--type <type>", "workflow | context").choices(PACK_TYPES))
|
|
855
|
-
.option("--query <query>", "free-text query")
|
|
856
|
-
.addOption(new Option("--search-mode <mode>", "keyword (default) or semantic; semantic blends keyword and vector relevance").choices(["keyword", "semantic"]))
|
|
857
|
-
.option("--page <page>", "1-based page number")
|
|
858
|
-
.option("--personal", "search personal/private-to-user packs")
|
|
859
|
-
.option("--projects <projects>", "JSON array or comma-separated project ids to search")
|
|
860
|
-
// TODO(remove-legacy-search-targets): drop these two hidden options.
|
|
861
|
-
.addOption(new Option("--project-ids <projectIds>", "deprecated; use --projects").hideHelp())
|
|
862
|
-
.addOption(new Option("--self <self>", "deprecated; use --personal").hideHelp())
|
|
863
|
-
.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)')
|
|
864
|
-
.action(async (options, command) => {
|
|
865
|
-
const selection = buildSearchSelection(command, options);
|
|
866
|
-
const payload = await resolveInput(options, {
|
|
867
|
-
type: getExplicitOptionOverride(command, "type", options.type),
|
|
868
|
-
query: getExplicitOptionOverride(command, "query", options.query),
|
|
869
|
-
searchMode: getExplicitOptionOverride(command, "searchMode", options.searchMode),
|
|
870
|
-
page: getExplicitOptionOverride(command, "page", parseOptionalPositiveInteger(options.page, "--page")),
|
|
871
|
-
scopes: selection.scopes,
|
|
872
|
-
targets: selection.targets,
|
|
873
|
-
filter: getExplicitOptionOverride(command, "filter", parseJsonObjectOption(options.filter, "--filter"))
|
|
874
|
-
});
|
|
875
|
-
const context = await resolveContext();
|
|
876
|
-
printJson(await searchPacks(context, payload));
|
|
877
|
-
});
|
|
878
|
-
pack.commands.at(-1)?.addHelpText("after", `
|
|
879
|
-
Examples:
|
|
880
|
-
epismo pack search --type workflow --query "onboarding"
|
|
881
|
-
epismo pack search --query "meeting notes"
|
|
882
|
-
epismo pack search --type workflow --projects proj1
|
|
883
|
-
epismo pack search --query "customer onboarding ideas" --search-mode semantic
|
|
884
|
-
epismo pack search --type workflow --personal --projects proj1
|
|
885
|
-
epismo pack search --type workflow --filter '{"visibility":["public"]}'
|
|
886
|
-
epismo pack search --type context --query "meeting notes"`);
|
|
887
|
-
pack.command("like")
|
|
888
|
-
.description("like or unlike an agent pack")
|
|
889
|
-
.argument("<reference>", "pack reference: id, alias, share URL, or hub URL")
|
|
890
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
891
|
-
.option("--liked", "mark as liked")
|
|
892
|
-
.option("--no-liked", "remove like")
|
|
893
|
-
.action(async (reference, options) => {
|
|
894
|
-
const payload = await resolveInput(options, {
|
|
895
|
-
liked: options.liked
|
|
896
|
-
});
|
|
897
|
-
if (typeof payload.liked !== "boolean") {
|
|
898
|
-
throw new CliError({
|
|
899
|
-
code: "INVALID_INPUT",
|
|
900
|
-
message: "Either --liked or --no-liked must be specified.",
|
|
901
|
-
hint: "Use --liked to add a like, or --no-liked to remove one."
|
|
902
|
-
});
|
|
903
|
-
}
|
|
904
|
-
const context = await resolveContext();
|
|
905
|
-
printJson(await likePack(context, reference, payload));
|
|
906
|
-
});
|
|
907
|
-
pack.commands.at(-1)?.addHelpText("after", `
|
|
908
|
-
Examples:
|
|
909
|
-
epismo pack like <id> --liked
|
|
910
|
-
epismo pack like @myproject --liked
|
|
911
|
-
epismo pack like <id> --no-liked`);
|
|
912
|
-
pack.command("rate")
|
|
913
|
-
.description("rate whether a pack worked when you used it")
|
|
914
|
-
.argument("<reference>", "pack reference: id, alias, share URL, or hub URL")
|
|
915
|
-
.addArgument(new Argument("<outcome>", "success | failure").choices(["success", "failure"]))
|
|
916
|
-
.action(async (reference, outcome) => {
|
|
917
|
-
const context = await resolveContext();
|
|
918
|
-
printJson(await ratePack(context, reference, { outcome }));
|
|
919
|
-
});
|
|
920
|
-
pack.commands.at(-1)?.addHelpText("after", `
|
|
921
|
-
Examples:
|
|
922
|
-
epismo pack rate <id> success
|
|
923
|
-
epismo pack rate @myproject failure`);
|
|
924
|
-
pack.command("delete")
|
|
925
|
-
.description("delete one agent pack and any of your aliases that point to it")
|
|
926
|
-
.argument("<reference>", "pack reference: id, alias, share URL, or hub URL")
|
|
927
|
-
.action(async (reference) => {
|
|
928
|
-
const context = await resolveContext();
|
|
929
|
-
printJson(await deletePack(context, reference));
|
|
930
|
-
});
|
|
931
|
-
pack.commands.at(-1)?.addHelpText("after", `
|
|
932
|
-
Examples:
|
|
933
|
-
epismo pack delete <id> # also removes your aliases for that pack
|
|
934
|
-
epismo pack delete @myproject
|
|
935
|
-
epismo pack delete https://epismo.ai/share/<token>`);
|
|
936
|
-
const suggestion = program.command("suggestion").description("manage improvement suggestions");
|
|
937
|
-
suggestion
|
|
938
|
-
.command("create")
|
|
939
|
-
.description("send an improvement suggestion for a pack")
|
|
940
|
-
.argument("<reference>", "pack reference: id, alias, share URL, or hub URL")
|
|
941
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
942
|
-
.option("--title <title>", "short summary")
|
|
943
|
-
.option("--content <content>", "suggestion content")
|
|
944
|
-
.action(async (reference, options) => {
|
|
945
|
-
const payload = await resolveInput(options, {
|
|
946
|
-
reference,
|
|
947
|
-
title: options.title,
|
|
948
|
-
content: options.content
|
|
949
|
-
});
|
|
950
|
-
const context = await resolveContext();
|
|
951
|
-
printJson(await createSuggestion(context, payload));
|
|
952
|
-
});
|
|
953
|
-
suggestion.commands.at(-1)?.addHelpText("after", `
|
|
954
|
-
Examples:
|
|
955
|
-
epismo suggestion create @market-research --title "Add review step" --content "A final human review step would reduce hallucinated findings."
|
|
956
|
-
epismo suggestion create <id> --input @suggestion.json`);
|
|
957
|
-
suggestion
|
|
958
|
-
.command("get")
|
|
959
|
-
.description("fetch one suggestion")
|
|
960
|
-
.argument("<id>", "suggestion id")
|
|
961
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
962
|
-
.option("--include-snapshot", "include the pack snapshot captured with the suggestion")
|
|
963
|
-
.action(async (id, options) => {
|
|
964
|
-
const payload = await resolveInput(options, {
|
|
965
|
-
includeSnapshot: options.includeSnapshot ? true : undefined
|
|
966
|
-
});
|
|
967
|
-
const context = await resolveContext();
|
|
968
|
-
printJson(await getSuggestion(context, id, payload));
|
|
969
|
-
});
|
|
970
|
-
suggestion.commands.at(-1)?.addHelpText("after", `
|
|
971
|
-
Examples:
|
|
972
|
-
epismo suggestion get <suggestion-id>
|
|
973
|
-
epismo suggestion get <suggestion-id> --include-snapshot`);
|
|
974
|
-
suggestion
|
|
975
|
-
.command("list")
|
|
976
|
-
.description("list suggestions")
|
|
977
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
978
|
-
.option("--reference <reference>", "filter by pack reference")
|
|
979
|
-
.option("--author <author>", "filter by author account id")
|
|
980
|
-
.option("--owner", "list suggestions for packs you own")
|
|
981
|
-
.option("--status <status>", "comma-separated statuses or JSON array")
|
|
982
|
-
.option("--page <page>", "1-based page number")
|
|
983
|
-
.option("--include-snapshots", "include captured snapshots")
|
|
984
|
-
.action(async (options, command) => {
|
|
985
|
-
const payload = await resolveInput(options, {
|
|
986
|
-
reference: getExplicitOptionOverride(command, "reference", options.reference),
|
|
987
|
-
author: getExplicitOptionOverride(command, "author", options.author),
|
|
988
|
-
owner: getExplicitOptionOverride(command, "owner", options.owner),
|
|
989
|
-
statuses: getExplicitOptionOverride(command, "status", parseStringArrayInput(options.status, "--status")),
|
|
990
|
-
page: getExplicitOptionOverride(command, "page", parseOptionalPositiveInteger(options.page, "--page")),
|
|
991
|
-
includeSnapshots: options.includeSnapshots ? true : undefined
|
|
992
|
-
});
|
|
993
|
-
const statuses = payload.statuses;
|
|
994
|
-
if (Array.isArray(statuses) &&
|
|
995
|
-
statuses.some((status) => !SUGGESTION_STATUSES.includes(status))) {
|
|
996
|
-
throw new CliError({
|
|
997
|
-
code: "INVALID_INPUT",
|
|
998
|
-
message: `Invalid --status: expected one of ${SUGGESTION_STATUSES.join(", ")}.`
|
|
999
|
-
});
|
|
1000
|
-
}
|
|
1001
|
-
const context = await resolveContext();
|
|
1002
|
-
printJson(await listSuggestions(context, payload));
|
|
1003
|
-
});
|
|
1004
|
-
suggestion.commands.at(-1)?.addHelpText("after", `
|
|
1005
|
-
Examples:
|
|
1006
|
-
epismo suggestion list --reference @market-research
|
|
1007
|
-
epismo suggestion list --owner --status open
|
|
1008
|
-
epismo suggestion list --status open,declined`);
|
|
1009
|
-
suggestion
|
|
1010
|
-
.command("resolve")
|
|
1011
|
-
.description("update a suggestion status")
|
|
1012
|
-
.argument("<id>", "suggestion id")
|
|
1013
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
1014
|
-
.addOption(new Option("--status <status>", "open | applied | declined | archived").choices(SUGGESTION_STATUSES))
|
|
1015
|
-
.action(async (id, options) => {
|
|
1016
|
-
const payload = await resolveInput(options, {
|
|
1017
|
-
status: options.status
|
|
1018
|
-
});
|
|
1019
|
-
if (!payload.status) {
|
|
1020
|
-
throw new CliError({
|
|
1021
|
-
code: "INVALID_INPUT",
|
|
1022
|
-
message: "--status is required."
|
|
1023
|
-
});
|
|
1024
|
-
}
|
|
1025
|
-
const context = await resolveContext();
|
|
1026
|
-
printJson(await resolveSuggestion(context, id, payload));
|
|
1027
|
-
});
|
|
1028
|
-
suggestion.commands.at(-1)?.addHelpText("after", `
|
|
1029
|
-
Examples:
|
|
1030
|
-
epismo suggestion resolve <suggestion-id> --status applied
|
|
1031
|
-
epismo suggestion resolve <suggestion-id> --status declined`);
|
|
1032
|
-
suggestion
|
|
1033
|
-
.command("update")
|
|
1034
|
-
.description("update a suggestion title or content")
|
|
1035
|
-
.argument("<id>", "suggestion id")
|
|
1036
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
1037
|
-
.option("--title <title>", "updated suggestion title")
|
|
1038
|
-
.option("--content <content>", "updated suggestion content")
|
|
1039
|
-
.action(async (id, options) => {
|
|
1040
|
-
const payload = await resolveInput(options, {
|
|
1041
|
-
title: options.title,
|
|
1042
|
-
content: options.content
|
|
1043
|
-
});
|
|
1044
|
-
if (!payload.title || !payload.content) {
|
|
1045
|
-
throw new CliError({
|
|
1046
|
-
code: "INVALID_INPUT",
|
|
1047
|
-
message: "--title and --content are required."
|
|
1048
|
-
});
|
|
1049
|
-
}
|
|
1050
|
-
const context = await resolveContext();
|
|
1051
|
-
printJson(await updateSuggestion(context, id, payload));
|
|
1052
|
-
});
|
|
1053
|
-
suggestion.commands.at(-1)?.addHelpText("after", `
|
|
1054
|
-
Examples:
|
|
1055
|
-
epismo suggestion update <suggestion-id> --title "Add review step" --content "Please add a reviewer approval step."`);
|
|
1056
|
-
const agent = program.command("agent").description("manage agent availability");
|
|
1057
|
-
agent
|
|
1058
|
-
.command("list")
|
|
1059
|
-
.description("list AI teammates and whether they appear in the assignee roster")
|
|
1060
|
-
.action(async () => {
|
|
1061
|
-
const context = await resolveContext();
|
|
1062
|
-
printJson(await listAgents(context));
|
|
1063
|
-
});
|
|
1064
|
-
agent.commands.at(-1)?.addHelpText("after", `
|
|
1065
|
-
Examples:
|
|
1066
|
-
epismo agent list`);
|
|
1067
|
-
agent
|
|
1068
|
-
.command("add")
|
|
1069
|
-
.description("add AI teammates to the assignee roster")
|
|
1070
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
1071
|
-
.option("--agent-ids <agentIds>", "JSON array or comma-separated agent ids")
|
|
1072
|
-
.action(async (options) => {
|
|
1073
|
-
const payload = await resolveInput(options, {
|
|
1074
|
-
agentIds: parseStringArrayInput(options.agentIds, "--agent-ids")
|
|
1075
|
-
});
|
|
1076
|
-
const context = await resolveContext();
|
|
1077
|
-
printJson(await addAgents(context, payload));
|
|
1078
|
-
});
|
|
1079
|
-
agent.commands.at(-1)?.addHelpText("after", `
|
|
1080
|
-
Examples:
|
|
1081
|
-
epismo agent add --agent-ids agent_a
|
|
1082
|
-
epismo agent add --agent-ids '["agent_a","agent_b"]'`);
|
|
1083
|
-
agent
|
|
1084
|
-
.command("remove")
|
|
1085
|
-
.description("remove AI teammates from the assignee roster")
|
|
1086
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
1087
|
-
.option("--agent-ids <agentIds>", "JSON array or comma-separated agent ids")
|
|
1088
|
-
.action(async (options) => {
|
|
1089
|
-
const payload = await resolveInput(options, {
|
|
1090
|
-
agentIds: parseStringArrayInput(options.agentIds, "--agent-ids")
|
|
1091
|
-
});
|
|
1092
|
-
const context = await resolveContext();
|
|
1093
|
-
printJson(await removeAgents(context, payload));
|
|
1094
|
-
});
|
|
1095
|
-
agent.commands.at(-1)?.addHelpText("after", `
|
|
1096
|
-
Examples:
|
|
1097
|
-
epismo agent remove --agent-ids agent_a
|
|
1098
|
-
epismo agent remove --agent-ids '["agent_a","agent_b"]'`);
|
|
1099
310
|
const credit = program.command("credit").description("view balance and purchase credits");
|
|
1100
311
|
credit
|
|
1101
312
|
.command("balance")
|
|
@@ -1122,73 +333,6 @@ Examples:
|
|
|
1122
333
|
credit.commands.at(-1)?.addHelpText("after", `
|
|
1123
334
|
Example:
|
|
1124
335
|
epismo credit checkout --quantity 500`);
|
|
1125
|
-
const alias = program.command("alias").description("manage pack aliases");
|
|
1126
|
-
alias
|
|
1127
|
-
.command("upsert")
|
|
1128
|
-
.description("create or update one alias")
|
|
1129
|
-
.argument("<alias>", "alias name (`alias` or `@alias`; stored without `@`)")
|
|
1130
|
-
.option("--input <input>", "JSON object, @file, or - for stdin")
|
|
1131
|
-
.option("--reference <reference>", "target pack reference: id, alias, share URL, or hub URL")
|
|
1132
|
-
.addOption(new Option("--namespace <namespace>", "personal (default) or workspace (shared with the active workspace)").choices(ALIAS_NAMESPACES))
|
|
1133
|
-
.action(async (aliasName, options) => {
|
|
1134
|
-
const payload = await resolveInput(options, {
|
|
1135
|
-
reference: options.reference,
|
|
1136
|
-
alias: aliasName,
|
|
1137
|
-
namespace: options.namespace
|
|
1138
|
-
});
|
|
1139
|
-
if (typeof payload.reference !== "string" || !payload.reference.trim()) {
|
|
1140
|
-
throw new CliError({
|
|
1141
|
-
code: "INVALID_INPUT",
|
|
1142
|
-
message: "`reference` is required.",
|
|
1143
|
-
hint: "Pass --reference <reference> or include reference in --input."
|
|
1144
|
-
});
|
|
1145
|
-
}
|
|
1146
|
-
const context = await resolveContext();
|
|
1147
|
-
printJson(await upsertAlias(context, payload));
|
|
1148
|
-
});
|
|
1149
|
-
alias.commands.at(-1)?.addHelpText("after", `
|
|
1150
|
-
Examples:
|
|
1151
|
-
epismo alias upsert @myproject --reference <pack-reference>
|
|
1152
|
-
epismo alias upsert @deploy --reference <pack-reference> --namespace workspace`);
|
|
1153
|
-
alias
|
|
1154
|
-
.command("get")
|
|
1155
|
-
.description("resolve one alias")
|
|
1156
|
-
.argument("<alias>", "alias reference (`@alias` or `@handle/alias`)")
|
|
1157
|
-
.addOption(new Option("--namespace <namespace>", "resolve a bare/`@alias` reference in personal or workspace (omit to try personal first, then workspace)").choices(ALIAS_NAMESPACES))
|
|
1158
|
-
.action(async (aliasRef, options) => {
|
|
1159
|
-
const context = await resolveContext();
|
|
1160
|
-
printJson(await getAlias(context, { alias: aliasRef, namespace: options.namespace }));
|
|
1161
|
-
});
|
|
1162
|
-
alias.commands.at(-1)?.addHelpText("after", `
|
|
1163
|
-
Examples:
|
|
1164
|
-
epismo alias get @myproject
|
|
1165
|
-
epismo alias get @deploy --namespace workspace
|
|
1166
|
-
epismo alias get @handle/myproject`);
|
|
1167
|
-
alias
|
|
1168
|
-
.command("list")
|
|
1169
|
-
.description("list your aliases")
|
|
1170
|
-
.addOption(new Option("--type <type>", "workflow | context").choices(PACK_TYPES))
|
|
1171
|
-
.action(async (options) => {
|
|
1172
|
-
const context = await resolveContext();
|
|
1173
|
-
printJson(await listAliases(context, { type: options.type }));
|
|
1174
|
-
});
|
|
1175
|
-
alias.commands.at(-1)?.addHelpText("after", `
|
|
1176
|
-
Example:
|
|
1177
|
-
epismo alias list
|
|
1178
|
-
epismo alias list --type workflow`);
|
|
1179
|
-
alias
|
|
1180
|
-
.command("delete")
|
|
1181
|
-
.description("delete one alias")
|
|
1182
|
-
.argument("<alias>", "alias name (`alias` or `@alias`; stored without `@`)")
|
|
1183
|
-
.addOption(new Option("--namespace <namespace>", "personal (default) or workspace (the active workspace's shared alias)").choices(ALIAS_NAMESPACES))
|
|
1184
|
-
.action(async (aliasName, options) => {
|
|
1185
|
-
const context = await resolveContext();
|
|
1186
|
-
printJson(await deleteAlias(context, { alias: aliasName, namespace: options.namespace }));
|
|
1187
|
-
});
|
|
1188
|
-
alias.commands.at(-1)?.addHelpText("after", `
|
|
1189
|
-
Examples:
|
|
1190
|
-
epismo alias delete @myproject
|
|
1191
|
-
epismo alias delete @deploy --namespace workspace`);
|
|
1192
336
|
const token = program.command("token").description("manage CLI tokens for CI/CD");
|
|
1193
337
|
token
|
|
1194
338
|
.command("create")
|
|
@@ -1209,6 +353,7 @@ Notes:
|
|
|
1209
353
|
Examples:
|
|
1210
354
|
epismo token create --workspace-id <workspace-id>
|
|
1211
355
|
epismo token create # uses saved default workspace, or personal space if none`);
|
|
356
|
+
registerPlaybookProgram(program, { resolveInput, resolveContext });
|
|
1212
357
|
return program;
|
|
1213
358
|
}
|
|
1214
359
|
//# sourceMappingURL=program.js.map
|