@geoly-ai/social-hub-cli 0.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.
Files changed (65) hide show
  1. package/dist/client.d.ts +5 -0
  2. package/dist/client.d.ts.map +1 -0
  3. package/dist/client.js +23 -0
  4. package/dist/client.js.map +1 -0
  5. package/dist/config.d.ts +24 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/config.js +96 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/config.test.d.ts +2 -0
  10. package/dist/config.test.d.ts.map +1 -0
  11. package/dist/config.test.js +13 -0
  12. package/dist/config.test.js.map +1 -0
  13. package/dist/context-state.d.ts +9 -0
  14. package/dist/context-state.d.ts.map +1 -0
  15. package/dist/context-state.js +29 -0
  16. package/dist/context-state.js.map +1 -0
  17. package/dist/dry-run.d.ts +12 -0
  18. package/dist/dry-run.d.ts.map +1 -0
  19. package/dist/dry-run.js +18 -0
  20. package/dist/dry-run.js.map +1 -0
  21. package/dist/dry-run.test.d.ts +2 -0
  22. package/dist/dry-run.test.d.ts.map +1 -0
  23. package/dist/dry-run.test.js +21 -0
  24. package/dist/dry-run.test.js.map +1 -0
  25. package/dist/index.d.ts +5 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +1342 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/index.test.d.ts +2 -0
  30. package/dist/index.test.d.ts.map +1 -0
  31. package/dist/index.test.js +303 -0
  32. package/dist/index.test.js.map +1 -0
  33. package/dist/output.d.ts +9 -0
  34. package/dist/output.d.ts.map +1 -0
  35. package/dist/output.js +75 -0
  36. package/dist/output.js.map +1 -0
  37. package/dist/permissions.d.ts +32 -0
  38. package/dist/permissions.d.ts.map +1 -0
  39. package/dist/permissions.js +101 -0
  40. package/dist/permissions.js.map +1 -0
  41. package/dist/permissions.test.d.ts +2 -0
  42. package/dist/permissions.test.d.ts.map +1 -0
  43. package/dist/permissions.test.js +17 -0
  44. package/dist/permissions.test.js.map +1 -0
  45. package/dist/register-admin.d.ts +3 -0
  46. package/dist/register-admin.d.ts.map +1 -0
  47. package/dist/register-admin.js +100 -0
  48. package/dist/register-admin.js.map +1 -0
  49. package/dist/register-batch.d.ts +3 -0
  50. package/dist/register-batch.d.ts.map +1 -0
  51. package/dist/register-batch.js +85 -0
  52. package/dist/register-batch.js.map +1 -0
  53. package/dist/register-extensions.d.ts +9 -0
  54. package/dist/register-extensions.d.ts.map +1 -0
  55. package/dist/register-extensions.js +550 -0
  56. package/dist/register-extensions.js.map +1 -0
  57. package/dist/register-ops.d.ts +4 -0
  58. package/dist/register-ops.d.ts.map +1 -0
  59. package/dist/register-ops.js +152 -0
  60. package/dist/register-ops.js.map +1 -0
  61. package/dist/register-shared.d.ts +3 -0
  62. package/dist/register-shared.d.ts.map +1 -0
  63. package/dist/register-shared.js +145 -0
  64. package/dist/register-shared.js.map +1 -0
  65. package/package.json +35 -0
