@geoly-ai/social-hub-cli 0.2.1 → 0.2.3

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/CHANGELOG.md CHANGED
@@ -4,6 +4,41 @@ All notable changes to `@geoly-ai/social-hub-cli` are documented in this file.
4
4
 
5
5
  Release workflow: `pnpm release:cli` → `pnpm publish:cli`.
6
6
 
7
+ ## [0.2.3] - 2026-07-14
8
+
9
+ content review 命令(评论 LLM 复审+优化,层③);reddit list 排序参数;brands system-update;seqNo 字段
10
+
11
+ ### Added
12
+
13
+ - 评论 LLM 复审+优化服务——发布前三层 gate 的层③(独立模型对抗式复审)
14
+ - Reddit 指标快照剔除内部自建品牌 + brands.is_internal 产品化
15
+ - 帖子表现新增数字序列号 seqNo——可编辑/列表展示/可排序
16
+ - 草稿一稿一投——entry 成功自动 published,禁止再排期(含并发安全与历史回填)
17
+ - publishing plan 状态改为 entries 聚合派生 + status 过滤真正生效
18
+ - CLI/API accounts reassign 命令(账号跨团队迁移产品化)
19
+ - 草稿变更追踪 + 乐观并发(updatedAt/version,防丢更新)
20
+ - 账号注册时间 registeredAt(可编辑)+ 派生只读 age
21
+ - 通用抓取加 scrollCount(无限滚动页懒加载)
22
+
23
+ ### Fixed
24
+
25
+ - 收官清扫——cron addBulk/seed 契约/快照幂等/intel partial 终态对齐
26
+ - sanction 解封语义收紧——枚举化+全写入口归一,web"解除"按钮从未真正解封
27
+ - 终态一致性——complete/fail/skip 幂等 + fail/skip 事务化 + cron 任何终态都续期
28
+ - Firecrawl 兜底改用低产量重试(自托管不支持 actions),去掉 scrape scrollCount
29
+
30
+ ### Documentation
31
+
32
+ - 说明 REVIEW_LLM_BASE_URL 三 provider 通用+allowlist 要求
33
+
34
+ ## [0.2.2] - 2026-07-03
35
+
36
+ skills install 未指定 agent 时默认自动探测机器上已有的 agent 目录安装(尊重 --global/--project;TUI 空选同样回退);不再报错。
37
+
38
+ ### Added
39
+
40
+ - skills install 未指定 agent 时默认自动装到机器上已有的 agent 目录
41
+
7
42
  ## [0.2.1] - 2026-07-03
8
43
 
9
44
  Reddit .json 抓取开放到 scrape:Reddit .json 走直连(curl_cffi+住宅代理),HTML 经 Firecrawl;scrape status 增 firecrawl/redditDirect 字段。
@@ -1,6 +1,6 @@
1
1
  {
2
- "generatedAt": "2026-07-03T03:56:08.083Z",
3
- "cliVersion": "0.2.1",
2
+ "generatedAt": "2026-07-14T09:50:49.977Z",
3
+ "cliVersion": "0.2.3",
4
4
  "commands": [
5
5
  "accounts",
6
6
  "accounts brand-bindings",
@@ -25,6 +25,7 @@
25
25
  "accounts personas",
26
26
  "accounts personas create",
27
27
  "accounts personas list",
28
+ "accounts reassign",
28
29
  "accounts status-snapshots",
29
30
  "accounts status-snapshots create",
30
31
  "accounts status-snapshots list",
@@ -71,6 +72,7 @@
71
72
  "brands list",
72
73
  "brands system-create",
73
74
  "brands system-list",
75
+ "brands system-update",
74
76
  "brands update",
75
77
  "calendar",
76
78
  "calendar list",
@@ -102,6 +104,8 @@
102
104
  "config init",
103
105
  "config set",
104
106
  "config show",
107
+ "content",
108
+ "content review",
105
109
  "context",
106
110
  "context account",
107
111
  "context current",
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2BpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAw9C9B,8DAA8D;AAC9D,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,GAAG,IAAI,CAOf;AAk2ED,OAAO,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2BpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AA2gD9B,8DAA8D;AAC9D,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,GAAG,IAAI,CAOf;AAy3ED,OAAO,EAAE,OAAO,EAAE,CAAC"}
package/dist/index.js CHANGED
@@ -334,6 +334,8 @@ reddit
334
334
  .option("--repost-type <t>", "repostType filter (none|first|second)")
335
335
  .option("--contains-brand-keyword <v>", "true | false | unset")
336
336
  .option("--primary-product <text>", "primary product contains match")
337
+ .option("--sort-by <f>", "score|comments_count|posted_at|view_count|seq_no")
338
+ .option("--sort-dir <d>", "asc|desc")
337
339
  .option("-n, --limit <n>", "limit per page", "100")
338
340
  .option("--offset <n>", "pagination offset")
339
341
  .option("--all", "fetch all pages (200 per request until total reached)")
@@ -351,6 +353,8 @@ reddit
351
353
  repostType: opts.repostType,
352
354
  containsBrandKeyword: opts.containsBrandKeyword,
353
355
  primaryProduct: opts.primaryProduct,
356
+ sortBy: opts.sortBy,
357
+ sortDir: opts.sortDir,
354
358
  ...redditAggregateQueryParams(opts),
355
359
  }, { fetchAll: Boolean(opts.all) });
