epismo 0.20.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -67
- package/dist/cases.js +25 -0
- package/dist/cases.js.map +1 -0
- package/dist/playbook-program.js +393 -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/README.md
CHANGED
|
@@ -1,104 +1,111 @@
|
|
|
1
1
|
# Epismo CLI
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
Hugging Face made AI models reusable.
|
|
5
|
-
Epismo makes AI work reusable.
|
|
6
|
-
|
|
7
|
-
Capture how you got your best results — not just the output — and share them as executable workflows that agents and humans can discover, adapt, and run across projects.
|
|
8
|
-
|
|
9
|
-
## CLI Contract
|
|
10
|
-
|
|
11
|
-
Epismo CLI is designed for agents first.
|
|
12
|
-
|
|
13
|
-
- Success output is machine-readable JSON on `stdout`, in both interactive and non-interactive runs.
|
|
14
|
-
- `stderr` carries prompts, browser-login guidance, warnings, and errors (all JSON-shaped).
|
|
15
|
-
- Exit code `0` means success; any non-zero code means failure.
|
|
16
|
-
- In non-interactive environments, commands that would need a prompt fail fast instead of waiting for input.
|
|
3
|
+
Agent-friendly CLI for Playbooks, Cases, Tasks, Records, Suggestions, Stars, and Aliases. Successful commands print JSON to stdout; warnings and failures are JSON-shaped on stderr.
|
|
17
4
|
|
|
18
5
|
## Install
|
|
19
6
|
|
|
20
7
|
Node.js 22.12 or newer is required.
|
|
21
8
|
|
|
22
9
|
```bash
|
|
23
|
-
npm install -g epismo
|
|
10
|
+
npm install -g epismo
|
|
11
|
+
# or
|
|
12
|
+
npx epismo <command>
|
|
24
13
|
```
|
|
25
14
|
|
|
26
|
-
## Authentication
|
|
15
|
+
## Authentication and workspace selection
|
|
27
16
|
|
|
28
17
|
```bash
|
|
29
|
-
epismo login
|
|
30
|
-
epismo login --email you@example.com
|
|
31
|
-
epismo
|
|
32
|
-
|
|
18
|
+
epismo login
|
|
19
|
+
epismo login --email you@example.com
|
|
20
|
+
epismo whoami
|
|
21
|
+
epismo logout
|
|
33
22
|
```
|
|
34
23
|
|
|
35
|
-
|
|
24
|
+
Commands use the workspace embedded in `EPISMO_TOKEN`, then the saved default from
|
|
25
|
+
`epismo workspace use`, then personal space. A workspace-scoped CI token can be issued
|
|
26
|
+
with `epismo token create --workspace-id <workspace-id>`.
|
|
36
27
|
|
|
37
28
|
## Commands
|
|
38
29
|
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
```text
|
|
31
|
+
epismo login | logout | whoami
|
|
41
32
|
|
|
42
|
-
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
| `track` | Create, update, search, and bulk-apply task/goal project tracks. |
|
|
49
|
-
| `log` | Append, list, and delete activity/comment logs on tracks. |
|
|
50
|
-
| `pack` | Create, update, fetch, search, like, rate, and delete packs. |
|
|
51
|
-
| `suggestion` | Send and triage improvement suggestions against packs. |
|
|
52
|
-
| `alias` | Manage pack aliases as a top-level resource. |
|
|
53
|
-
| `credit` | Check the credit balance and start credit checkout. |
|
|
54
|
-
| `token` | Issue workspace-scoped CLI tokens for CI/CD. |
|
|
33
|
+
epismo workspace list | current | use | clear | create | checkout | update
|
|
34
|
+
epismo workspace member list | upsert | delete
|
|
35
|
+
epismo project list | create | update
|
|
36
|
+
epismo project member list | add | delete
|
|
37
|
+
epismo credit balance | checkout
|
|
38
|
+
epismo token create
|
|
55
39
|
|
|
56
|
-
|
|
40
|
+
epismo playbook search | create | get | acl | archive | star | unstar | starred
|
|
41
|
+
epismo playbook version list | get | publish
|
|
42
|
+
epismo playbook share create
|
|
43
|
+
epismo alias set | list | delete
|
|
57
44
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
- **`log`** entries are immutable comments/activity notes attached to a track (`kind`: `comment`, `update`, `review`, or the reserved `system`). `log list <track-reference>` reads one track, newest first by default; pass a task/goal UUID or URL containing it. Omit `<track-reference>` for an ACL-scoped activity feed across every track you can access, optionally `--author-id`-filtered either way. `--order asc|desc` and `--cursor <logId>` (the previous response's `nextCursor`) control pagination. Appending a log is free; listing costs credits like other reads. Authors outside what the caller can see (e.g. someone who has since left) come back as `"unknown"`.
|
|
45
|
+
epismo case start | get | list | assign | acl | update | close | reopen
|
|
46
|
+
epismo task create | list | assign | update | close | reopen
|
|
47
|
+
epismo record append | list
|
|
62
48
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
Any command that takes a pack accepts a bare UUID, an alias (`@alias` or `@handle/alias`), a share URL, or a hub URL interchangeably.
|
|
66
|
-
|
|
67
|
-
### Track references
|
|
49
|
+
epismo suggestion create | get | list | update | resolve
|
|
50
|
+
```
|
|
68
51
|
|
|
69
|
-
|
|
52
|
+
The Playbook, Case, Task, Record, Suggestion, Star, and Alias operations are also
|
|
53
|
+
available through MCP. MCP names mirror the CLI resource/verb hierarchy in snake_case;
|
|
54
|
+
for example, `epismo_playbook_version_list` maps to `epismo playbook version list`.
|
|
70
55
|
|
|
71
|
-
|
|
56
|
+
Run `epismo <command> --help` for flags and positional arguments.
|
|
72
57
|
|
|
73
|
-
|
|
74
|
-
The matching CLI flags are `--personal`, `--projects <id...>`, and `--share-with <userIdOrEmail...>`.
|
|
75
|
-
Search uses the same selectors additively; omit them to use the default scope for the current context.
|
|
58
|
+
## Structured input
|
|
76
59
|
|
|
77
|
-
|
|
60
|
+
Commands that accept payloads support:
|
|
78
61
|
|
|
79
|
-
|
|
62
|
+
```bash
|
|
63
|
+
epismo playbook create --input @playbook.json
|
|
64
|
+
epismo record append <case-id> --input @record.json
|
|
65
|
+
epismo suggestion create --input - < suggestion.json
|
|
66
|
+
```
|
|
80
67
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
68
|
+
`--input` accepts an inline JSON object, `@file`, or `-` for stdin. Explicit flags
|
|
69
|
+
override fields from `--input`. Complex Playbook Definitions and close-time Record
|
|
70
|
+
arrays are best supplied through files.
|
|
84
71
|
|
|
85
|
-
|
|
72
|
+
`--input` always carries the whole request payload, so `epismo case start` takes the
|
|
73
|
+
Case's own input object through `--case-input` instead:
|
|
86
74
|
|
|
87
75
|
```bash
|
|
88
|
-
epismo
|
|
89
|
-
|
|
76
|
+
epismo case start --version-id <version-id> --acl <account-id> \
|
|
77
|
+
--case-input '{"companyName":"Acme"}'
|
|
90
78
|
```
|
|
91
79
|
|
|
92
|
-
|
|
80
|
+
Mutation commands accept `--idempotency-key <uuid>`. When omitted, the CLI generates
|
|
81
|
+
a UUID automatically. Reuse an explicit key when retrying a command whose first result
|
|
82
|
+
was uncertain; reusing one with different arguments is rejected.
|
|
83
|
+
|
|
84
|
+
Every mutation of an existing Case or Task requires `--lock-version`, taken from the
|
|
85
|
+
most recent object returned by the API: `case assign | acl | update | close | reopen`
|
|
86
|
+
and `task assign | update | close | reopen`. After a conflict, re-read the object and
|
|
87
|
+
decide again rather than resending with a bumped number. Updates are partial: Case
|
|
88
|
+
currently supports `title`, while Task supports `title` and `instructions`.
|
|
89
|
+
|
|
90
|
+
`epismo record list` is a cross-Case activity feed constrained by current Case ACLs.
|
|
91
|
+
Use `--case-id`, `--task-id`, `--created-by`, `--kinds`, `--origins`, or `--acl` to
|
|
92
|
+
narrow it; these filters never grant access. Results default to newest first, and
|
|
93
|
+
`--order asc` walks a timeline forward.
|
|
94
|
+
|
|
95
|
+
## Playbook references
|
|
93
96
|
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
The CLI's REST commands currently use UUIDs for Playbook path arguments. Aliases are
|
|
98
|
+
managed with `epismo alias`; MCP exposes the same alias set/list/delete operations and
|
|
99
|
+
also accepts `pb:alias` and `pb:handle/alias` in `epismo_playbook_get`.
|
|
100
|
+
|
|
101
|
+
## Output contract
|
|
102
|
+
|
|
103
|
+
- Success: JSON on stdout and exit code `0`.
|
|
104
|
+
- Failure: JSON on stderr and a non-zero exit code.
|
|
105
|
+
- Non-interactive commands fail instead of waiting for an unavailable prompt.
|
|
96
106
|
|
|
97
107
|
```json
|
|
98
|
-
{ "error": { "code": "NOT_FOUND", "message": "...", "retryable": false
|
|
108
|
+
{ "error": { "code": "NOT_FOUND", "message": "...", "retryable": false } }
|
|
99
109
|
```
|
|
100
110
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
Update checks run once per day in interactive sessions.
|
|
104
|
-
Set `EPISMO_UPDATE_CHECK=0` to disable the background npm version check.
|
|
111
|
+
Set `EPISMO_UPDATE_CHECK=0` to disable the daily interactive npm update check.
|
package/dist/cases.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { requestJson, withWorkspaceQuery } from "./api.js";
|
|
2
|
+
import { resolveApiUrl } from "./config.js";
|
|
3
|
+
import { toObjectInput } from "./input.js";
|
|
4
|
+
import { withIdempotency, withQuery } from "./playbooks.js";
|
|
5
|
+
const part = (value) => encodeURIComponent(value);
|
|
6
|
+
async function call(context, pathname, method = "GET", body) {
|
|
7
|
+
return requestJson(resolveApiUrl(), withWorkspaceQuery(pathname, context.workspaceId), { method, authToken: context.auth.accessToken, ...(body === undefined ? {} : { body }) });
|
|
8
|
+
}
|
|
9
|
+
export const caseApi = {
|
|
10
|
+
start: (c, input) => call(c, "/v1/cases", "POST", withIdempotency(input)),
|
|
11
|
+
get: (c, id) => call(c, `/v1/cases/${part(id)}`),
|
|
12
|
+
list: (c, input) => call(c, withQuery("/v1/cases", input)),
|
|
13
|
+
assign: (c, id, input) => call(c, `/v1/cases/${part(id)}/assignee`, "PATCH", withIdempotency(input)),
|
|
14
|
+
updateAcl: (c, id, input) => call(c, `/v1/cases/${part(id)}/acl`, "PATCH", withIdempotency(input)),
|
|
15
|
+
update: (c, id, input) => call(c, `/v1/cases/${part(id)}`, "PATCH", withIdempotency(input)),
|
|
16
|
+
createTask: (c, id, input) => call(c, "/v1/tasks", "POST", withIdempotency({ ...toObjectInput(input), caseId: id })),
|
|
17
|
+
listTasks: (c, input) => call(c, withQuery("/v1/tasks", input)),
|
|
18
|
+
assignTask: (c, taskId, input) => call(c, `/v1/tasks/${part(taskId)}/assignee`, "PATCH", withIdempotency(input)),
|
|
19
|
+
closeTask: (c, taskId, input) => call(c, `/v1/tasks/${part(taskId)}/close`, "POST", withIdempotency(input)),
|
|
20
|
+
reopenTask: (c, taskId, input) => call(c, `/v1/tasks/${part(taskId)}/reopen`, "POST", withIdempotency(input)),
|
|
21
|
+
updateTask: (c, taskId, input) => call(c, `/v1/tasks/${part(taskId)}`, "PATCH", withIdempotency(input)),
|
|
22
|
+
close: (c, id, input) => call(c, `/v1/cases/${part(id)}/close`, "POST", withIdempotency(input)),
|
|
23
|
+
reopen: (c, id, input) => call(c, `/v1/cases/${part(id)}/reopen`, "POST", withIdempotency(input))
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=cases.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cases.js","sourceRoot":"","sources":["../src/cases.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import { Option } from "commander";
|
|
2
|
+
import { parseJsonArrayOption, parseJsonObjectOption, parseStringArrayInput } from "./input.js";
|
|
3
|
+
import { printJson } from "./output.js";
|
|
4
|
+
import { playbookApi } from "./playbooks.js";
|
|
5
|
+
import { caseApi } from "./cases.js";
|
|
6
|
+
import { suggestionApi } from "./suggestions.js";
|
|
7
|
+
import { recordApi } from "./records.js";
|
|
8
|
+
const number = (value) => Number(value);
|
|
9
|
+
function input(command) {
|
|
10
|
+
return command.option("--input <input>", "JSON object, @file, or - for stdin");
|
|
11
|
+
}
|
|
12
|
+
function paging(command) {
|
|
13
|
+
return command
|
|
14
|
+
.option("--page-size <number>", "results per page (1-100)", number)
|
|
15
|
+
.option("--cursor <cursor>", "cursor returned by the previous page");
|
|
16
|
+
}
|
|
17
|
+
function mutation(command) {
|
|
18
|
+
return input(command).option("--idempotency-key <uuid>", "retry key; generated automatically when omitted");
|
|
19
|
+
}
|
|
20
|
+
async function execute(deps, options, overrides, action) {
|
|
21
|
+
const payload = await deps.resolveInput(options, overrides);
|
|
22
|
+
printJson(await action(await deps.resolveContext(), payload));
|
|
23
|
+
}
|
|
24
|
+
function commonPage(options) {
|
|
25
|
+
return { pageSize: options.pageSize, cursor: options.cursor };
|
|
26
|
+
}
|
|
27
|
+
export function registerPlaybookProgram(program, deps) {
|
|
28
|
+
const playbook = program.command("playbook").description("manage reusable Playbooks");
|
|
29
|
+
paging(input(playbook.command("search").description("search readable Playbooks")))
|
|
30
|
+
.option("--query <text>", "full-text query")
|
|
31
|
+
.addOption(new Option("--category <category>").choices([
|
|
32
|
+
"productivity",
|
|
33
|
+
"programming",
|
|
34
|
+
"design",
|
|
35
|
+
"sales",
|
|
36
|
+
"marketing",
|
|
37
|
+
"operations",
|
|
38
|
+
"learning"
|
|
39
|
+
]))
|
|
40
|
+
.option("--filter-expression <expression>", "search projection filter")
|
|
41
|
+
.option("--aggregations <json>", "JSON array of aggregation options")
|
|
42
|
+
.action(async (options) => execute(deps, options, {
|
|
43
|
+
query: options.query,
|
|
44
|
+
category: options.category,
|
|
45
|
+
...commonPage(options),
|
|
46
|
+
filterExpression: options.filterExpression,
|
|
47
|
+
aggregationOptions: parseJsonArrayOption(options.aggregations, "--aggregations")
|
|
48
|
+
}, playbookApi.search));
|
|
49
|
+
mutation(playbook.command("create").description("create a Playbook and its first Version"))
|
|
50
|
+
.option("--owner-id <uuid>", "owner Account ID")
|
|
51
|
+
.option("--acl <principals>", "comma-separated ACL principals")
|
|
52
|
+
.option("--definition <json>", "Playbook Definition JSON object")
|
|
53
|
+
.action(async (options) => execute(deps, options, {
|
|
54
|
+
ownerId: options.ownerId,
|
|
55
|
+
acl: parseStringArrayInput(options.acl, "--acl"),
|
|
56
|
+
definition: parseJsonObjectOption(options.definition, "--definition"),
|
|
57
|
+
idempotencyKey: options.idempotencyKey
|
|
58
|
+
}, playbookApi.create));
|
|
59
|
+
playbook
|
|
60
|
+
.command("get")
|
|
61
|
+
.description("get a Playbook and its latest immutable Version")
|
|
62
|
+
.argument("<playbook-id>")
|
|
63
|
+
.action(async (id) => printJson(await playbookApi.get(await deps.resolveContext(), id)));
|
|
64
|
+
const version = playbook.command("version").description("read and publish immutable Versions");
|
|
65
|
+
paging(version.command("list").argument("<playbook-id>").description("list Versions")).action(async (id, options) => execute(deps, options, commonPage(options), (context, payload) => playbookApi.listVersions(context, id, payload)));
|
|
66
|
+
version
|
|
67
|
+
.command("get")
|
|
68
|
+
.argument("<playbook-id>")
|
|
69
|
+
.argument("<version-id>")
|
|
70
|
+
.description("get one immutable Version")
|
|
71
|
+
.action(async (playbookId, versionId) => printJson(await playbookApi.getVersion(await deps.resolveContext(), playbookId, versionId)));
|
|
72
|
+
mutation(version.command("publish").argument("<playbook-id>").description("publish a Version"))
|
|
73
|
+
.option("--base-version-id <uuid>", "current latest Version ID")
|
|
74
|
+
.option("--definition <json>", "new Playbook Definition JSON object")
|
|
75
|
+
.action(async (id, options) => execute(deps, options, {
|
|
76
|
+
baseVersionId: options.baseVersionId,
|
|
77
|
+
definition: parseJsonObjectOption(options.definition, "--definition"),
|
|
78
|
+
idempotencyKey: options.idempotencyKey
|
|
79
|
+
}, (context, payload) => playbookApi.publish(context, id, payload)));
|
|
80
|
+
mutation(playbook.command("acl").argument("<playbook-id>").description("replace the ACL"))
|
|
81
|
+
.requiredOption("--acl <principals>", "comma-separated ACL principals")
|
|
82
|
+
.action(async (id, options) => execute(deps, options, {
|
|
83
|
+
acl: parseStringArrayInput(options.acl, "--acl"),
|
|
84
|
+
idempotencyKey: options.idempotencyKey
|
|
85
|
+
}, (context, payload) => playbookApi.updateAcl(context, id, payload)));
|
|
86
|
+
for (const [name, description, action] of [
|
|
87
|
+
["archive", "archive a Playbook", playbookApi.archive],
|
|
88
|
+
["star", "star a Playbook", playbookApi.star],
|
|
89
|
+
["unstar", "remove a Playbook star", playbookApi.unstar]
|
|
90
|
+
]) {
|
|
91
|
+
mutation(playbook.command(name).argument("<playbook-id>").description(description)).action(async (id, options) => execute(deps, options, { idempotencyKey: options.idempotencyKey }, (context, payload) => action(context, id, payload)));
|
|
92
|
+
}
|
|
93
|
+
paging(playbook.command("starred").description("list your starred Playbooks")).action(async (options) => execute(deps, options, commonPage(options), playbookApi.listStarred));
|
|
94
|
+
const share = playbook.command("share").description("create short share URLs");
|
|
95
|
+
mutation(share.command("create").argument("<playbook-id>").description("create a share token"))
|
|
96
|
+
.option("--expires-at <timestamp>", "optional ISO-8601 expiration")
|
|
97
|
+
.action(async (id, options) => execute(deps, options, { expiresAt: options.expiresAt, idempotencyKey: options.idempotencyKey }, (context, payload) => playbookApi.createShare(context, id, payload)));
|
|
98
|
+
registerAliasProgram(program, deps);
|
|
99
|
+
registerCaseProgram(program, deps);
|
|
100
|
+
registerTaskProgram(program, deps);
|
|
101
|
+
registerRecordProgram(program, deps);
|
|
102
|
+
registerSuggestionProgram(program, deps);
|
|
103
|
+
}
|
|
104
|
+
function registerAliasProgram(program, deps) {
|
|
105
|
+
const alias = program.command("alias").description("manage Playbook aliases");
|
|
106
|
+
mutation(alias
|
|
107
|
+
.command("set")
|
|
108
|
+
.argument("<alias>")
|
|
109
|
+
.argument("<playbook-id>")
|
|
110
|
+
.description("point an alias at a Playbook, replacing any existing target"))
|
|
111
|
+
.requiredOption("--owner-id <uuid>", "alias namespace owner Account ID")
|
|
112
|
+
.action(async (name, playbookId, options) => execute(deps, options, {
|
|
113
|
+
ownerId: options.ownerId,
|
|
114
|
+
alias: name,
|
|
115
|
+
playbookId,
|
|
116
|
+
idempotencyKey: options.idempotencyKey
|
|
117
|
+
}, playbookApi.setAlias));
|
|
118
|
+
paging(input(alias.command("list").description("list aliases by namespace or Playbook")))
|
|
119
|
+
.option("--owner-id <uuid>", "alias namespace owner Account ID")
|
|
120
|
+
.option("--playbook-id <uuid>", "only aliases pointing at this Playbook")
|
|
121
|
+
.action(async (options) => execute(deps, options, {
|
|
122
|
+
ownerId: options.ownerId,
|
|
123
|
+
playbookId: options.playbookId,
|
|
124
|
+
...commonPage(options)
|
|
125
|
+
}, playbookApi.listAliases));
|
|
126
|
+
mutation(alias
|
|
127
|
+
.command("delete")
|
|
128
|
+
.argument("<alias>")
|
|
129
|
+
.description("delete an alias without touching the Playbook it pointed at"))
|
|
130
|
+
.requiredOption("--owner-id <uuid>", "alias namespace owner Account ID")
|
|
131
|
+
.action(async (name, options) => execute(deps, options, { ownerId: options.ownerId, idempotencyKey: options.idempotencyKey }, (context, payload) => playbookApi.deleteAlias(context, name, payload)));
|
|
132
|
+
}
|
|
133
|
+
function registerCaseProgram(program, deps) {
|
|
134
|
+
const cases = program.command("case").description("start, assign, and close Cases");
|
|
135
|
+
mutation(cases.command("start").description("start a Playbook or ad-hoc Case"))
|
|
136
|
+
.option("--version-id <uuid>")
|
|
137
|
+
.option("--title <title>")
|
|
138
|
+
.option("--case-input <json>", "Case input JSON object")
|
|
139
|
+
.option("--acl <principals>", "comma-separated ACL principals")
|
|
140
|
+
.action(async (options) => execute(deps, options, {
|
|
141
|
+
versionId: options.versionId,
|
|
142
|
+
title: options.title,
|
|
143
|
+
input: parseJsonObjectOption(options.caseInput, "--case-input"),
|
|
144
|
+
acl: parseStringArrayInput(options.acl, "--acl"),
|
|
145
|
+
idempotencyKey: options.idempotencyKey
|
|
146
|
+
}, caseApi.start));
|
|
147
|
+
cases
|
|
148
|
+
.command("get")
|
|
149
|
+
.argument("<case-id>")
|
|
150
|
+
.description("get a Case with its status, ACL, and lock version")
|
|
151
|
+
.action(async (id) => printJson(await caseApi.get(await deps.resolveContext(), id)));
|
|
152
|
+
paging(input(cases.command("list").description("list readable Cases")))
|
|
153
|
+
.option("--assigned-to <uuid>", "only Cases assigned to this account")
|
|
154
|
+
.addOption(new Option("--status <status>").choices(["open", "closed"]))
|
|
155
|
+
.action(async (options) => execute(deps, options, { assignedTo: options.assignedTo, status: options.status, ...commonPage(options) }, caseApi.list));
|
|
156
|
+
mutation(cases
|
|
157
|
+
.command("assign")
|
|
158
|
+
.argument("<case-id>")
|
|
159
|
+
.description("hand overall responsibility for a Case to a user the ACL already covers"))
|
|
160
|
+
.requiredOption("--assigned-to <uuid>", "account to make responsible for the Case")
|
|
161
|
+
.requiredOption("--lock-version <number>", "expected lock version", number)
|
|
162
|
+
.action(async (id, options) => execute(deps, options, {
|
|
163
|
+
assignedTo: options.assignedTo,
|
|
164
|
+
expectedLockVersion: options.lockVersion,
|
|
165
|
+
idempotencyKey: options.idempotencyKey
|
|
166
|
+
}, (context, payload) => caseApi.assign(context, id, payload)));
|
|
167
|
+
mutation(cases
|
|
168
|
+
.command("acl")
|
|
169
|
+
.argument("<case-id>")
|
|
170
|
+
.description("replace a Case ACL; it must still cover every current assignee"))
|
|
171
|
+
.requiredOption("--acl <principals>", "comma-separated ACL principals")
|
|
172
|
+
.requiredOption("--lock-version <number>", "expected lock version", number)
|
|
173
|
+
.action(async (id, options) => execute(deps, options, {
|
|
174
|
+
acl: parseStringArrayInput(options.acl, "--acl"),
|
|
175
|
+
expectedLockVersion: options.lockVersion,
|
|
176
|
+
idempotencyKey: options.idempotencyKey
|
|
177
|
+
}, (context, payload) => caseApi.updateAcl(context, id, payload)));
|
|
178
|
+
mutation(cases.command("update").argument("<case-id>").description("update editable Case fields"))
|
|
179
|
+
.option("--title <title>")
|
|
180
|
+
.requiredOption("--lock-version <number>", "expected lock version", number)
|
|
181
|
+
.action(async (id, options) => execute(deps, options, {
|
|
182
|
+
title: options.title,
|
|
183
|
+
expectedLockVersion: options.lockVersion,
|
|
184
|
+
idempotencyKey: options.idempotencyKey
|
|
185
|
+
}, (context, payload) => caseApi.update(context, id, payload)));
|
|
186
|
+
mutation(cases
|
|
187
|
+
.command("close")
|
|
188
|
+
.argument("<case-id>")
|
|
189
|
+
.description("close a Case; completed requires no open Tasks, cancelled and abandoned close the rest"))
|
|
190
|
+
.addOption(new Option("--outcome <outcome>").choices(["completed", "cancelled", "abandoned"]))
|
|
191
|
+
.requiredOption("--lock-version <number>", "expected lock version", number)
|
|
192
|
+
.option("--records <json>", "JSON array of final Records")
|
|
193
|
+
.action(async (id, options) => execute(deps, options, {
|
|
194
|
+
outcome: options.outcome,
|
|
195
|
+
expectedLockVersion: options.lockVersion,
|
|
196
|
+
records: parseJsonArrayOption(options.records, "--records"),
|
|
197
|
+
idempotencyKey: options.idempotencyKey
|
|
198
|
+
}, (context, payload) => caseApi.close(context, id, payload)));
|
|
199
|
+
mutation(cases
|
|
200
|
+
.command("reopen")
|
|
201
|
+
.argument("<case-id>")
|
|
202
|
+
.description("reopen a closed Case; its Tasks stay closed until reopened separately"))
|
|
203
|
+
.requiredOption("--lock-version <number>", "expected lock version", number)
|
|
204
|
+
.action(async (id, options) => execute(deps, options, {
|
|
205
|
+
expectedLockVersion: options.lockVersion,
|
|
206
|
+
idempotencyKey: options.idempotencyKey
|
|
207
|
+
}, (context, payload) => caseApi.reopen(context, id, payload)));
|
|
208
|
+
}
|
|
209
|
+
function registerRecordProgram(program, deps) {
|
|
210
|
+
const record = program
|
|
211
|
+
.command("record")
|
|
212
|
+
.description("append Records and browse the ACL-scoped activity feed");
|
|
213
|
+
mutation(record
|
|
214
|
+
.command("append")
|
|
215
|
+
.argument("<case-id>")
|
|
216
|
+
.description("append an immutable Record to an open Case"))
|
|
217
|
+
.option("--task-id <uuid>", "Task this Record belongs to")
|
|
218
|
+
.option("--source-step-id <id>", "four-character Step ID from the Case's pinned Version")
|
|
219
|
+
.option("--kind <kind>", "application-defined Record kind, 1-64 characters")
|
|
220
|
+
.option("--content <text>")
|
|
221
|
+
.option("--data <json>", "Record data JSON object")
|
|
222
|
+
.addOption(new Option("--origin <origin>").choices(["user", "agent"]))
|
|
223
|
+
.option("--client-name <name>")
|
|
224
|
+
.option("--client-version <version>")
|
|
225
|
+
.action(async (id, options) => execute(deps, options, {
|
|
226
|
+
taskId: options.taskId,
|
|
227
|
+
sourceStepId: options.sourceStepId,
|
|
228
|
+
kind: options.kind,
|
|
229
|
+
content: options.content,
|
|
230
|
+
data: parseJsonObjectOption(options.data, "--data"),
|
|
231
|
+
origin: options.origin,
|
|
232
|
+
clientName: options.clientName,
|
|
233
|
+
clientVersion: options.clientVersion,
|
|
234
|
+
idempotencyKey: options.idempotencyKey
|
|
235
|
+
}, (context, payload) => recordApi.append(context, id, payload)));
|
|
236
|
+
paging(input(record
|
|
237
|
+
.command("list")
|
|
238
|
+
.description("browse Records across every readable Case, newest first by default")))
|
|
239
|
+
.option("--case-id <uuid>")
|
|
240
|
+
.option("--task-id <uuid>")
|
|
241
|
+
.option("--created-by <uuid>")
|
|
242
|
+
.option("--kinds <kinds>", "comma-separated Record kinds")
|
|
243
|
+
.option("--origins <origins>", "comma-separated user,agent,system")
|
|
244
|
+
.option("--acl <principals>", "narrow to Cases overlapping these ACL principals")
|
|
245
|
+
.addOption(new Option("--order <order>").choices(["asc", "desc"]).default("desc"))
|
|
246
|
+
.action(async (options) => execute(deps, options, {
|
|
247
|
+
caseId: options.caseId,
|
|
248
|
+
taskId: options.taskId,
|
|
249
|
+
createdBy: options.createdBy,
|
|
250
|
+
kinds: parseStringArrayInput(options.kinds, "--kinds"),
|
|
251
|
+
origins: parseStringArrayInput(options.origins, "--origins"),
|
|
252
|
+
acl: parseStringArrayInput(options.acl, "--acl"),
|
|
253
|
+
order: options.order,
|
|
254
|
+
...commonPage(options)
|
|
255
|
+
}, recordApi.list));
|
|
256
|
+
}
|
|
257
|
+
function registerTaskProgram(program, deps) {
|
|
258
|
+
const task = program.command("task").description("manage materialized Case Tasks");
|
|
259
|
+
mutation(task
|
|
260
|
+
.command("create")
|
|
261
|
+
.argument("<case-id>")
|
|
262
|
+
.description("create a work or review Task when the work needs its own owner"))
|
|
263
|
+
.addOption(new Option("--kind <kind>").choices(["work", "review"]))
|
|
264
|
+
.option("--title <title>")
|
|
265
|
+
.option("--instructions <text>")
|
|
266
|
+
.option("--source-step-id <id>", "four-character Step ID from the Case's pinned Version")
|
|
267
|
+
.option("--assigned-to <uuid>", "assignee the Case ACL already covers; required for review")
|
|
268
|
+
.option("--subject-record-id <uuid>", "Record under review; review Tasks only")
|
|
269
|
+
.action(async (id, options) => execute(deps, options, {
|
|
270
|
+
kind: options.kind,
|
|
271
|
+
title: options.title,
|
|
272
|
+
instructions: options.instructions,
|
|
273
|
+
sourceStepId: options.sourceStepId,
|
|
274
|
+
assignedTo: options.assignedTo,
|
|
275
|
+
subjectRecordId: options.subjectRecordId,
|
|
276
|
+
idempotencyKey: options.idempotencyKey
|
|
277
|
+
}, (context, payload) => caseApi.createTask(context, id, payload)));
|
|
278
|
+
paging(input(task
|
|
279
|
+
.command("list")
|
|
280
|
+
.description("list Tasks in a Case, or your Tasks across Cases with --assigned-to")))
|
|
281
|
+
.option("--case-id <uuid>")
|
|
282
|
+
.option("--assigned-to <uuid>", "required when --case-id is omitted")
|
|
283
|
+
.addOption(new Option("--status <status>").choices(["open", "closed"]))
|
|
284
|
+
.action(async (options) => execute(deps, options, {
|
|
285
|
+
caseId: options.caseId,
|
|
286
|
+
assignedTo: options.assignedTo,
|
|
287
|
+
status: options.status,
|
|
288
|
+
...commonPage(options)
|
|
289
|
+
}, caseApi.listTasks));
|
|
290
|
+
mutation(task
|
|
291
|
+
.command("assign")
|
|
292
|
+
.argument("<task-id>")
|
|
293
|
+
.description("assign a Task to a user the Case ACL already covers"))
|
|
294
|
+
.option("--assigned-to <uuid>", "omit in --input to clear assignment")
|
|
295
|
+
.requiredOption("--lock-version <number>", "expected lock version", number)
|
|
296
|
+
.action(async (taskId, options) => execute(deps, options, {
|
|
297
|
+
assignedTo: options.assignedTo,
|
|
298
|
+
expectedLockVersion: options.lockVersion,
|
|
299
|
+
idempotencyKey: options.idempotencyKey
|
|
300
|
+
}, (context, payload) => caseApi.assignTask(context, taskId, payload)));
|
|
301
|
+
mutation(task
|
|
302
|
+
.command("update")
|
|
303
|
+
.argument("<task-id>")
|
|
304
|
+
.description("update editable Task fields while the Task and Case are open"))
|
|
305
|
+
.option("--title <title>")
|
|
306
|
+
.option("--instructions <text>")
|
|
307
|
+
.requiredOption("--lock-version <number>", "expected lock version", number)
|
|
308
|
+
.action(async (taskId, options) => execute(deps, options, {
|
|
309
|
+
title: options.title,
|
|
310
|
+
instructions: options.instructions,
|
|
311
|
+
expectedLockVersion: options.lockVersion,
|
|
312
|
+
idempotencyKey: options.idempotencyKey
|
|
313
|
+
}, (context, payload) => caseApi.updateTask(context, taskId, payload)));
|
|
314
|
+
mutation(task
|
|
315
|
+
.command("close")
|
|
316
|
+
.argument("<task-id>")
|
|
317
|
+
.description("close a Task with an outcome, optionally appending its final Records"))
|
|
318
|
+
.requiredOption("--outcome <outcome>", "free-text result of the Task")
|
|
319
|
+
.requiredOption("--lock-version <number>", "expected lock version", number)
|
|
320
|
+
.option("--records <json>", "JSON array of final Records")
|
|
321
|
+
.action(async (taskId, options) => execute(deps, options, {
|
|
322
|
+
outcome: options.outcome,
|
|
323
|
+
expectedLockVersion: options.lockVersion,
|
|
324
|
+
records: parseJsonArrayOption(options.records, "--records"),
|
|
325
|
+
idempotencyKey: options.idempotencyKey
|
|
326
|
+
}, (context, payload) => caseApi.closeTask(context, taskId, payload)));
|
|
327
|
+
mutation(task
|
|
328
|
+
.command("reopen")
|
|
329
|
+
.argument("<task-id>")
|
|
330
|
+
.description("reopen a closed Task while its parent Case is still open"))
|
|
331
|
+
.requiredOption("--lock-version <number>", "expected lock version", number)
|
|
332
|
+
.action(async (taskId, options) => execute(deps, options, {
|
|
333
|
+
expectedLockVersion: options.lockVersion,
|
|
334
|
+
idempotencyKey: options.idempotencyKey
|
|
335
|
+
}, (context, payload) => caseApi.reopenTask(context, taskId, payload)));
|
|
336
|
+
}
|
|
337
|
+
function registerSuggestionProgram(program, deps) {
|
|
338
|
+
const suggestion = program.command("suggestion").description("manage Playbook Suggestions");
|
|
339
|
+
mutation(suggestion
|
|
340
|
+
.command("create")
|
|
341
|
+
.description("propose a change against an immutable base Version"))
|
|
342
|
+
.option("--playbook-id <uuid>")
|
|
343
|
+
.option("--base-version-id <uuid>", "Version the proposal was written against")
|
|
344
|
+
.option("--target-step-id <id>", "four-character Step ID within the base Version")
|
|
345
|
+
.option("--title <title>")
|
|
346
|
+
.option("--content <text>")
|
|
347
|
+
.action(async (options) => execute(deps, options, {
|
|
348
|
+
playbookId: options.playbookId,
|
|
349
|
+
baseVersionId: options.baseVersionId,
|
|
350
|
+
targetStepId: options.targetStepId,
|
|
351
|
+
title: options.title,
|
|
352
|
+
content: options.content,
|
|
353
|
+
idempotencyKey: options.idempotencyKey
|
|
354
|
+
}, suggestionApi.create));
|
|
355
|
+
suggestion
|
|
356
|
+
.command("get")
|
|
357
|
+
.argument("<suggestion-id>")
|
|
358
|
+
.description("get a Suggestion and its resolution state")
|
|
359
|
+
.action(async (id) => printJson(await suggestionApi.get(await deps.resolveContext(), id)));
|
|
360
|
+
paging(input(suggestion.command("list").description("list readable Suggestions")))
|
|
361
|
+
.option("--playbook-id <uuid>")
|
|
362
|
+
.option("--author-id <uuid>")
|
|
363
|
+
.option("--statuses <statuses>", "comma-separated open,applied,declined,archived")
|
|
364
|
+
.action(async (options) => execute(deps, options, {
|
|
365
|
+
playbookId: options.playbookId,
|
|
366
|
+
authorId: options.authorId,
|
|
367
|
+
statuses: parseStringArrayInput(options.statuses, "--statuses"),
|
|
368
|
+
...commonPage(options)
|
|
369
|
+
}, suggestionApi.list));
|
|
370
|
+
mutation(suggestion
|
|
371
|
+
.command("update")
|
|
372
|
+
.argument("<suggestion-id>")
|
|
373
|
+
.description("edit your own open Suggestion"))
|
|
374
|
+
.option("--title <title>")
|
|
375
|
+
.option("--content <text>")
|
|
376
|
+
.action(async (id, options) => execute(deps, options, {
|
|
377
|
+
title: options.title,
|
|
378
|
+
content: options.content,
|
|
379
|
+
idempotencyKey: options.idempotencyKey
|
|
380
|
+
}, (context, payload) => suggestionApi.update(context, id, payload)));
|
|
381
|
+
mutation(suggestion
|
|
382
|
+
.command("resolve")
|
|
383
|
+
.argument("<suggestion-id>")
|
|
384
|
+
.description("apply, decline, archive, or reopen a Suggestion"))
|
|
385
|
+
.addOption(new Option("--status <status>").choices(["open", "applied", "declined", "archived"]))
|
|
386
|
+
.option("--result-version-id <uuid>", "Version published from it; required for applied")
|
|
387
|
+
.action(async (id, options) => execute(deps, options, {
|
|
388
|
+
status: options.status,
|
|
389
|
+
resultVersionId: options.resultVersionId,
|
|
390
|
+
idempotencyKey: options.idempotencyKey
|
|
391
|
+
}, (context, payload) => suggestionApi.resolve(context, id, payload)));
|
|
392
|
+
}
|
|
393
|
+
//# sourceMappingURL=playbook-program.js.map
|