package/dist/index.js ADDED
@@ -0,0 +1,1342 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { getSocialHubHealth } from "@geoly-ai/social-hub-sdk";
4
+ import { getBaseUrl, requireClient } from "./client.js";
5
+ import { registerAccountsExtensions, registerAuthAndConfig, registerPermissionsExplain, registerRedditExtensions, } from "./register-extensions.js";
6
+ import { registerAdminCommands } from "./register-admin.js";
7
+ import { registerBatchAndExport } from "./register-batch.js";
8
+ import { registerAgentContext, registerOpsRuntime, } from "./register-ops.js";
9
+ import { registerDoctorAndVersion } from "./register-shared.js";
10
+ const program = new Command();
11
+ program
12
+ .name("social-hub")
13
+ .description("Social Ops Hub CLI(API 与 @geoly-ai/social-hub-sdk 对齐)")
14
+ .showHelpAfterError();
15
+ registerAuthAndConfig(program);
16
+ registerDoctorAndVersion(program);
17
+ registerOpsRuntime(program);
18
+ registerAgentContext(program);
19
+ registerAdminCommands(program);
20
+ registerBatchAndExport(program);
21
+ program
22
+ .command("health")
23
+ .description("GET /health(无需 API Key)")
24
+ .action(async () => {
25
+ const baseUrl = getBaseUrl();
26
+ try {
27
+ const h = await getSocialHubHealth(baseUrl);
28
+ console.log(JSON.stringify(h, null, 2));
29
+ }
30
+ catch (e) {
31
+ console.error(e instanceof Error ? e.message : e);
32
+ process.exit(1);
33
+ }
34
+ });
35
+ // --- events ---
36
+ const events = program.command("events").description("互动事件");
37
+ events
38
+ .command("append")
39
+ .requiredOption("-t, --team <teamId>", "Team UUID")
40
+ .requiredOption("--type <type>", "事件类型,如 comment")
41
+ .option("--payload <json>", "JSON 对象", "{}")
42
+ .action(async (opts) => {
43
+ let payload = {};
44
+ try {
45
+ payload = JSON.parse(opts.payload ?? "{}");
46
+ }
47
+ catch {
48
+ console.error("Invalid --payload JSON");
49
+ process.exit(1);
50
+ }
51
+ const res = await requireClient().appendEvent(opts.team, {
52
+ type: opts.type,
53
+ payload,
54
+ });
55
+ console.log(JSON.stringify(res, null, 2));
56
+ });
57
+ events
58
+ .command("list")
59
+ .requiredOption("-t, --team <teamId>", "Team UUID")
60
+ .option("-n, --limit <n>", "条数", "20")
61
+ .action(async (opts) => {
62
+ const res = await requireClient().listEvents(opts.team, Number(opts.limit));
63
+ console.log(JSON.stringify(res, null, 2));
64
+ });
65
+ events
66
+ .command("batch")
67
+ .description("POST /events/batch")
68
+ .requiredOption("-t, --team <teamId>", "Team UUID")
69
+ .requiredOption("-j, --json <json>", '{ "events": [ ... ] }')
70
+ .action(async (opts) => {
71
+ let body;
72
+ try {
73
+ body = JSON.parse(opts.json);
74
+ }
75
+ catch {
76
+ console.error("Invalid -j / --json");
77
+ process.exit(1);
78
+ }
79
+ const res = await requireClient().appendEventsBatch(opts.team, body);
80
+ console.log(JSON.stringify(res, null, 2));
81
+ });
82
+ // --- dashboard ---
83
+ const dashboard = program.command("dashboard").description("运营总览");
84
+ dashboard
85
+ .command("summary")
86
+ .description("GET /dashboard/summary")
87
+ .requiredOption("-t, --team <teamId>", "Team UUID")
88
+ .option("--from <iso>", "from ISO 日期")
89
+ .option("--to <iso>", "to ISO 日期")
90
+ .option("--trend-days <n>", "interactionTrendDays: 7 | 14 | 30")
91
+ .option("--campaign <uuid>", "campaignId 过滤")
92
+ .option("--brand <uuid>", "brandId 过滤")
93
+ .action(async (opts) => {
94
+ const res = await requireClient().getDashboardSummary(opts.team, {
95
+ from: opts.from,
96
+ to: opts.to,
97
+ interactionTrendDays: opts.trendDays ? Number(opts.trendDays) : undefined,
98
+ campaignId: opts.campaign,
99
+ brandId: opts.brand,
100
+ });
101
+ console.log(JSON.stringify(res, null, 2));
102
+ });
103
+ // --- calendar ---
104
+ const calendar = program.command("calendar").description("发布日历条目");
105
+ calendar
106
+ .command("list")
107
+ .description("GET /calendar-entries")
108
+ .requiredOption("-t, --team <teamId>", "Team UUID")
109
+ .option("--campaign <uuid>", "campaignId")
110
+ .option("--status <st>", "scheduled | running | succeeded | …")
111
+ .option("--from <iso>", "from 时间 ISO")
112
+ .option("--to <iso>", "to 时间 ISO")
113
+ .option("-n, --limit <n>", "limit", "50")
114
+ .action(async (opts) => {
115
+ const res = await requireClient().listCalendarEntries(opts.team, {
116
+ campaignId: opts.campaign,
117
+ status: opts.status,
118
+ from: opts.from,
119
+ to: opts.to,
120
+ limit: Number(opts.limit),
121
+ });
122
+ console.log(JSON.stringify(res, null, 2));
123
+ });
124
+ calendar
125
+ .command("patch")
126
+ .description("PATCH /calendar-entries/:id(--body 为 JSON)")
127
+ .requiredOption("-t, --team <teamId>", "Team UUID")
128
+ .requiredOption("-e, --entry <entryId>", "Calendar entry UUID")
129
+ .requiredOption("--body <json>", '例如 {"status":"succeeded","permalink":"https://www.reddit.com/..."}')
130
+ .action(async (opts) => {
131
+ let body;
132
+ try {
133
+ body = JSON.parse(opts.body);
134
+ }
135
+ catch {
136
+ console.error("Invalid --body JSON");
137
+ process.exit(1);
138
+ }
139
+ const res = await requireClient().updateCalendarEntry(opts.team, opts.entry, body);
140
+ console.log(JSON.stringify(res, null, 2));
141
+ });
142
+ // --- reddit ---
143
+ const reddit = program.command("reddit").description("Reddit 帖快照");
144
+ registerRedditExtensions(reddit);
145
+ reddit
146
+ .command("list")
147
+ .description("GET /reddit-post-snapshots")
148
+ .requiredOption("-t, --team <teamId>", "Team UUID")
149
+ .option("--campaign <uuid>", "campaignId")
150
+ .option("--entry <uuid>", "calendarEntryId")
151
+ .option("-n, --limit <n>", "limit", "100")
152
+ .action(async (opts) => {
153
+ const res = await requireClient().listRedditPostSnapshots(opts.team, {
154
+ limit: Number(opts.limit),
155
+ campaignId: opts.campaign,
156
+ calendarEntryId: opts.entry,
157
+ });
158
+ console.log(JSON.stringify(res, null, 2));
159
+ });
160
+ reddit
161
+ .command("create-snapshot")
162
+ .description("POST /reddit-post-snapshots(手工补录)")
163
+ .requiredOption("-t, --team <teamId>", "Team UUID")
164
+ .requiredOption("-j, --json <json>", "createRedditPostSnapshot body JSON")
165
+ .action(async (opts) => {
166
+ let body;
167
+ try {
168
+ body = JSON.parse(opts.json);
169
+ }
170
+ catch {
171
+ console.error("Invalid -j / --json");
172
+ process.exit(1);
173
+ }
174
+ const res = await requireClient().createRedditPostSnapshot(opts.team, body);
175
+ console.log(JSON.stringify(res, null, 2));
176
+ });
177
+ // --- jobs ---
178
+ const jobs = program.command("jobs").description("调度任务(scheduled jobs)");
179
+ jobs
180
+ .command("list")
181
+ .description("GET /scheduled-jobs")
182
+ .requiredOption("-t, --team <teamId>", "Team UUID")
183
+ .option("--status <st>", "scheduled | running | …")
184
+ .option("-n, --limit <n>", "limit", "50")
185
+ .action(async (opts) => {
186
+ const res = await requireClient().listScheduledJobs(opts.team, {
187
+ limit: Number(opts.limit),
188
+ status: opts.status,
189
+ });
190
+ console.log(JSON.stringify(res, null, 2));
191
+ });
192
+ jobs
193
+ .command("summary")
194
+ .description("GET /scheduled-jobs/automation-summary")
195
+ .requiredOption("-t, --team <teamId>", "Team UUID")
196
+ .option("--hours <n>", "时间窗口(小时)", "24")
197
+ .action(async (opts) => {
198
+ const res = await requireClient().getScheduledJobsAutomationSummary(opts.team, Number(opts.hours));
199
+ console.log(JSON.stringify(res, null, 2));
200
+ });
201
+ jobs
202
+ .command("create")
203
+ .description("POST /scheduled-jobs(--json 为完整 body)")
204
+ .requiredOption("-t, --team <teamId>", "Team UUID")
205
+ .requiredOption("-j, --json <json>", "createScheduledJobBody JSON")
206
+ .action(async (opts) => {
207
+ let body;
208
+ try {
209
+ body = JSON.parse(opts.json);
210
+ }
211
+ catch {
212
+ console.error("Invalid -j / --json");
213
+ process.exit(1);
214
+ }
215
+ const res = await requireClient().createScheduledJob(opts.team, body);
216
+ console.log(JSON.stringify(res, null, 2));
217
+ });
218
+ jobs
219
+ .command("batch")
220
+ .description("POST /scheduled-jobs/batch")
221
+ .requiredOption("-t, --team <teamId>", "Team UUID")
222
+ .requiredOption("-j, --json <json>", '{ "jobs": [ ... ] }')
223
+ .action(async (opts) => {
224
+ let body;
225
+ try {
226
+ body = JSON.parse(opts.json);
227
+ }
228
+ catch {
229
+ console.error("Invalid -j / --json");
230
+ process.exit(1);
231
+ }
232
+ const res = await requireClient().createScheduledJobsBatch(opts.team, body);
233
+ console.log(JSON.stringify(res, null, 2));
234
+ });
235
+ jobs
236
+ .command("retry")
237
+ .description("POST /scheduled-jobs/:id/retry")
238
+ .requiredOption("-t, --team <teamId>", "Team UUID")
239
+ .requiredOption("-i, --id <jobId>", "Job UUID")
240
+ .action(async (opts) => {
241
+ const res = await requireClient().retryScheduledJob(opts.team, opts.id);
242
+ console.log(JSON.stringify(res, null, 2));
243
+ });
244
+ jobs
245
+ .command("cancel")
246
+ .description("POST /scheduled-jobs/:id/cancel")
247
+ .requiredOption("-t, --team <teamId>", "Team UUID")
248
+ .requiredOption("-i, --id <jobId>", "Job UUID")
249
+ .action(async (opts) => {
250
+ const res = await requireClient().cancelScheduledJob(opts.team, opts.id);
251
+ console.log(JSON.stringify(res, null, 2));
252
+ });
253
+ // --- drafts & reports ---
254
+ const drafts = program.command("drafts").description("内容草稿");
255
+ drafts
256
+ .command("list")
257
+ .description("GET /content-drafts")
258
+ .requiredOption("-t, --team <teamId>", "Team UUID")
259
+ .option("-n, --limit <n>", "limit", "50")
260
+ .action(async (opts) => {
261
+ const res = await requireClient().listContentDrafts(opts.team, Number(opts.limit));
262
+ console.log(JSON.stringify(res, null, 2));
263
+ });
264
+ const reports = program.command("reports").description("报告库");
265
+ reports
266
+ .command("list")
267
+ .description("GET /reports")
268
+ .requiredOption("-t, --team <teamId>", "Team UUID")
269
+ .option("-n, --limit <n>", "limit", "50")
270
+ .option("--type <t>", "reddit-post-snapshot | account-status-snapshot | campaign-digest")
271
+ .action(async (opts) => {
272
+ const res = await requireClient().listReports(opts.team, {
273
+ limit: Number(opts.limit),
274
+ reportType: opts.type,
275
+ });
276
+ console.log(JSON.stringify(res, null, 2));
277
+ });
278
+ reports
279
+ .command("ingest")
280
+ .description("POST /reports/ingest")
281
+ .requiredOption("-t, --team <teamId>", "Team UUID")
282
+ .requiredOption("-j, --json <json>", "{ reportType, source, traceId? }")
283
+ .action(async (opts) => {
284
+ let body;
285
+ try {
286
+ body = JSON.parse(opts.json);
287
+ }
288
+ catch {
289
+ console.error("Invalid -j / --json");
290
+ process.exit(1);
291
+ }
292
+ const res = await requireClient().ingestReport(opts.team, {
293
+ reportType: body.reportType,
294
+ source: body.source,
295
+ traceId: body.traceId,
296
+ });
297
+ console.log(JSON.stringify(res, null, 2));
298
+ });
299
+ // --- accounts ---
300
+ const accounts = program.command("accounts").description("社交账号");
301
+ registerAccountsExtensions(accounts);
302
+ accounts
303
+ .command("list")
304
+ .description("GET /accounts")
305
+ .requiredOption("-t, --team <teamId>", "Team UUID")
306
+ .option("--status <st>", "warming | active | …")
307
+ .option("--platform <p>", "平台")
308
+ .option("--campaign <uuid>", "campaignId")
309
+ .option("-n, --limit <n>", "limit", "50")
310
+ .action(async (opts) => {
311
+ const res = await requireClient().listAccounts(opts.team, {
312
+ limit: Number(opts.limit),
313
+ status: opts.status,
314
+ platform: opts.platform,
315
+ campaignId: opts.campaign,
316
+ });
317
+ console.log(JSON.stringify(res, null, 2));
318
+ });
319
+ accounts
320
+ .command("create")
321
+ .description("POST /accounts")
322
+ .requiredOption("-t, --team <teamId>", "Team UUID")
323
+ .requiredOption("-j, --json <json>", "createAccount body JSON")
324
+ .action(async (opts) => {
325
+ let body;
326
+ try {
327
+ body = JSON.parse(opts.json);
328
+ }
329
+ catch {
330
+ console.error("Invalid -j / --json");
331
+ process.exit(1);
332
+ }
333
+ const res = await requireClient().createAccount(opts.team, body);
334
+ console.log(JSON.stringify(res, null, 2));
335
+ });
336
+ // --- brands & campaigns ---
337
+ const brands = program.command("brands").description("品牌");
338
+ brands
339
+ .command("list")
340
+ .requiredOption("-t, --team <teamId>", "Team UUID")
341
+ .action(async (opts) => {
342
+ const res = await requireClient().listBrands(opts.team);
343
+ console.log(JSON.stringify(res, null, 2));
344
+ });
345
+ brands
346
+ .command("create")
347
+ .requiredOption("-t, --team <teamId>", "Team UUID")
348
+ .requiredOption("-j, --json <json>", "{ name, slug? }")
349
+ .action(async (opts) => {
350
+ let body;
351
+ try {
352
+ body = JSON.parse(opts.json);
353
+ }
354
+ catch {
355
+ console.error("Invalid -j / --json");
356
+ process.exit(1);
357
+ }
358
+ const res = await requireClient().createBrand(opts.team, {
359
+ name: String(body.name ?? ""),
360
+ slug: body.slug,
361
+ });
362
+ console.log(JSON.stringify(res, null, 2));
363
+ });
364
+ brands
365
+ .command("update")
366
+ .description("PATCH /brands/:id")
367
+ .requiredOption("-t, --team <teamId>", "Team UUID")
368
+ .requiredOption("-b, --brand <brandId>", "Brand UUID")
369
+ .requiredOption("-j, --json <json>", "update body")
370
+ .action(async (opts) => {
371
+ let body;
372
+ try {
373
+ body = JSON.parse(opts.json);
374
+ }
375
+ catch {
376
+ console.error("Invalid -j / --json");
377
+ process.exit(1);
378
+ }
379
+ const res = await requireClient().updateBrand(opts.team, opts.brand, body);
380
+ console.log(JSON.stringify(res, null, 2));
381
+ });
382
+ const campaigns = program.command("campaigns").description("活动 Campaign");
383
+ campaigns
384
+ .command("list")
385
+ .requiredOption("-t, --team <teamId>", "Team UUID")
386
+ .option("--brand <uuid>", "brandId")
387
+ .action(async (opts) => {
388
+ const res = await requireClient().listCampaigns(opts.team, {
389
+ brandId: opts.brand,
390
+ });
391
+ console.log(JSON.stringify(res, null, 2));
392
+ });
393
+ campaigns
394
+ .command("create")
395
+ .requiredOption("-t, --team <teamId>", "Team UUID")
396
+ .requiredOption("-j, --json <json>", "{ brandId, name, startsAt?, endsAt? }")
397
+ .action(async (opts) => {
398
+ let body;
399
+ try {
400
+ body = JSON.parse(opts.json);
401
+ }
402
+ catch {
403
+ console.error("Invalid -j / --json");
404
+ process.exit(1);
405
+ }
406
+ const res = await requireClient().createCampaign(opts.team, body);
407
+ console.log(JSON.stringify(res, null, 2));
408
+ });
409
+ // --- publishing plans ---
410
+ const plans = program.command("plans").description("发布计划");
411
+ plans
412
+ .command("list")
413
+ .requiredOption("-t, --team <teamId>", "Team UUID")
414
+ .option("--campaign <uuid>", "campaignId")
415
+ .action(async (opts) => {
416
+ const res = await requireClient().listPublishingPlans(opts.team, {
417
+ campaignId: opts.campaign,
418
+ });
419
+ console.log(JSON.stringify(res, null, 2));
420
+ });
421
+ plans
422
+ .command("create")
423
+ .description("POST /publishing-plans(body 需含 entries 等)")
424
+ .requiredOption("-t, --team <teamId>", "Team UUID")
425
+ .requiredOption("-j, --json <json>", "createPublishingPlanBody JSON")
426
+ .action(async (opts) => {
427
+ let body;
428
+ try {
429
+ body = JSON.parse(opts.json);
430
+ }
431
+ catch {
432
+ console.error("Invalid -j / --json");
433
+ process.exit(1);
434
+ }
435
+ const res = await requireClient().createPublishingPlan(opts.team, body);
436
+ console.log(JSON.stringify(res, null, 2));
437
+ });
438
+ // --- audit & permissions & graph ---
439
+ const audit = program.command("audit").description("审计日志");
440
+ audit
441
+ .command("list")
442
+ .requiredOption("-t, --team <teamId>", "Team UUID")
443
+ .option("-n, --limit <n>", "limit", "50")
444
+ .option("--type <t>", "事件 type 前缀")
445
+ .option("--actor <a>", "user | agent | cron")
446
+ .option("--result <r>", "succeeded | failed | skipped")
447
+ .option("--account <uuid>", "socialAccountId")
448
+ .action(async (opts) => {
449
+ const res = await requireClient().listAuditLogs(opts.team, {
450
+ limit: Number(opts.limit),
451
+ type: opts.type,
452
+ actor: opts.actor,
453
+ result: opts.result,
454
+ socialAccountId: opts.account,
455
+ });
456
+ console.log(JSON.stringify(res, null, 2));
457
+ });
458
+ const permissionsCmd = program
459
+ .command("permissions")
460
+ .description("权限矩阵与 CLI 能力说明");
461
+ permissionsCmd
462
+ .command("matrix")
463
+ .description("GET /permissions-matrix(原 social-hub permissions)")
464
+ .requiredOption("-t, --team <teamId>", "Team UUID")
465
+ .action(async (opts) => {
466
+ const res = await requireClient().getPermissionsMatrix(opts.team);
467
+ console.log(JSON.stringify(res, null, 2));
468
+ });
469
+ registerPermissionsExplain(permissionsCmd);
470
+ const graph = program.command("graph").description("账号图谱");
471
+ graph
472
+ .command("list")
473
+ .description("GET /account-graph")
474
+ .requiredOption("-t, --team <teamId>", "Team UUID")
475
+ .option("--account <uuid>", "socialAccountId")
476
+ .option("--edge <type>", "edgeType")
477
+ .option("-n, --limit <n>", "limit", "100")
478
+ .action(async (opts) => {
479
+ const res = await requireClient().listAccountGraphEdges(opts.team, {
480
+ limit: Number(opts.limit),
481
+ socialAccountId: opts.account,
482
+ edgeType: opts.edge,
483
+ });
484
+ console.log(JSON.stringify(res, null, 2));
485
+ });
486
+ // --- drafts extended ---
487
+ drafts
488
+ .command("create")
489
+ .description("POST /content-drafts")
490
+ .requiredOption("-t, --team <teamId>", "Team UUID")
491
+ .requiredOption("-j, --json <json>", "{ campaignId, title, body }")
492
+ .action(async (opts) => {
493
+ let body;
494
+ try {
495
+ body = JSON.parse(opts.json);
496
+ }
497
+ catch {
498
+ console.error("Invalid -j / --json");
499
+ process.exit(1);
500
+ }
501
+ const res = await requireClient().createContentDraft(opts.team, body);
502
+ console.log(JSON.stringify(res, null, 2));
503
+ });
504
+ // --- compliance ---
505
+ const compliance = program.command("compliance").description("合规 / 风控");
506
+ compliance
507
+ .command("sanctions-list")
508
+ .description("GET /subreddit-sanctions")
509
+ .requiredOption("-t, --team <teamId>", "Team UUID")
510
+ .option("--account <uuid>", "socialAccountId")
511
+ .option("--sub <name>", "subreddit")
512
+ .option("-n, --limit <n>", "limit", "50")
513
+ .action(async (opts) => {
514
+ const res = await requireClient().listSubredditSanctions(opts.team, {
515
+ limit: Number(opts.limit),
516
+ socialAccountId: opts.account,
517
+ subreddit: opts.sub,
518
+ });
519
+ console.log(JSON.stringify(res, null, 2));
520
+ });
521
+ compliance
522
+ .command("sanctions-create")
523
+ .description("POST /subreddit-sanctions")
524
+ .requiredOption("-t, --team <teamId>", "Team UUID")
525
+ .requiredOption("-j, --json <json>", "body JSON")
526
+ .action(async (opts) => {
527
+ let body;
528
+ try {
529
+ body = JSON.parse(opts.json);
530
+ }
531
+ catch {
532
+ console.error("Invalid -j / --json");
533
+ process.exit(1);
534
+ }
535
+ const res = await requireClient().createSubredditSanction(opts.team, body);
536
+ console.log(JSON.stringify(res, null, 2));
537
+ });
538
+ compliance
539
+ .command("risk-list")
540
+ .description("GET /account-risk-profiles")
541
+ .requiredOption("-t, --team <teamId>", "Team UUID")
542
+ .option("-n, --limit <n>", "limit", "100")
543
+ .action(async (opts) => {
544
+ const res = await requireClient().listAccountRiskProfiles(opts.team, Number(opts.limit));
545
+ console.log(JSON.stringify(res, null, 2));
546
+ });
547
+ compliance
548
+ .command("risk-get")
549
+ .description("GET /social-accounts/:id/risk-profile")
550
+ .requiredOption("-t, --team <teamId>", "Team UUID")
551
+ .requiredOption("-a, --account <uuid>", "socialAccountId")
552
+ .action(async (opts) => {
553
+ const res = await requireClient().getAccountRiskProfile(opts.team, opts.account);
554
+ console.log(JSON.stringify(res, null, 2));
555
+ });
556
+ compliance
557
+ .command("risk-put")
558
+ .description("PUT /social-accounts/:id/risk-profile")
559
+ .requiredOption("-t, --team <teamId>", "Team UUID")
560
+ .requiredOption("-a, --account <uuid>", "socialAccountId")
561
+ .requiredOption("-j, --json <json>", "body")
562
+ .action(async (opts) => {
563
+ let body;
564
+ try {
565
+ body = JSON.parse(opts.json);
566
+ }
567
+ catch {
568
+ console.error("Invalid -j / --json");
569
+ process.exit(1);
570
+ }
571
+ const res = await requireClient().upsertAccountRiskProfile(opts.team, opts.account, body);
572
+ console.log(JSON.stringify(res, null, 2));
573
+ });
574
+ // --- openclaw ---
575
+ program
576
+ .command("openclaw-ingest")
577
+ .description("POST /openclaw-ingest")
578
+ .requiredOption("-t, --team <teamId>", "Team UUID")
579
+ .option("-j, --json <json>", '默认 {"mode":"dry-run"}')
580
+ .action(async (opts) => {
581
+ let body = {
582
+ mode: "dry-run",
583
+ };
584
+ if (opts.json) {
585
+ try {
586
+ body = JSON.parse(opts.json);
587
+ }
588
+ catch {
589
+ console.error("Invalid -j / --json");
590
+ process.exit(1);
591
+ }
592
+ }
593
+ const res = await requireClient().triggerOpenClawIngest(opts.team, body);
594
+ console.log(JSON.stringify(res, null, 2));
595
+ });
596
+ // ═══════════════════════════════════════════════════════════════════════════
597
+ // Group A: single-resource CRUD additions to existing command groups
598
+ // ═══════════════════════════════════════════════════════════════════════════
599
+ accounts
600
+ .command("get")
601
+ .description("GET /accounts/:id")
602
+ .requiredOption("-t, --team <teamId>", "Team UUID")
603
+ .requiredOption("--account <uuid>", "Account UUID")
604
+ .action(async (opts) => {
605
+ const res = await requireClient().getAccount(opts.team, opts.account);
606
+ console.log(JSON.stringify(res, null, 2));
607
+ });
608
+ accounts
609
+ .command("update")
610
+ .description("PATCH /accounts/:id — 更新 handle / status / credentialsRef")
611
+ .requiredOption("-t, --team <teamId>", "Team UUID")
612
+ .requiredOption("--account <uuid>", "Account UUID")
613
+ .requiredOption("-j, --json <json>", "{ handle?, profileUrl?, status?, externalId?, karma?, accountAgeDays?, workflowStage?, metricsSource?, metricsUpdatedAt?, credentialsRef? }")
614
+ .action(async (opts) => {
615
+ const body = JSON.parse(opts.json);
616
+ const res = await requireClient().updateAccount(opts.team, opts.account, body);
617
+ console.log(JSON.stringify(res, null, 2));
618
+ });
619
+ campaigns
620
+ .command("get")
621
+ .description("GET /campaigns/:id")
622
+ .requiredOption("-t, --team <teamId>", "Team UUID")
623
+ .requiredOption("--campaign <uuid>", "Campaign UUID")
624
+ .action(async (opts) => {
625
+ const res = await requireClient().getCampaign(opts.team, opts.campaign);
626
+ console.log(JSON.stringify(res, null, 2));
627
+ });
628
+ campaigns
629
+ .command("update")
630
+ .description("PATCH /campaigns/:id")
631
+ .requiredOption("-t, --team <teamId>", "Team UUID")
632
+ .requiredOption("--campaign <uuid>", "Campaign UUID")
633
+ .requiredOption("-j, --json <json>", "{ name?, startsAt?, endsAt? }")
634
+ .action(async (opts) => {
635
+ const body = JSON.parse(opts.json);
636
+ const res = await requireClient().updateCampaign(opts.team, opts.campaign, body);
637
+ console.log(JSON.stringify(res, null, 2));
638
+ });
639
+ drafts
640
+ .command("get")
641
+ .description("GET /content-drafts/:id")
642
+ .requiredOption("-t, --team <teamId>", "Team UUID")
643
+ .requiredOption("--draft <uuid>", "Draft UUID")
644
+ .action(async (opts) => {
645
+ const res = await requireClient().getContentDraft(opts.team, opts.draft);
646
+ console.log(JSON.stringify(res, null, 2));
647
+ });
648
+ drafts
649
+ .command("update")
650
+ .description("PATCH /content-drafts/:id")
651
+ .requiredOption("-t, --team <teamId>", "Team UUID")
652
+ .requiredOption("--draft <uuid>", "Draft UUID")
653
+ .requiredOption("-j, --json <json>", "{ title?, body?, status? }")
654
+ .action(async (opts) => {
655
+ const body = JSON.parse(opts.json);
656
+ const res = await requireClient().updateContentDraft(opts.team, opts.draft, body);
657
+ console.log(JSON.stringify(res, null, 2));
658
+ });
659
+ drafts
660
+ .command("delete")
661
+ .description("DELETE /content-drafts/:id")
662
+ .requiredOption("-t, --team <teamId>", "Team UUID")
663
+ .requiredOption("--draft <uuid>", "Draft UUID")
664
+ .action(async (opts) => {
665
+ await requireClient().deleteContentDraft(opts.team, opts.draft);
666
+ console.log("OK");
667
+ });
668
+ plans
669
+ .command("cancel")
670
+ .description("DELETE /publishing-plans/:id(取消)")
671
+ .requiredOption("-t, --team <teamId>", "Team UUID")
672
+ .requiredOption("--plan <uuid>", "Plan UUID")
673
+ .action(async (opts) => {
674
+ await requireClient().cancelPublishingPlan(opts.team, opts.plan);
675
+ console.log("OK");
676
+ });
677
+ // ═══════════════════════════════════════════════════════════════════════════
678
+ // Group B: new command groups
679
+ // ═══════════════════════════════════════════════════════════════════════════
680
+ // --- agent-teams ---
681
+ const agentTeams = program.command("agent-teams").description("Agent 团队管理(admin only)");
682
+ agentTeams
683
+ .command("list")
684
+ .description("GET /v1/agent-teams")
685
+ .action(async () => {
686
+ const res = await requireClient().listAgentTeams();
687
+ console.log(JSON.stringify(res, null, 2));
688
+ });
689
+ agentTeams
690
+ .command("workspace-docs")
691
+ .description("GET /v1/agent-teams/:teamId/workspace-documents")
692
+ .requiredOption("-t, --team <teamId>", "Team UUID")
693
+ .option("--kind <kind>", "file|daily_report|weekly_report|ops_record")
694
+ .option("-n, --limit <n>", "limit", "50")
695
+ .action(async (opts) => {
696
+ const res = await requireClient().listWorkspaceDocuments(opts.team, {
697
+ kind: opts.kind,
698
+ limit: Number(opts.limit),
699
+ });
700
+ console.log(JSON.stringify(res, null, 2));
701
+ });
702
+ agentTeams
703
+ .command("create")
704
+ .description("POST /v1/agent-teams — 新建团队(admin only)")
705
+ .requiredOption("--slug <slug>", "团队 slug(小写字母、数字、横线)")
706
+ .requiredOption("--name <name>", "团队名称")
707
+ .action(async (opts) => {
708
+ const res = await requireClient().createTeam({ slug: opts.slug, name: opts.name });
709
+ console.log(JSON.stringify(res, null, 2));
710
+ });
711
+ agentTeams
712
+ .command("update")
713
+ .description("PATCH /v1/agent-teams/:teamId — 更新团队(admin only)")
714
+ .requiredOption("-t, --team <teamId>", "Team UUID")
715
+ .requiredOption("-j, --json <json>", "{ slug?, name? }")
716
+ .action(async (opts) => {
717
+ const body = JSON.parse(opts.json);
718
+ const res = await requireClient().updateTeam(opts.team, body);
719
+ console.log(JSON.stringify(res, null, 2));
720
+ });
721
+ agentTeams
722
+ .command("add-member")
723
+ .description("POST /v1/agent-teams/:teamId/members — 添加成员(admin only)")
724
+ .requiredOption("-t, --team <teamId>", "Team UUID")
725
+ .requiredOption("--user <userId>", "User UUID")
726
+ .requiredOption("--role <role>", "admin|manager|supervisor|senior|internal|client")
727
+ .action(async (opts) => {
728
+ const res = await requireClient().addTeamMember(opts.team, {
729
+ userId: opts.user,
730
+ role: opts.role,
731
+ });
732
+ console.log(JSON.stringify(res, null, 2));
733
+ });
734
+ // --- intelligence (subreddit-intelligence) ---
735
+ const intel = program.command("intelligence").description("板块情报与 KOL 挖掘");
736
+ intel
737
+ .command("industry-pools-list")
738
+ .description("GET .../subreddit-intelligence/industry-pools")
739
+ .requiredOption("-t, --team <teamId>", "Team UUID")
740
+ .option("-n, --limit <n>", "limit", "50")
741
+ .action(async (opts) => {
742
+ const res = await requireClient().listIndustryPools(opts.team, {
743
+ limit: Number(opts.limit),
744
+ });
745
+ console.log(JSON.stringify(res, null, 2));
746
+ });
747
+ intel
748
+ .command("watchlists-list")
749
+ .description("GET .../subreddit-intelligence/watchlists")
750
+ .requiredOption("-t, --team <teamId>", "Team UUID")
751
+ .option("--campaign <uuid>", "campaignId")
752
+ .option("-n, --limit <n>", "limit", "100")
753
+ .option("--offset <n>", "offset", "0")
754
+ .action(async (opts) => {
755
+ const res = await requireClient().listSubredditWatchlists(opts.team, {
756
+ campaignId: opts.campaign,
757
+ limit: Number(opts.limit),
758
+ offset: Number(opts.offset),
759
+ });
760
+ console.log(JSON.stringify(res, null, 2));
761
+ });
762
+ intel
763
+ .command("watchlists-create")
764
+ .description("POST .../subreddit-intelligence/watchlists")
765
+ .requiredOption("-t, --team <teamId>", "Team UUID")
766
+ .requiredOption("-j, --json <json>", "{ subreddit, tags? }")
767
+ .action(async (opts) => {
768
+ const body = JSON.parse(opts.json);
769
+ const res = await requireClient().createSubredditWatchlist(opts.team, body);
770
+ console.log(JSON.stringify(res, null, 2));
771
+ });
772
+ intel
773
+ .command("watchlists-update")
774
+ .description("PATCH .../subreddit-intelligence/watchlists/:id")
775
+ .requiredOption("-t, --team <teamId>", "Team UUID")
776
+ .requiredOption("--id <uuid>", "Watchlist UUID")
777
+ .requiredOption("-j, --json <json>", "update body")
778
+ .action(async (opts) => {
779
+ const body = JSON.parse(opts.json);
780
+ const res = await requireClient().updateSubredditWatchlist(opts.team, opts.id, body);
781
+ console.log(JSON.stringify(res, null, 2));
782
+ });
783
+ intel
784
+ .command("watchlists-delete")
785
+ .description("DELETE .../subreddit-intelligence/watchlists/:id")
786
+ .requiredOption("-t, --team <teamId>", "Team UUID")
787
+ .requiredOption("--id <uuid>", "Watchlist UUID")
788
+ .action(async (opts) => {
789
+ await requireClient().deleteSubredditWatchlist(opts.team, opts.id);
790
+ console.log("OK");
791
+ });
792
+ intel
793
+ .command("hot-posts")
794
+ .description("GET .../subreddit-intelligence/hot-posts")
795
+ .requiredOption("-t, --team <teamId>", "Team UUID")
796
+ .option("--subreddit <name>", "板块名称")
797
+ .option("--sort <by>", "score|comments|capturedAt|upvoteRatio", "score")
798
+ .option("-n, --limit <n>", "limit", "100")
799
+ .option("--offset <n>", "offset", "0")
800
+ .action(async (opts) => {
801
+ const res = await requireClient().listHotPosts(opts.team, {
802
+ subreddit: opts.subreddit,
803
+ sortBy: opts.sort,
804
+ limit: Number(opts.limit),
805
+ offset: Number(opts.offset),
806
+ });
807
+ console.log(JSON.stringify(res, null, 2));
808
+ });
809
+ intel
810
+ .command("hot-posts-create")
811
+ .description("POST .../subreddit-intelligence/hot-posts")
812
+ .requiredOption("-t, --team <teamId>", "Team UUID")
813
+ .requiredOption("-j, --json <json>", "hot post body")
814
+ .action(async (opts) => {
815
+ const body = JSON.parse(opts.json);
816
+ const res = await requireClient().createHotPost(opts.team, body);
817
+ console.log(JSON.stringify(res, null, 2));
818
+ });
819
+ intel
820
+ .command("hot-posts-export")
821
+ .description("GET .../subreddit-intelligence/hot-posts/export.csv")
822
+ .requiredOption("-t, --team <teamId>", "Team UUID")
823
+ .option("--subreddit <name>", "板块名称")
824
+ .option("-n, --limit <n>", "limit", "500")
825
+ .action(async (opts) => {
826
+ const csv = await requireClient().exportHotPostsCsv(opts.team, {
827
+ subreddit: opts.subreddit,
828
+ limit: Number(opts.limit),
829
+ });
830
+ process.stdout.write(csv);
831
+ });
832
+ intel
833
+ .command("kol-intents")
834
+ .description("GET .../subreddit-intelligence/kol-intents")
835
+ .requiredOption("-t, --team <teamId>", "Team UUID")
836
+ .option("--campaign <uuid>", "campaignId")
837
+ .option("--status <status>", "interested|contacting|connected|not_interested")
838
+ .option("--sort <by>", "createdAt|status|rating|karma|activity|lastActive", "createdAt")
839
+ .option("--order <order>", "asc|desc", "desc")
840
+ .option("-n, --limit <n>", "limit", "100")
841
+ .option("--offset <n>", "offset", "0")
842
+ .action(async (opts) => {
843
+ const res = await requireClient().listKolIntents(opts.team, {
844
+ campaignId: opts.campaign,
845
+ status: opts.status,
846
+ sortBy: opts.sort,
847
+ sortOrder: opts.order,
848
+ limit: Number(opts.limit),
849
+ offset: Number(opts.offset),
850
+ });
851
+ console.log(JSON.stringify(res, null, 2));
852
+ });
853
+ intel
854
+ .command("kol-intents-create")
855
+ .description("POST .../subreddit-intelligence/kol-intents")
856
+ .requiredOption("-t, --team <teamId>", "Team UUID")
857
+ .requiredOption("-j, --json <json>", "kol intent body")
858
+ .action(async (opts) => {
859
+ const body = JSON.parse(opts.json);
860
+ const res = await requireClient().createKolIntent(opts.team, body);
861
+ console.log(JSON.stringify(res, null, 2));
862
+ });
863
+ intel
864
+ .command("dispatch")
865
+ .description("POST .../subreddit-intelligence/hot-posts/dispatch-task")
866
+ .requiredOption("-t, --team <teamId>", "Team UUID")
867
+ .requiredOption("-j, --json <json>", "{ hotPostId, socialAccountId, action, runAt? }")
868
+ .action(async (opts) => {
869
+ const body = JSON.parse(opts.json);
870
+ const res = await requireClient().dispatchTaskFromHotPost(opts.team, body);
871
+ console.log(JSON.stringify(res, null, 2));
872
+ });
873
+ // --- users ---
874
+ const usersCmd = program.command("users").description("团队成员管理");
875
+ usersCmd
876
+ .command("list")
877
+ .description("GET /users")
878
+ .requiredOption("-t, --team <teamId>", "Team UUID")
879
+ .action(async (opts) => {
880
+ const res = await requireClient().listUsers(opts.team);
881
+ console.log(JSON.stringify(res, null, 2));
882
+ });
883
+ usersCmd
884
+ .command("create")
885
+ .description("POST /users")
886
+ .requiredOption("-t, --team <teamId>", "Team UUID")
887
+ .requiredOption("-j, --json <json>", "{ email, password, role? }")
888
+ .action(async (opts) => {
889
+ const body = JSON.parse(opts.json);
890
+ const res = await requireClient().createUser(opts.team, body);
891
+ console.log(JSON.stringify(res, null, 2));
892
+ });
893
+ // --- brand-members ---
894
+ const brandMembersCmd = program.command("brand-members").description("品牌成员");
895
+ brandMembersCmd
896
+ .command("list")
897
+ .description("GET /brand-members")
898
+ .requiredOption("-t, --team <teamId>", "Team UUID")
899
+ .option("--user <uuid>", "userId 过滤")
900
+ .action(async (opts) => {
901
+ const res = await requireClient().listBrandMembers(opts.team, { userId: opts.user });
902
+ console.log(JSON.stringify(res, null, 2));
903
+ });
904
+ brandMembersCmd
905
+ .command("create")
906
+ .description("POST /brand-members")
907
+ .requiredOption("-t, --team <teamId>", "Team UUID")
908
+ .requiredOption("-j, --json <json>", "{ brandId, userId, role? }")
909
+ .action(async (opts) => {
910
+ const body = JSON.parse(opts.json);
911
+ const res = await requireClient().createBrandMember(opts.team, body);
912
+ console.log(JSON.stringify(res, null, 2));
913
+ });
914
+ // --- notification-channels ---
915
+ const notifChannels = program
916
+ .command("notification-channels")
917
+ .description("通知渠道管理");
918
+ notifChannels
919
+ .command("list")
920
+ .description("GET /notification-channels")
921
+ .requiredOption("-t, --team <teamId>", "Team UUID")
922
+ .option("--campaign <uuid>", "campaignId 过滤")
923
+ .action(async (opts) => {
924
+ const res = await requireClient().listNotificationChannels(opts.team, {
925
+ campaignId: opts.campaign,
926
+ });
927
+ console.log(JSON.stringify(res, null, 2));
928
+ });
929
+ notifChannels
930
+ .command("create")
931
+ .description("POST /notification-channels")
932
+ .requiredOption("-t, --team <teamId>", "Team UUID")
933
+ .requiredOption("-j, --json <json>", "{ provider, externalId, minRole?, campaignId? }")
934
+ .action(async (opts) => {
935
+ const body = JSON.parse(opts.json);
936
+ const res = await requireClient().createNotificationChannel(opts.team, body);
937
+ console.log(JSON.stringify(res, null, 2));
938
+ });
939
+ notifChannels
940
+ .command("update")
941
+ .description("PATCH /notification-channels/:id")
942
+ .requiredOption("-t, --team <teamId>", "Team UUID")
943
+ .requiredOption("--channel <uuid>", "Channel UUID")
944
+ .requiredOption("-j, --json <json>", "update body")
945
+ .action(async (opts) => {
946
+ const body = JSON.parse(opts.json);
947
+ const res = await requireClient().updateNotificationChannel(opts.team, opts.channel, body);
948
+ console.log(JSON.stringify(res, null, 2));
949
+ });
950
+ notifChannels
951
+ .command("delete")
952
+ .description("DELETE /notification-channels/:id")
953
+ .requiredOption("-t, --team <teamId>", "Team UUID")
954
+ .requiredOption("--channel <uuid>", "Channel UUID")
955
+ .action(async (opts) => {
956
+ await requireClient().deleteNotificationChannel(opts.team, opts.channel);
957
+ console.log("OK");
958
+ });
959
+ notifChannels
960
+ .command("test")
961
+ .description("POST /notification-channels/:id/test")
962
+ .requiredOption("-t, --team <teamId>", "Team UUID")
963
+ .requiredOption("--channel <uuid>", "Channel UUID")
964
+ .action(async (opts) => {
965
+ const res = await requireClient().testNotificationChannel(opts.team, opts.channel);
966
+ console.log(JSON.stringify(res, null, 2));
967
+ });
968
+ // --- api-keys ---
969
+ const apiKeys = program.command("api-keys").description("API Key 管理");
970
+ apiKeys
971
+ .command("list")
972
+ .description("GET /api-keys")
973
+ .requiredOption("-t, --team <teamId>", "Team UUID")
974
+ .option("-n, --limit <n>", "limit", "50")
975
+ .action(async (opts) => {
976
+ const res = await requireClient().listApiKeys(opts.team, { limit: Number(opts.limit) });
977
+ console.log(JSON.stringify(res, null, 2));
978
+ });
979
+ apiKeys
980
+ .command("create")
981
+ .description("POST /api-keys")
982
+ .requiredOption("-t, --team <teamId>", "Team UUID")
983
+ .requiredOption("-j, --json <json>", "{ name, role, visibleCampaignIds? }")
984
+ .action(async (opts) => {
985
+ const body = JSON.parse(opts.json);
986
+ const res = await requireClient().createApiKey(opts.team, body);
987
+ console.log(JSON.stringify(res, null, 2));
988
+ });
989
+ apiKeys
990
+ .command("delete")
991
+ .description("DELETE /api-keys/:id")
992
+ .requiredOption("-t, --team <teamId>", "Team UUID")
993
+ .requiredOption("--key <uuid>", "API Key UUID")
994
+ .action(async (opts) => {
995
+ await requireClient().deleteApiKey(opts.team, opts.key);
996
+ console.log("OK");
997
+ });
998
+ apiKeys
999
+ .command("rotate")
1000
+ .description("POST /api-keys/:id/rotate")
1001
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1002
+ .requiredOption("--key <uuid>", "API Key UUID")
1003
+ .action(async (opts) => {
1004
+ const res = await requireClient().rotateApiKey(opts.team, opts.key);
1005
+ console.log(JSON.stringify(res, null, 2));
1006
+ });
1007
+ apiKeys
1008
+ .command("batch-revoke")
1009
+ .description("POST /api-keys/batch/revoke")
1010
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1011
+ .requiredOption("-j, --json <json>", '{ "ids": ["uuid1","uuid2"] }')
1012
+ .action(async (opts) => {
1013
+ const body = JSON.parse(opts.json);
1014
+ const res = await requireClient().batchRevokeApiKeys(opts.team, body.ids);
1015
+ console.log(JSON.stringify(res, null, 2));
1016
+ });
1017
+ apiKeys
1018
+ .command("batch-rotate")
1019
+ .description("POST /api-keys/batch/rotate")
1020
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1021
+ .requiredOption("-j, --json <json>", '{ "ids": ["uuid1","uuid2"] }')
1022
+ .action(async (opts) => {
1023
+ const body = JSON.parse(opts.json);
1024
+ const res = await requireClient().batchRotateApiKeys(opts.team, body.ids);
1025
+ console.log(JSON.stringify(res, null, 2));
1026
+ });
1027
+ // ═══════════════════════════════════════════════════════════════════════════
1028
+ // Group C: scattered endpoint additions
1029
+ // ═══════════════════════════════════════════════════════════════════════════
1030
+ events
1031
+ .command("export-csv")
1032
+ .description("GET /events/export.csv(输出 CSV 到 stdout)")
1033
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1034
+ .option("--type <type>", "事件 type 过滤")
1035
+ .option("--actor <actor>", "user|agent|cron")
1036
+ .option("--result <result>", "succeeded|failed|skipped")
1037
+ .option("--account <uuid>", "socialAccountId 过滤")
1038
+ .option("--from <iso>", "createdFrom ISO 时间")
1039
+ .option("--to <iso>", "createdTo ISO 时间")
1040
+ .option("-n, --limit <n>", "limit", "1000")
1041
+ .action(async (opts) => {
1042
+ const csv = await requireClient().exportEventsCsv(opts.team, {
1043
+ type: opts.type,
1044
+ actor: opts.actor,
1045
+ result: opts.result,
1046
+ socialAccountId: opts.account,
1047
+ createdFrom: opts.from,
1048
+ createdTo: opts.to,
1049
+ limit: Number(opts.limit),
1050
+ });
1051
+ process.stdout.write(csv);
1052
+ });
1053
+ reports
1054
+ .command("create")
1055
+ .description("POST /reports(直写入库,非队列 ingest)")
1056
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1057
+ .requiredOption("-j, --json <json>", "{ reportType, title, source, contentMarkdown, summary?, campaignId?, traceId? }")
1058
+ .action(async (opts) => {
1059
+ const body = JSON.parse(opts.json);
1060
+ const res = await requireClient().createReport(opts.team, body);
1061
+ console.log(JSON.stringify(res, null, 2));
1062
+ });
1063
+ jobs
1064
+ .command("agent-status")
1065
+ .description("POST /scheduled-jobs/:id/agent-status(Agent 回写任务状态)")
1066
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1067
+ .requiredOption("-i, --id <jobId>", "Job UUID")
1068
+ .requiredOption("-j, --json <json>", '{ "status": "running"|"succeeded"|"failed", "lastError"?, "payload"? }')
1069
+ .action(async (opts) => {
1070
+ const body = JSON.parse(opts.json);
1071
+ const res = await requireClient().updateJobAgentStatus(opts.team, opts.id, body);
1072
+ console.log(JSON.stringify(res, null, 2));
1073
+ });
1074
+ program
1075
+ .command("permissions-update")
1076
+ .description("PATCH /permissions-matrix(更新权限矩阵,admin only)")
1077
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1078
+ .requiredOption("-j, --json <json>", "权限矩阵更新 body")
1079
+ .action(async (opts) => {
1080
+ const body = JSON.parse(opts.json);
1081
+ const res = await requireClient().updatePermissionsMatrix(opts.team, body);
1082
+ console.log(JSON.stringify(res, null, 2));
1083
+ });
1084
+ graph
1085
+ .command("drilldown")
1086
+ .description("GET /account-graph/drilldown(账号追溯)")
1087
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1088
+ .requiredOption("--account <uuid>", "socialAccountId")
1089
+ .option("-n, --limit <n>", "limit", "20")
1090
+ .action(async (opts) => {
1091
+ const res = await requireClient().getAccountGraphDrilldown(opts.team, {
1092
+ socialAccountId: opts.account,
1093
+ limit: Number(opts.limit),
1094
+ });
1095
+ console.log(JSON.stringify(res, null, 2));
1096
+ });
1097
+ // ═══════════════════════════════════════════════════════════════════════════
1098
+ // Group D: add filter params to existing list commands
1099
+ // ═══════════════════════════════════════════════════════════════════════════
1100
+ // events list → enhanced version
1101
+ events
1102
+ .command("list-full")
1103
+ .description("GET /events(含全部过滤参数)")
1104
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1105
+ .option("--type <type>", "事件 type")
1106
+ .option("--actor <actor>", "user|agent|cron")
1107
+ .option("--result <result>", "succeeded|failed|skipped")
1108
+ .option("--account <uuid>", "socialAccountId")
1109
+ .option("--from <iso>", "createdFrom ISO 时间")
1110
+ .option("--to <iso>", "createdTo ISO 时间")
1111
+ .option("-n, --limit <n>", "limit", "100")
1112
+ .action(async (opts) => {
1113
+ const res = await requireClient().listEventsFiltered(opts.team, {
1114
+ type: opts.type,
1115
+ actor: opts.actor,
1116
+ result: opts.result,
1117
+ socialAccountId: opts.account,
1118
+ createdFrom: opts.from,
1119
+ createdTo: opts.to,
1120
+ limit: Number(opts.limit),
1121
+ });
1122
+ console.log(JSON.stringify(res, null, 2));
1123
+ });
1124
+ calendar
1125
+ .command("list-full")
1126
+ .description("GET /calendar-entries(含全部过滤参数)")
1127
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1128
+ .option("--campaign <uuid>", "campaignId")
1129
+ .option("--plan <uuid>", "publishingPlanId")
1130
+ .option("--account <uuid>", "socialAccountId")
1131
+ .option("--status <st>", "scheduled|running|succeeded|…")
1132
+ .option("--from <iso>", "from ISO 时间")
1133
+ .option("--to <iso>", "to ISO 时间")
1134
+ .option("-n, --limit <n>", "limit", "50")
1135
+ .action(async (opts) => {
1136
+ const res = await requireClient().listCalendarEntries(opts.team, {
1137
+ campaignId: opts.campaign,
1138
+ publishingPlanId: opts.plan,
1139
+ socialAccountId: opts.account,
1140
+ status: opts.status,
1141
+ from: opts.from,
1142
+ to: opts.to,
1143
+ limit: Number(opts.limit),
1144
+ });
1145
+ console.log(JSON.stringify(res, null, 2));
1146
+ });
1147
+ jobs
1148
+ .command("list-full")
1149
+ .description("GET /scheduled-jobs(含全部过滤参数)")
1150
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1151
+ .option("--status <st>", "scheduled|running|…")
1152
+ .option("--account <uuid>", "socialAccountId")
1153
+ .option("--from <iso>", "from ISO 时间")
1154
+ .option("--to <iso>", "to ISO 时间")
1155
+ .option("-n, --limit <n>", "limit", "50")
1156
+ .action(async (opts) => {
1157
+ const res = await requireClient().listScheduledJobs(opts.team, {
1158
+ status: opts.status,
1159
+ socialAccountId: opts.account,
1160
+ from: opts.from,
1161
+ to: opts.to,
1162
+ limit: Number(opts.limit),
1163
+ });
1164
+ console.log(JSON.stringify(res, null, 2));
1165
+ });
1166
+ reddit
1167
+ .command("list-full")
1168
+ .description("GET /reddit-post-snapshots(含全部过滤参数)")
1169
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1170
+ .option("--campaign <uuid>", "campaignId")
1171
+ .option("--entry <uuid>", "calendarEntryId")
1172
+ .option("--account <uuid>", "socialAccountId")
1173
+ .option("-n, --limit <n>", "limit", "100")
1174
+ .action(async (opts) => {
1175
+ const res = await requireClient().listRedditPostSnapshots(opts.team, {
1176
+ campaignId: opts.campaign,
1177
+ calendarEntryId: opts.entry,
1178
+ socialAccountId: opts.account,
1179
+ limit: Number(opts.limit),
1180
+ });
1181
+ console.log(JSON.stringify(res, null, 2));
1182
+ });
1183
+ // --- session ---
1184
+ const session = program.command("session").description("会话管理(cookie-based)");
1185
+ session
1186
+ .command("login")
1187
+ .description("POST /v1/session/login")
1188
+ .requiredOption("--email <email>", "邮箱")
1189
+ .requiredOption("--password <password>", "密码")
1190
+ .action(async (opts) => {
1191
+ const res = await requireClient().sessionLogin({ email: opts.email, password: opts.password });
1192
+ console.log(JSON.stringify(res, null, 2));
1193
+ });
1194
+ session
1195
+ .command("logout")
1196
+ .description("POST /v1/session/logout")
1197
+ .action(async () => {
1198
+ const res = await requireClient().sessionLogout();
1199
+ console.log(JSON.stringify(res, null, 2));
1200
+ });
1201
+ session
1202
+ .command("me")
1203
+ .description("GET /v1/session/me")
1204
+ .action(async () => {
1205
+ const res = await requireClient().sessionMe();
1206
+ console.log(JSON.stringify(res, null, 2));
1207
+ });
1208
+ session
1209
+ .command("active-team")
1210
+ .description("POST /v1/session/active-team")
1211
+ .requiredOption("--team <teamId>", "Team UUID")
1212
+ .action(async (opts) => {
1213
+ const res = await requireClient().sessionActiveTeam({ teamId: opts.team });
1214
+ console.log(JSON.stringify(res, null, 2));
1215
+ });
1216
+ session
1217
+ .command("set-password")
1218
+ .description("POST /v1/session/set-password")
1219
+ .requiredOption("--email <email>", "邮箱")
1220
+ .requiredOption("--password <password>", "新密码")
1221
+ .option("--team <teamId>", "Team UUID(可选)")
1222
+ .action(async (opts) => {
1223
+ const res = await requireClient().sessionSetPassword({ email: opts.email, password: opts.password, teamId: opts.team });
1224
+ console.log(JSON.stringify(res, null, 2));
1225
+ });
1226
+ session
1227
+ .command("update-profile")
1228
+ .description("PATCH /v1/session/profile")
1229
+ .requiredOption("--name <name>", "新姓名")
1230
+ .action(async (opts) => {
1231
+ const res = await requireClient().sessionUpdateProfile({ name: opts.name });
1232
+ console.log(JSON.stringify(res, null, 2));
1233
+ });
1234
+ // --- accounts browser-envs (sub-commands under existing `accounts`) ---
1235
+ const browserEnvs = accounts.command("browser-envs").description("浏览器环境");
1236
+ browserEnvs
1237
+ .command("list-team")
1238
+ .description("GET /browser-environments(Team 全量)")
1239
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1240
+ .action(async (opts) => {
1241
+ const res = await requireClient().listTeamBrowserEnvironments(opts.team);
1242
+ console.log(JSON.stringify(res, null, 2));
1243
+ });
1244
+ browserEnvs
1245
+ .command("list")
1246
+ .description("GET /accounts/:accountId/browser-environments")
1247
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1248
+ .requiredOption("-a, --account <accountId>", "Account UUID")
1249
+ .action(async (opts) => {
1250
+ const res = await requireClient().listAccountBrowserEnvironments(opts.team, opts.account);
1251
+ console.log(JSON.stringify(res, null, 2));
1252
+ });
1253
+ browserEnvs
1254
+ .command("create")
1255
+ .description("POST /accounts/:accountId/browser-environments")
1256
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1257
+ .requiredOption("-a, --account <accountId>", "Account UUID")
1258
+ .option("-j, --json <json>", "env body JSON", "{}")
1259
+ .action(async (opts) => {
1260
+ let body = {};
1261
+ try {
1262
+ body = JSON.parse(opts.json);
1263
+ }
1264
+ catch {
1265
+ console.error("Invalid -j / --json");
1266
+ process.exit(1);
1267
+ }
1268
+ const res = await requireClient().createBrowserEnvironment(opts.team, opts.account, body);
1269
+ console.log(JSON.stringify(res, null, 2));
1270
+ });
1271
+ // --- accounts personas ---
1272
+ const personas = accounts.command("personas").description("账号人设");
1273
+ personas
1274
+ .command("list")
1275
+ .description("GET /accounts/:accountId/personas")
1276
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1277
+ .requiredOption("-a, --account <accountId>", "Account UUID")
1278
+ .action(async (opts) => {
1279
+ const res = await requireClient().listAccountPersonas(opts.team, opts.account);
1280
+ console.log(JSON.stringify(res, null, 2));
1281
+ });
1282
+ personas
1283
+ .command("create")
1284
+ .description("POST /accounts/:accountId/personas")
1285
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1286
+ .requiredOption("-a, --account <accountId>", "Account UUID")
1287
+ .requiredOption("--markdown <text>", "人设 Markdown 文本")
1288
+ .action(async (opts) => {
1289
+ const res = await requireClient().createAccountPersona(opts.team, opts.account, { markdown: opts.markdown });
1290
+ console.log(JSON.stringify(res, null, 2));
1291
+ });
1292
+ // --- campaigns accounts ---
1293
+ const campaignAccounts = campaigns.command("accounts").description("Campaign 账号分配");
1294
+ campaignAccounts
1295
+ .command("list")
1296
+ .description("GET /campaigns/:campaignId/accounts")
1297
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1298
+ .requiredOption("-c, --campaign <campaignId>", "Campaign UUID")
1299
+ .action(async (opts) => {
1300
+ const res = await requireClient().listCampaignAccounts(opts.team, opts.campaign);
1301
+ console.log(JSON.stringify(res, null, 2));
1302
+ });
1303
+ campaignAccounts
1304
+ .command("assign")
1305
+ .description("POST /campaigns/:campaignId/accounts")
1306
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1307
+ .requiredOption("-c, --campaign <campaignId>", "Campaign UUID")
1308
+ .requiredOption("-a, --account <socialAccountId>", "社交账号 UUID")
1309
+ .option("--visibility <v>", "public | private | internal")
1310
+ .action(async (opts) => {
1311
+ const res = await requireClient().assignCampaignAccount(opts.team, opts.campaign, {
1312
+ socialAccountId: opts.account,
1313
+ visibility: opts.visibility,
1314
+ });
1315
+ console.log(JSON.stringify(res, null, 2));
1316
+ });
1317
+ campaignAccounts
1318
+ .command("remove")
1319
+ .description("DELETE /campaigns/:campaignId/accounts/:socialAccountId")
1320
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1321
+ .requiredOption("-c, --campaign <campaignId>", "Campaign UUID")
1322
+ .requiredOption("-a, --account <socialAccountId>", "社交账号 UUID")
1323
+ .action(async (opts) => {
1324
+ const res = await requireClient().removeCampaignAccount(opts.team, opts.campaign, opts.account);
1325
+ console.log(JSON.stringify(res, null, 2));
1326
+ });
1327
+ // --- brand-members remove ---
1328
+ brandMembersCmd
1329
+ .command("remove")
1330
+ .description("DELETE /brand-members/:memberId")
1331
+ .requiredOption("-t, --team <teamId>", "Team UUID")
1332
+ .requiredOption("-m, --member <memberId>", "BrandMember UUID")
1333
+ .action(async (opts) => {
1334
+ const res = await requireClient().deleteBrandMember(opts.team, opts.member);
1335
+ console.log(JSON.stringify(res, null, 2));
1336
+ });
1337
+ // Only parse when run directly (not when imported for testing)
1338
+ if (!process.env["VITEST"]) {
1339
+ program.parse();
1340
+ }
1341
+ export { program };
1342
+ //# sourceMappingURL=index.js.map