356
360
  console.log(JSON.stringify(res, null, 2));
@@ -449,6 +453,26 @@ jobs
449
453
  console.log(JSON.stringify(res, null, 2));
450
454
  });
451
455
  // --- drafts & reports ---
456
+ const content = program
457
+ .command("content")
458
+ .description("内容质量(发布前 LLM 复审)");
459
+ content
460
+ .command("review")
461
+ .description("POST /content-review — 评论发布前独立 LLM 复审+优化(层③);degraded 时降级本地自审")
462
+ .requiredOption("-t, --team <teamId>", "Team UUID")
463
+ .requiredOption("-j, --json <json>", "{ accountId, draft, commentType, thread:{subreddit,postTitle,...}, rewrite?, stage?, attempt? }")
464
+ .action(async (opts) => {
465
+ let body;
466
+ try {
467
+ body = JSON.parse(opts.json);
468
+ }
469
+ catch {
470
+ console.error("Invalid -j / --json");
471
+ process.exit(1);
472
+ }
473
+ const res = await requireClient().contentReview(opts.team, body);
474
+ console.log(JSON.stringify(res, null, 2));
475
+ });
452
476
  const drafts = program.command("drafts").description("内容草稿");
453
477
  drafts
454
478
  .command("list")
@@ -555,7 +579,7 @@ brands
555
579
  brands
556
580
  .command("system-create")
557
581
  .description("POST /system/brands (preferred)")
