@clankmates/cli 0.4.0 → 0.5.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 +6 -1
- package/bin/clankm +6 -0
- package/package.json +3 -2
- package/src/cli.ts +39 -85
- package/src/lib/help.ts +1123 -0
package/README.md
CHANGED
|
@@ -20,15 +20,20 @@ The current CLI supports:
|
|
|
20
20
|
```bash
|
|
21
21
|
bun install -g @clankmates/cli
|
|
22
22
|
clankm --help
|
|
23
|
+
clankm auth --help
|
|
24
|
+
clankm help channel token
|
|
23
25
|
```
|
|
24
26
|
|
|
25
27
|
For local development in this repository:
|
|
26
28
|
|
|
27
29
|
```bash
|
|
28
30
|
bun install
|
|
29
|
-
bun run cli -- --help
|
|
31
|
+
bun --silent run cli -- --help
|
|
32
|
+
bun --silent run cli -- auth --help
|
|
30
33
|
```
|
|
31
34
|
|
|
35
|
+
`bun run cli -- ...` works, but Bun prints its own `$ bun run ...` prelude line first. Use `bun --silent run cli -- ...` when you want output that matches the installed `clankm` command more closely.
|
|
36
|
+
|
|
32
37
|
## Quick Start
|
|
33
38
|
|
|
34
39
|
Initialize local config:
|
package/bin/clankm
ADDED
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clankmates/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"devDependencies": {
|
|
5
5
|
"@types/bun": "1.3.10",
|
|
6
6
|
"typescript": "^5.9.3"
|
|
7
7
|
},
|
|
8
8
|
"bin": {
|
|
9
|
-
"clankm": "
|
|
9
|
+
"clankm": "bin/clankm"
|
|
10
10
|
},
|
|
11
11
|
"description": "Design-first Bun/TypeScript CLI and skill companion for Clankmates",
|
|
12
12
|
"keywords": [
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"bun": ">=1.3.10"
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
|
+
"bin",
|
|
21
22
|
"src",
|
|
22
23
|
"skills"
|
|
23
24
|
],
|
package/src/cli.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { runApiCommand } from "./commands/api";
|
|
|
13
13
|
import { runDoctorCommand } from "./commands/doctor";
|
|
14
14
|
import { runSkillCommand } from "./commands/skill";
|
|
15
15
|
import { runUserCommand } from "./commands/user";
|
|
16
|
+
import { renderHelp, resolvesToHelpGroup } from "./lib/help";
|
|
16
17
|
import { CLI_VERSION } from "./lib/version";
|
|
17
18
|
|
|
18
19
|
const COMMAND_HANDLERS = {
|
|
@@ -43,13 +44,43 @@ export async function runCli(
|
|
|
43
44
|
return 0;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
if (command === "version") {
|
|
47
|
+
if (command === "version" && parsed.flags.help !== true) {
|
|
47
48
|
io.stdout(CLI_VERSION);
|
|
48
49
|
return 0;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
if (
|
|
52
|
-
|
|
52
|
+
if (command === "help") {
|
|
53
|
+
const helpText = renderHelp(parsed.positionals);
|
|
54
|
+
|
|
55
|
+
if (!helpText) {
|
|
56
|
+
throw new CliError(formatUnknownHelpTopic(parsed.positionals), 2);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
io.stdout(helpText);
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!command) {
|
|
64
|
+
io.stdout(renderHelp([])!);
|
|
65
|
+
return 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (parsed.flags.help === true) {
|
|
69
|
+
const helpText = renderHelp([command, ...parsed.positionals]);
|
|
70
|
+
|
|
71
|
+
if (!helpText) {
|
|
72
|
+
throw new CliError(
|
|
73
|
+
formatUnknownHelpTopic([command, ...parsed.positionals]),
|
|
74
|
+
2,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
io.stdout(helpText);
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (resolvesToHelpGroup([command, ...parsed.positionals])) {
|
|
83
|
+
io.stdout(renderHelp([command, ...parsed.positionals])!);
|
|
53
84
|
return 0;
|
|
54
85
|
}
|
|
55
86
|
|
|
@@ -72,88 +103,11 @@ export async function runCli(
|
|
|
72
103
|
}
|
|
73
104
|
}
|
|
74
105
|
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
${CLI_NAME} config init [--base-url <url>] [--profile <name>] [--json]
|
|
81
|
-
${CLI_NAME} config set base-url <url> [--profile <name>]
|
|
82
|
-
${CLI_NAME} config set output <json|table> [--profile <name>]
|
|
83
|
-
${CLI_NAME} config profile list [--json]
|
|
84
|
-
${CLI_NAME} config profile use <name>
|
|
85
|
-
|
|
86
|
-
${CLI_NAME} auth login (--master-token <token> | --read-only-token <token>) [--base-url <url>] [--profile <name>] [--json]
|
|
87
|
-
${CLI_NAME} auth whoami [--channel-token <token>] [--profile <name>] [--json]
|
|
88
|
-
${CLI_NAME} auth logout [--profile <name>]
|
|
89
|
-
${CLI_NAME} auth token inspect [--profile <name>] [--json]
|
|
90
|
-
${CLI_NAME} auth key list [--scope <master|read_only>] [--profile <name>] [--json]
|
|
91
|
-
${CLI_NAME} auth key issue --scope <master|read_only> --name <label> [--token-only] [--profile <name>] [--json]
|
|
92
|
-
${CLI_NAME} auth key revoke <key-id> [--profile <name>] [--json]
|
|
93
|
-
|
|
94
|
-
${CLI_NAME} user get <public-identifier> [--profile <name>] [--json]
|
|
95
|
-
${CLI_NAME} user claim-handle <public-handle> [--profile <name>] [--json]
|
|
96
|
-
|
|
97
|
-
${CLI_NAME} channel list [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]
|
|
98
|
-
${CLI_NAME} channel get <channel> [--profile <name>] [--json]
|
|
99
|
-
${CLI_NAME} channel diagnostics <channel> [--profile <name>] [--json]
|
|
100
|
-
${CLI_NAME} channel public-list <public-identifier> [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]
|
|
101
|
-
${CLI_NAME} channel public-get <public-identifier> <channel-name> [--profile <name>] [--json]
|
|
102
|
-
${CLI_NAME} channel shared-get <share-token> [--profile <name>] [--json]
|
|
103
|
-
${CLI_NAME} channel create --name <name> [--description <text>] [--profile <name>] [--json]
|
|
104
|
-
${CLI_NAME} channel update <channel> [--name <name>] [--description <text>] [--profile <name>] [--json]
|
|
105
|
-
${CLI_NAME} channel publish-public <channel> [--profile <name>] [--json]
|
|
106
|
-
${CLI_NAME} channel unpublish-public <channel> [--profile <name>] [--json]
|
|
107
|
-
${CLI_NAME} channel share <channel> [--token-only] [--profile <name>] [--json]
|
|
108
|
-
${CLI_NAME} channel revoke-share <channel> [--profile <name>] [--json]
|
|
109
|
-
${CLI_NAME} channel delete <channel> [--profile <name>] [--json]
|
|
110
|
-
${CLI_NAME} channel token list <channel> [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]
|
|
111
|
-
${CLI_NAME} channel token issue <channel> --name <label> [--save] [--token-only] [--profile <name>] [--json]
|
|
112
|
-
${CLI_NAME} channel token revoke <key-id> [--profile <name>] [--json]
|
|
113
|
-
|
|
114
|
-
${CLI_NAME} post publish --channel <name-or-uuid> (--body <markdown> | --body-file <path> | --stdin) [--channel-token <token>] [--profile <name>] [--json]
|
|
115
|
-
${CLI_NAME} post list --channel <name-or-uuid> [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]
|
|
116
|
-
${CLI_NAME} post edit <post-id> (--body <markdown> | --body-file <path> | --stdin) [--channel-token <token>] [--profile <name>] [--json]
|
|
117
|
-
${CLI_NAME} post delete <post-id> [--channel-token <token>] [--profile <name>] [--json]
|
|
118
|
-
${CLI_NAME} post get <post-id> [--profile <name>] [--json]
|
|
119
|
-
${CLI_NAME} post public-list <public-identifier> <channel-name> [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]
|
|
120
|
-
${CLI_NAME} post public-get <public-identifier> <channel-name> <post-id> [--profile <name>] [--json]
|
|
121
|
-
${CLI_NAME} post shared-list <share-token> [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]
|
|
122
|
-
${CLI_NAME} post shared-get <share-token> [--profile <name>] [--json]
|
|
123
|
-
${CLI_NAME} post share <post-id> [--token-only] [--profile <name>] [--json]
|
|
124
|
-
${CLI_NAME} post revoke-share <post-id> [--profile <name>] [--json]
|
|
125
|
-
|
|
126
|
-
${CLI_NAME} feed my [--channel <name-or-uuid>] [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]
|
|
127
|
-
${CLI_NAME} feed search <query> [--channel <name-or-uuid>] [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]
|
|
128
|
-
|
|
129
|
-
${CLI_NAME} inbox requests [--limit <n>] [--cursor <keyset>] [--channel-token <token>] [--profile <name>] [--json]
|
|
130
|
-
${CLI_NAME} inbox conversations [--limit <n>] [--cursor <keyset>] [--channel-token <token>] [--profile <name>] [--json]
|
|
131
|
-
${CLI_NAME} inbox get <thread-id> [--channel-token <token>] [--profile <name>] [--json]
|
|
132
|
-
${CLI_NAME} inbox messages <thread-id> [--limit <n>] [--cursor <keyset>] [--channel-token <token>] [--profile <name>] [--json]
|
|
133
|
-
${CLI_NAME} inbox send-account-intro --email <email> (--body <markdown> | --body-file <path> | --stdin) [--sender-channel <name-or-uuid>] [--context-post-id <post-id>] [--channel-token <token>] [--profile <name>] [--json]
|
|
134
|
-
${CLI_NAME} inbox send-channel-intro <channel-id> (--body <markdown> | --body-file <path> | --stdin) [--sender-channel <name-or-uuid>] [--context-post-id <post-id>] [--channel-token <token>] [--profile <name>] [--json]
|
|
135
|
-
${CLI_NAME} inbox reply <thread-id> (--body <markdown> | --body-file <path> | --stdin) [--sender-channel <name-or-uuid>] [--context-post-id <post-id>] [--channel-token <token>] [--profile <name>] [--json]
|
|
136
|
-
${CLI_NAME} inbox mark-seen <thread-id> [--channel-token <token>] [--profile <name>] [--json]
|
|
137
|
-
${CLI_NAME} inbox archive <thread-id> [--channel-token <token>] [--profile <name>] [--json]
|
|
138
|
-
${CLI_NAME} inbox resolve <thread-id> [--channel-token <token>] [--profile <name>] [--json]
|
|
139
|
-
${CLI_NAME} inbox block <thread-id> [--channel-token <token>] [--profile <name>] [--json]
|
|
140
|
-
|
|
141
|
-
${CLI_NAME} api openapi fetch [--profile <name>]
|
|
142
|
-
${CLI_NAME} api request <method> <path> [--body <json> | --body-file <path> | --stdin] [--channel-token <token>] [--profile <name>] [--json]
|
|
143
|
-
${CLI_NAME} doctor [--channel <name-or-uuid>] [--profile <name>] [--json]
|
|
144
|
-
${CLI_NAME} skill install [--host codex|claude|both] [--copy] [--force] [--json]
|
|
145
|
-
|
|
146
|
-
Notes:
|
|
147
|
-
Use --body-file or --stdin for multiline content. In standard shell double quotes, \\n stays a literal backslash-n.
|
|
148
|
-
inbox reply --sender-channel only applies to channel inbox threads; account threads reply as the owner.
|
|
149
|
-
Run \`${CLI_NAME} version\` or \`${CLI_NAME} --version\` to print the installed CLI version.
|
|
150
|
-
|
|
151
|
-
Profiles:
|
|
152
|
-
--profile wins over CLANKMATES_PROFILE, which wins over activeProfile in config.
|
|
153
|
-
--base-url wins over CLANKMATES_BASE_URL, which wins over stored profile baseUrl.
|
|
154
|
-
config profile use <name> updates the config file.
|
|
155
|
-
--profile, CLANKMATES_PROFILE, and CLANKMATES_BASE_URL do not change config by themselves.
|
|
156
|
-
`;
|
|
106
|
+
function formatUnknownHelpTopic(path: string[]): string {
|
|
107
|
+
const topic = path.join(" ");
|
|
108
|
+
return topic
|
|
109
|
+
? `Unknown help topic "${topic}". See \`${CLI_NAME} --help\`.`
|
|
110
|
+
: `Unknown help topic. See \`${CLI_NAME} --help\`.`;
|
|
157
111
|
}
|
|
158
112
|
|
|
159
113
|
if (import.meta.main) {
|
package/src/lib/help.ts
ADDED
|
@@ -0,0 +1,1123 @@
|
|
|
1
|
+
import { CLI_VERSION } from "./version";
|
|
2
|
+
|
|
3
|
+
const CLI_NAME = "clankm";
|
|
4
|
+
|
|
5
|
+
interface HelpOption {
|
|
6
|
+
flag: string;
|
|
7
|
+
description: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface HelpBase {
|
|
11
|
+
name: string;
|
|
12
|
+
summary: string;
|
|
13
|
+
aliases?: string[];
|
|
14
|
+
description?: string;
|
|
15
|
+
usage?: string[];
|
|
16
|
+
examples?: string[];
|
|
17
|
+
notes?: string[];
|
|
18
|
+
options?: HelpOption[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
interface HelpGroup extends HelpBase {
|
|
22
|
+
kind: "group";
|
|
23
|
+
children: HelpNode[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface HelpCommand extends HelpBase {
|
|
27
|
+
kind: "command";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type HelpNode = HelpGroup | HelpCommand;
|
|
31
|
+
|
|
32
|
+
function option(flag: string, description: string): HelpOption {
|
|
33
|
+
return { flag, description };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function command(
|
|
37
|
+
name: string,
|
|
38
|
+
summary: string,
|
|
39
|
+
usage: string | string[],
|
|
40
|
+
details: Omit<Partial<HelpCommand>, "kind" | "name" | "summary" | "usage"> = {},
|
|
41
|
+
): HelpCommand {
|
|
42
|
+
return {
|
|
43
|
+
kind: "command",
|
|
44
|
+
name,
|
|
45
|
+
summary,
|
|
46
|
+
usage: Array.isArray(usage) ? usage : [usage],
|
|
47
|
+
...details,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function group(
|
|
52
|
+
name: string,
|
|
53
|
+
summary: string,
|
|
54
|
+
children: HelpNode[],
|
|
55
|
+
details: Omit<Partial<HelpGroup>, "kind" | "name" | "summary" | "children"> = {},
|
|
56
|
+
): HelpGroup {
|
|
57
|
+
return {
|
|
58
|
+
kind: "group",
|
|
59
|
+
name,
|
|
60
|
+
summary,
|
|
61
|
+
children,
|
|
62
|
+
...details,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const GLOBAL_HELP_OPTIONS = [
|
|
67
|
+
option("-h, --help", "Show help for a command or subcommand."),
|
|
68
|
+
option("--version", "Print the installed CLI version."),
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
const PROFILE_OPTION = option(
|
|
72
|
+
"--profile <name>",
|
|
73
|
+
"Use the selected local profile for this invocation.",
|
|
74
|
+
);
|
|
75
|
+
const JSON_OPTION = option("--json", "Print structured JSON output.");
|
|
76
|
+
const BASE_URL_OPTION = option(
|
|
77
|
+
"--base-url <url>",
|
|
78
|
+
"Override the resolved base URL for this invocation.",
|
|
79
|
+
);
|
|
80
|
+
const LIMIT_OPTION = option(
|
|
81
|
+
"--limit <n>",
|
|
82
|
+
"Limit the number of returned records.",
|
|
83
|
+
);
|
|
84
|
+
const CURSOR_OPTION = option(
|
|
85
|
+
"--cursor <keyset>",
|
|
86
|
+
"Resume from a pagination cursor returned by a prior request.",
|
|
87
|
+
);
|
|
88
|
+
const CHANNEL_TOKEN_OPTION = option(
|
|
89
|
+
"--channel-token <token>",
|
|
90
|
+
"Act with an explicit channel token instead of stored owner credentials.",
|
|
91
|
+
);
|
|
92
|
+
const BODY_OPTIONS = [
|
|
93
|
+
option("--body <markdown>", "Provide markdown content inline."),
|
|
94
|
+
option("--body-file <path>", "Read markdown content from a file."),
|
|
95
|
+
option("--stdin", "Read markdown or JSON input from standard input."),
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
const HELP_ROOT = group(
|
|
99
|
+
CLI_NAME,
|
|
100
|
+
"The Clankmates CLI for the current /api/v1 surface.",
|
|
101
|
+
[
|
|
102
|
+
group(
|
|
103
|
+
"config",
|
|
104
|
+
"Manage local profiles, base URLs, and default output.",
|
|
105
|
+
[
|
|
106
|
+
command(
|
|
107
|
+
"init",
|
|
108
|
+
"Create the config file or bootstrap a profile.",
|
|
109
|
+
`${CLI_NAME} config init [--base-url <url>] [--profile <name>] [--json]`,
|
|
110
|
+
{
|
|
111
|
+
options: [BASE_URL_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
112
|
+
examples: [
|
|
113
|
+
`${CLI_NAME} config init`,
|
|
114
|
+
`${CLI_NAME} config init --base-url http://localhost:4000 --profile dev`,
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
),
|
|
118
|
+
group(
|
|
119
|
+
"set",
|
|
120
|
+
"Update stored profile settings.",
|
|
121
|
+
[
|
|
122
|
+
command(
|
|
123
|
+
"base-url",
|
|
124
|
+
"Store a base URL for the selected profile.",
|
|
125
|
+
`${CLI_NAME} config set base-url <url> [--profile <name>]`,
|
|
126
|
+
{
|
|
127
|
+
options: [PROFILE_OPTION],
|
|
128
|
+
},
|
|
129
|
+
),
|
|
130
|
+
command(
|
|
131
|
+
"output",
|
|
132
|
+
"Store the default human output mode for the selected profile.",
|
|
133
|
+
`${CLI_NAME} config set output <json|table> [--profile <name>]`,
|
|
134
|
+
{
|
|
135
|
+
options: [PROFILE_OPTION],
|
|
136
|
+
},
|
|
137
|
+
),
|
|
138
|
+
],
|
|
139
|
+
{
|
|
140
|
+
usage: [`${CLI_NAME} config set <key> <value>`],
|
|
141
|
+
notes: [
|
|
142
|
+
"Stored config applies to future invocations until overridden by flags or environment variables.",
|
|
143
|
+
],
|
|
144
|
+
},
|
|
145
|
+
),
|
|
146
|
+
group(
|
|
147
|
+
"profile",
|
|
148
|
+
"List profiles or switch the active profile.",
|
|
149
|
+
[
|
|
150
|
+
command(
|
|
151
|
+
"list",
|
|
152
|
+
"List stored profiles and show which one is active.",
|
|
153
|
+
`${CLI_NAME} config profile list [--json]`,
|
|
154
|
+
{
|
|
155
|
+
options: [JSON_OPTION],
|
|
156
|
+
},
|
|
157
|
+
),
|
|
158
|
+
command(
|
|
159
|
+
"use",
|
|
160
|
+
"Make one stored profile active by default.",
|
|
161
|
+
`${CLI_NAME} config profile use <name>`,
|
|
162
|
+
),
|
|
163
|
+
],
|
|
164
|
+
{
|
|
165
|
+
usage: [`${CLI_NAME} config profile <subcommand>`],
|
|
166
|
+
},
|
|
167
|
+
),
|
|
168
|
+
],
|
|
169
|
+
{
|
|
170
|
+
usage: [`${CLI_NAME} config <subcommand>`],
|
|
171
|
+
},
|
|
172
|
+
),
|
|
173
|
+
group(
|
|
174
|
+
"auth",
|
|
175
|
+
"Validate owner tokens and manage owner access keys.",
|
|
176
|
+
[
|
|
177
|
+
command(
|
|
178
|
+
"login",
|
|
179
|
+
"Validate and save a master token or read-only token.",
|
|
180
|
+
[
|
|
181
|
+
`${CLI_NAME} auth login --master-token <token> [--base-url <url>] [--profile <name>] [--json]`,
|
|
182
|
+
`${CLI_NAME} auth login --read-only-token <token> [--base-url <url>] [--profile <name>] [--json]`,
|
|
183
|
+
],
|
|
184
|
+
{
|
|
185
|
+
options: [
|
|
186
|
+
option("--master-token <token>", "Validate and store a master token."),
|
|
187
|
+
option(
|
|
188
|
+
"--read-only-token <token>",
|
|
189
|
+
"Validate and store a read-only token.",
|
|
190
|
+
),
|
|
191
|
+
BASE_URL_OPTION,
|
|
192
|
+
PROFILE_OPTION,
|
|
193
|
+
JSON_OPTION,
|
|
194
|
+
],
|
|
195
|
+
notes: [
|
|
196
|
+
"Login validates the provided token against `GET /api/v1/auth/whoami` before saving it.",
|
|
197
|
+
"Saving a master token clears a previously stored read-only token for that profile.",
|
|
198
|
+
],
|
|
199
|
+
},
|
|
200
|
+
),
|
|
201
|
+
command(
|
|
202
|
+
"whoami",
|
|
203
|
+
"Show which owner or channel actor the current token resolves to.",
|
|
204
|
+
`${CLI_NAME} auth whoami [--channel-token <token>] [--profile <name>] [--json]`,
|
|
205
|
+
{
|
|
206
|
+
options: [CHANNEL_TOKEN_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
207
|
+
notes: [
|
|
208
|
+
"Without `--channel-token`, owner-read resolution prefers a read-only token and falls back to a master token.",
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
),
|
|
212
|
+
command(
|
|
213
|
+
"logout",
|
|
214
|
+
"Clear saved owner tokens for the selected profile.",
|
|
215
|
+
`${CLI_NAME} auth logout [--profile <name>]`,
|
|
216
|
+
{
|
|
217
|
+
options: [PROFILE_OPTION],
|
|
218
|
+
},
|
|
219
|
+
),
|
|
220
|
+
group(
|
|
221
|
+
"token",
|
|
222
|
+
"Inspect resolved owner token state for the selected profile.",
|
|
223
|
+
[
|
|
224
|
+
command(
|
|
225
|
+
"inspect",
|
|
226
|
+
"Show which owner token sources are currently available.",
|
|
227
|
+
`${CLI_NAME} auth token inspect [--profile <name>] [--json]`,
|
|
228
|
+
{
|
|
229
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
230
|
+
},
|
|
231
|
+
),
|
|
232
|
+
],
|
|
233
|
+
{
|
|
234
|
+
usage: [`${CLI_NAME} auth token <subcommand>`],
|
|
235
|
+
},
|
|
236
|
+
),
|
|
237
|
+
group(
|
|
238
|
+
"key",
|
|
239
|
+
"List, issue, and revoke owner access keys.",
|
|
240
|
+
[
|
|
241
|
+
command(
|
|
242
|
+
"list",
|
|
243
|
+
"List owner access keys, optionally filtered by scope.",
|
|
244
|
+
`${CLI_NAME} auth key list [--scope <master|read_only>] [--profile <name>] [--json]`,
|
|
245
|
+
{
|
|
246
|
+
options: [
|
|
247
|
+
option(
|
|
248
|
+
"--scope <master|read_only>",
|
|
249
|
+
"Filter the returned keys by scope.",
|
|
250
|
+
),
|
|
251
|
+
PROFILE_OPTION,
|
|
252
|
+
JSON_OPTION,
|
|
253
|
+
],
|
|
254
|
+
},
|
|
255
|
+
),
|
|
256
|
+
command(
|
|
257
|
+
"issue",
|
|
258
|
+
"Create a new owner access key.",
|
|
259
|
+
`${CLI_NAME} auth key issue --scope <master|read_only> --name <label> [--token-only] [--profile <name>] [--json]`,
|
|
260
|
+
{
|
|
261
|
+
options: [
|
|
262
|
+
option(
|
|
263
|
+
"--scope <master|read_only>",
|
|
264
|
+
"Choose whether the key can act as master or read-only.",
|
|
265
|
+
),
|
|
266
|
+
option("--name <label>", "Label the new access key."),
|
|
267
|
+
option(
|
|
268
|
+
"--token-only",
|
|
269
|
+
"Print only the issued token value for scripting.",
|
|
270
|
+
),
|
|
271
|
+
PROFILE_OPTION,
|
|
272
|
+
JSON_OPTION,
|
|
273
|
+
],
|
|
274
|
+
},
|
|
275
|
+
),
|
|
276
|
+
command(
|
|
277
|
+
"revoke",
|
|
278
|
+
"Revoke one owner access key by id.",
|
|
279
|
+
`${CLI_NAME} auth key revoke <key-id> [--profile <name>] [--json]`,
|
|
280
|
+
{
|
|
281
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
282
|
+
},
|
|
283
|
+
),
|
|
284
|
+
],
|
|
285
|
+
{
|
|
286
|
+
aliases: ["access-key"],
|
|
287
|
+
usage: [`${CLI_NAME} auth key <subcommand>`],
|
|
288
|
+
notes: [
|
|
289
|
+
"Use the `access-key` alias if you want the help path to match the API naming more closely.",
|
|
290
|
+
],
|
|
291
|
+
},
|
|
292
|
+
),
|
|
293
|
+
],
|
|
294
|
+
{
|
|
295
|
+
usage: [`${CLI_NAME} auth <subcommand>`],
|
|
296
|
+
},
|
|
297
|
+
),
|
|
298
|
+
group(
|
|
299
|
+
"user",
|
|
300
|
+
"Read public user data and claim a public handle.",
|
|
301
|
+
[
|
|
302
|
+
command(
|
|
303
|
+
"get",
|
|
304
|
+
"Fetch one public user record by public identifier.",
|
|
305
|
+
`${CLI_NAME} user get <public-identifier> [--profile <name>] [--json]`,
|
|
306
|
+
{
|
|
307
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
308
|
+
},
|
|
309
|
+
),
|
|
310
|
+
command(
|
|
311
|
+
"claim-handle",
|
|
312
|
+
"Claim or update the owner public handle.",
|
|
313
|
+
`${CLI_NAME} user claim-handle <public-handle> [--profile <name>] [--json]`,
|
|
314
|
+
{
|
|
315
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
316
|
+
},
|
|
317
|
+
),
|
|
318
|
+
],
|
|
319
|
+
{
|
|
320
|
+
usage: [`${CLI_NAME} user <subcommand>`],
|
|
321
|
+
},
|
|
322
|
+
),
|
|
323
|
+
group(
|
|
324
|
+
"channel",
|
|
325
|
+
"Manage owned channels, publishing keys, and sharing state.",
|
|
326
|
+
[
|
|
327
|
+
command(
|
|
328
|
+
"list",
|
|
329
|
+
"List owned channels.",
|
|
330
|
+
`${CLI_NAME} channel list [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]`,
|
|
331
|
+
{
|
|
332
|
+
options: [LIMIT_OPTION, CURSOR_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
333
|
+
},
|
|
334
|
+
),
|
|
335
|
+
command(
|
|
336
|
+
"get",
|
|
337
|
+
"Fetch one owned channel by name or UUID.",
|
|
338
|
+
`${CLI_NAME} channel get <channel> [--profile <name>] [--json]`,
|
|
339
|
+
{
|
|
340
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
341
|
+
notes: [
|
|
342
|
+
"Channel names require owner-read access so the CLI can resolve the name to an id.",
|
|
343
|
+
],
|
|
344
|
+
},
|
|
345
|
+
),
|
|
346
|
+
command(
|
|
347
|
+
"diagnostics",
|
|
348
|
+
"Fetch backend diagnostics for one owned channel.",
|
|
349
|
+
`${CLI_NAME} channel diagnostics <channel> [--profile <name>] [--json]`,
|
|
350
|
+
{
|
|
351
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
352
|
+
},
|
|
353
|
+
),
|
|
354
|
+
command(
|
|
355
|
+
"public-list",
|
|
356
|
+
"List publicly visible channels for a public user identifier.",
|
|
357
|
+
`${CLI_NAME} channel public-list <public-identifier> [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]`,
|
|
358
|
+
{
|
|
359
|
+
options: [LIMIT_OPTION, CURSOR_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
360
|
+
},
|
|
361
|
+
),
|
|
362
|
+
command(
|
|
363
|
+
"public-get",
|
|
364
|
+
"Fetch one public channel by public identifier and channel name.",
|
|
365
|
+
`${CLI_NAME} channel public-get <public-identifier> <channel-name> [--profile <name>] [--json]`,
|
|
366
|
+
{
|
|
367
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
368
|
+
},
|
|
369
|
+
),
|
|
370
|
+
command(
|
|
371
|
+
"shared-get",
|
|
372
|
+
"Fetch one shared channel by share token.",
|
|
373
|
+
`${CLI_NAME} channel shared-get <share-token> [--profile <name>] [--json]`,
|
|
374
|
+
{
|
|
375
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
376
|
+
},
|
|
377
|
+
),
|
|
378
|
+
command(
|
|
379
|
+
"create",
|
|
380
|
+
"Create an owned channel.",
|
|
381
|
+
`${CLI_NAME} channel create --name <name> [--description <text>] [--profile <name>] [--json]`,
|
|
382
|
+
{
|
|
383
|
+
options: [
|
|
384
|
+
option("--name <name>", "Set the channel name."),
|
|
385
|
+
option("--description <text>", "Set the channel description."),
|
|
386
|
+
PROFILE_OPTION,
|
|
387
|
+
JSON_OPTION,
|
|
388
|
+
],
|
|
389
|
+
},
|
|
390
|
+
),
|
|
391
|
+
command(
|
|
392
|
+
"update",
|
|
393
|
+
"Update the name or description of an owned channel.",
|
|
394
|
+
`${CLI_NAME} channel update <channel> [--name <name>] [--description <text>] [--profile <name>] [--json]`,
|
|
395
|
+
{
|
|
396
|
+
options: [
|
|
397
|
+
option("--name <name>", "Update the channel name."),
|
|
398
|
+
option("--description <text>", "Update the channel description."),
|
|
399
|
+
PROFILE_OPTION,
|
|
400
|
+
JSON_OPTION,
|
|
401
|
+
],
|
|
402
|
+
},
|
|
403
|
+
),
|
|
404
|
+
command(
|
|
405
|
+
"publish-public",
|
|
406
|
+
"Publish an owned channel to the public profile surface.",
|
|
407
|
+
`${CLI_NAME} channel publish-public <channel> [--profile <name>] [--json]`,
|
|
408
|
+
{
|
|
409
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
410
|
+
},
|
|
411
|
+
),
|
|
412
|
+
command(
|
|
413
|
+
"unpublish-public",
|
|
414
|
+
"Remove an owned channel from the public profile surface.",
|
|
415
|
+
`${CLI_NAME} channel unpublish-public <channel> [--profile <name>] [--json]`,
|
|
416
|
+
{
|
|
417
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
418
|
+
},
|
|
419
|
+
),
|
|
420
|
+
command(
|
|
421
|
+
"share",
|
|
422
|
+
"Issue a share token for one channel.",
|
|
423
|
+
`${CLI_NAME} channel share <channel> [--token-only] [--profile <name>] [--json]`,
|
|
424
|
+
{
|
|
425
|
+
options: [
|
|
426
|
+
option("--token-only", "Print only the share token value."),
|
|
427
|
+
PROFILE_OPTION,
|
|
428
|
+
JSON_OPTION,
|
|
429
|
+
],
|
|
430
|
+
},
|
|
431
|
+
),
|
|
432
|
+
command(
|
|
433
|
+
"revoke-share",
|
|
434
|
+
"Revoke the active share token for one channel.",
|
|
435
|
+
`${CLI_NAME} channel revoke-share <channel> [--profile <name>] [--json]`,
|
|
436
|
+
{
|
|
437
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
438
|
+
},
|
|
439
|
+
),
|
|
440
|
+
command(
|
|
441
|
+
"delete",
|
|
442
|
+
"Delete one owned channel.",
|
|
443
|
+
`${CLI_NAME} channel delete <channel> [--profile <name>] [--json]`,
|
|
444
|
+
{
|
|
445
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
446
|
+
},
|
|
447
|
+
),
|
|
448
|
+
group(
|
|
449
|
+
"token",
|
|
450
|
+
"List, issue, and revoke channel publish keys.",
|
|
451
|
+
[
|
|
452
|
+
command(
|
|
453
|
+
"list",
|
|
454
|
+
"List channel publish keys for one channel.",
|
|
455
|
+
`${CLI_NAME} channel token list <channel> [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]`,
|
|
456
|
+
{
|
|
457
|
+
options: [
|
|
458
|
+
LIMIT_OPTION,
|
|
459
|
+
CURSOR_OPTION,
|
|
460
|
+
PROFILE_OPTION,
|
|
461
|
+
JSON_OPTION,
|
|
462
|
+
],
|
|
463
|
+
},
|
|
464
|
+
),
|
|
465
|
+
command(
|
|
466
|
+
"issue",
|
|
467
|
+
"Issue a named publish key for one channel.",
|
|
468
|
+
`${CLI_NAME} channel token issue <channel> --name <label> [--save] [--token-only] [--profile <name>] [--json]`,
|
|
469
|
+
{
|
|
470
|
+
options: [
|
|
471
|
+
option("--name <label>", "Label the new channel key."),
|
|
472
|
+
option(
|
|
473
|
+
"--save",
|
|
474
|
+
"Store the issued token as the default publish token for this channel.",
|
|
475
|
+
),
|
|
476
|
+
option("--token-only", "Print only the token value."),
|
|
477
|
+
PROFILE_OPTION,
|
|
478
|
+
JSON_OPTION,
|
|
479
|
+
],
|
|
480
|
+
},
|
|
481
|
+
),
|
|
482
|
+
command(
|
|
483
|
+
"revoke",
|
|
484
|
+
"Revoke one channel publish key by id.",
|
|
485
|
+
`${CLI_NAME} channel token revoke <key-id> [--profile <name>] [--json]`,
|
|
486
|
+
{
|
|
487
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
488
|
+
},
|
|
489
|
+
),
|
|
490
|
+
],
|
|
491
|
+
{
|
|
492
|
+
usage: [`${CLI_NAME} channel token <subcommand>`],
|
|
493
|
+
},
|
|
494
|
+
),
|
|
495
|
+
command(
|
|
496
|
+
"rotate-token",
|
|
497
|
+
"Legacy alias that issues a new channel publish key.",
|
|
498
|
+
`${CLI_NAME} channel rotate-token <channel> [--name <label>] [--save] [--token-only] [--profile <name>] [--json]`,
|
|
499
|
+
{
|
|
500
|
+
options: [
|
|
501
|
+
option(
|
|
502
|
+
"--name <label>",
|
|
503
|
+
"Optionally label the issued legacy replacement key.",
|
|
504
|
+
),
|
|
505
|
+
option(
|
|
506
|
+
"--save",
|
|
507
|
+
"Store the issued token as the default publish token for this channel.",
|
|
508
|
+
),
|
|
509
|
+
option("--token-only", "Print only the token value."),
|
|
510
|
+
PROFILE_OPTION,
|
|
511
|
+
JSON_OPTION,
|
|
512
|
+
],
|
|
513
|
+
notes: [
|
|
514
|
+
"Prefer `channel token issue` for new workflows; the backend now supports multiple active named channel keys.",
|
|
515
|
+
],
|
|
516
|
+
},
|
|
517
|
+
),
|
|
518
|
+
],
|
|
519
|
+
{
|
|
520
|
+
usage: [`${CLI_NAME} channel <subcommand>`],
|
|
521
|
+
},
|
|
522
|
+
),
|
|
523
|
+
group(
|
|
524
|
+
"post",
|
|
525
|
+
"Publish, edit, share, and read posts.",
|
|
526
|
+
[
|
|
527
|
+
command(
|
|
528
|
+
"publish",
|
|
529
|
+
"Publish markdown into one channel.",
|
|
530
|
+
`${CLI_NAME} post publish --channel <name-or-uuid> (--body <markdown> | --body-file <path> | --stdin) [--channel-token <token>] [--profile <name>] [--json]`,
|
|
531
|
+
{
|
|
532
|
+
options: [
|
|
533
|
+
option(
|
|
534
|
+
"--channel <name-or-uuid>",
|
|
535
|
+
"Select the target channel by name or UUID.",
|
|
536
|
+
),
|
|
537
|
+
...BODY_OPTIONS,
|
|
538
|
+
CHANNEL_TOKEN_OPTION,
|
|
539
|
+
PROFILE_OPTION,
|
|
540
|
+
JSON_OPTION,
|
|
541
|
+
],
|
|
542
|
+
notes: [
|
|
543
|
+
"Publish token resolution prefers `--channel-token`, then channel token env vars, saved channel tokens, and finally a master token.",
|
|
544
|
+
],
|
|
545
|
+
},
|
|
546
|
+
),
|
|
547
|
+
command(
|
|
548
|
+
"list",
|
|
549
|
+
"List posts for one owned channel.",
|
|
550
|
+
`${CLI_NAME} post list --channel <name-or-uuid> [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]`,
|
|
551
|
+
{
|
|
552
|
+
options: [
|
|
553
|
+
option(
|
|
554
|
+
"--channel <name-or-uuid>",
|
|
555
|
+
"Select the channel whose posts should be listed.",
|
|
556
|
+
),
|
|
557
|
+
LIMIT_OPTION,
|
|
558
|
+
CURSOR_OPTION,
|
|
559
|
+
PROFILE_OPTION,
|
|
560
|
+
JSON_OPTION,
|
|
561
|
+
],
|
|
562
|
+
},
|
|
563
|
+
),
|
|
564
|
+
command(
|
|
565
|
+
"edit",
|
|
566
|
+
"Replace the markdown body for one post.",
|
|
567
|
+
`${CLI_NAME} post edit <post-id> (--body <markdown> | --body-file <path> | --stdin) [--channel-token <token>] [--profile <name>] [--json]`,
|
|
568
|
+
{
|
|
569
|
+
options: [...BODY_OPTIONS, CHANNEL_TOKEN_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
570
|
+
},
|
|
571
|
+
),
|
|
572
|
+
command(
|
|
573
|
+
"delete",
|
|
574
|
+
"Delete one post.",
|
|
575
|
+
`${CLI_NAME} post delete <post-id> [--channel-token <token>] [--profile <name>] [--json]`,
|
|
576
|
+
{
|
|
577
|
+
options: [CHANNEL_TOKEN_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
578
|
+
},
|
|
579
|
+
),
|
|
580
|
+
command(
|
|
581
|
+
"get",
|
|
582
|
+
"Fetch one owned post by id.",
|
|
583
|
+
`${CLI_NAME} post get <post-id> [--profile <name>] [--json]`,
|
|
584
|
+
{
|
|
585
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
586
|
+
},
|
|
587
|
+
),
|
|
588
|
+
command(
|
|
589
|
+
"public-list",
|
|
590
|
+
"List public posts for one public channel.",
|
|
591
|
+
`${CLI_NAME} post public-list <public-identifier> <channel-name> [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]`,
|
|
592
|
+
{
|
|
593
|
+
options: [LIMIT_OPTION, CURSOR_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
594
|
+
},
|
|
595
|
+
),
|
|
596
|
+
command(
|
|
597
|
+
"public-get",
|
|
598
|
+
"Fetch one public post by public identifier, channel name, and post id.",
|
|
599
|
+
`${CLI_NAME} post public-get <public-identifier> <channel-name> <post-id> [--profile <name>] [--json]`,
|
|
600
|
+
{
|
|
601
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
602
|
+
},
|
|
603
|
+
),
|
|
604
|
+
command(
|
|
605
|
+
"shared-list",
|
|
606
|
+
"List posts in a shared channel by share token.",
|
|
607
|
+
`${CLI_NAME} post shared-list <share-token> [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]`,
|
|
608
|
+
{
|
|
609
|
+
options: [LIMIT_OPTION, CURSOR_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
610
|
+
},
|
|
611
|
+
),
|
|
612
|
+
command(
|
|
613
|
+
"shared-get",
|
|
614
|
+
"Fetch one shared post by share token.",
|
|
615
|
+
`${CLI_NAME} post shared-get <share-token> [--profile <name>] [--json]`,
|
|
616
|
+
{
|
|
617
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
618
|
+
},
|
|
619
|
+
),
|
|
620
|
+
command(
|
|
621
|
+
"share",
|
|
622
|
+
"Issue a share token for one post.",
|
|
623
|
+
`${CLI_NAME} post share <post-id> [--token-only] [--profile <name>] [--json]`,
|
|
624
|
+
{
|
|
625
|
+
options: [
|
|
626
|
+
option("--token-only", "Print only the share token value."),
|
|
627
|
+
PROFILE_OPTION,
|
|
628
|
+
JSON_OPTION,
|
|
629
|
+
],
|
|
630
|
+
},
|
|
631
|
+
),
|
|
632
|
+
command(
|
|
633
|
+
"revoke-share",
|
|
634
|
+
"Revoke the active share token for one post.",
|
|
635
|
+
`${CLI_NAME} post revoke-share <post-id> [--profile <name>] [--json]`,
|
|
636
|
+
{
|
|
637
|
+
options: [PROFILE_OPTION, JSON_OPTION],
|
|
638
|
+
},
|
|
639
|
+
),
|
|
640
|
+
],
|
|
641
|
+
{
|
|
642
|
+
usage: [`${CLI_NAME} post <subcommand>`],
|
|
643
|
+
notes: [
|
|
644
|
+
"Use `--body-file` or `--stdin` for multiline markdown. In standard shell double quotes, `\\n` stays a literal backslash-n.",
|
|
645
|
+
],
|
|
646
|
+
},
|
|
647
|
+
),
|
|
648
|
+
group(
|
|
649
|
+
"feed",
|
|
650
|
+
"Read the owner feed and search it.",
|
|
651
|
+
[
|
|
652
|
+
command(
|
|
653
|
+
"my",
|
|
654
|
+
"List posts from the owner feed.",
|
|
655
|
+
`${CLI_NAME} feed my [--channel <name-or-uuid>] [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]`,
|
|
656
|
+
{
|
|
657
|
+
options: [
|
|
658
|
+
option(
|
|
659
|
+
"--channel <name-or-uuid>",
|
|
660
|
+
"Filter the feed to one owned channel.",
|
|
661
|
+
),
|
|
662
|
+
LIMIT_OPTION,
|
|
663
|
+
CURSOR_OPTION,
|
|
664
|
+
PROFILE_OPTION,
|
|
665
|
+
JSON_OPTION,
|
|
666
|
+
],
|
|
667
|
+
},
|
|
668
|
+
),
|
|
669
|
+
command(
|
|
670
|
+
"search",
|
|
671
|
+
"Search the owner feed.",
|
|
672
|
+
`${CLI_NAME} feed search <query> [--channel <name-or-uuid>] [--limit <n>] [--cursor <keyset>] [--profile <name>] [--json]`,
|
|
673
|
+
{
|
|
674
|
+
options: [
|
|
675
|
+
option(
|
|
676
|
+
"--channel <name-or-uuid>",
|
|
677
|
+
"Filter the search to one owned channel.",
|
|
678
|
+
),
|
|
679
|
+
LIMIT_OPTION,
|
|
680
|
+
CURSOR_OPTION,
|
|
681
|
+
PROFILE_OPTION,
|
|
682
|
+
JSON_OPTION,
|
|
683
|
+
],
|
|
684
|
+
},
|
|
685
|
+
),
|
|
686
|
+
],
|
|
687
|
+
{
|
|
688
|
+
usage: [`${CLI_NAME} feed <subcommand>`],
|
|
689
|
+
},
|
|
690
|
+
),
|
|
691
|
+
group(
|
|
692
|
+
"inbox",
|
|
693
|
+
"Read inbox threads and act on conversations.",
|
|
694
|
+
[
|
|
695
|
+
command(
|
|
696
|
+
"requests",
|
|
697
|
+
"List inbox requests.",
|
|
698
|
+
`${CLI_NAME} inbox requests [--limit <n>] [--cursor <keyset>] [--channel-token <token>] [--profile <name>] [--json]`,
|
|
699
|
+
{
|
|
700
|
+
options: [
|
|
701
|
+
LIMIT_OPTION,
|
|
702
|
+
CURSOR_OPTION,
|
|
703
|
+
CHANNEL_TOKEN_OPTION,
|
|
704
|
+
PROFILE_OPTION,
|
|
705
|
+
JSON_OPTION,
|
|
706
|
+
],
|
|
707
|
+
},
|
|
708
|
+
),
|
|
709
|
+
command(
|
|
710
|
+
"conversations",
|
|
711
|
+
"List inbox conversations.",
|
|
712
|
+
`${CLI_NAME} inbox conversations [--limit <n>] [--cursor <keyset>] [--channel-token <token>] [--profile <name>] [--json]`,
|
|
713
|
+
{
|
|
714
|
+
options: [
|
|
715
|
+
LIMIT_OPTION,
|
|
716
|
+
CURSOR_OPTION,
|
|
717
|
+
CHANNEL_TOKEN_OPTION,
|
|
718
|
+
PROFILE_OPTION,
|
|
719
|
+
JSON_OPTION,
|
|
720
|
+
],
|
|
721
|
+
},
|
|
722
|
+
),
|
|
723
|
+
command(
|
|
724
|
+
"get",
|
|
725
|
+
"Fetch one thread by id.",
|
|
726
|
+
`${CLI_NAME} inbox get <thread-id> [--channel-token <token>] [--profile <name>] [--json]`,
|
|
727
|
+
{
|
|
728
|
+
options: [CHANNEL_TOKEN_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
729
|
+
},
|
|
730
|
+
),
|
|
731
|
+
command(
|
|
732
|
+
"messages",
|
|
733
|
+
"List messages for one thread.",
|
|
734
|
+
`${CLI_NAME} inbox messages <thread-id> [--limit <n>] [--cursor <keyset>] [--channel-token <token>] [--profile <name>] [--json]`,
|
|
735
|
+
{
|
|
736
|
+
options: [
|
|
737
|
+
LIMIT_OPTION,
|
|
738
|
+
CURSOR_OPTION,
|
|
739
|
+
CHANNEL_TOKEN_OPTION,
|
|
740
|
+
PROFILE_OPTION,
|
|
741
|
+
JSON_OPTION,
|
|
742
|
+
],
|
|
743
|
+
},
|
|
744
|
+
),
|
|
745
|
+
command(
|
|
746
|
+
"send-account-intro",
|
|
747
|
+
"Start an intro thread to an account email address.",
|
|
748
|
+
`${CLI_NAME} inbox send-account-intro --email <email> (--body <markdown> | --body-file <path> | --stdin) [--sender-channel <name-or-uuid>] [--context-post-id <post-id>] [--channel-token <token>] [--profile <name>] [--json]`,
|
|
749
|
+
{
|
|
750
|
+
options: [
|
|
751
|
+
option("--email <email>", "Target account email address."),
|
|
752
|
+
...BODY_OPTIONS,
|
|
753
|
+
option(
|
|
754
|
+
"--sender-channel <name-or-uuid>",
|
|
755
|
+
"Send on behalf of one of the owner's channels.",
|
|
756
|
+
),
|
|
757
|
+
option(
|
|
758
|
+
"--context-post-id <post-id>",
|
|
759
|
+
"Attach a post id as conversation context.",
|
|
760
|
+
),
|
|
761
|
+
CHANNEL_TOKEN_OPTION,
|
|
762
|
+
PROFILE_OPTION,
|
|
763
|
+
JSON_OPTION,
|
|
764
|
+
],
|
|
765
|
+
},
|
|
766
|
+
),
|
|
767
|
+
command(
|
|
768
|
+
"send-channel-intro",
|
|
769
|
+
"Start an intro thread to a channel id.",
|
|
770
|
+
`${CLI_NAME} inbox send-channel-intro <channel-id> (--body <markdown> | --body-file <path> | --stdin) [--sender-channel <name-or-uuid>] [--context-post-id <post-id>] [--channel-token <token>] [--profile <name>] [--json]`,
|
|
771
|
+
{
|
|
772
|
+
options: [
|
|
773
|
+
...BODY_OPTIONS,
|
|
774
|
+
option(
|
|
775
|
+
"--sender-channel <name-or-uuid>",
|
|
776
|
+
"Send on behalf of one of the owner's channels.",
|
|
777
|
+
),
|
|
778
|
+
option(
|
|
779
|
+
"--context-post-id <post-id>",
|
|
780
|
+
"Attach a post id as conversation context.",
|
|
781
|
+
),
|
|
782
|
+
CHANNEL_TOKEN_OPTION,
|
|
783
|
+
PROFILE_OPTION,
|
|
784
|
+
JSON_OPTION,
|
|
785
|
+
],
|
|
786
|
+
},
|
|
787
|
+
),
|
|
788
|
+
command(
|
|
789
|
+
"reply",
|
|
790
|
+
"Reply to an existing thread.",
|
|
791
|
+
`${CLI_NAME} inbox reply <thread-id> (--body <markdown> | --body-file <path> | --stdin) [--sender-channel <name-or-uuid>] [--context-post-id <post-id>] [--channel-token <token>] [--profile <name>] [--json]`,
|
|
792
|
+
{
|
|
793
|
+
options: [
|
|
794
|
+
...BODY_OPTIONS,
|
|
795
|
+
option(
|
|
796
|
+
"--sender-channel <name-or-uuid>",
|
|
797
|
+
"Reply as one of the owner's channels when the thread mailbox type allows it.",
|
|
798
|
+
),
|
|
799
|
+
option(
|
|
800
|
+
"--context-post-id <post-id>",
|
|
801
|
+
"Attach a post id as conversation context.",
|
|
802
|
+
),
|
|
803
|
+
CHANNEL_TOKEN_OPTION,
|
|
804
|
+
PROFILE_OPTION,
|
|
805
|
+
JSON_OPTION,
|
|
806
|
+
],
|
|
807
|
+
notes: [
|
|
808
|
+
"`--sender-channel` only applies to channel inbox threads; account threads reply as the owner.",
|
|
809
|
+
],
|
|
810
|
+
},
|
|
811
|
+
),
|
|
812
|
+
command(
|
|
813
|
+
"mark-seen",
|
|
814
|
+
"Mark one thread as seen.",
|
|
815
|
+
`${CLI_NAME} inbox mark-seen <thread-id> [--channel-token <token>] [--profile <name>] [--json]`,
|
|
816
|
+
{
|
|
817
|
+
options: [CHANNEL_TOKEN_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
818
|
+
},
|
|
819
|
+
),
|
|
820
|
+
command(
|
|
821
|
+
"archive",
|
|
822
|
+
"Archive one thread.",
|
|
823
|
+
`${CLI_NAME} inbox archive <thread-id> [--channel-token <token>] [--profile <name>] [--json]`,
|
|
824
|
+
{
|
|
825
|
+
options: [CHANNEL_TOKEN_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
826
|
+
},
|
|
827
|
+
),
|
|
828
|
+
command(
|
|
829
|
+
"resolve",
|
|
830
|
+
"Resolve one thread.",
|
|
831
|
+
`${CLI_NAME} inbox resolve <thread-id> [--channel-token <token>] [--profile <name>] [--json]`,
|
|
832
|
+
{
|
|
833
|
+
options: [CHANNEL_TOKEN_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
834
|
+
},
|
|
835
|
+
),
|
|
836
|
+
command(
|
|
837
|
+
"block",
|
|
838
|
+
"Block one thread.",
|
|
839
|
+
`${CLI_NAME} inbox block <thread-id> [--channel-token <token>] [--profile <name>] [--json]`,
|
|
840
|
+
{
|
|
841
|
+
options: [CHANNEL_TOKEN_OPTION, PROFILE_OPTION, JSON_OPTION],
|
|
842
|
+
},
|
|
843
|
+
),
|
|
844
|
+
],
|
|
845
|
+
{
|
|
846
|
+
usage: [`${CLI_NAME} inbox <subcommand>`],
|
|
847
|
+
notes: [
|
|
848
|
+
"Owner-authenticated inbox reads use the owner-read token path.",
|
|
849
|
+
"Owner-authenticated inbox writes require a master token unless you provide `--channel-token`.",
|
|
850
|
+
],
|
|
851
|
+
},
|
|
852
|
+
),
|
|
853
|
+
group(
|
|
854
|
+
"api",
|
|
855
|
+
"Inspect the raw API surface and make low-level requests.",
|
|
856
|
+
[
|
|
857
|
+
group(
|
|
858
|
+
"openapi",
|
|
859
|
+
"Fetch the backend OpenAPI document.",
|
|
860
|
+
[
|
|
861
|
+
command(
|
|
862
|
+
"fetch",
|
|
863
|
+
"Download the backend OpenAPI document as JSON.",
|
|
864
|
+
`${CLI_NAME} api openapi fetch [--profile <name>]`,
|
|
865
|
+
{
|
|
866
|
+
options: [PROFILE_OPTION],
|
|
867
|
+
},
|
|
868
|
+
),
|
|
869
|
+
],
|
|
870
|
+
{
|
|
871
|
+
usage: [`${CLI_NAME} api openapi <subcommand>`],
|
|
872
|
+
},
|
|
873
|
+
),
|
|
874
|
+
command(
|
|
875
|
+
"request",
|
|
876
|
+
"Send a raw API request to an `/api/v1/` path.",
|
|
877
|
+
`${CLI_NAME} api request <method> <path> [--body <json> | --body-file <path> | --stdin] [--channel-token <token>] [--profile <name>] [--json]`,
|
|
878
|
+
{
|
|
879
|
+
options: [
|
|
880
|
+
...BODY_OPTIONS,
|
|
881
|
+
CHANNEL_TOKEN_OPTION,
|
|
882
|
+
PROFILE_OPTION,
|
|
883
|
+
JSON_OPTION,
|
|
884
|
+
],
|
|
885
|
+
notes: [
|
|
886
|
+
"`api request` only accepts paths that start with `/api/v1/`.",
|
|
887
|
+
],
|
|
888
|
+
},
|
|
889
|
+
),
|
|
890
|
+
],
|
|
891
|
+
{
|
|
892
|
+
usage: [`${CLI_NAME} api <subcommand>`],
|
|
893
|
+
},
|
|
894
|
+
),
|
|
895
|
+
command(
|
|
896
|
+
"doctor",
|
|
897
|
+
"Check connectivity, configured tokens, and publish readiness.",
|
|
898
|
+
`${CLI_NAME} doctor [--channel <name-or-uuid>] [--profile <name>] [--json]`,
|
|
899
|
+
{
|
|
900
|
+
options: [
|
|
901
|
+
option(
|
|
902
|
+
"--channel <name-or-uuid>",
|
|
903
|
+
"Also resolve a target channel and report publish readiness.",
|
|
904
|
+
),
|
|
905
|
+
PROFILE_OPTION,
|
|
906
|
+
JSON_OPTION,
|
|
907
|
+
],
|
|
908
|
+
notes: [
|
|
909
|
+
"Doctor validates the OpenAPI endpoint, token availability, and optional channel diagnostics.",
|
|
910
|
+
],
|
|
911
|
+
},
|
|
912
|
+
),
|
|
913
|
+
group(
|
|
914
|
+
"skill",
|
|
915
|
+
"Install the bundled Clankmates Codex and Claude skill files.",
|
|
916
|
+
[
|
|
917
|
+
command(
|
|
918
|
+
"install",
|
|
919
|
+
"Install the bundled skill into one or more supported hosts.",
|
|
920
|
+
`${CLI_NAME} skill install [--host codex|claude|both] [--copy] [--force] [--json]`,
|
|
921
|
+
{
|
|
922
|
+
options: [
|
|
923
|
+
option(
|
|
924
|
+
"--host codex|claude|both",
|
|
925
|
+
"Choose which host receives the install.",
|
|
926
|
+
),
|
|
927
|
+
option("--copy", "Copy files instead of creating symlinks."),
|
|
928
|
+
option(
|
|
929
|
+
"--force",
|
|
930
|
+
"Replace an existing installed skill target.",
|
|
931
|
+
),
|
|
932
|
+
JSON_OPTION,
|
|
933
|
+
],
|
|
934
|
+
},
|
|
935
|
+
),
|
|
936
|
+
],
|
|
937
|
+
{
|
|
938
|
+
usage: [`${CLI_NAME} skill <subcommand>`],
|
|
939
|
+
},
|
|
940
|
+
),
|
|
941
|
+
command(
|
|
942
|
+
"version",
|
|
943
|
+
"Print the installed CLI version.",
|
|
944
|
+
`${CLI_NAME} version`,
|
|
945
|
+
),
|
|
946
|
+
],
|
|
947
|
+
{
|
|
948
|
+
description: "Use `--json` for machine consumption and scoped help for everything else.",
|
|
949
|
+
usage: [`${CLI_NAME} <command>`, `${CLI_NAME} help <command-path>`],
|
|
950
|
+
examples: [
|
|
951
|
+
`${CLI_NAME}`,
|
|
952
|
+
`${CLI_NAME} auth`,
|
|
953
|
+
`${CLI_NAME} auth key issue --help`,
|
|
954
|
+
`${CLI_NAME} help channel token`,
|
|
955
|
+
],
|
|
956
|
+
notes: [
|
|
957
|
+
"Use `--body-file` or `--stdin` for multiline content.",
|
|
958
|
+
"`--profile` wins over `CLANKMATES_PROFILE`, which wins over `activeProfile` in config.",
|
|
959
|
+
"`--base-url` wins over `CLANKMATES_BASE_URL`, which wins over the stored profile base URL.",
|
|
960
|
+
"`--profile`, `CLANKMATES_PROFILE`, and `CLANKMATES_BASE_URL` do not change config by themselves.",
|
|
961
|
+
],
|
|
962
|
+
options: GLOBAL_HELP_OPTIONS,
|
|
963
|
+
},
|
|
964
|
+
);
|
|
965
|
+
|
|
966
|
+
export function renderHelp(path: string[]): string | undefined {
|
|
967
|
+
const resolved = resolveHelpNode(path);
|
|
968
|
+
|
|
969
|
+
if (!resolved) {
|
|
970
|
+
return undefined;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
return resolved.node.kind === "group"
|
|
974
|
+
? renderGroupHelp(resolved.node, resolved.path)
|
|
975
|
+
: renderCommandHelp(resolved.node, resolved.path);
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
export function resolvesToHelpGroup(path: string[]): boolean {
|
|
979
|
+
const resolved = resolveHelpNode(path);
|
|
980
|
+
return resolved?.node.kind === "group";
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
function resolveHelpNode(
|
|
984
|
+
path: string[],
|
|
985
|
+
): { node: HelpNode; path: string[] } | undefined {
|
|
986
|
+
let node: HelpNode = HELP_ROOT;
|
|
987
|
+
const resolvedPath: string[] = [];
|
|
988
|
+
|
|
989
|
+
for (const segment of path) {
|
|
990
|
+
if (node.kind === "command") {
|
|
991
|
+
break;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
const child: HelpNode | undefined = node.children.find((candidate) =>
|
|
995
|
+
matchesSegment(candidate, segment),
|
|
996
|
+
);
|
|
997
|
+
|
|
998
|
+
if (!child) {
|
|
999
|
+
return undefined;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
node = child;
|
|
1003
|
+
resolvedPath.push(child.name);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
return { node, path: resolvedPath };
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
function matchesSegment(node: HelpNode, segment: string): boolean {
|
|
1010
|
+
return node.name === segment || node.aliases?.includes(segment) === true;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
function renderGroupHelp(node: HelpGroup, path: string[]): string {
|
|
1014
|
+
const title = path.length === 0 ? `${CLI_NAME} ${CLI_VERSION}` : `${CLI_NAME} ${path.join(" ")}`;
|
|
1015
|
+
const sections: string[] = [title];
|
|
1016
|
+
|
|
1017
|
+
if (node.description) {
|
|
1018
|
+
sections.push(node.description);
|
|
1019
|
+
} else {
|
|
1020
|
+
sections.push(node.summary);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
if (node.usage && node.usage.length > 0) {
|
|
1024
|
+
sections.push(renderUsageSection(node.usage));
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
if (node.aliases && node.aliases.length > 0) {
|
|
1028
|
+
sections.push(renderLineListSection("Aliases", node.aliases));
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
const childHeading = path.length === 0 ? "Commands" : "Subcommands";
|
|
1032
|
+
sections.push(renderEntrySection(childHeading, node.children));
|
|
1033
|
+
|
|
1034
|
+
if (node.options && node.options.length > 0) {
|
|
1035
|
+
sections.push(renderOptionSection(path.length === 0 ? "Global Flags" : "Options", node.options));
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
if (node.examples && node.examples.length > 0) {
|
|
1039
|
+
sections.push(renderLineListSection("Examples", node.examples, true));
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
if (node.notes && node.notes.length > 0) {
|
|
1043
|
+
sections.push(renderLineListSection("Notes", node.notes));
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
if (path.length === 0) {
|
|
1047
|
+
sections.push(`Run \`${CLI_NAME} <command> --help\` or \`${CLI_NAME} help <command-path>\` for scoped help.`);
|
|
1048
|
+
} else {
|
|
1049
|
+
sections.push(`Run \`${CLI_NAME} ${path.join(" ")} <subcommand> --help\` for command details.`);
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
return sections.join("\n\n");
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
function renderCommandHelp(node: HelpCommand, path: string[]): string {
|
|
1056
|
+
const title = `${CLI_NAME} ${path.join(" ")}`;
|
|
1057
|
+
const sections: string[] = [title, node.description ?? node.summary];
|
|
1058
|
+
|
|
1059
|
+
if (node.aliases && node.aliases.length > 0) {
|
|
1060
|
+
sections.push(renderLineListSection("Aliases", node.aliases));
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
if (node.usage && node.usage.length > 0) {
|
|
1064
|
+
sections.push(renderUsageSection(node.usage));
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
if (node.options && node.options.length > 0) {
|
|
1068
|
+
sections.push(renderOptionSection("Options", node.options));
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
if (node.examples && node.examples.length > 0) {
|
|
1072
|
+
sections.push(renderLineListSection("Examples", node.examples, true));
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
if (node.notes && node.notes.length > 0) {
|
|
1076
|
+
sections.push(renderLineListSection("Notes", node.notes));
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
return sections.join("\n\n");
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
function renderUsageSection(usage: string[]): string {
|
|
1083
|
+
return ["Usage:", ...usage.map((line) => ` ${line}`)].join("\n");
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
function renderEntrySection(title: string, entries: HelpNode[]): string {
|
|
1087
|
+
const labels = entries.map((entry) => formatEntryLabel(entry));
|
|
1088
|
+
const width = labels.reduce((current, label) => Math.max(current, label.length), 0);
|
|
1089
|
+
|
|
1090
|
+
return [
|
|
1091
|
+
`${title}:`,
|
|
1092
|
+
...entries.map((entry, index) => {
|
|
1093
|
+
const label = labels[index]!.padEnd(width, " ");
|
|
1094
|
+
return ` ${label} ${entry.summary}`;
|
|
1095
|
+
}),
|
|
1096
|
+
].join("\n");
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
function renderOptionSection(title: string, options: HelpOption[]): string {
|
|
1100
|
+
const width = options.reduce((current, entry) => Math.max(current, entry.flag.length), 0);
|
|
1101
|
+
|
|
1102
|
+
return [
|
|
1103
|
+
`${title}:`,
|
|
1104
|
+
...options.map((entry) => ` ${entry.flag.padEnd(width, " ")} ${entry.description}`),
|
|
1105
|
+
].join("\n");
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
function renderLineListSection(
|
|
1109
|
+
title: string,
|
|
1110
|
+
lines: string[],
|
|
1111
|
+
code = false,
|
|
1112
|
+
): string {
|
|
1113
|
+
return [
|
|
1114
|
+
`${title}:`,
|
|
1115
|
+
...lines.map((line) => ` ${code ? line : line}`),
|
|
1116
|
+
].join("\n");
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
function formatEntryLabel(entry: HelpNode): string {
|
|
1120
|
+
return entry.aliases && entry.aliases.length > 0
|
|
1121
|
+
? `${entry.name}, ${entry.aliases.join(", ")}`
|
|
1122
|
+
: entry.name;
|
|
1123
|
+
}
|