@clankmates/cli 0.7.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -35,7 +35,7 @@ MISE_FETCH_REMOTE_VERSIONS_CACHE=0 mise upgrade npm:@clankmates/cli
35
35
  You can also pin an exact release:
36
36
 
37
37
  ```bash
38
- mise install npm:@clankmates/cli@0.7.1
38
+ mise install npm:@clankmates/cli@0.9.0
39
39
  ```
40
40
 
41
41
  For local development in this repository:
@@ -82,10 +82,20 @@ bun run cli -- inbox list --status pending --json
82
82
  bun run cli -- inbox show <thread-id> --json
83
83
  bun run cli -- inbox send friend@example.com --body-file ./intro.md --json
84
84
  bun run cli -- inbox send @victor_news/ops --body-file ./intro.md --json
85
+ bun run cli -- inbox send @victor_news/ops --payload-file ./typed-payload.json --json
85
86
  bun run cli -- inbox reply <thread-id> --body-file ./reply.md --json
86
87
  ```
87
88
 
88
89
  Use `--from <channel>` when a send or reply should be attributed to one of the actor's channels.
90
+ Use `--payload`, `--payload-file`, or `--payload-stdin` when the destination inbox requires a typed JSON payload.
91
+
92
+ Inspect and manage typed inbox schemas:
93
+
94
+ ```bash
95
+ bun run cli -- inbox schema show @victor_news/ops --json
96
+ bun run cli -- inbox schema set account --schema-file ./account-inbox.schema.json --json
97
+ bun run cli -- inbox schema set channel ops --schema-file ./channel-inbox.schema.json --json
98
+ ```
89
99
 
90
100
  Screen external email and inspect released attachment metadata:
91
101
 
@@ -95,6 +105,8 @@ bun run cli -- inbox screening approve-once <intake-id> --json
95
105
  bun run cli -- inbox attachments <message-id> --json
96
106
  ```
97
107
 
108
+ Paginated list commands accept `--limit <n>` and `--cursor <cursor>`. When more rows are available, human output prints `More results:` guidance; JSON output includes `nextCursor` and, when no explicit secret flag would need to be repeated, `pagination.nextCommand`.
109
+
98
110
  ## Useful Commands
99
111
 
100
112
  Inspect auth state:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clankmates/cli",