558
- .requiredOption("-j, --json <json>", "{ name, slug? }")
582
+ .requiredOption("-j, --json <json>", "{ name, slug?, isInternal? }")
559
583
  .action(async (opts) => {
560
584
  let body;
561
585
  try {
@@ -568,9 +592,27 @@ brands
568
592
  const res = await requireClient().createSystemBrand({
569
593
  name: String(body.name ?? ""),
570
594
  slug: body.slug,
595
+ isInternal: body.isInternal,
571
596
  });
572
597
  console.log(JSON.stringify(res, null, 2));
573
598
  });
599
+ brands
600
+ .command("system-update")
601
+ .description("PATCH /system/brands/:id")
602
+ .requiredOption("--brand <uuid>", "Brand UUID")
603
+ .requiredOption("-j, --json <json>", "{ name?, status?, isInternal? }")
604
+ .action(async (opts) => {
605
+ let body;
606
+ try {
607
+ body = JSON.parse(opts.json);
608
+ }
609
+ catch {
610
+ console.error("Invalid -j / --json");
611
+ process.exit(1);
612
+ }
613
+ const res = await requireClient().updateSystemBrand(opts.brand, body);
614
+ console.log(JSON.stringify(res, null, 2));
615
+ });
574
616
  brands
575
617
  .command("list")
576
618
  .description("GET /teams/:teamId/brands (compat)")
@@ -821,10 +863,12 @@ plans
821
863
  .requiredOption("-t, --team <teamId>", "Team UUID")
822
864
  .option("--brand <uuid>", "brandId 过滤(推荐)")
823
865
  .option("--campaign <uuid>", "campaignId 过滤(legacy)")
866
+ .option("--status <status>", "派生状态过滤(scheduled/running/succeeded/failed/cancelled;无 entries 的计划保留存储值 draft/exported)")
824
867
  .action(async (opts) => {
825
868
  const res = await requireClient().listPublishingPlans(opts.team, {
826
869
  brandId: opts.brand,
827
870
  campaignId: opts.campaign,
871
+ status: opts.status,
828
872
  });
829
873
  console.log(JSON.stringify(res, null, 2));
830
874
  });
@@ -1253,7 +1297,7 @@ accounts
1253
1297
  .description("PATCH /accounts/:id — 更新 handle/status/karma/accountAgeDays 等核心字段。安全时段/时区/风险级别请用 `compliance risk-put`;浏览器环境请用 `browser-envs`")
1254
1298
  .requiredOption("-t, --team <teamId>", "Team UUID")
1255
1299
  .requiredOption("--account <uuid>", "Account UUID")
1256
- .requiredOption("-j, --json <json>", "{ handle?, profileUrl?, status?, externalId?, externalRef?, personaId?, karma?, accountAgeDays?, workflowStage?, metricsSource?, metricsUpdatedAt?, credentialsRef?, primaryProducts? }")
1300
+ .requiredOption("-j, --json <json>", "{ handle?, profileUrl?, status?, externalId?, externalRef?, personaId?, karma?, accountAgeDays?, registeredAt?, workflowStage?, metricsSource?, metricsUpdatedAt?, credentialsRef?, primaryProducts? }")
1257
1301
  .action(async (opts) => {
1258
1302
  const body = JSON.parse(opts.json);
1259
1303
  const misplaced = detectMisplacedAccountFields(body);
@@ -1264,6 +1308,18 @@ accounts
1264
1308
  const res = await requireClient().updateAccount(opts.team, opts.account, body);
1265
1309
  console.log(JSON.stringify(res, null, 2));
1266
1310
  });
1311
+ accounts
1312
+ .command("reassign")
1313
+ .description("POST /accounts/:id/reassign — 把账号从 -t <team> 移到 --to <team>。运营配置(浏览器环境/人设/子版亲和/封禁)跟账号走,纯历史留原队,原队待跑任务取消。目标队撞唯一键返回 409")
1314
+ .requiredOption("-t, --team <teamId>", "源 Team UUID(账号当前所属)")
1315
+ .requiredOption("--account <uuid>", "Account UUID")
1316
+ .requiredOption("--to <teamId>", "目标 Team UUID")
1317
+ .action(async (opts) => {
1318
+ const res = await requireClient().reassignAccount(opts.team, opts.account, {
1319
+ toTeamId: opts.to,
1320
+ });
1321
+ console.log(JSON.stringify(res, null, 2));
1322
+ });
1267
1323
  // 账号数据多面一次性同步:纯 CLI 编排——把单个 JSON 拆成各写入面,依次调用
1268
1324
  // 已有的 per-resource SDK 方法。服务端无新端点;每个面仍走各自校验过的路由。
1269
1325
  // JSON 中出现的面才写,未出现的跳过;逐面 continue-and-report,任一面失败退出码非零。
@@ -1439,7 +1495,7 @@ drafts
1439
1495
  .description("PATCH /content-drafts/:id")
1440
1496
  .requiredOption("-t, --team <teamId>", "Team UUID")
1441
1497
  .requiredOption("--draft <uuid>", "Draft UUID")
1442
- .requiredOption("-j, --json <json>", "{ title?, body?, status? }")
1498
+ .requiredOption("-j, --json <json>", "{ title?, body?, status?, expectedVersion? }(传 expectedVersion 开乐观并发,版本不匹配→409)")
1443
1499
  .action(async (opts) => {
1444
1500
  const body = JSON.parse(opts.json);
1445
1501
  const res = await requireClient().updateContentDraft(opts.team, opts.draft, body);
@@ -1950,7 +2006,7 @@ intel
1950
2006
  .command("runs-list")
1951
2007
  .description("GET .../subreddit-intelligence/runs")
1952
2008
  .option("--dimension <d>", "industry|keywords|tier")
1953
- .option("--status <s>", "queued|running|succeeded|failed")
2009
+ .option("--status <s>", "queued|running|succeeded|partial|failed")
1954
2010
  .option("-n, --limit <n>", "limit", "50")
1955
2011
  .option("--offset <n>", "offset", "0")
1956
2012
  .action(async (opts) => {
@@ -2781,6 +2837,8 @@ reddit
2781
2837
  .option("--repost-type <t>", "repostType filter (none|first|second)")
2782
2838
  .option("--contains-brand-keyword <v>", "true | false | unset")
2783
2839
  .option("--primary-product <text>", "primary product contains match")
2840
+ .option("--sort-by <f>", "score|comments_count|posted_at|view_count|seq_no")
2841
+ .option("--sort-dir <d>", "asc|desc")
2784
2842
  .option("-n, --limit <n>", "limit per page", "100")
2785
2843
  .option("--offset <n>", "pagination offset")
2786
2844
  .option("--all", "fetch all pages (200 per request until total reached)")
@@ -2797,6 +2855,8 @@ reddit
2797
2855
  repostType: opts.repostType,
2798
2856
  containsBrandKeyword: opts.containsBrandKeyword,
2799
2857
  primaryProduct: opts.primaryProduct,
2858
+ sortBy: opts.sortBy,
2859
+ sortDir: opts.sortDir,
2800
2860
  limit: Number(opts.limit),
2801
2861
  offset: opts.offset !== undefined ? Number(opts.offset) : undefined,
2802
2862
  ...redditAggregateQueryParams(opts),