@geoly-ai/social-hub-cli 0.3.18 → 0.3.20

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 (63) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/cmd-manifest.json +4 -2
  3. package/dist/content-review.test.js +1 -1
  4. package/dist/index.d.ts +24 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +98 -8
  7. package/dist/index.js.map +1 -1
  8. package/dist/register-calendar-directives.d.ts +64 -0
  9. package/dist/register-calendar-directives.d.ts.map +1 -0
  10. package/dist/register-calendar-directives.js +135 -0
  11. package/dist/register-calendar-directives.js.map +1 -0
  12. package/dist/register-calendar-directives.test.d.ts +2 -0
  13. package/dist/register-calendar-directives.test.d.ts.map +1 -0
  14. package/dist/register-calendar-directives.test.js +127 -0
  15. package/dist/register-calendar-directives.test.js.map +1 -0
  16. package/dist/scrape-output.test.d.ts +2 -0
  17. package/dist/scrape-output.test.d.ts.map +1 -0
  18. package/dist/scrape-output.test.js +58 -0
  19. package/dist/scrape-output.test.js.map +1 -0
  20. package/package.json +2 -2
  21. package/skills/README.md +23 -22
  22. package/skills/manifest.json +6 -1
  23. package/skills/reddit-content-rewrite/SKILL.md +29 -0
  24. package/skills/reddit-content-writing/SKILL.md +54 -5
  25. package/skills/reddit-content-writing/references/phase4-execution-table.md +24 -3
  26. package/skills/reddit-content-writing/references/phase4-writing.md +123 -3
  27. package/skills/reddit-content-writing/references/post-writing-templates.md +14 -6
  28. package/skills/reddit-delivery-check/SKILL.md +39 -6
  29. package/skills/reddit-delivery-check/references/phase5-delivery.md +7 -1
  30. package/skills/reddit-matrix.lock.json +10 -10
  31. package/skills/reddit-phase-brief/SKILL.md +62 -11
  32. package/skills/reddit-phase-brief/references/brand-SKU-PGC-rules.md +223 -36
  33. package/skills/reddit-phase-brief/references/phase4-brief-workflow.md +405 -19
  34. package/skills/reddit-phase-planning/SKILL.md +13 -0
  35. package/skills/reddit-phase-planning/references/phase4-execution-table.md +16 -2
  36. package/skills/reddit-phase-planning/references/phase4-planning.md +74 -15
  37. package/skills/reddit-phase-planning/references/scheduling-decision-procedure.md +386 -0
  38. package/skills/reddit-phase-research/SKILL.md +7 -1
  39. package/skills/reddit-phase-research/references/phase01-research.md +93 -29
  40. package/skills/reddit-strategy-orchestrator/SKILL.md +120 -18
  41. package/skills/reddit-strategy-shared/SKILL.md +4 -2
  42. package/skills/reddit-strategy-shared/references/content-diversity-contract.md +26 -5
  43. package/skills/reddit-strategy-shared/references/content-review-gate.md +48 -1
  44. package/skills/reddit-strategy-shared/references/context-contract.md +45 -11
  45. package/skills/reddit-strategy-shared/references/evidence-policy.md +139 -0
  46. package/skills/reddit-strategy-shared/references/handoff-schemas.md +88 -3
  47. package/skills/reddit-strategy-shared/references/native-copy-profile.md +207 -0
  48. package/skills/reddit-strategy-shared/references/path-conventions.md +26 -4
  49. package/skills/reddit-strategy-shared/references/persona-card-contract.md +210 -0
  50. package/skills/reddit-strategy-shared/references/prerequisites/README.md +57 -0
  51. package/skills/reddit-strategy-shared/references/prerequisites/{reddit-master-canvas-agent-prompt-template.md → archive/reddit-master-canvas-agent-prompt-template.md} +7 -0
  52. package/skills/reddit-strategy-shared/references/prerequisites/{reddit-sop-v2-universal.md → archive/reddit-sop-v2-universal.md} +7 -0
  53. package/skills/reddit-strategy-shared/references/prerequisites/{reddit-strategy-prerequisites-read.md → archive/reddit-strategy-prerequisites-read.md} +7 -0
  54. package/skills/reddit-strategy-shared/references/prerequisites/{reddit-strategy-reuse-playbook.md → archive/reddit-strategy-reuse-playbook.md} +7 -0
  55. package/skills/reddit-strategy-shared/references/subreddit-research-profile.md +514 -0
  56. package/skills/reddit-strategy-shared/references/version-manifest.md +89 -2
  57. package/skills/reddit-subreddit-compliance/SKILL.md +28 -1
  58. package/skills/reddit-voc-volume/matrix-contract.md +16 -1
  59. package/skills/social-hub-calendar-directives/SKILL.md +548 -0
  60. package/skills/social-hub-calendar-jobs/SKILL.md +10 -0
  61. package/skills/social-hub-cli/SKILL.md +2 -0
  62. package/skills/social-hub-notifications/SKILL.md +7 -0
  63. package/skills/social-hub-publishing/SKILL.md +5 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,35 @@ 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.3.20] - 2026-08-18
