@geoly-ai/social-hub-cli 0.3.11 → 0.3.13
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 +14 -0
- package/dist/cmd-manifest.json +2 -2
- package/dist/content-review.test.d.ts +2 -0
- package/dist/content-review.test.d.ts.map +1 -0
- package/dist/content-review.test.js +222 -0
- package/dist/content-review.test.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +39 -15
- package/dist/index.js.map +1 -1
- package/dist/lib/content-review-args.d.ts +43 -0
- package/dist/lib/content-review-args.d.ts.map +1 -0
- package/dist/lib/content-review-args.js +77 -0
- package/dist/lib/content-review-args.js.map +1 -0
- package/dist/lib/content-review-args.test.d.ts +2 -0
- package/dist/lib/content-review-args.test.d.ts.map +1 -0
- package/dist/lib/content-review-args.test.js +126 -0
- package/dist/lib/content-review-args.test.js.map +1 -0
- package/dist/permissions-gates-admin.d.ts.map +1 -1
- package/dist/permissions-gates-admin.js +10 -1
- package/dist/permissions-gates-admin.js.map +1 -1
- package/dist/permissions-gates-admin.test.js +11 -0
- package/dist/permissions-gates-admin.test.js.map +1 -1
- package/dist/register-notify.d.ts +0 -12
- package/dist/register-notify.d.ts.map +1 -1
- package/dist/register-notify.js +30 -3
- package/dist/register-notify.js.map +1 -1
- package/dist/register-subreddit-post-style.d.ts +8 -0
- package/dist/register-subreddit-post-style.d.ts.map +1 -0
- package/dist/register-subreddit-post-style.js +161 -0
- package/dist/register-subreddit-post-style.js.map +1 -0
- package/package.json +3 -3
- package/skills/manifest.json +1 -1
- package/skills/reddit-voc-volume/services/firecrawl/examples/o1_web_crawler/o1_web_crawler.py +152 -152
- package/skills/social-hub-content-review/SKILL.md +58 -1
- package/skills/social-hub-notifications/SKILL.md +67 -13
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `social-hub content review` 的便利参数合并(作者关系轴)。
|
|
3
|
+
*
|
|
4
|
+
* 抽成纯函数是为了单测:合并逻辑有两条容易写错的边界 ——
|
|
5
|
+
* (1) `resolveJsonArg<unknown>` 的返回只是**类型断言**,运行时 body 仍可能是
|
|
6
|
+
* `null` / 数组 / 字符串,直接展开会静默丢数据;
|
|
7
|
+
* (2) `--thread-permalink` 要写进嵌套的 `thread` 对象,但 `thread.subreddit` / `postTitle`
|
|
8
|
+
* 是服务端必填 —— body 里没有 thread 时**本地报错**,绝不凭空造一个只有 permalink 的
|
|
9
|
+
* thread(那只会换来一个更晚、更难懂的 400)。
|
|
10
|
+
*
|
|
11
|
+
* ⚠️ `authorRelationHint` 只是**非权威提示**:服务端按账号 handle × permalink × 帖子快照
|
|
12
|
+
* 派生权威 `authorRelation`,证据永远覆盖 hint。本模块不做任何「本地推断身份」的事。
|
|
13
|
+
*/
|
|
14
|
+
import type { ContentReviewAuthorRelationHint } from "@geoly-ai/social-hub-sdk";
|
|
15
|
+
/** 参数级错误(CLI 侧本地拒绝,不发请求)。 */
|
|
16
|
+
export declare class ContentReviewArgError extends Error {
|
|
17
|
+
constructor(message: string);
|
|
18
|
+
}
|
|
19
|
+
export declare const AUTHOR_RELATION_HINT_VALUES: readonly ContentReviewAuthorRelationHint[];
|
|
20
|
+
/** 与 contracts `contentReviewThreadSchema.threadPermalink` 的上限一致。 */
|
|
21
|
+
export declare const MAX_THREAD_PERMALINK_LENGTH = 2048;
|
|
22
|
+
/**
|
|
23
|
+
* 解析 `--author-relation-hint`。只收精确的枚举值:大小写/空白一律不猜 ——
|
|
24
|
+
* 猜错会把「声称是作者」和「声称不是」搞反,而前者失配是 422 硬失败。
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseAuthorRelationHint(raw: string): ContentReviewAuthorRelationHint;
|
|
27
|
+
export type ContentReviewFlagInput = {
|
|
28
|
+
threadPermalink?: string;
|
|
29
|
+
authorRelationHint?: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* 把便利参数合并进 body(不原地修改入参;便利参数覆盖 `-j` 里的同名值,
|
|
33
|
+
* 与既有 `--brand-context` 的覆盖语义一致)。
|
|
34
|
+
*/
|
|
35
|
+
export declare function applyContentReviewFlags(body: unknown, flags: ContentReviewFlagInput): Record<string, unknown>;
|
|
36
|
+
/**
|
|
37
|
+
* 422 `AUTHOR_RELATION_MISMATCH` 的可行动提示。
|
|
38
|
+
*
|
|
39
|
+
* 刻意**不打印服务端 details**:里面含规范化 handle / 帖子作者 / permalink。
|
|
40
|
+
* 也刻意不建议「换一个 permalink 重试」—— 那是 anchor shopping,正是这条 422 要防的。
|
|
41
|
+
*/
|
|
42
|
+
export declare const AUTHOR_RELATION_MISMATCH_HINT: string;
|
|
43
|
+
//# sourceMappingURL=content-review-args.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-review-args.d.ts","sourceRoot":"","sources":["../../src/lib/content-review-args.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,0BAA0B,CAAC;AAEhF,6BAA6B;AAC7B,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,eAAO,MAAM,2BAA2B,EAAE,SAAS,+BAA+B,EACxD,CAAC;AAE3B,qEAAqE;AACrE,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAMhD;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,MAAM,GACV,+BAA+B,CASjC;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,sBAAsB,GAC5B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsCzB;AAED;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,QAIiC,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `social-hub content review` 的便利参数合并(作者关系轴)。
|
|
3
|
+
*
|
|
4
|
+
* 抽成纯函数是为了单测:合并逻辑有两条容易写错的边界 ——
|
|
5
|
+
* (1) `resolveJsonArg<unknown>` 的返回只是**类型断言**,运行时 body 仍可能是
|
|
6
|
+
* `null` / 数组 / 字符串,直接展开会静默丢数据;
|
|
7
|
+
* (2) `--thread-permalink` 要写进嵌套的 `thread` 对象,但 `thread.subreddit` / `postTitle`
|
|
8
|
+
* 是服务端必填 —— body 里没有 thread 时**本地报错**,绝不凭空造一个只有 permalink 的
|
|
9
|
+
* thread(那只会换来一个更晚、更难懂的 400)。
|
|
10
|
+
*
|
|
11
|
+
* ⚠️ `authorRelationHint` 只是**非权威提示**:服务端按账号 handle × permalink × 帖子快照
|
|
12
|
+
* 派生权威 `authorRelation`,证据永远覆盖 hint。本模块不做任何「本地推断身份」的事。
|
|
13
|
+
*/
|
|
14
|
+
/** 参数级错误(CLI 侧本地拒绝,不发请求)。 */
|
|
15
|
+
export class ContentReviewArgError extends Error {
|
|
16
|
+
constructor(message) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = "ContentReviewArgError";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export const AUTHOR_RELATION_HINT_VALUES = ["post_author", "other"];
|
|
22
|
+
/** 与 contracts `contentReviewThreadSchema.threadPermalink` 的上限一致。 */
|
|
23
|
+
export const MAX_THREAD_PERMALINK_LENGTH = 2048;
|
|
24
|
+
function isPlainRecord(value) {
|
|
25
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 解析 `--author-relation-hint`。只收精确的枚举值:大小写/空白一律不猜 ——
|
|
29
|
+
* 猜错会把「声称是作者」和「声称不是」搞反,而前者失配是 422 硬失败。
|
|
30
|
+
*/
|
|
31
|
+
export function parseAuthorRelationHint(raw) {
|
|
32
|
+
if (AUTHOR_RELATION_HINT_VALUES.includes(raw) === false) {
|
|
33
|
+
throw new ContentReviewArgError(`--author-relation-hint 只接受 ${AUTHOR_RELATION_HINT_VALUES.join(" | ")}(区分大小写),收到: ${JSON.stringify(raw)}`);
|
|
34
|
+
}
|
|
35
|
+
return raw;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 把便利参数合并进 body(不原地修改入参;便利参数覆盖 `-j` 里的同名值,
|
|
39
|
+
* 与既有 `--brand-context` 的覆盖语义一致)。
|
|
40
|
+
*/
|
|
41
|
+
export function applyContentReviewFlags(body, flags) {
|
|
42
|
+
if (!isPlainRecord(body)) {
|
|
43
|
+
throw new ContentReviewArgError(`content review 的 JSON 入参必须是一个对象,收到: ${Array.isArray(body) ? "array" : String(body === null ? "null" : typeof body)}`);
|
|
44
|
+
}
|
|
45
|
+
const next = { ...body };
|
|
46
|
+
if (flags.authorRelationHint !== undefined) {
|
|
47
|
+
next["authorRelationHint"] = parseAuthorRelationHint(flags.authorRelationHint);
|
|
48
|
+
}
|
|
49
|
+
if (flags.threadPermalink !== undefined) {
|
|
50
|
+
// 空串/纯空白不是「不给」:它会覆盖掉 -j 里本来有效的 permalink,而服务端
|
|
51
|
+
// `z.string().trim().min(1)` 只会回一个 400。本地拒绝,给出能直接照做的提示。
|
|
52
|
+
const permalink = flags.threadPermalink.trim();
|
|
53
|
+
if (permalink.length === 0) {
|
|
54
|
+
throw new ContentReviewArgError("--thread-permalink 不能为空:要么给出所审原帖的真实 permalink,要么整个省略该参数(省略=按 unknown 基线审核,不受惩罚)。");
|
|
55
|
+
}
|
|
56
|
+
if (permalink.length > MAX_THREAD_PERMALINK_LENGTH) {
|
|
57
|
+
throw new ContentReviewArgError(`--thread-permalink 超过服务端上限 ${MAX_THREAD_PERMALINK_LENGTH} 字符(收到 ${permalink.length})。`);
|
|
58
|
+
}
|
|
59
|
+
const thread = next["thread"];
|
|
60
|
+
if (!isPlainRecord(thread)) {
|
|
61
|
+
throw new ContentReviewArgError("--thread-permalink 需要 JSON 入参里已有 thread 对象(thread.subreddit / thread.postTitle 是必填,CLI 不会替你编造)。");
|
|
62
|
+
}
|
|
63
|
+
next["thread"] = { ...thread, threadPermalink: permalink };
|
|
64
|
+
}
|
|
65
|
+
return next;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* 422 `AUTHOR_RELATION_MISMATCH` 的可行动提示。
|
|
69
|
+
*
|
|
70
|
+
* 刻意**不打印服务端 details**:里面含规范化 handle / 帖子作者 / permalink。
|
|
71
|
+
* 也刻意不建议「换一个 permalink 重试」—— 那是 anchor shopping,正是这条 422 要防的。
|
|
72
|
+
*/
|
|
73
|
+
export const AUTHOR_RELATION_MISMATCH_HINT = "提示:你显式声称 --author-relation-hint post_author,但 Hub 侧帖子快照显示本次发布账号不是该帖作者。\n" +
|
|
74
|
+
" 这是硬失败(本次一次 LLM 都没调用,服务端已落安全审计),重试不会自愈,换一个能通过校验的 permalink 更不行。\n" +
|
|
75
|
+
" 请核对:发布账号是否搞错了 / thread.threadPermalink 是否确实指向本次要回复的那篇帖子。\n" +
|
|
76
|
+
" 如果你本来就不是原帖作者:去掉 --author-relation-hint 重跑即可(不声称=正常按证据派生,不影响评分标准)。";
|
|
77
|
+
//# sourceMappingURL=content-review-args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-review-args.js","sourceRoot":"","sources":["../../src/lib/content-review-args.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,6BAA6B;AAC7B,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED,MAAM,CAAC,MAAM,2BAA2B,GACtC,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;AAE3B,qEAAqE;AACrE,MAAM,CAAC,MAAM,2BAA2B,GAAG,IAAI,CAAC;AAEhD,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,GAAW;IAEX,IACG,2BAAiD,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,KAAK,EAC1E,CAAC;QACD,MAAM,IAAI,qBAAqB,CAC7B,8BAA8B,2BAA2B,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAC1G,CAAC;IACJ,CAAC;IACD,OAAO,GAAsC,CAAC;AAChD,CAAC;AAOD;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACrC,IAAa,EACb,KAA6B;IAE7B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,qBAAqB,CAC7B,uCAAuC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,EAAE,CACtH,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAA4B,EAAE,GAAG,IAAI,EAAE,CAAC;IAElD,IAAI,KAAK,CAAC,kBAAkB,KAAK,SAAS,EAAE,CAAC;QAC3C,IAAI,CAAC,oBAAoB,CAAC,GAAG,uBAAuB,CAClD,KAAK,CAAC,kBAAkB,CACzB,CAAC;IACJ,CAAC;IAED,IAAI,KAAK,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;QACxC,8CAA8C;QAC9C,wDAAwD;QACxD,MAAM,SAAS,GAAG,KAAK,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;QAC/C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,qBAAqB,CAC7B,kFAAkF,CACnF,CAAC;QACJ,CAAC;QACD,IAAI,SAAS,CAAC,MAAM,GAAG,2BAA2B,EAAE,CAAC;YACnD,MAAM,IAAI,qBAAqB,CAC7B,8BAA8B,2BAA2B,UAAU,SAAS,CAAC,MAAM,IAAI,CACxF,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC9B,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,qBAAqB,CAC7B,iGAAiG,CAClG,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC;IAC7D,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,6BAA6B,GACxC,0EAA0E;IAC1E,wEAAwE;IACxE,kEAAkE;IAClE,yEAAyE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-review-args.test.d.ts","sourceRoot":"","sources":["../../src/lib/content-review-args.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `content review` 便利参数合并的纯函数单测。
|
|
3
|
+
*
|
|
4
|
+
* 重点不是「flag 能写进 body」,而是几条 fail-closed 边界:
|
|
5
|
+
* - JSON 入参运行时不是对象(null/数组/字符串)必须本地报错,不能静默展开成空对象;
|
|
6
|
+
* - `--thread-permalink` 不会凭空造 thread(subreddit/postTitle 是服务端必填);
|
|
7
|
+
* - hint 只收精确枚举值 —— 猜大小写会把「声称是作者」和「声称不是」搞反,而前者失配是
|
|
8
|
+
* 422 硬失败。
|
|
9
|
+
*/
|
|
10
|
+
import { describe, expect, it } from "vitest";
|
|
11
|
+
import { applyContentReviewFlags, AUTHOR_RELATION_MISMATCH_HINT, ContentReviewArgError, MAX_THREAD_PERMALINK_LENGTH, parseAuthorRelationHint, } from "./content-review-args.js";
|
|
12
|
+
const baseBody = {
|
|
13
|
+
draft: "Update: turned out to be the PSU cable.",
|
|
14
|
+
commentType: "top_level",
|
|
15
|
+
thread: {
|
|
16
|
+
subreddit: "buildapc",
|
|
17
|
+
postTitle: "PC reboots under load",
|
|
18
|
+
topComments: ["check the PSU"],
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
describe("applyContentReviewFlags", () => {
|
|
22
|
+
it("无 flag 时内容不变,且不原地修改入参", () => {
|
|
23
|
+
const input = structuredClone(baseBody);
|
|
24
|
+
const out = applyContentReviewFlags(input, {});
|
|
25
|
+
expect(out).toEqual(baseBody);
|
|
26
|
+
expect(out).not.toBe(input);
|
|
27
|
+
expect(input).toEqual(baseBody);
|
|
28
|
+
});
|
|
29
|
+
it("--thread-permalink 写进 thread 并保留 thread 其他字段", () => {
|
|
30
|
+
const input = structuredClone(baseBody);
|
|
31
|
+
const out = applyContentReviewFlags(input, {
|
|
32
|
+
threadPermalink: "https://www.reddit.com/r/buildapc/comments/abc/x/",
|
|
33
|
+
});
|
|
34
|
+
expect(out["thread"]).toEqual({
|
|
35
|
+
subreddit: "buildapc",
|
|
36
|
+
postTitle: "PC reboots under load",
|
|
37
|
+
topComments: ["check the PSU"],
|
|
38
|
+
threadPermalink: "https://www.reddit.com/r/buildapc/comments/abc/x/",
|
|
39
|
+
});
|
|
40
|
+
// 原 body.thread 未被就地改写。
|
|
41
|
+
expect(input.thread).not.toHaveProperty("threadPermalink");
|
|
42
|
+
});
|
|
43
|
+
it("flag 覆盖 -j 里的同名值(与 --brand-context 覆盖语义一致)", () => {
|
|
44
|
+
const out = applyContentReviewFlags({
|
|
45
|
+
...structuredClone(baseBody),
|
|
46
|
+
authorRelationHint: "other",
|
|
47
|
+
thread: { ...baseBody.thread, threadPermalink: "https://old/" },
|
|
48
|
+
}, {
|
|
49
|
+
threadPermalink: "https://new/",
|
|
50
|
+
authorRelationHint: "post_author",
|
|
51
|
+
});
|
|
52
|
+
expect(out["authorRelationHint"]).toBe("post_author");
|
|
53
|
+
expect(out["thread"]["threadPermalink"]).toBe("https://new/");
|
|
54
|
+
});
|
|
55
|
+
it("hint 可以单独给(不强制配 permalink;服务端负责派生 unknown + 记 unverified claim)", () => {
|
|
56
|
+
const out = applyContentReviewFlags(structuredClone(baseBody), {
|
|
57
|
+
authorRelationHint: "post_author",
|
|
58
|
+
});
|
|
59
|
+
expect(out["authorRelationHint"]).toBe("post_author");
|
|
60
|
+
expect(out["thread"]["threadPermalink"]).toBe(undefined);
|
|
61
|
+
});
|
|
62
|
+
it.each([
|
|
63
|
+
["null", null],
|
|
64
|
+
["数组", [1, 2]],
|
|
65
|
+
["字符串", "not-json-object"],
|
|
66
|
+
["数字", 42],
|
|
67
|
+
])("根 JSON 是 %s → 本地参数错误", (_label, raw) => {
|
|
68
|
+
expect(() => applyContentReviewFlags(raw, {})).toThrow(ContentReviewArgError);
|
|
69
|
+
});
|
|
70
|
+
it.each([
|
|
71
|
+
["缺失", {}],
|
|
72
|
+
["null", { thread: null }],
|
|
73
|
+
["数组", { thread: [] }],
|
|
74
|
+
["字符串", { thread: "buildapc" }],
|
|
75
|
+
])("thread %s 时 --thread-permalink 报错而非凭空造 thread", (_l, body) => {
|
|
76
|
+
expect(() => applyContentReviewFlags(body, { threadPermalink: "https://x/" })).toThrow(/thread 对象/);
|
|
77
|
+
});
|
|
78
|
+
it.each([
|
|
79
|
+
["空串", ""],
|
|
80
|
+
["纯空白", " "],
|
|
81
|
+
["制表/换行", "\t\n"],
|
|
82
|
+
])("--thread-permalink 是 %s → 报错(否则会静默覆盖掉 -j 里的有效 permalink,把可核验审核降级成 unknown)", (_l, raw) => {
|
|
83
|
+
expect(() => applyContentReviewFlags(structuredClone(baseBody), {
|
|
84
|
+
threadPermalink: raw,
|
|
85
|
+
})).toThrow(/不能为空/);
|
|
86
|
+
});
|
|
87
|
+
it("permalink 两端空白被 trim 后写入", () => {
|
|
88
|
+
const out = applyContentReviewFlags(structuredClone(baseBody), {
|
|
89
|
+
threadPermalink: " https://x/ ",
|
|
90
|
+
});
|
|
91
|
+
expect(out["thread"]["threadPermalink"]).toBe("https://x/");
|
|
92
|
+
});
|
|
93
|
+
it("permalink 超过服务端上限 → 本地报错", () => {
|
|
94
|
+
expect(() => applyContentReviewFlags(structuredClone(baseBody), {
|
|
95
|
+
threadPermalink: "a".repeat(MAX_THREAD_PERMALINK_LENGTH + 1),
|
|
96
|
+
})).toThrow(new RegExp(String(MAX_THREAD_PERMALINK_LENGTH)));
|
|
97
|
+
// 边界值本身放行。
|
|
98
|
+
expect(() => applyContentReviewFlags(structuredClone(baseBody), {
|
|
99
|
+
threadPermalink: "a".repeat(MAX_THREAD_PERMALINK_LENGTH),
|
|
100
|
+
})).not.toThrow();
|
|
101
|
+
});
|
|
102
|
+
it("thread 缺失但只给 hint 时不报错(hint 不依赖 thread 结构)", () => {
|
|
103
|
+
const out = applyContentReviewFlags({ draft: "x" }, { authorRelationHint: "other" });
|
|
104
|
+
expect(out["authorRelationHint"]).toBe("other");
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
describe("parseAuthorRelationHint", () => {
|
|
108
|
+
it("接受两个精确枚举值", () => {
|
|
109
|
+
expect(parseAuthorRelationHint("post_author")).toBe("post_author");
|
|
110
|
+
expect(parseAuthorRelationHint("other")).toBe("other");
|
|
111
|
+
});
|
|
112
|
+
it.each(["POST_AUTHOR", "Post_Author", " post_author", "op", "unknown", ""])("拒绝 %o(不猜大小写/空白/别名)", (raw) => {
|
|
113
|
+
expect(() => parseAuthorRelationHint(raw)).toThrow(ContentReviewArgError);
|
|
114
|
+
});
|
|
115
|
+
it("unknown 不是可声明的 hint(它是派生结果)", () => {
|
|
116
|
+
expect(() => parseAuthorRelationHint("unknown")).toThrow(/post_author \| other/);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe("AUTHOR_RELATION_MISMATCH_HINT", () => {
|
|
120
|
+
it("说明是硬失败、不建议重试,且不诱导换 permalink(anchor shopping)", () => {
|
|
121
|
+
expect(AUTHOR_RELATION_MISMATCH_HINT).toContain("硬失败");
|
|
122
|
+
expect(AUTHOR_RELATION_MISMATCH_HINT).toContain("重试不会自愈");
|
|
123
|
+
expect(AUTHOR_RELATION_MISMATCH_HINT).toMatch(/换一个能通过校验的 permalink 更不行/);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
//# sourceMappingURL=content-review-args.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-review-args.test.js","sourceRoot":"","sources":["../../src/lib/content-review-args.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions-gates-admin.d.ts","sourceRoot":"","sources":["../src/permissions-gates-admin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,uDAAuD;AACvD,eAAO,MAAM,sBAAsB,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"permissions-gates-admin.d.ts","sourceRoot":"","sources":["../src/permissions-gates-admin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,uDAAuD;AACvD,eAAO,MAAM,sBAAsB,EAAE,iBAAiB,EA8IrD,CAAC"}
|
|
@@ -118,11 +118,20 @@ export const ADMIN_PERMISSION_GATES = [
|
|
|
118
118
|
resource: "apiKey",
|
|
119
119
|
action: "update",
|
|
120
120
|
},
|
|
121
|
+
{
|
|
122
|
+
// 读矩阵也是 admin only —— 端点返回的是**全角色 × 全资源 × 全动作**矩阵 +
|
|
123
|
+
// 字段可见性矩阵(治理配置全貌,不是「我有什么权限」的自查面)。登记它是为了让
|
|
124
|
+
// `auth explain` 本地就说明白,而不是让人打过去吃一个 403。
|
|
125
|
+
command: "permissions matrix",
|
|
126
|
+
resource: "permissionMatrix",
|
|
127
|
+
action: "read",
|
|
128
|
+
note: "admin only;且只认不受限的交互式登录(拒 api_key / 服务 token / 受限 CLI token)",
|
|
129
|
+
},
|
|
121
130
|
{
|
|
122
131
|
command: "permissions-update",
|
|
123
132
|
resource: "permissionMatrix",
|
|
124
133
|
action: "update",
|
|
125
|
-
note: "admin only",
|
|
134
|
+
note: "admin only;且只认不受限的交互式登录(拒 api_key / 服务 token / 受限 CLI token)",
|
|
126
135
|
},
|
|
127
136
|
{
|
|
128
137
|
// 🔴 **update 不是笔误**:能看见「谁在何时改过哪一格权限」是治理信息
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions-gates-admin.js","sourceRoot":"","sources":["../src/permissions-gates-admin.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"permissions-gates-admin.js","sourceRoot":"","sources":["../src/permissions-gates-admin.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,6 +9,17 @@ describe("admin permission gates", () => {
|
|
|
9
9
|
action: "update",
|
|
10
10
|
}));
|
|
11
11
|
});
|
|
12
|
+
// 读矩阵此前**没有登记** —— `auth explain` 于是不会提示它是 admin only,只能等
|
|
13
|
+
// 服务端 403。登记后本地预检就能说明白。
|
|
14
|
+
it("maps `permissions matrix` to permissionMatrix:read (admin only)", () => {
|
|
15
|
+
const gate = findGateForCommand("permissions matrix");
|
|
16
|
+
expect(gate).toEqual(expect.objectContaining({
|
|
17
|
+
resource: "permissionMatrix",
|
|
18
|
+
action: "read",
|
|
19
|
+
}));
|
|
20
|
+
// 读写两条 gate 的 action 必须不同:read/update 的不对称是有意设计。
|
|
21
|
+
expect(findGateForCommand("permissions-update")?.action).toBe("update");
|
|
22
|
+
});
|
|
12
23
|
it("gates `permissions revisions` on permissionMatrix:UPDATE (not read)", () => {
|
|
13
24
|
// 回归护栏:能看见「谁在何时把哪一格从 deny 改成 allow」是治理信息(还露出 actor
|
|
14
25
|
// user id),门槛必须等同「能改权限」。降成 read 会让矩阵只读角色拿到轨迹。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions-gates-admin.test.js","sourceRoot":"","sources":["../src/permissions-gates-admin.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE5E,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,IAAI,GAAG,kBAAkB,CAAC,oBAAoB,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAClB,MAAM,CAAC,gBAAgB,CAAC;YACtB,QAAQ,EAAE,kBAAkB;YAC5B,MAAM,EAAE,QAAQ;SACjB,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,mDAAmD;QACnD,8CAA8C;QAC9C,MAAM,IAAI,GAAG,kBAAkB,CAAC,uBAAuB,CAAC,CAAC;QACzD,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAClB,MAAM,CAAC,gBAAgB,CAAC;YACtB,QAAQ,EAAE,kBAAkB;YAC5B,MAAM,EAAE,QAAQ;SACjB,CAAC,CACH,CAAC;QACF,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,QAAQ,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAC9D,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC7C,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAChD,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;QACjD,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;QACjD,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,YAAY,GAAG,oBAAoB,CAAC,MAAM,CAC9C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,gBAAgB,CACtC,CAAC;QACF,MAAM,CAAC,YAAY,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"permissions-gates-admin.test.js","sourceRoot":"","sources":["../src/permissions-gates-admin.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE5E,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,IAAI,GAAG,kBAAkB,CAAC,oBAAoB,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAClB,MAAM,CAAC,gBAAgB,CAAC;YACtB,QAAQ,EAAE,kBAAkB;YAC5B,MAAM,EAAE,QAAQ;SACjB,CAAC,CACH,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,0DAA0D;IAC1D,wBAAwB;IACxB,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,IAAI,GAAG,kBAAkB,CAAC,oBAAoB,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAClB,MAAM,CAAC,gBAAgB,CAAC;YACtB,QAAQ,EAAE,kBAAkB;YAC5B,MAAM,EAAE,MAAM;SACf,CAAC,CACH,CAAC;QACF,iDAAiD;QACjD,MAAM,CAAC,kBAAkB,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,mDAAmD;QACnD,8CAA8C;QAC9C,MAAM,IAAI,GAAG,kBAAkB,CAAC,uBAAuB,CAAC,CAAC;QACzD,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAClB,MAAM,CAAC,gBAAgB,CAAC;YACtB,QAAQ,EAAE,kBAAkB;YAC5B,MAAM,EAAE,QAAQ;SACjB,CAAC,CACH,CAAC;QACF,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,QAAQ,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAC9D,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC7C,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAC;QAChD,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;QACjD,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;QACjD,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,6BAA6B,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,YAAY,GAAG,oBAAoB,CAAC,MAAM,CAC9C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,gBAAgB,CACtC,CAAC;QACF,MAAM,CAAC,YAAY,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -65,18 +65,6 @@ export type NotifyErrorClassification = {
|
|
|
65
65
|
/** 给 agent 的下一步动作提示(stderr 上打印)。 */
|
|
66
66
|
hint?: string;
|
|
67
67
|
};
|
|
68
|
-
/**
|
|
69
|
-
* 把任意错误映射成退出码。
|
|
70
|
-
*
|
|
71
|
-
* 关键取舍:
|
|
72
|
-
* - **pull 的 410(`SUBSCRIPTION_CURSOR_EXPIRED`)判 1 而不是 2**。它需要人工确认后
|
|
73
|
-
* `notify subscriptions reset`;若判成「可重试」,supervisor 会对同一个 stale 订阅
|
|
74
|
-
* 无限重启。
|
|
75
|
-
* - **ack 的 409 与 410 都判 3**,方便调用方统一进入「游标恢复分支」;具体动作靠
|
|
76
|
-
* stderr 里的 `code` 区分(409 → 重读订阅/重新 pull 拿新 receipt;410 → 人工 reset)。
|
|
77
|
-
* - **`PULL_RECEIPT_INVALID` 判 1**:签名/epoch/filterVersion 已变,重试同一 receipt
|
|
78
|
-
* 永远不会成功,必须重新 pull。
|
|
79
|
-
*/
|
|
80
68
|
export declare function classifyNotifyError(e: unknown, phase: NotifyPhase): NotifyErrorClassification;
|
|
81
69
|
/**
|
|
82
70
|
* receipt sidecar 的形状。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register-notify.d.ts","sourceRoot":"","sources":["../src/register-notify.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EAChC,KAAK,eAAe,EACrB,MAAM,0BAA0B,CAAC;AAKlC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,eAAO,MAAM,WAAW;;IAEtB,4BAA4B;;IAE5B,2CAA2C;;IAE3C,wCAAwC;;IAExC,gCAAgC;;CAExB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAC;AAsB5E;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAIzD;AAED,mDAAmD;AACnD,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CASlD;AAED,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,CAAC;AAEnD,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,EAAE,cAAc,CAAC;IACzB,oCAAoC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;
|
|
1
|
+
{"version":3,"file":"register-notify.d.ts","sourceRoot":"","sources":["../src/register-notify.ts"],"names":[],"mappings":"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"}
|
package/dist/register-notify.js
CHANGED
|
@@ -96,6 +96,35 @@ export function isNetworkError(e) {
|
|
|
96
96
|
* - **`PULL_RECEIPT_INVALID` 判 1**:签名/epoch/filterVersion 已变,重试同一 receipt
|
|
97
97
|
* 永远不会成功,必须重新 pull。
|
|
98
98
|
*/
|
|
99
|
+
/**
|
|
100
|
+
* 不可重试错误的处置提示。
|
|
101
|
+
*
|
|
102
|
+
* 🔴 三个「跨团队订阅滥用控制」的码各有**不同**的处置,必须分开说:
|
|
103
|
+
* - `SUBSCRIPTION_NAME_TAKEN`:换个名字重试就行;
|
|
104
|
+
* - `SUBSCRIPTION_NAME_PREFIX_*`:换名字**没用**,要换命名空间分区
|
|
105
|
+
* (details 里已经带上服务端算好的 `requiredPrefix`,直接拼上用);
|
|
106
|
+
* - `SUBSCRIPTION_QUOTA_EXCEEDED`:重试永远不会自愈;而且 `basis=total` 那档
|
|
107
|
+
* **删订阅也不还额度**(名字永久唯一),只能复用已有订阅或找运维调限额。
|
|
108
|
+
*/
|
|
109
|
+
function fatalHintFor(e) {
|
|
110
|
+
const details = e.details;
|
|
111
|
+
switch (e.code) {
|
|
112
|
+
case "SUBSCRIPTION_NAME_TAKEN":
|
|
113
|
+
return "这个 team 里已经有同名订阅(软删的也占着名字):换一个名字重试。";
|
|
114
|
+
case "SUBSCRIPTION_NAME_PREFIX_REQUIRED":
|
|
115
|
+
return `你不是目标 team 的成员,订阅名必须落在保留命名空间里:用 "${details?.requiredPrefix ?? "xsub/<你的 userId>/"}<name>"(<name> 只收 [A-Za-z0-9][A-Za-z0-9._-]*)。换普通名字重试没用。`;
|
|
116
|
+
case "SUBSCRIPTION_NAME_PREFIX_RESERVED":
|
|
117
|
+
return '"xsub/" 是留给「非本团队成员」的保留前缀:你是本 team 成员,换一个不以它开头的名字。';
|
|
118
|
+
case "SUBSCRIPTION_QUOTA_EXCEEDED":
|
|
119
|
+
return details?.basis === "total"
|
|
120
|
+
? "订阅**占名**配额已满。⚠️ 删订阅不会归还这档额度(`(teamId, name)` 永久唯一,软删不释放名字):复用已有订阅,或让运维物理清理 / 调高上限。"
|
|
121
|
+
: "订阅配额已满:删掉或复用一条已有订阅,或让运维调高上限。重试不会自愈。";
|
|
122
|
+
default:
|
|
123
|
+
return e.status === 401 || e.status === 403
|
|
124
|
+
? "鉴权/权限问题:`social-hub auth whoami` 确认身份;字段权限不足会整个订阅 403(不做字段级脱敏)。"
|
|
125
|
+
: undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
99
128
|
export function classifyNotifyError(e, phase) {
|
|
100
129
|
if (e instanceof SocialHubHttpError) {
|
|
101
130
|
const base = {
|
|
@@ -130,9 +159,7 @@ export function classifyNotifyError(e, phase) {
|
|
|
130
159
|
...base,
|
|
131
160
|
exitCode: NOTIFY_EXIT.FATAL,
|
|
132
161
|
retryable: false,
|
|
133
|
-
hint: e
|
|
134
|
-
? "鉴权/权限问题:`social-hub auth whoami` 确认身份;字段权限不足会整个订阅 403(不做字段级脱敏)。"
|
|
135
|
-
: undefined,
|
|
162
|
+
hint: fatalHintFor(e),
|
|
136
163
|
};
|
|
137
164
|
}
|
|
138
165
|
if (isNetworkError(e)) {
|