@clankmates/cli 0.11.0 → 0.12.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 +14 -3
- package/package.json +1 -1
- package/skills/codex/clankmates/SKILL.md +4 -3
- package/src/cli.ts +2 -0
- package/src/commands/cache.ts +124 -0
- package/src/commands/feed.ts +192 -11
- package/src/commands/inbox.ts +290 -16
- package/src/commands/post.ts +195 -20
- package/src/lib/args.ts +11 -0
- package/src/lib/cache.ts +553 -0
- package/src/lib/client.ts +40 -1
- package/src/lib/help.ts +109 -10
- package/src/lib/pagination.ts +16 -0
- package/src/lib/paths.ts +26 -0
- package/src/types/api.ts +1 -0
package/src/commands/post.ts
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertSinceFlags,
|
|
3
|
+
authenticatedActorKey,
|
|
4
|
+
cacheFlags,
|
|
5
|
+
cacheResult,
|
|
6
|
+
ownedPostsScope,
|
|
7
|
+
prepareCachePlan,
|
|
8
|
+
publicPostsScope,
|
|
9
|
+
saveCacheTimestamp,
|
|
10
|
+
sharedPostsScope,
|
|
11
|
+
type CachePlan,
|
|
12
|
+
type CacheResult,
|
|
13
|
+
type CacheScope,
|
|
14
|
+
} from "../lib/cache";
|
|
1
15
|
import {
|
|
2
16
|
booleanFlag,
|
|
3
17
|
integerFlag,
|
|
@@ -50,52 +64,112 @@ export async function runPostCommand(args: ParsedArgs, io: Io): Promise<void> {
|
|
|
50
64
|
}
|
|
51
65
|
|
|
52
66
|
case "list": {
|
|
67
|
+
assertSinceFlags(args);
|
|
68
|
+
const channelId = await context.client.resolveChannelId(
|
|
69
|
+
requiredChannelFlag(args.flags),
|
|
70
|
+
);
|
|
71
|
+
const cacheScope = await maybeOwnedPostsScope(args, context, channelId);
|
|
72
|
+
const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
|
|
53
73
|
const response = await context.client.listChannelPosts({
|
|
54
|
-
channelId
|
|
55
|
-
requiredChannelFlag(args.flags),
|
|
56
|
-
),
|
|
74
|
+
channelId,
|
|
57
75
|
limit: integerFlag(args.flags, "limit", { label: "--limit" }),
|
|
58
76
|
cursor: stringFlag(args.flags, "cursor"),
|
|
77
|
+
before: stringFlag(args.flags, "before"),
|
|
59
78
|
order: parseLatestFirstOrder(stringFlag(args.flags, "order")),
|
|
60
|
-
since:
|
|
79
|
+
since: resolvedSince(args, cachePlan),
|
|
61
80
|
});
|
|
81
|
+
const savedServerTimestamp = await maybeSaveCacheTimestamp(
|
|
82
|
+
args,
|
|
83
|
+
context,
|
|
84
|
+
cacheScope,
|
|
85
|
+
response.meta,
|
|
86
|
+
response.nextCursor === undefined,
|
|
87
|
+
);
|
|
62
88
|
|
|
63
|
-
printPostCollection(
|
|
89
|
+
printPostCollection(
|
|
90
|
+
args,
|
|
91
|
+
context.outputMode,
|
|
92
|
+
io,
|
|
93
|
+
response,
|
|
94
|
+
cacheResult(cachePlan, savedServerTimestamp),
|
|
95
|
+
);
|
|
64
96
|
return;
|
|
65
97
|
}
|
|
66
98
|
|
|
67
99
|
case "public-list": {
|
|
100
|
+
assertSinceFlags(args);
|
|
101
|
+
const publicHandle = requiredPositional(
|
|
102
|
+
args.positionals,
|
|
103
|
+
1,
|
|
104
|
+
"Missing public handle",
|
|
105
|
+
);
|
|
106
|
+
const channelName = requiredPositional(
|
|
107
|
+
args.positionals,
|
|
108
|
+
2,
|
|
109
|
+
"Missing public channel name",
|
|
110
|
+
);
|
|
111
|
+
const cacheScope = maybePublicPostsScope(
|
|
112
|
+
args,
|
|
113
|
+
context,
|
|
114
|
+
publicHandle,
|
|
115
|
+
channelName,
|
|
116
|
+
);
|
|
117
|
+
const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
|
|
68
118
|
const response = await context.client.listPublicChannelPosts({
|
|
69
|
-
publicHandle
|
|
70
|
-
|
|
71
|
-
1,
|
|
72
|
-
"Missing public handle",
|
|
73
|
-
),
|
|
74
|
-
channelName: requiredPositional(
|
|
75
|
-
args.positionals,
|
|
76
|
-
2,
|
|
77
|
-
"Missing public channel name",
|
|
78
|
-
),
|
|
119
|
+
publicHandle,
|
|
120
|
+
channelName,
|
|
79
121
|
limit: integerFlag(args.flags, "limit", { label: "--limit" }),
|
|
80
122
|
cursor: stringFlag(args.flags, "cursor"),
|
|
123
|
+
before: stringFlag(args.flags, "before"),
|
|
81
124
|
order: parseLatestFirstOrder(stringFlag(args.flags, "order")),
|
|
82
|
-
since:
|
|
125
|
+
since: resolvedSince(args, cachePlan),
|
|
83
126
|
});
|
|
127
|
+
const savedServerTimestamp = await maybeSaveCacheTimestamp(
|
|
128
|
+
args,
|
|
129
|
+
context,
|
|
130
|
+
cacheScope,
|
|
131
|
+
response.meta,
|
|
132
|
+
response.nextCursor === undefined,
|
|
133
|
+
);
|
|
84
134
|
|
|
85
|
-
printPostCollection(
|
|
135
|
+
printPostCollection(
|
|
136
|
+
args,
|
|
137
|
+
context.outputMode,
|
|
138
|
+
io,
|
|
139
|
+
response,
|
|
140
|
+
cacheResult(cachePlan, savedServerTimestamp),
|
|
141
|
+
);
|
|
86
142
|
return;
|
|
87
143
|
}
|
|
88
144
|
|
|
89
145
|
case "shared-list": {
|
|
146
|
+
assertSinceFlags(args);
|
|
147
|
+
const token = requiredPositional(args.positionals, 1, "Missing share token");
|
|
148
|
+
const cacheScope = maybeSharedPostsScope(args, context, token);
|
|
149
|
+
const cachePlan = await maybePrepareCachePlan(args, context, cacheScope);
|
|
90
150
|
const response = await context.client.listSharedChannelPosts({
|
|
91
|
-
token
|
|
151
|
+
token,
|
|
92
152
|
limit: integerFlag(args.flags, "limit", { label: "--limit" }),
|
|
93
153
|
cursor: stringFlag(args.flags, "cursor"),
|
|
154
|
+
before: stringFlag(args.flags, "before"),
|
|
94
155
|
order: parseLatestFirstOrder(stringFlag(args.flags, "order")),
|
|
95
|
-
since:
|
|
156
|
+
since: resolvedSince(args, cachePlan),
|
|
96
157
|
});
|
|
158
|
+
const savedServerTimestamp = await maybeSaveCacheTimestamp(
|
|
159
|
+
args,
|
|
160
|
+
context,
|
|
161
|
+
cacheScope,
|
|
162
|
+
response.meta,
|
|
163
|
+
response.nextCursor === undefined,
|
|
164
|
+
);
|
|
97
165
|
|
|
98
|
-
printPostCollection(
|
|
166
|
+
printPostCollection(
|
|
167
|
+
args,
|
|
168
|
+
context.outputMode,
|
|
169
|
+
io,
|
|
170
|
+
response,
|
|
171
|
+
cacheResult(cachePlan, savedServerTimestamp),
|
|
172
|
+
);
|
|
99
173
|
return;
|
|
100
174
|
}
|
|
101
175
|
|
|
@@ -234,6 +308,7 @@ function printPostCollection(
|
|
|
234
308
|
nextCursor?: string;
|
|
235
309
|
meta?: Record<string, unknown>;
|
|
236
310
|
},
|
|
311
|
+
cache?: CacheResult,
|
|
237
312
|
): void {
|
|
238
313
|
if (outputMode === "json") {
|
|
239
314
|
printJson(
|
|
@@ -242,6 +317,7 @@ function printPostCollection(
|
|
|
242
317
|
items: response.items,
|
|
243
318
|
nextCursor: response.nextCursor,
|
|
244
319
|
meta: response.meta,
|
|
320
|
+
...(cache ? { cache } : {}),
|
|
245
321
|
}),
|
|
246
322
|
);
|
|
247
323
|
return;
|
|
@@ -267,6 +343,8 @@ function printPostCollection(
|
|
|
267
343
|
if (message) {
|
|
268
344
|
io.stdout(message);
|
|
269
345
|
}
|
|
346
|
+
|
|
347
|
+
printCacheNote(io, cache);
|
|
270
348
|
}
|
|
271
349
|
|
|
272
350
|
function parseLatestFirstOrder(value: string | undefined): LatestFirstOrder | undefined {
|
|
@@ -281,6 +359,103 @@ function parseLatestFirstOrder(value: string | undefined): LatestFirstOrder | un
|
|
|
281
359
|
throw new CliError("--order must be one of: latest, oldest", 2);
|
|
282
360
|
}
|
|
283
361
|
|
|
362
|
+
async function maybePrepareCachePlan(
|
|
363
|
+
args: ParsedArgs,
|
|
364
|
+
context: Awaited<ReturnType<typeof createCommandContext>>,
|
|
365
|
+
scope: CacheScope | undefined,
|
|
366
|
+
): Promise<CachePlan | undefined> {
|
|
367
|
+
return cacheFlags(args).sinceCache && scope
|
|
368
|
+
? prepareCachePlan(context, scope)
|
|
369
|
+
: undefined;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
async function maybeSaveCacheTimestamp(
|
|
373
|
+
args: ParsedArgs,
|
|
374
|
+
context: Awaited<ReturnType<typeof createCommandContext>>,
|
|
375
|
+
scope: CacheScope | undefined,
|
|
376
|
+
meta: Record<string, unknown> | undefined,
|
|
377
|
+
shouldSave: boolean,
|
|
378
|
+
): Promise<string | undefined> {
|
|
379
|
+
return cacheFlags(args).saveCache && scope && shouldSave
|
|
380
|
+
? saveCacheTimestamp(context, scope, meta)
|
|
381
|
+
: undefined;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
async function maybeOwnedPostsScope(
|
|
385
|
+
args: ParsedArgs,
|
|
386
|
+
context: Awaited<ReturnType<typeof createCommandContext>>,
|
|
387
|
+
channelId: string,
|
|
388
|
+
): Promise<CacheScope | undefined> {
|
|
389
|
+
if (!cacheFlags(args).sinceCache && !cacheFlags(args).saveCache) {
|
|
390
|
+
return undefined;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return ownedPostsScope({
|
|
394
|
+
context,
|
|
395
|
+
actorKey: await authenticatedActorKey(context),
|
|
396
|
+
channelId,
|
|
397
|
+
before: stringFlag(args.flags, "before"),
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function maybePublicPostsScope(
|
|
402
|
+
args: ParsedArgs,
|
|
403
|
+
context: Awaited<ReturnType<typeof createCommandContext>>,
|
|
404
|
+
publicHandle: string,
|
|
405
|
+
channelName: string,
|
|
406
|
+
): CacheScope | undefined {
|
|
407
|
+
if (!cacheFlags(args).sinceCache && !cacheFlags(args).saveCache) {
|
|
408
|
+
return undefined;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return publicPostsScope({
|
|
412
|
+
context,
|
|
413
|
+
publicHandle,
|
|
414
|
+
channelName,
|
|
415
|
+
before: stringFlag(args.flags, "before"),
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function maybeSharedPostsScope(
|
|
420
|
+
args: ParsedArgs,
|
|
421
|
+
context: Awaited<ReturnType<typeof createCommandContext>>,
|
|
422
|
+
shareToken: string,
|
|
423
|
+
): CacheScope | undefined {
|
|
424
|
+
if (!cacheFlags(args).sinceCache && !cacheFlags(args).saveCache) {
|
|
425
|
+
return undefined;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return sharedPostsScope({
|
|
429
|
+
context,
|
|
430
|
+
shareToken,
|
|
431
|
+
before: stringFlag(args.flags, "before"),
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function resolvedSince(
|
|
436
|
+
args: ParsedArgs,
|
|
437
|
+
cachePlan: CachePlan | undefined,
|
|
438
|
+
): string | undefined {
|
|
439
|
+
return stringFlag(args.flags, "since") ?? cachePlan?.previousServerTimestamp;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function printCacheNote(io: Io, cache: CacheResult | undefined): void {
|
|
443
|
+
if (!cache) {
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
const details = [
|
|
448
|
+
cache.previousServerTimestamp
|
|
449
|
+
? `used ${cache.previousServerTimestamp}`
|
|
450
|
+
: cache.hit
|
|
451
|
+
? "used cache"
|
|
452
|
+
: "no cached timestamp",
|
|
453
|
+
cache.savedServerTimestamp ? `saved ${cache.savedServerTimestamp}` : undefined,
|
|
454
|
+
].filter(Boolean);
|
|
455
|
+
|
|
456
|
+
io.stdout(`Cache: ${details.join("; ")}.`);
|
|
457
|
+
}
|
|
458
|
+
|
|
284
459
|
function renderPostDetail(
|
|
285
460
|
post: { id: string; attributes: PostAttributes },
|
|
286
461
|
options: { title?: string; channelId?: string } = {},
|
package/src/lib/args.ts
CHANGED
|
@@ -49,10 +49,21 @@ const CLI_OPTIONS = {
|
|
|
49
49
|
"schema-stdin": { type: "boolean" },
|
|
50
50
|
limit: { type: "string" },
|
|
51
51
|
cursor: { type: "string" },
|
|
52
|
+
before: { type: "string" },
|
|
52
53
|
order: { type: "string" },
|
|
53
54
|
since: { type: "string" },
|
|
55
|
+
sinceCache: { type: "boolean" },
|
|
56
|
+
"since-cache": { type: "boolean" },
|
|
57
|
+
saveCache: { type: "boolean" },
|
|
58
|
+
"save-cache": { type: "boolean" },
|
|
54
59
|
status: { type: "string" },
|
|
55
60
|
mailbox: { type: "string" },
|
|
61
|
+
participant: { type: "string" },
|
|
62
|
+
participantScope: { type: "string" },
|
|
63
|
+
"participant-scope": { type: "string" },
|
|
64
|
+
query: { type: "string" },
|
|
65
|
+
hasAttachment: { type: "boolean" },
|
|
66
|
+
"has-attachment": { type: "boolean" },
|
|
56
67
|
} as const;
|
|
57
68
|
|
|
58
69
|
type ParsedValue = string | boolean;
|