@clankmates/cli 0.4.0 → 0.5.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 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
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { runCli } from "../src/cli.ts";
4
+
5
+ const exitCode = await runCli(process.argv.slice(2));
6
+ process.exit(exitCode);
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@clankmates/cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.2",
4
4
  "devDependencies": {
5
5
  "@types/bun": "1.3.10",
6
6
  "typescript": "^5.9.3"
7
7
  },
8
8
  "bin": {
9
- "clankm": "./src/cli.ts"
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,55 @@ 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 (!command || parsed.flags.help === true) {
52
- io.stdout(helpText());
52
+ if (command === "help") {
53
+ const helpText = renderHelp(parsed.positionals, {
54
+ boldSectionTitles: shouldBoldHelpSections(io),
55
+ });
56
+
57
+ if (!helpText) {
58
+ throw new CliError(formatUnknownHelpTopic(parsed.positionals), 2);
59
+ }
60
+
61
+ io.stdout(helpText);
62
+ return 0;
63
+ }
64
+
65
+ if (!command) {
66
+ io.stdout(
67
+ renderHelp([], {
68
+ boldSectionTitles: shouldBoldHelpSections(io),
69
+ })!,
70
+ );
71
+ return 0;
72
+ }
73
+
74
+ if (parsed.flags.help === true) {
75
+ const helpText = renderHelp([command, ...parsed.positionals], {
76
+ boldSectionTitles: shouldBoldHelpSections(io),
77
+ });
78
+
79
+ if (!helpText) {
80
+ throw new CliError(
81
+ formatUnknownHelpTopic([command, ...parsed.positionals]),
82
+ 2,
83
+ );
84
+ }
85
+
86
+ io.stdout(helpText);
87
+ return 0;
88
+ }
89
+
90
+ if (resolvesToHelpGroup([command, ...parsed.positionals])) {
91
+ io.stdout(
92
+ renderHelp([command, ...parsed.positionals], {
93
+ boldSectionTitles: shouldBoldHelpSections(io),
94
+ })!,
95
+ );
53
96
  return 0;
54
97
  }
55
98
 
@@ -72,88 +115,31 @@ export async function runCli(
72
115
  }
73
116
  }
74
117
 
75
- function helpText(): string {
76
- return `${CLI_NAME} ${CLI_VERSION}
77
-
78
- Commands:
79
- ${CLI_NAME} version
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
- `;
118
+ function shouldBoldHelpSections(io: Io): boolean {
119
+ if (io.stdoutIsTTY !== true) {
120
+ return false;
121
+ }
122
+
123
+ if (process.env.NO_COLOR !== undefined) {
124
+ return false;
125
+ }
126
+
127
+ if (process.env.CLICOLOR === "0" || process.env.FORCE_COLOR === "0") {
128
+ return false;
129
+ }
130
+
131
+ if (process.env.TERM === "dumb") {
132
+ return false;
133
+ }
134
+
135
+ return true;
136
+ }
137
+
138
+ function formatUnknownHelpTopic(path: string[]): string {
139
+ const topic = path.join(" ");
140
+ return topic
141
+ ? `Unknown help topic "${topic}". See \`${CLI_NAME} --help\`.`
142
+ : `Unknown help topic. See \`${CLI_NAME} --help\`.`;
157
143
  }
158
144
 
159
145
  if (import.meta.main) {