8
+
9
+ ### Added
10
+
11
+ - 发布日历指令端到端接线(Block 5) + 封死 D1 旁路
12
+ - 发布日历指令的 SDK/CLI/skills 交付面(Block 6)
13
+
14
+ ### Changed
15
+
16
+ - response mock 的 rubricVersion 跟到 content-review.v5
17
+
18
+ ### Documentation
19
+
20
+ - 写作侧 matrix skill 对齐冻结契约(块 2d)+ 删掉 WeaklyVerified
21
+
22
+ ## [0.3.19] - 2026-08-14
23
+
24
+ ### Added
25
+
26
+ - classify outcomes instead of reporting 2xx login pages as success
27
+
28
+ ### Fixed
29
+
30
+ - align AUTHZ_POLICY_VERSION with package version
31
+
32
+ ### Changed
33
+
34
+ - rebuild reddit matrix SOP around evidence and decision gates
35
+
7
36
  ## [0.3.18] - 2026-08-13
8
37
 
9
38
  ### Added
@@ -1,6 +1,6 @@
1
1
  {
2
- "generatedAt": "2026-08-13T06:30:51.783Z",
3
- "cliVersion": "0.3.18",
2
+ "generatedAt": "2026-08-18T09:08:50.530Z",
3
+ "cliVersion": "0.3.20",
4
4
  "commands": [
5
5
  "accounts",
6
6
  "accounts brand-bindings",
@@ -111,6 +111,8 @@
111
111
  "calendar list",
112
112
  "calendar list-full",
113
113
  "calendar patch",
114
+ "calendar preflight",
115
+ "calendar set-delivery-mode",
114
116
  "campaigns",
115
117
  "campaigns accounts",
116
118
  "campaigns accounts assign",
@@ -73,7 +73,7 @@ const okResult = {
73
73
  optimized: null,
74
74
  rationale: null,
75
75
  reviewModel: "m",
76
- rubricVersion: "content-review.v4",
76
+ rubricVersion: "content-review.v5",
77
77
  thresholdSnapshot: {},
78
78
  latencyMs: 12,
79
79
  degradedReason: null,
package/dist/index.d.ts CHANGED
@@ -22,5 +22,29 @@ export declare function orchestrateVocAcquire(client: VocAcquireClient, params:
22
22
  exitCode: 0 | 1 | 2;
23
23
  output: Record<string, unknown>;
24
24
  }>;
25
+ /**
26
+ * 业务失败(HTTP 200 + ok:false)的人类可读摘要:抓到了页面,但**不是正文**。
27
+ * 结论(outcome) + 阶段 + provider request id 全部打出来,别再让人对着通用错误猜。
28
+ */
29
+ export declare function formatScrapeFailure(res: {
30
+ outcome: string;
31
+ finalUrl?: string;
32
+ targetStatusCode?: number | null;
33
+ failureStage?: string | null;
34
+ providerRequestId?: string | null;
35
+ requestId?: string | null;
36
+ attempts?: number;
37
+ retryAfterMs?: number | null;
38
+ classifierVersion?: string;
39
+ classificationEvidence?: Array<{
40
+ ruleId: string;
41
+ signal: string;
42
+ }>;
43
+ }): string;
44
+ /**
45
+ * 技术层失败(429/502/504 等)的摘要:把 provider typed code / 失败阶段 /
46
+ * request id 从 `details` 里挖出来,取代以前的「Scrape service returned HTTP 500」。
47
+ */
48
+ export declare function formatScrapeError(e: unknown): string;
25
49
  export { program };
26
50
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuDpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AA8+E9B,8DAA8D;AAC9D,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,GAAG,IAAI,CAOf;AAg+BD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1D,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjE,CAAC;AAQF,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE;IACN,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC,GACA,OAAO,CAAC;IAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,CAkJnE;AA47ED,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;AA4DpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AA2gF9B,8DAA8D;AAC9D,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,GAAG,IAAI,CAOf;AAg+BD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1D,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjE,CAAC;AAQF,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE;IACN,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC,GACA,OAAO,CAAC;IAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC,CAkJnE;AAyqBD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,sBAAsB,CAAC,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpE,GAAG,MAAM,CAiBT;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAyCpD;AAgyDD,OAAO,EAAE,OAAO,EAAE,CAAC"}
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@ import { registerSubredditStyleCommands } from "./register-subreddit-style.js";
8
8
  import { registerContentClassificationCommands } from "./register-content-classification.js";
9
9
  import { registerNotifyCommands } from "./register-notify.js";
10
10
  import { registerFeishuIdentityCommands } from "./register-feishu-identities.js";
11
+ import { registerCalendarDirectiveCommands, calendarPatchNeedsGate, deliveryModeChangeRequiresApply, } from "./register-calendar-directives.js";
11
12
  import { assertApplyOrDryRun } from "./dry-run.js";
12
13
  import { withPermissionGate } from "./permission-runner.js";
13
14
  import { registerBatchAndExport } from "./register-batch.js";
@@ -284,6 +285,7 @@ dashboard
284
285
  });
285
286
  // --- calendar ---
286
287
  const calendar = program.command("calendar").description("发布日历条目");
288
+ registerCalendarDirectiveCommands(calendar);
287
289
  calendar
288
290
  .command("list")
289
291
  .description("GET /calendar-entries")
@@ -311,6 +313,8 @@ calendar
311
313
  .option("-t, --team <teamId>", "Team UUID(缺省用当前 context)")
312
314
  .requiredOption("-e, --entry <entryId>", "Calendar entry UUID")
313
315
  .requiredOption("--body <json>", '例如 {"status":"succeeded","permalink":"https://www.reddit.com/..."}')
316
+ .option("--dry-run", "预览写入,不调用 API", false)
317
+ .option("--apply", "执行写入(仅 deliveryMode 变更必填)", false)
314
318
  .action(async (opts) => {
315
319
  let body;
316
320
  try {
@@ -320,7 +324,31 @@ calendar
320
324
  console.error("Invalid --body JSON");
321
325
  process.exit(1);
322
326
  }
323
- const res = await requireClient().updateCalendarEntry(resolveTeamId(opts.team), opts.entry, body);
327
+ const teamId = resolveTeamId(opts.team);
328
+ // 两道门,判据不同,不能合成一条:
329
+ //
330
+ // `--dry-run` **对任何 body 都必须生效** —— 全局 flag 契约是「预览写入,不调用
331
+ // API」(docs/command-governance.md)。只在 deliveryMode 分支上认它,就会出现
332
+ // 「我明明加了 --dry-run,它却真的把状态改了」这种最不该有的意外写入。
333
+ //
334
+ // `--apply` **只在 body 含 `deliveryMode` 时必填**。它是防重复发帖的唯一闸门
335
+ // (方案 D1):改它会让服务端在同一事务里撤销/创建内部 publish_post job 并
336
+ // append 指令。`calendar set-delivery-mode` 已经带这道门,raw patch 必须同样
337
+ // 挡住,否则那道门只是装饰。其余字段(status/permalink/…)不加必填门,既有
338
+ // 自动化行为完全不变。
339
+ if (calendarPatchNeedsGate(body, opts) &&
340
+ !assertApplyOrDryRun(opts, {
341
+ command: deliveryModeChangeRequiresApply(body)
342
+ ? "calendar patch (deliveryMode)"
343
+ : "calendar patch",
344
+ danger: deliveryModeChangeRequiresApply(body)
345
+ ? "切换发布主体:转 external_agent 会撤销内部 publish_post job 并发 upsert 指令;转 hub_managed 会发 cancel 指令并建内部 job。改错 = 双发或谁都不发。"
346
+ : "更新日历条目",
347
+ summary: { teamId, calendarEntryId: opts.entry, body },
348
+ })) {
349
+ return;
350
+ }
351
+ const res = await requireClient().updateCalendarEntry(teamId, opts.entry, body);
324
352
  console.log(JSON.stringify(res, null, 2));
325
353
  });
326
354
  // --- reddit ---
@@ -3272,6 +3300,56 @@ intel
3272
3300
  const scrapeCmd = program
3273
3301
  .command("scrape")
3274
3302
  .description("通用网页抓取(Reddit .json 直连 / HTML 经 Firecrawl)");
3303
+ /**
3304
+ * 业务失败(HTTP 200 + ok:false)的人类可读摘要:抓到了页面,但**不是正文**。
3305
+ * 结论(outcome) + 阶段 + provider request id 全部打出来,别再让人对着通用错误猜。
3306
+ */
3307
+ export function formatScrapeFailure(res) {
3308
+ const evidence = (res.classificationEvidence ?? [])
3309
+ .map((e) => `${e.ruleId}(${e.signal})`)
3310
+ .join(", ");
3311
+ const parts = [
3312
+ `scrape 未取得正文:outcome=${res.outcome}`,
3313
+ `targetStatus=${res.targetStatusCode ?? "null"}`,
3314
+ `finalUrl=${res.finalUrl ?? "null"}`,
3315
+ `stage=${res.failureStage ?? "null"}`,
3316
+ `attempts=${res.attempts ?? 1}`,
3317
+ ];
3318
+ if (res.retryAfterMs != null)
3319
+ parts.push(`retryAfterMs=${res.retryAfterMs}`);
3320
+ parts.push(`requestId=${res.requestId ?? "null"}`);
3321
+ parts.push(`providerRequestId=${res.providerRequestId ?? "null"}`);
3322
+ if (res.classifierVersion)
3323
+ parts.push(`classifier=${res.classifierVersion}`);
3324
+ if (evidence)
3325
+ parts.push(`evidence=[${evidence}]`);
3326
+ return parts.join(" ");
3327
+ }
3328
+ /**
3329
+ * 技术层失败(429/502/504 等)的摘要:把 provider typed code / 失败阶段 /
3330
+ * request id 从 `details` 里挖出来,取代以前的「Scrape service returned HTTP 500」。
3331
+ */
3332
+ export function formatScrapeError(e) {
3333
+ const err = e;
3334
+ const base = err?.message ?? String(e);
3335
+ const d = err?.details;
3336
+ if (!d?.outcome)
3337
+ return base;
3338
+ const p = d.diagnostics?.provider ?? {};
3339
+ const x = d.diagnostics?.execution ?? {};
3340
+ return [
3341
+ base,
3342
+ `code=${err.code ?? "null"}`,
3343
+ `outcome=${d.outcome}`,
3344
+ `stage=${x.failureStage ?? "null"}`,
3345
+ `providerStatus=${p.providerStatusCode ?? "null"}`,
3346
+ `providerErrorCode=${p.providerErrorCode ?? "null"}`,
3347
+ `providerRequestId=${p.providerRequestId ?? "null"}`,
3348
+ `providerScrapeId=${p.providerScrapeId ?? "null"}`,
3349
+ `attempts=${x.attemptCount ?? 1}`,
3350
+ ...(x.retryAfterMs != null ? [`retryAfterMs=${x.retryAfterMs}`] : []),
3351
+ ].join(" ");
3352
+ }
3275
3353
  scrapeCmd
3276
3354
  .command("url <url>")
3277
3355
  .description("POST /v1/system/scrape —— 抓取任意网页(Reddit .json 或 HTML)")
@@ -3285,13 +3363,25 @@ scrapeCmd
3285
3363
  .map((s) => s.trim())
3286
3364
  .filter(Boolean)
3287
3365
  : undefined;
3288
- const res = await requireClient().scrapeUrl({
3289
- url,
3290
- formats,
3291
- mode: opts.redditJson ? "reddit-json" : undefined,
3292
- timeoutMs: opts.timeout ? Number(opts.timeout) : undefined,
3293
- });
3294
- console.log(JSON.stringify(res, null, 2));
3366
+ try {
3367
+ const res = await requireClient().scrapeUrl({
3368
+ url,
3369
+ formats,
3370
+ mode: opts.redditJson ? "reddit-json" : undefined,
3371
+ timeoutMs: opts.timeout ? Number(opts.timeout) : undefined,
3372
+ });
3373
+ console.log(JSON.stringify(res, null, 2));
3374
+ if (!res.ok) {
3375
+ // 业务失败(2xx 登录墙/验证码/空正文/目标站限流…):HTTP 是 200,但**不是正文**。
3376
+ // 退出码必须非零,否则 shell/agent 会把「抓到登录页」当成抓取成功。
3377
+ console.error(formatScrapeFailure(res));
3378
+ process.exit(2);
3379
+ }
3380
+ }
3381
+ catch (e) {
3382
+ console.error(formatScrapeError(e));
3383
+ process.exit(1);
3384
+ }
3295
3385
  });
3296
3386
  scrapeCmd
3297
3387
  .command("status")