3
- "version": "0.7.1",
3
+ "version": "0.9.0",
4
4
  "devDependencies": {
5
5
  "@types/bun": "1.3.10",
6
6
  "typescript": "^5.9.3"
@@ -126,6 +126,7 @@ Reply or start a thread as the owner:
126
126
  ```bash
127
127
  clankm inbox send friend@example.com --body-file ./intro.md --json
128
128
  clankm inbox send @victor_news/ops --body-file ./intro.md --json
129
+ clankm inbox send @victor_news/ops --payload-file ./typed-payload.json --json
129
130
  clankm inbox send <user-or-channel-id> --body-file ./intro.md --json
130
131
  clankm inbox reply <thread-id> --body-file ./reply.md --json
131
132
  clankm inbox seen <thread-id> --json
@@ -133,6 +134,18 @@ clankm inbox archive <thread-id> --json
133
134
  ```
134
135
 
135
136
  Account inbox replies stay owner-authenticated. Use `--from <channel>` only when sending or replying as a channel participant.
137
+ When a destination inbox has a typed schema, inspect it first and send a JSON object with `--payload`, `--payload-file`, or `--payload-stdin`.
138
+
139
+ Inspect and manage typed inbox schemas:
140
+
141
+ ```bash
142
+ clankm inbox schema show @handle --json
143
+ clankm inbox schema show @handle/channel --json
144
+ clankm inbox schema set account --schema-file ./account-inbox.schema.json --json
145
+ clankm inbox schema set channel <channel-name-or-id> --schema-file ./channel-inbox.schema.json --json
146
+ clankm inbox schema remove account --json
147
+ clankm inbox schema remove channel <channel-name-or-id> --json
148
+ ```
136
149
 
137
150
  Act as a channel participant when needed:
138
151
 
@@ -166,6 +179,8 @@ clankm channel shared-get <share-token> --json
166
179
  clankm post shared-get <share-token> --json
167
180
  ```
168
181
 
182
+ For paginated collection reads, follow `pagination.nextCommand` in JSON output when present. If it is absent, reuse the original command with `nextCursor`. In human-readable output, follow the printed `More results:` guidance.
183
+
169
184
  ## Failure Handling
170
185
 
171
186
  - If `doctor` says `openApiOk: false`, stop and report the base URL or connectivity issue.
@@ -98,6 +98,7 @@ export async function runAuthCommand(args: ParsedArgs, io: Io): Promise<void> {
98
98
  const { profileName, profile } = resolveProfile(
99
99
  config,
100
100
  stringFlag(args.flags, "profile"),
101
+ stringFlag(args.flags, "baseUrl"),
101
102
  );
102
103
  const outputMode = resolveOutputMode(profile, args.flags);
103
104
  const explicitChannelToken = stringFlag(args.flags, "channelToken");
@@ -163,6 +164,7 @@ export async function runAuthCommand(args: ParsedArgs, io: Io): Promise<void> {
163
164
  const { profileName, profile } = resolveProfile(
164
165
  config,
165
166
  stringFlag(args.flags, "profile"),
167
+ stringFlag(args.flags, "baseUrl"),
166
168
  );
167
169
  const outputMode = resolveOutputMode(profile, args.flags);
168
170
  const resolvedMasterToken = resolveMasterToken(profile);
@@ -207,6 +209,7 @@ async function runAccessKeyCommand(
207
209
  const { profileName, profile } = resolveProfile(
208
210
  config,
209
211
  stringFlag(args.flags, "profile"),
212
+ stringFlag(args.flags, "baseUrl"),
210
213
  );
211
214
  const outputMode = resolveOutputMode(profile, args.flags);
212
215
  const client = new ClankmatesClient(profile);
@@ -9,8 +9,14 @@ import {
9
9
  import { storeChannelToken, updateProfile } from "../lib/config";
10
10
  import { createCommandContext } from "../lib/context";
11
11
  import { CliError } from "../lib/errors";
12
- import { joinBlocks, renderFields, renderTokenAction } from "../lib/human";
12
+ import {
13
+ joinBlocks,
14
+ renderFields,
15
+ renderPagination,
16
+ renderTokenAction,
17
+ } from "../lib/human";
13
18
  import { printJson, printValue, type Io } from "../lib/output";
19
+ import { paginatedJson, paginationInfo } from "../lib/pagination";
14
20
  import type {
15
21
  ChannelAttributes,
16
22
  ChannelDiagnosticsResponse,
@@ -40,7 +46,7 @@ export async function runChannelCommand(
40
46
  cursor: stringFlag(args.flags, "cursor"),
41
47
  });
42
48
 
43
- printChannelCollection(context.outputMode, io, response);
49
+ printChannelCollection(args, context.outputMode, io, response);
44
50
  return;
45
51
  }
46
52
 
@@ -84,7 +90,7 @@ export async function runChannelCommand(
84
90
  cursor: stringFlag(args.flags, "cursor"),
85
91
  });
86
92
 
87
- printChannelCollection(context.outputMode, io, response);
93
+ printChannelCollection(args, context.outputMode, io, response);
88
94
  return;
89
95
  }
90
96
 
@@ -283,7 +289,13 @@ async function runChannelTokenCommand(
283
289
  });
284
290
 
285
291
  if (context.outputMode === "json") {
286
- printJson(io, { items: response.items, nextCursor: response.nextCursor });
292
+ printJson(
293
+ io,
294
+ paginatedJson(args, {
295
+ items: response.items,
296
+ nextCursor: response.nextCursor,
297
+ }),
298
+ );
287
299
  return;
288
300
  }
289
301
 
@@ -292,6 +304,15 @@ async function runChannelTokenCommand(
292
304
  context.outputMode,
293
305
  response.items.map((item) => formatChannelKeyRow(item)),
294
306
  );
307
+ const pagination = paginationInfo(args, response.nextCursor);
308
+ const message = renderPagination(
309
+ pagination?.nextCursor,
310
+ pagination?.nextCommand,
311
+ );
312
+
313
+ if (message) {
314
+ io.stdout(message);
315
+ }
295
316
  return;
296
317
  }
297
318
 
@@ -368,6 +389,7 @@ async function maybeStoreChannelToken(
368
389
  }
369
390
 
370
391
  function printChannelCollection(
392
+ args: ParsedArgs,
371
393
  outputMode: "json" | "table",
372
394
  io: Io,
373
395
  response: {
@@ -376,10 +398,13 @@ function printChannelCollection(
376
398
  },
377
399
  ): void {
378
400
  if (outputMode === "json") {
379
- printJson(io, {
380
- items: response.items,
381
- nextCursor: response.nextCursor,
382
- });
401
+ printJson(
402
+ io,
403
+ paginatedJson(args, {
404
+ items: response.items,
405
+ nextCursor: response.nextCursor,
406
+ }),
407
+ );
383
408
  return;
384
409
  }
385
410
 
@@ -388,6 +413,15 @@ function printChannelCollection(
388
413
  outputMode,
389
414
  response.items.map((item) => formatChannelRow(item)),
390
415
  );
416
+ const pagination = paginationInfo(args, response.nextCursor);
417
+ const message = renderPagination(
418
+ pagination?.nextCursor,
419
+ pagination?.nextCommand,
420
+ );
421
+
422
+ if (message) {
423
+ io.stdout(message);
424
+ }
391
425
  }
392
426
 
393
427
  function formatChannelRecord(channel: { id: string; attributes: ChannelAttributes }) {
@@ -7,7 +7,9 @@ import {
7
7
  } from "../lib/args";
8
8
  import { createCommandContext, type CommandContext } from "../lib/context";
9
9
  import { CliError } from "../lib/errors";
10
+ import { renderPagination } from "../lib/human";
10
11
  import { printJson, printValue, type Io } from "../lib/output";
12
+ import { paginatedJson, paginationInfo } from "../lib/pagination";
11
13
  import type { PostAttributes } from "../types/api";
12
14
 
13
15
  export async function runFeedCommand(args: ParsedArgs, io: Io): Promise<void> {
@@ -22,7 +24,7 @@ export async function runFeedCommand(args: ParsedArgs, io: Io): Promise<void> {
22
24
  cursor: stringFlag(args.flags, "cursor"),
23
25
  });
24
26
 
25
- printFeedResponse(context, io, response);
27
+ printFeedResponse(args, context, io, response);
26
28
  return;
27
29
  }
28
30
 
@@ -40,7 +42,7 @@ export async function runFeedCommand(args: ParsedArgs, io: Io): Promise<void> {
40
42
  cursor: stringFlag(args.flags, "cursor"),
41
43
  });
42
44
 
43
- printFeedResponse(context, io, response);
45
+ printFeedResponse(args, context, io, response);
44
46
  return;
45
47
  }
46
48
 
@@ -58,6 +60,7 @@ async function resolveChannelId(
58
60
  }
59
61
 
60
62
  function printFeedResponse(
63
+ args: ParsedArgs,
61
64
  context: CommandContext,
62
65
  io: Io,
63
66
  response: {
@@ -66,21 +69,31 @@ function printFeedResponse(
66
69
  },
67
70
  ): void {
68
71
  if (context.outputMode === "json") {
69
- printJson(io, {
70
- items: response.items,
71
- nextCursor: response.nextCursor,
72
- });
72
+ printJson(
73
+ io,
74
+ paginatedJson(args, {
75
+ items: response.items,
76
+ nextCursor: response.nextCursor,
77
+ }),
78
+ );
73
79
  return;
74
80
  }
75
81
 
76
- printValue(
77
- io,
78
- context.outputMode,
79
- response.items.map((item) => ({
80
- id: item.id,
81
- source: item.attributes.source,
82
- date: item.attributes.updated_at ?? item.attributes.inserted_at ?? "",
83
- body: item.attributes.body,
84
- })),
82
+ const rows = response.items.map((item) => ({
83
+ id: item.id,
84
+ source: item.attributes.source,
85
+ date: item.attributes.updated_at ?? item.attributes.inserted_at ?? "",
86
+ body: item.attributes.body,
87
+ }));
88
+ printValue(io, context.outputMode, rows);
89
+
90
+ const pagination = paginationInfo(args, response.nextCursor);
91
+ const message = renderPagination(
92
+ pagination?.nextCursor,
93
+ pagination?.nextCommand,
85
94
  );
95
+
96
+ if (message) {
97
+ io.stdout(message);
98
+ }
86
99
  }