@geoly-ai/social-hub-cli 0.2.23 → 0.2.24
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 +6 -0
- package/dist/client.d.ts +21 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +64 -1
- package/dist/client.js.map +1 -1
- package/dist/client.test.d.ts +2 -0
- package/dist/client.test.d.ts.map +1 -0
- package/dist/client.test.js +123 -0
- package/dist/client.test.js.map +1 -0
- package/dist/cmd-manifest.json +14 -2
- package/dist/cmd-manifest.test.js +4 -0
- package/dist/cmd-manifest.test.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/permission-runner.d.ts +21 -4
- package/dist/permission-runner.d.ts.map +1 -1
- package/dist/permission-runner.js +36 -9
- package/dist/permission-runner.js.map +1 -1
- package/dist/permission-runner.test.js +76 -0
- package/dist/permission-runner.test.js.map +1 -1
- package/dist/permissions-gates-subreddit-style.d.ts +10 -0
- package/dist/permissions-gates-subreddit-style.d.ts.map +1 -0
- package/dist/permissions-gates-subreddit-style.js +66 -0
- package/dist/permissions-gates-subreddit-style.js.map +1 -0
- package/dist/permissions-gates-subreddit-style.test.d.ts +2 -0
- package/dist/permissions-gates-subreddit-style.test.d.ts.map +1 -0
- package/dist/permissions-gates-subreddit-style.test.js +44 -0
- package/dist/permissions-gates-subreddit-style.test.js.map +1 -0
- package/dist/permissions.d.ts +10 -0
- package/dist/permissions.d.ts.map +1 -1
- package/dist/permissions.js +9 -2
- package/dist/permissions.js.map +1 -1
- package/dist/register-extensions.d.ts.map +1 -1
- package/dist/register-extensions.js +1 -0
- package/dist/register-extensions.js.map +1 -1
- package/dist/register-subreddit-style-actions.test.d.ts +2 -0
- package/dist/register-subreddit-style-actions.test.d.ts.map +1 -0
- package/dist/register-subreddit-style-actions.test.js +295 -0
- package/dist/register-subreddit-style-actions.test.js.map +1 -0
- package/dist/register-subreddit-style.d.ts +57 -0
- package/dist/register-subreddit-style.d.ts.map +1 -0
- package/dist/register-subreddit-style.js +418 -0
- package/dist/register-subreddit-style.js.map +1 -0
- package/dist/register-subreddit-style.test.d.ts +2 -0
- package/dist/register-subreddit-style.test.d.ts.map +1 -0
- package/dist/register-subreddit-style.test.js +183 -0
- package/dist/register-subreddit-style.test.js.map +1 -0
- package/package.json +3 -3
- package/skills/README.md +1 -0
- package/skills/manifest.json +6 -1
- package/skills/social-hub-cli/SKILL.md +1 -0
- package/skills/social-hub-style-profiles/SKILL.md +126 -0
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
import { hubRequest, HubHttpError, resolveTeamId } from "./client.js";
|
|
2
|
+
import { assertApplyOrDryRun } from "./dry-run.js";
|
|
3
|
+
import { parseJsonOption, printResult, withCliErrorBoundary, } from "./output.js";
|
|
4
|
+
import { withPermissionGates } from "./permission-runner.js";
|
|
5
|
+
/**
|
|
6
|
+
* 去 AI 审核门 Block 8b —— 板块画像(subreddit_style_profiles,系统级四眼治理)
|
|
7
|
+
* 与帖子标注(subreddit_post_annotations,team 维度)的 CLI 管理面。
|
|
8
|
+
* SDK 尚未覆盖这两组端点,HTTP 走 client.ts 的 hubRequest(行为对齐 SDK fetchJson)。
|
|
9
|
+
*
|
|
10
|
+
* 画像乐观锁:写端点必须带 If-Match(值=GET 返回的 profile.rowVersion)。CLI 约定
|
|
11
|
+
* --row-version 显式传则直接用;缺省自动 GET 一次取当前值(便利读取,竞态保护仍在
|
|
12
|
+
* 服务端锁内 If-Match——409 PROFILE_STALE 原样失败并提示重取,**绝不自动重试**,
|
|
13
|
+
* 否则绕过用户对特定版本的确认;Codex 计划轮 P1)。
|
|
14
|
+
*/
|
|
15
|
+
const PROFILES_BASE = "/v1/system/subreddit-style-profiles";
|
|
16
|
+
/**
|
|
17
|
+
* If-Match token 归一:接受成对引号(GET 的 ETag 形状)或裸 token。
|
|
18
|
+
* fail-closed(Codex 验收 P2):W/ 弱 ETag、* 通配、多值(含逗号)、引号不成对
|
|
19
|
+
* 一律判无效——CLI 只接受单个 strong token,非法形状本地即拒,不留给服务端。
|
|
20
|
+
*/
|
|
21
|
+
export function normalizeRowVersionToken(raw) {
|
|
22
|
+
const trimmed = raw?.trim();
|
|
23
|
+
if (!trimmed)
|
|
24
|
+
return undefined;
|
|
25
|
+
if (/^w\//i.test(trimmed))
|
|
26
|
+
return undefined;
|
|
27
|
+
if (trimmed === "*")
|
|
28
|
+
return undefined;
|
|
29
|
+
const lead = trimmed.startsWith('"');
|
|
30
|
+
const trail = trimmed.endsWith('"');
|
|
31
|
+
if (lead !== trail)
|
|
32
|
+
return undefined;
|
|
33
|
+
const unquoted = lead ? trimmed.slice(1, -1) : trimmed;
|
|
34
|
+
if (!unquoted || unquoted.includes(",") || unquoted.includes('"')) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
return unquoted;
|
|
38
|
+
}
|
|
39
|
+
/** 显式 token 与目标画像明显不符的软检查(前缀 ssp:<id>:);权威校验仍在服务端。 */
|
|
40
|
+
export function rowVersionMatchesId(id, token) {
|
|
41
|
+
return token.startsWith(`ssp:${id}:`);
|
|
42
|
+
}
|
|
43
|
+
async function fetchStyleProfile(id) {
|
|
44
|
+
const res = await hubRequest(`${PROFILES_BASE}/${encodeURIComponent(id)}`);
|
|
45
|
+
return res.profile;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* rowVersion 解析:**传过 --row-version 就必须用显式值**——归一后为空(如 '""')
|
|
49
|
+
* fail-closed 退出,绝不回退自动 GET(否则用户想用指定版本保护的写会意外作用于
|
|
50
|
+
* 最新版本;Codex diff 轮 P1)。未传才自动 GET 当前值(便利读取)。
|
|
51
|
+
* fetcher 可注入(测试)。
|
|
52
|
+
*/
|
|
53
|
+
export async function resolveRowVersion(input, fetcher = fetchStyleProfile) {
|
|
54
|
+
if (input.rowVersion !== undefined) {
|
|
55
|
+
const explicit = normalizeRowVersionToken(input.rowVersion);
|
|
56
|
+
if (!explicit) {
|
|
57
|
+
console.error("--row-version 无效(归一后为空):传完整的 rowVersion,或不带该参数让 CLI 自动 GET。");
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
if (!rowVersionMatchesId(input.id, explicit)) {
|
|
61
|
+
console.error(`警告:--row-version 与画像 ${input.id} 前缀不符,仍以服务端 If-Match 校验为准。`);
|
|
62
|
+
}
|
|
63
|
+
return { rowVersion: explicit, head: null };
|
|
64
|
+
}
|
|
65
|
+
const head = await fetcher(input.id);
|
|
66
|
+
// 自动分支同样 fail-closed(Codex 复评 P2):响应缺陷产生空 rowVersion 时
|
|
67
|
+
// 绝不发空 If-Match。
|
|
68
|
+
const fetched = normalizeRowVersionToken(head.rowVersion);
|
|
69
|
+
if (!fetched) {
|
|
70
|
+
console.error(`GET 返回的 rowVersion 为空(画像 ${input.id}):无法构造 If-Match,请检查服务端响应。`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
return { rowVersion: fetched, head };
|
|
74
|
+
}
|
|
75
|
+
/** 画像稳定错误码的针对性提示(随错误边界输出,不改变退出码)。 */
|
|
76
|
+
function hintStyleProfileError(e) {
|
|
77
|
+
if (!(e instanceof HubHttpError))
|
|
78
|
+
return;
|
|
79
|
+
if (e.code === "PROFILE_STALE") {
|
|
80
|
+
console.error("提示:画像已被他人变更。重新 `social-hub style-profiles get --id <id>` " +
|
|
81
|
+
"核对最新 rowVersion 后重试(CLI 不会自动重试)。");
|
|
82
|
+
}
|
|
83
|
+
else if (e.code === "SELF_APPROVE") {
|
|
84
|
+
console.error("提示:四眼审批——提案人本人不能 approve,请换另一位 manager/admin 操作。");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function registerProfileTransition(profiles, name, meta) {
|
|
88
|
+
const cmd = profiles
|
|
89
|
+
.command(name)
|
|
90
|
+
.description(meta.description)
|
|
91
|
+
.requiredOption("--id <profileId>", "画像 UUID")
|
|
92
|
+
.option("--row-version <token>", "If-Match 用的 rowVersion(缺省自动 GET 当前值;也接受带引号的 ETag)")
|
|
93
|
+
.option("--dry-run", "预览", false)
|
|
94
|
+
.option("--apply", "执行写入", false);
|
|
95
|
+
if (meta.needsReason) {
|
|
96
|
+
cmd.requiredOption("--reason <text>", "原因(必填,落审计 retire_reason)");
|
|
97
|
+
}
|
|
98
|
+
cmd.action(async (opts) => {
|
|
99
|
+
await withCliErrorBoundary(async () => {
|
|
100
|
+
await withPermissionGates({
|
|
101
|
+
command: `style-profiles ${name}`,
|
|
102
|
+
gates: [
|
|
103
|
+
{ resource: "subredditStyleProfile", action: meta.gateAction },
|
|
104
|
+
],
|
|
105
|
+
userOnly: true,
|
|
106
|
+
}, async () => {
|
|
107
|
+
const { rowVersion, head } = await resolveRowVersion({
|
|
108
|
+
id: opts.id,
|
|
109
|
+
rowVersion: opts.rowVersion,
|
|
110
|
+
});
|
|
111
|
+
const summary = {
|
|
112
|
+
id: opts.id,
|
|
113
|
+
rowVersion,
|
|
114
|
+
};
|
|
115
|
+
if (opts.reason)
|
|
116
|
+
summary.reason = opts.reason;
|
|
117
|
+
if (head) {
|
|
118
|
+
summary.subreddit = head.subreddit;
|
|
119
|
+
summary.status = head.status;
|
|
120
|
+
summary.version = head.version;
|
|
121
|
+
summary.summary = head.summary;
|
|
122
|
+
summary.proposedByUserId = head.proposedByUserId;
|
|
123
|
+
}
|
|
124
|
+
if (!assertApplyOrDryRun(opts, {
|
|
125
|
+
command: `style-profiles ${name}`,
|
|
126
|
+
danger: meta.danger,
|
|
127
|
+
summary,
|
|
128
|
+
})) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
printResult(await hubRequest(`${PROFILES_BASE}/${encodeURIComponent(opts.id)}/${name}`, {
|
|
133
|
+
method: "POST",
|
|
134
|
+
headers: { "If-Match": rowVersion },
|
|
135
|
+
body: meta.needsReason
|
|
136
|
+
? { reason: opts.reason }
|
|
137
|
+
: undefined,
|
|
138
|
+
}));
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
hintStyleProfileError(e);
|
|
142
|
+
throw e;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
// ── 标注 upsert 本地校验(契约 upsertSubredditPostAnnotationBodySchema 的高频
|
|
149
|
+
// 子集:permalink 形状/type×brand 互斥/score 范围/brandId UUID/label·note 长度;
|
|
150
|
+
// contracts 非 CLI 依赖,正则在此复制一份)。非法输入在 dry-run 前就拒,避免打出
|
|
151
|
+
// 看似可成功的预览(Codex 计划轮 P1,diff 轮 P2 补 UUID/长度)。
|
|
152
|
+
const REDDIT_POST_PERMALINK_FORMAT = /^https:\/\/(?:[a-z0-9-]+\.)*reddit\.com\/r\/[A-Za-z0-9_]+\/comments\//i;
|
|
153
|
+
const UUID_FORMAT = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
154
|
+
export function buildAnnotationUpsertBody(input) {
|
|
155
|
+
const fail = (msg) => {
|
|
156
|
+
console.error(msg);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
};
|
|
159
|
+
const type = input.type;
|
|
160
|
+
if (type !== "style_fit" && type !== "brand_friendliness") {
|
|
161
|
+
return fail("--type 须为 style_fit | brand_friendliness");
|
|
162
|
+
}
|
|
163
|
+
if (!REDDIT_POST_PERMALINK_FORMAT.test(input.permalink)) {
|
|
164
|
+
return fail("--permalink 须为 reddit.com 的 /r/<sub>/comments/ 帖子链接(https)");
|
|
165
|
+
}
|
|
166
|
+
const score = Number(input.score);
|
|
167
|
+
if (!Number.isInteger(score) || score < 1 || score > 5) {
|
|
168
|
+
return fail("--score 须为 1-5 整数(1=最差/敌意 … 5=最佳/友好)");
|
|
169
|
+
}
|
|
170
|
+
if (type === "brand_friendliness" && !input.brand) {
|
|
171
|
+
return fail("--type brand_friendliness 必须带 --brand <brandId>");
|
|
172
|
+
}
|
|
173
|
+
if (type === "style_fit" && input.brand) {
|
|
174
|
+
return fail("--type style_fit 不得带 --brand");
|
|
175
|
+
}
|
|
176
|
+
if (input.brand && !UUID_FORMAT.test(input.brand)) {
|
|
177
|
+
return fail("--brand 须为 brandId UUID");
|
|
178
|
+
}
|
|
179
|
+
const label = input.label?.trim();
|
|
180
|
+
if (input.label !== undefined && (!label || label.length > 64)) {
|
|
181
|
+
return fail("--label 须为 1-64 字符(去空白后)");
|
|
182
|
+
}
|
|
183
|
+
const note = input.note?.trim();
|
|
184
|
+
if (input.note !== undefined && (!note || note.length > 2000)) {
|
|
185
|
+
return fail("--note 须为 1-2000 字符(去空白后)");
|
|
186
|
+
}
|
|
187
|
+
const scope = input.scope;
|
|
188
|
+
if (scope !== "team" && scope !== "global") {
|
|
189
|
+
return fail("--scope 须为 team | global");
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
subreddit: input.subreddit,
|
|
193
|
+
permalink: input.permalink,
|
|
194
|
+
annotationType: type,
|
|
195
|
+
...(input.brand ? { brandId: input.brand } : {}),
|
|
196
|
+
score,
|
|
197
|
+
...(label ? { label } : {}),
|
|
198
|
+
...(note ? { note } : {}),
|
|
199
|
+
scope,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
export function registerSubredditStyleCommands(program) {
|
|
203
|
+
// ── 板块画像(系统级;/v1/system/subreddit-style-profiles)──────────────────
|
|
204
|
+
const profiles = program
|
|
205
|
+
.command("style-profiles")
|
|
206
|
+
.description("板块画像(系统级四眼治理;写操作 user-only,拒 API Key)");
|
|
207
|
+
profiles
|
|
208
|
+
.command("list")
|
|
209
|
+
.description("GET /v1/system/subreddit-style-profiles")
|
|
210
|
+
.option("--subreddit <name>", "板块过滤")
|
|
211
|
+
.option("--scope <scope>", "global | brand")
|
|
212
|
+
.option("--brand <uuid>", "brandId 过滤")
|
|
213
|
+
.option("--status <csv>", "proposed,approved,retired(可逗号多值)")
|
|
214
|
+
.option("-n, --limit <n>", "limit", "50")
|
|
215
|
+
.option("--offset <n>", "offset", "0")
|
|
216
|
+
.action(async (opts) => {
|
|
217
|
+
await withCliErrorBoundary(async () => {
|
|
218
|
+
await withPermissionGates({
|
|
219
|
+
command: "style-profiles list",
|
|
220
|
+
gates: [{ resource: "subredditStyleProfile", action: "read" }],
|
|
221
|
+
}, async () => {
|
|
222
|
+
const params = new URLSearchParams();
|
|
223
|
+
if (opts.subreddit)
|
|
224
|
+
params.set("subreddit", opts.subreddit);
|
|
225
|
+
if (opts.scope)
|
|
226
|
+
params.set("scope", opts.scope);
|
|
227
|
+
if (opts.brand)
|
|
228
|
+
params.set("brandId", opts.brand);
|
|
229
|
+
if (opts.status)
|
|
230
|
+
params.set("status", opts.status);
|
|
231
|
+
params.set("limit", String(opts.limit));
|
|
232
|
+
params.set("offset", String(opts.offset));
|
|
233
|
+
printResult(await hubRequest(`${PROFILES_BASE}?${params.toString()}`));
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
profiles
|
|
238
|
+
.command("get")
|
|
239
|
+
.description("GET /v1/system/subreddit-style-profiles/:id(响应 profile.rowVersion 即写操作的 If-Match 值)")
|
|
240
|
+
.requiredOption("--id <profileId>", "画像 UUID")
|
|
241
|
+
.action(async (opts) => {
|
|
242
|
+
await withCliErrorBoundary(async () => {
|
|
243
|
+
await withPermissionGates({
|
|
244
|
+
command: "style-profiles get",
|
|
245
|
+
gates: [{ resource: "subredditStyleProfile", action: "read" }],
|
|
246
|
+
}, async () => {
|
|
247
|
+
printResult(await hubRequest(`${PROFILES_BASE}/${encodeURIComponent(opts.id)}`));
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
profiles
|
|
252
|
+
.command("active")
|
|
253
|
+
.description("GET .../active — 生效中的 approved 画像(--brand 优先 brand override、无则回退 global;无画像输出 null,退出码 0)")
|
|
254
|
+
.requiredOption("--subreddit <name>", "板块名")
|
|
255
|
+
.option("--brand <uuid>", "brandId(查 brand override)")
|
|
256
|
+
.action(async (opts) => {
|
|
257
|
+
await withCliErrorBoundary(async () => {
|
|
258
|
+
await withPermissionGates({
|
|
259
|
+
command: "style-profiles active",
|
|
260
|
+
gates: [{ resource: "subredditStyleProfile", action: "read" }],
|
|
261
|
+
}, async () => {
|
|
262
|
+
const params = new URLSearchParams({
|
|
263
|
+
subreddit: opts.subreddit,
|
|
264
|
+
});
|
|
265
|
+
if (opts.brand)
|
|
266
|
+
params.set("brandId", opts.brand);
|
|
267
|
+
printResult(await hubRequest(`${PROFILES_BASE}/active?${params.toString()}`));
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
profiles
|
|
272
|
+
.command("propose")
|
|
273
|
+
.description("POST /v1/system/subreddit-style-profiles — 人工提案新画像版本(proposed,待另一位 manager/admin 审批)")
|
|
274
|
+
.requiredOption("-j, --json <json>", '{ "scope":"global|brand", "subreddit":"...", "brandId?":"...", "profile":{...}, "summary?":"..." }')
|
|
275
|
+
.option("--dry-run", "预览", false)
|
|
276
|
+
.option("--apply", "执行写入", false)
|
|
277
|
+
.action(async (opts) => {
|
|
278
|
+
await withCliErrorBoundary(async () => {
|
|
279
|
+
await withPermissionGates({
|
|
280
|
+
command: "style-profiles propose",
|
|
281
|
+
gates: [{ resource: "subredditStyleProfile", action: "create" }],
|
|
282
|
+
userOnly: true,
|
|
283
|
+
}, async () => {
|
|
284
|
+
const body = parseJsonOption(opts.json);
|
|
285
|
+
if (!assertApplyOrDryRun(opts, {
|
|
286
|
+
command: "style-profiles propose",
|
|
287
|
+
danger: "write",
|
|
288
|
+
summary: body,
|
|
289
|
+
})) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
printResult(await hubRequest(PROFILES_BASE, { method: "POST", body }));
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
registerProfileTransition(profiles, "approve", {
|
|
297
|
+
description: "POST .../:id/approve — 四眼审批 proposed → approved(提案人本人不可批,SELF_APPROVE→409)",
|
|
298
|
+
danger: "admin",
|
|
299
|
+
gateAction: "update",
|
|
300
|
+
needsReason: false,
|
|
301
|
+
});
|
|
302
|
+
registerProfileTransition(profiles, "reject", {
|
|
303
|
+
description: "POST .../:id/reject — 审批人驳回 proposed → retired(retire_reason=rejected:<reason>)",
|
|
304
|
+
danger: "admin",
|
|
305
|
+
gateAction: "update",
|
|
306
|
+
needsReason: true,
|
|
307
|
+
});
|
|
308
|
+
registerProfileTransition(profiles, "cancel", {
|
|
309
|
+
description: "POST .../:id/cancel — 提案人本人撤回 proposed → retired(仅本人;worker/LLM 提案请用 reject)",
|
|
310
|
+
danger: "delete",
|
|
311
|
+
gateAction: "delete",
|
|
312
|
+
needsReason: true,
|
|
313
|
+
});
|
|
314
|
+
registerProfileTransition(profiles, "retire", {
|
|
315
|
+
description: "POST .../:id/retire — 停用 approved 画像(可审计)",
|
|
316
|
+
danger: "admin",
|
|
317
|
+
gateAction: "update",
|
|
318
|
+
needsReason: true,
|
|
319
|
+
});
|
|
320
|
+
// ── 帖子标注(team 维度;/v1/teams/:teamId/subreddit-post-annotations)────────
|
|
321
|
+
const annotations = program
|
|
322
|
+
.command("subreddit-annotations")
|
|
323
|
+
.description("Reddit 板块帖子标注(style_fit / brand_friendliness)");
|
|
324
|
+
annotations
|
|
325
|
+
.command("list")
|
|
326
|
+
.description("GET /v1/teams/:teamId/subreddit-post-annotations(本团队行+全局行;响应 teamId=null 为全局行)")
|
|
327
|
+
.option("-t, --team <teamId>", "Team UUID(缺省用当前 context)")
|
|
328
|
+
.option("--subreddit <name>", "板块过滤")
|
|
329
|
+
.option("--permalink <url>", "permalink 过滤")
|
|
330
|
+
.option("--type <t>", "style_fit | brand_friendliness")
|
|
331
|
+
.option("--brand <uuid>", "brandId 过滤")
|
|
332
|
+
.option("--source <s>", "llm | human")
|
|
333
|
+
.option("-n, --limit <n>", "limit", "50")
|
|
334
|
+
.option("--offset <n>", "offset", "0")
|
|
335
|
+
.action(async (opts) => {
|
|
336
|
+
await withCliErrorBoundary(async () => {
|
|
337
|
+
const teamId = resolveTeamId(opts.team);
|
|
338
|
+
await withPermissionGates({
|
|
339
|
+
command: "subreddit-annotations list",
|
|
340
|
+
gates: [{ resource: "subredditPostAnnotation", action: "read" }],
|
|
341
|
+
teamId,
|
|
342
|
+
}, async () => {
|
|
343
|
+
const params = new URLSearchParams();
|
|
344
|
+
if (opts.subreddit)
|
|
345
|
+
params.set("subreddit", opts.subreddit);
|
|
346
|
+
if (opts.permalink)
|
|
347
|
+
params.set("permalink", opts.permalink);
|
|
348
|
+
if (opts.type)
|
|
349
|
+
params.set("annotationType", opts.type);
|
|
350
|
+
if (opts.brand)
|
|
351
|
+
params.set("brandId", opts.brand);
|
|
352
|
+
if (opts.source)
|
|
353
|
+
params.set("source", opts.source);
|
|
354
|
+
params.set("limit", String(opts.limit));
|
|
355
|
+
params.set("offset", String(opts.offset));
|
|
356
|
+
printResult(await hubRequest(`/v1/teams/${encodeURIComponent(teamId)}/subreddit-post-annotations?${params.toString()}`));
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
annotations
|
|
361
|
+
.command("upsert")
|
|
362
|
+
.description("POST .../subreddit-post-annotations/upsert — 人工标注(source 服务端固定 human;last-write-wins 覆盖,审计留痕;scope=global 需 manager/admin)")
|
|
363
|
+
.option("-t, --team <teamId>", "Team UUID(缺省用当前 context)")
|
|
364
|
+
.requiredOption("--subreddit <name>", "板块名")
|
|
365
|
+
.requiredOption("--permalink <url>", "Reddit 帖链接(https://*.reddit.com/r/<sub>/comments/...)")
|
|
366
|
+
.requiredOption("--type <t>", "style_fit | brand_friendliness")
|
|
367
|
+
.requiredOption("--score <n>", "1-5(1=最差/敌意 … 5=最佳/友好)")
|
|
368
|
+
.option("--brand <uuid>", "brandId(brand_friendliness 必填;style_fit 禁带)")
|
|
369
|
+
.option("--label <text>", "标签(≤64 字符)")
|
|
370
|
+
.option("--note <text>", "备注(≤2000 字符)")
|
|
371
|
+
.option("--scope <scope>", "team | global", "team")
|
|
372
|
+
.option("--dry-run", "预览", false)
|
|
373
|
+
.option("--apply", "执行写入", false)
|
|
374
|
+
.action(async (opts) => {
|
|
375
|
+
await withCliErrorBoundary(async () => {
|
|
376
|
+
const teamId = resolveTeamId(opts.team);
|
|
377
|
+
const body = buildAnnotationUpsertBody({
|
|
378
|
+
subreddit: opts.subreddit,
|
|
379
|
+
permalink: opts.permalink,
|
|
380
|
+
type: opts.type,
|
|
381
|
+
score: opts.score,
|
|
382
|
+
brand: opts.brand,
|
|
383
|
+
label: opts.label,
|
|
384
|
+
note: opts.note,
|
|
385
|
+
scope: opts.scope,
|
|
386
|
+
});
|
|
387
|
+
// API 侧 create+update 双 gate(防权限矩阵 create=true/update=false 分裂
|
|
388
|
+
// 绕过);scope=global 写系统共享知识库,另过 subredditStyleProfile:update。
|
|
389
|
+
const gates = [
|
|
390
|
+
{ resource: "subredditPostAnnotation", action: "create" },
|
|
391
|
+
{ resource: "subredditPostAnnotation", action: "update" },
|
|
392
|
+
...(body.scope === "global"
|
|
393
|
+
? [{ resource: "subredditStyleProfile", action: "update" }]
|
|
394
|
+
: []),
|
|
395
|
+
];
|
|
396
|
+
await withPermissionGates({
|
|
397
|
+
command: "subreddit-annotations upsert",
|
|
398
|
+
gates,
|
|
399
|
+
teamId,
|
|
400
|
+
userOnly: true,
|
|
401
|
+
}, async () => {
|
|
402
|
+
if (!assertApplyOrDryRun(opts, {
|
|
403
|
+
command: "subreddit-annotations upsert",
|
|
404
|
+
danger: body.scope === "global" ? "admin" : "write",
|
|
405
|
+
summary: {
|
|
406
|
+
teamId,
|
|
407
|
+
...body,
|
|
408
|
+
semantics: "last-write-wins:同源 identity 重复会覆盖既有标注(审计留痕)",
|
|
409
|
+
},
|
|
410
|
+
})) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
printResult(await hubRequest(`/v1/teams/${encodeURIComponent(teamId)}/subreddit-post-annotations/upsert`, { method: "POST", body }));
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
//# sourceMappingURL=register-subreddit-style.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-subreddit-style.js","sourceRoot":"","sources":["../src/register-subreddit-style.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-subreddit-style.test.d.ts","sourceRoot":"","sources":["../src/register-subreddit-style.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { beforeAll, beforeEach, afterEach, describe, expect, it, vi, } from "vitest";
|
|
2
|
+
import { listAllCommandPaths } from "./cmd-manifest.js";
|
|
3
|
+
vi.mock("@geoly-ai/social-hub-sdk", () => ({
|
|
4
|
+
SocialHubClient: vi.fn().mockImplementation(() => ({})),
|
|
5
|
+
getSocialHubHealth: vi.fn(),
|
|
6
|
+
}));
|
|
7
|
+
let program;
|
|
8
|
+
let buildAnnotationUpsertBody;
|
|
9
|
+
let normalizeRowVersionToken;
|
|
10
|
+
let rowVersionMatchesId;
|
|
11
|
+
let resolveRowVersion;
|
|
12
|
+
beforeAll(async () => {
|
|
13
|
+
const mod = await import("./index.js");
|
|
14
|
+
program = mod.program;
|
|
15
|
+
const reg = await import("./register-subreddit-style.js");
|
|
16
|
+
buildAnnotationUpsertBody = reg.buildAnnotationUpsertBody;
|
|
17
|
+
normalizeRowVersionToken = reg.normalizeRowVersionToken;
|
|
18
|
+
rowVersionMatchesId = reg.rowVersionMatchesId;
|
|
19
|
+
resolveRowVersion = reg.resolveRowVersion;
|
|
20
|
+
});
|
|
21
|
+
describe("register-subreddit-style command tree", () => {
|
|
22
|
+
it("注册画像与标注全部命令路径", () => {
|
|
23
|
+
const paths = listAllCommandPaths(program);
|
|
24
|
+
for (const p of [
|
|
25
|
+
"style-profiles list",
|
|
26
|
+
"style-profiles get",
|
|
27
|
+
"style-profiles active",
|
|
28
|
+
"style-profiles propose",
|
|
29
|
+
"style-profiles approve",
|
|
30
|
+
"style-profiles reject",
|
|
31
|
+
"style-profiles cancel",
|
|
32
|
+
"style-profiles retire",
|
|
33
|
+
"subreddit-annotations list",
|
|
34
|
+
"subreddit-annotations upsert",
|
|
35
|
+
]) {
|
|
36
|
+
expect(paths).toContain(p);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe("normalizeRowVersionToken / rowVersionMatchesId", () => {
|
|
41
|
+
it("接受成对引号(ETag 形状)与裸 token", () => {
|
|
42
|
+
expect(normalizeRowVersionToken('"ssp:abc:proposed:2026-07-26"')).toBe("ssp:abc:proposed:2026-07-26");
|
|
43
|
+
expect(normalizeRowVersionToken("ssp:abc:proposed:2026-07-26")).toBe("ssp:abc:proposed:2026-07-26");
|
|
44
|
+
});
|
|
45
|
+
it("空/未传 → undefined", () => {
|
|
46
|
+
expect(normalizeRowVersionToken(undefined)).toBeUndefined();
|
|
47
|
+
expect(normalizeRowVersionToken(" ")).toBeUndefined();
|
|
48
|
+
});
|
|
49
|
+
it("非法形状 fail-closed:W/ 弱 ETag、*、多值、引号不成对(Codex 验收 P2)", () => {
|
|
50
|
+
expect(normalizeRowVersionToken('W/"ssp:abc:proposed:x"')).toBeUndefined();
|
|
51
|
+
expect(normalizeRowVersionToken("w/ssp:abc")).toBeUndefined();
|
|
52
|
+
expect(normalizeRowVersionToken("*")).toBeUndefined();
|
|
53
|
+
expect(normalizeRowVersionToken("ssp:a,ssp:b")).toBeUndefined();
|
|
54
|
+
expect(normalizeRowVersionToken('"ssp:abc,ssp:def"')).toBeUndefined();
|
|
55
|
+
expect(normalizeRowVersionToken('"ssp:abc')).toBeUndefined();
|
|
56
|
+
expect(normalizeRowVersionToken('ssp:abc"')).toBeUndefined();
|
|
57
|
+
expect(normalizeRowVersionToken('""')).toBeUndefined();
|
|
58
|
+
});
|
|
59
|
+
it("前缀软检查:ssp:<id>: 匹配", () => {
|
|
60
|
+
expect(rowVersionMatchesId("abc", "ssp:abc:proposed:x")).toBe(true);
|
|
61
|
+
expect(rowVersionMatchesId("abc", "ssp:other:proposed:x")).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe("resolveRowVersion", () => {
|
|
65
|
+
beforeEach(() => {
|
|
66
|
+
vi.spyOn(process, "exit").mockImplementation((() => {
|
|
67
|
+
throw new Error("process.exit");
|
|
68
|
+
}));
|
|
69
|
+
vi.spyOn(console, "error").mockImplementation(() => { });
|
|
70
|
+
});
|
|
71
|
+
afterEach(() => {
|
|
72
|
+
vi.restoreAllMocks();
|
|
73
|
+
});
|
|
74
|
+
const head = {
|
|
75
|
+
id: "p1",
|
|
76
|
+
rowVersion: "ssp:p1:proposed:2026-07-26T00:00:00.000Z",
|
|
77
|
+
};
|
|
78
|
+
it("显式 token 直接用,不触发 GET", async () => {
|
|
79
|
+
const fetcher = vi.fn();
|
|
80
|
+
const res = await resolveRowVersion({ id: "p1", rowVersion: "ssp:p1:proposed:x" }, fetcher);
|
|
81
|
+
expect(res).toEqual({ rowVersion: "ssp:p1:proposed:x", head: null });
|
|
82
|
+
expect(fetcher).not.toHaveBeenCalled();
|
|
83
|
+
});
|
|
84
|
+
it("显式空 token('\"\"' 或空串)fail-closed,绝不回退自动 GET", async () => {
|
|
85
|
+
const fetcher = vi.fn();
|
|
86
|
+
await expect(resolveRowVersion({ id: "p1", rowVersion: '""' }, fetcher)).rejects.toThrow("process.exit");
|
|
87
|
+
await expect(resolveRowVersion({ id: "p1", rowVersion: " " }, fetcher)).rejects.toThrow("process.exit");
|
|
88
|
+
expect(fetcher).not.toHaveBeenCalled();
|
|
89
|
+
});
|
|
90
|
+
it("未传 --row-version 才自动 GET", async () => {
|
|
91
|
+
const fetcher = vi.fn().mockResolvedValue(head);
|
|
92
|
+
const res = await resolveRowVersion({ id: "p1" }, fetcher);
|
|
93
|
+
expect(res.rowVersion).toBe(head.rowVersion);
|
|
94
|
+
expect(res.head).toEqual(head);
|
|
95
|
+
expect(fetcher).toHaveBeenCalledWith("p1");
|
|
96
|
+
});
|
|
97
|
+
it("自动 GET 返回空 rowVersion 同样 fail-closed(不发空 If-Match)", async () => {
|
|
98
|
+
const fetcher = vi.fn().mockResolvedValue({ ...head, rowVersion: '""' });
|
|
99
|
+
await expect(resolveRowVersion({ id: "p1" }, fetcher)).rejects.toThrow("process.exit");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
describe("buildAnnotationUpsertBody", () => {
|
|
103
|
+
beforeEach(() => {
|
|
104
|
+
vi.spyOn(process, "exit").mockImplementation((() => {
|
|
105
|
+
throw new Error("process.exit");
|
|
106
|
+
}));
|
|
107
|
+
vi.spyOn(console, "error").mockImplementation(() => { });
|
|
108
|
+
});
|
|
109
|
+
afterEach(() => {
|
|
110
|
+
vi.restoreAllMocks();
|
|
111
|
+
});
|
|
112
|
+
const valid = {
|
|
113
|
+
subreddit: "sports",
|
|
114
|
+
permalink: "https://www.reddit.com/r/sports/comments/abc123/title/",
|
|
115
|
+
type: "style_fit",
|
|
116
|
+
score: "4",
|
|
117
|
+
scope: "team",
|
|
118
|
+
};
|
|
119
|
+
const BRAND_UUID = "123e4567-e89b-42d3-a456-426614174000";
|
|
120
|
+
it("合法 style_fit 输入 → body 无 brandId", () => {
|
|
121
|
+
expect(buildAnnotationUpsertBody(valid)).toEqual({
|
|
122
|
+
subreddit: "sports",
|
|
123
|
+
permalink: "https://www.reddit.com/r/sports/comments/abc123/title/",
|
|
124
|
+
annotationType: "style_fit",
|
|
125
|
+
score: 4,
|
|
126
|
+
scope: "team",
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
it("brand_friendliness 必须带 --brand;style_fit 禁带", () => {
|
|
130
|
+
expect(() => buildAnnotationUpsertBody({
|
|
131
|
+
...valid,
|
|
132
|
+
type: "brand_friendliness",
|
|
133
|
+
})).toThrow("process.exit");
|
|
134
|
+
expect(() => buildAnnotationUpsertBody({ ...valid, brand: BRAND_UUID })).toThrow("process.exit");
|
|
135
|
+
expect(buildAnnotationUpsertBody({
|
|
136
|
+
...valid,
|
|
137
|
+
type: "brand_friendliness",
|
|
138
|
+
brand: BRAND_UUID,
|
|
139
|
+
scope: "global",
|
|
140
|
+
})).toMatchObject({
|
|
141
|
+
annotationType: "brand_friendliness",
|
|
142
|
+
brandId: BRAND_UUID,
|
|
143
|
+
scope: "global",
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
it("--brand 须为 UUID;label/note 去空白后长度受限", () => {
|
|
147
|
+
expect(() => buildAnnotationUpsertBody({
|
|
148
|
+
...valid,
|
|
149
|
+
type: "brand_friendliness",
|
|
150
|
+
brand: "b1",
|
|
151
|
+
})).toThrow("process.exit");
|
|
152
|
+
expect(() => buildAnnotationUpsertBody({ ...valid, label: " " })).toThrow("process.exit");
|
|
153
|
+
expect(() => buildAnnotationUpsertBody({ ...valid, label: "x".repeat(65) })).toThrow("process.exit");
|
|
154
|
+
expect(() => buildAnnotationUpsertBody({ ...valid, note: "x".repeat(2001) })).toThrow("process.exit");
|
|
155
|
+
expect(buildAnnotationUpsertBody({ ...valid, label: " tone ", note: " ok " })).toMatchObject({ label: "tone", note: "ok" });
|
|
156
|
+
});
|
|
157
|
+
it("score 须 1-5 整数", () => {
|
|
158
|
+
for (const bad of ["0", "6", "3.5", "abc"]) {
|
|
159
|
+
expect(() => buildAnnotationUpsertBody({ ...valid, score: bad })).toThrow("process.exit");
|
|
160
|
+
}
|
|
161
|
+
expect(buildAnnotationUpsertBody({ ...valid, score: "1" }).score).toBe(1);
|
|
162
|
+
expect(buildAnnotationUpsertBody({ ...valid, score: "5" }).score).toBe(5);
|
|
163
|
+
});
|
|
164
|
+
it("permalink 强制 Reddit /r/<sub>/comments/ 形状", () => {
|
|
165
|
+
for (const bad of [
|
|
166
|
+
"https://example.com/r/sports/comments/abc",
|
|
167
|
+
"http://www.reddit.com/r/sports/comments/abc",
|
|
168
|
+
"https://www.reddit.com/r/sports/",
|
|
169
|
+
"not-a-url",
|
|
170
|
+
]) {
|
|
171
|
+
expect(() => buildAnnotationUpsertBody({ ...valid, permalink: bad })).toThrow("process.exit");
|
|
172
|
+
}
|
|
173
|
+
expect(buildAnnotationUpsertBody({
|
|
174
|
+
...valid,
|
|
175
|
+
permalink: "https://old.reddit.com/r/sports/comments/x/y",
|
|
176
|
+
}).permalink).toContain("old.reddit.com");
|
|
177
|
+
});
|
|
178
|
+
it("非法 type/scope 拒绝", () => {
|
|
179
|
+
expect(() => buildAnnotationUpsertBody({ ...valid, type: "other" })).toThrow("process.exit");
|
|
180
|
+
expect(() => buildAnnotationUpsertBody({ ...valid, scope: "universe" })).toThrow("process.exit");
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
//# sourceMappingURL=register-subreddit-style.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-subreddit-style.test.js","sourceRoot":"","sources":["../src/register-subreddit-style.test.ts"],"names":[],"mappings":"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"}
|