@geoly-ai/social-hub-cli 0.0.7 → 0.0.9

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 (46) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/feishu/reddit-post-import.d.ts +79 -0
  3. package/dist/feishu/reddit-post-import.d.ts.map +1 -0
  4. package/dist/feishu/reddit-post-import.js +239 -0
  5. package/dist/feishu/reddit-post-import.js.map +1 -0
  6. package/dist/feishu/reddit-post-import.test.d.ts +2 -0
  7. package/dist/feishu/reddit-post-import.test.d.ts.map +1 -0
  8. package/dist/feishu/reddit-post-import.test.js +47 -0
  9. package/dist/feishu/reddit-post-import.test.js.map +1 -0
  10. package/dist/feishu/sync-feishu-posts.d.ts +4 -0
  11. package/dist/feishu/sync-feishu-posts.d.ts.map +1 -0
  12. package/dist/feishu/sync-feishu-posts.js +112 -0
  13. package/dist/feishu/sync-feishu-posts.js.map +1 -0
  14. package/dist/index.test.js +1 -1
  15. package/dist/index.test.js.map +1 -1
  16. package/dist/permissions.js +1 -1
  17. package/dist/permissions.js.map +1 -1
  18. package/dist/register-extensions.d.ts.map +1 -1
  19. package/dist/register-extensions.js +22 -16
  20. package/dist/register-extensions.js.map +1 -1
  21. package/dist/register-skills.d.ts.map +1 -1
  22. package/dist/register-skills.js +24 -6
  23. package/dist/register-skills.js.map +1 -1
  24. package/dist/skills/doctor.js +1 -1
  25. package/dist/skills/doctor.js.map +1 -1
  26. package/dist/skills/target-detector.d.ts +8 -1
  27. package/dist/skills/target-detector.d.ts.map +1 -1
  28. package/dist/skills/target-detector.js +69 -34
  29. package/dist/skills/target-detector.js.map +1 -1
  30. package/dist/skills/target-detector.test.d.ts +2 -0
  31. package/dist/skills/target-detector.test.d.ts.map +1 -0
  32. package/dist/skills/target-detector.test.js +66 -0
  33. package/dist/skills/target-detector.test.js.map +1 -0
  34. package/dist/skills/tui.d.ts +19 -1
  35. package/dist/skills/tui.d.ts.map +1 -1
  36. package/dist/skills/tui.js +120 -28
  37. package/dist/skills/tui.js.map +1 -1
  38. package/dist/skills/tui.test.d.ts +2 -0
  39. package/dist/skills/tui.test.d.ts.map +1 -0
  40. package/dist/skills/tui.test.js +37 -0
  41. package/dist/skills/tui.test.js.map +1 -0
  42. package/package.json +3 -2
  43. package/skills/README.md +20 -14
  44. package/skills/manifest.json +1 -1
  45. package/skills/social-hub-cli/SKILL.md +7 -5
  46. package/skills/social-hub-posts/SKILL.md +41 -3
package/CHANGELOG.md ADDED
@@ -0,0 +1,56 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@geoly-ai/social-hub-cli` are documented in this file.
4
+
5
+ Release workflow: `pnpm release:cli` → `pnpm publish:cli`.
6
+
7
+ ## [0.0.9] - 2026-05-21
8
+
9
+ Remove reddit import-feishu; add reddit batch-upsert for Feishu-to-Hub sync via local lark-cli.
10
+
11
+ ### Added
12
+ - add reddit batch-upsert and drop import-feishu command
13
+
14
+ ### Fixed
15
+ - parse conventional commit subjects for CHANGELOG
16
+
17
+ ### Changed
18
+ - automate CLI versioning and CHANGELOG
19
+ - add publish:cli script for single-package npm publish
20
+ ## [0.0.8] - 2026-05-21
21
+
22
+ ### Fixed
23
+
24
+ - Default `skills install` to interactive TUI; CLI flags pre-fill agent, skill, and scope
25
+ - Bare install no longer auto-detects all agent directories; bundled `skills/` source dirs are excluded from install targets
26
+
27
+ ### Changed
28
+
29
+ - Add `publish:cli` script for single-package npm publish
30
+
31
+ ## [0.0.7] - 2026-05-21
32
+
33
+ ### Changed
34
+
35
+ - Auth-first, shared-first layout for all Hub agent skills
36
+ - Skills bundle aligned with CLI release
37
+
38
+ ## [0.0.6] - 2026-05-18
39
+
40
+ ### Changed
41
+
42
+ - Bundled skills sync with npm CLI tarball
43
+
44
+ ### Fixed
45
+
46
+ - Copy skills into Docker builder for CLI build
47
+
48
+ ## [0.0.4] - 2026-05-18
49
+
50
+ ### Added
51
+
52
+ - Bundled skills installer and npm publish pipeline
53
+
54
+ ### Fixed
55
+
56
+ - Harden CLI token validation and production acceptance
@@ -0,0 +1,79 @@
1
+ export declare class FeishuImportError extends Error {
2
+ readonly code: string;
3
+ constructor(code: string, message: string);
4
+ }
5
+ export type FeishuImportOptions = {
6
+ baseToken?: string;
7
+ tableId?: string;
8
+ viewId?: string;
9
+ teamField?: string;
10
+ teamMap?: Record<string, string>;
11
+ autoTeamMap?: boolean;
12
+ dryRun?: boolean;
13
+ };
14
+ export type FeishuImportResult = {
15
+ imported: number;
16
+ updated: number;
17
+ skipped: number;
18
+ skippedReasons: Record<string, number>;
19
+ byTeam: Record<string, {
20
+ imported: number;
21
+ updated: number;
22
+ skipped: number;
23
+ }>;
24
+ dryRun?: boolean;
25
+ };
26
+ export type FeishuSnapshotPayload = {
27
+ permalink: string;
28
+ subreddit: string;
29
+ title?: string;
30
+ postedAt?: string;
31
+ source: "feishu";
32
+ score?: number;
33
+ commentsCount?: number;
34
+ body?: string | null;
35
+ opsStatus?: string | null;
36
+ draftStatus?: string | null;
37
+ postType?: string | null;
38
+ accountType?: string | null;
39
+ };
40
+ type LarkRecordListPayload = {
41
+ ok?: boolean;
42
+ data?: {
43
+ items?: Array<{
44
+ fields?: Record<string, unknown>;
45
+ }>;
46
+ fields?: string[];
47
+ data?: unknown[][];
48
+ has_more?: boolean;
49
+ };
50
+ };
51
+ export declare const DEFAULT_FEISHU_BASE_TOKEN = "MR0ObIxu2aJrnBsG7L0cfuXbn1f";
52
+ export declare const DEFAULT_FEISHU_TABLE_ID = "tblYtqjhitQpiIC1";
53
+ export declare const DEFAULT_FEISHU_VIEW_ID = "vewoajgDMm";
54
+ export declare function extractFeishuPermalink(raw: unknown): string | null;
55
+ export declare function parseFeishuArrayField(val: unknown): string[];
56
+ export declare function extractSubredditFromUrl(url: string): string;
57
+ export declare function normalizeSubreddit(raw: string, permalink: string): string;
58
+ export declare function parseFeishuNumberField(value: unknown): number | undefined;
59
+ export declare function parseFeishuRecordListPayload(parsed: LarkRecordListPayload): Array<Record<string, unknown>>;
60
+ export declare function fetchFeishuRecordsViaLarkCli(input: {
61
+ baseToken: string;
62
+ tableId: string;
63
+ viewId?: string;
64
+ }): Array<Record<string, unknown>>;
65
+ export declare function feishuFieldsToSnapshotInput(fields: Record<string, unknown>): Omit<FeishuSnapshotPayload, "source"> | null;
66
+ export declare function buildTeamMap(explicit: Record<string, string> | undefined, teams: Array<{
67
+ id: string;
68
+ slug: string;
69
+ name: string;
70
+ }>): Record<string, string>;
71
+ export declare function resolveTargetTeamId(input: {
72
+ fields: Record<string, unknown>;
73
+ teamField?: string;
74
+ teamMap: Record<string, string>;
75
+ fallbackTeamId: string;
76
+ }): string | null;
77
+ export declare function bumpTeamStats(byTeam: FeishuImportResult["byTeam"], teamId: string, kind: "imported" | "updated" | "skipped"): void;
78
+ export {};
79
+ //# sourceMappingURL=reddit-post-import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reddit-post-import.d.ts","sourceRoot":"","sources":["../../src/feishu/reddit-post-import.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,239 @@
1
+ import { spawnSync } from "node:child_process";
2
+ export class FeishuImportError extends Error {
3
+ code;
4
+ constructor(code, message) {
5
+ super(message);
6
+ this.code = code;
7
+ this.name = "FeishuImportError";
8
+ }
9
+ }
10
+ export const DEFAULT_FEISHU_BASE_TOKEN = "MR0ObIxu2aJrnBsG7L0cfuXbn1f";
11
+ export const DEFAULT_FEISHU_TABLE_ID = "tblYtqjhitQpiIC1";
12
+ export const DEFAULT_FEISHU_VIEW_ID = "vewoajgDMm";
13
+ const TEAM_FIELD_ALIASES = ["所属团队", "团队", "Agent Team", "Team", "品牌"];
14
+ const PERMALINK_FIELDS = ["帖子链接", "链接", "Link"];
15
+ const TITLE_FIELDS = ["帖子标题", "标题", "Title"];
16
+ const SUBREDDIT_FIELDS = ["板块社区", "板块", "Subreddit"];
17
+ const POSTED_AT_FIELDS = ["发布时间", "日期", "Posted At"];
18
+ const SCORE_FIELDS = ["点赞量", "Upvotes", "赞数"];
19
+ const COMMENT_FIELDS = ["评论量", "Comments", "评论数"];
20
+ const BODY_FIELDS = ["帖子内容", "Body"];
21
+ export function extractFeishuPermalink(raw) {
22
+ if (!raw || raw === "-" || raw === "/")
23
+ return null;
24
+ const str = String(raw).trim();
25
+ const mdMatch = str.match(/\[.*?\]\((https?:\/\/[^)]+)\)/);
26
+ if (mdMatch)
27
+ return mdMatch[1].trim();
28
+ if (str.startsWith("http"))
29
+ return str;
30
+ return null;
31
+ }
32
+ export function parseFeishuArrayField(val) {
33
+ if (!val)
34
+ return [];
35
+ if (Array.isArray(val)) {
36
+ return val.map((v) => typeof v === "object" && v !== null
37
+ ? (v.id ??
38
+ v.name ??
39
+ JSON.stringify(v))
40
+ : String(v));
41
+ }
42
+ if (typeof val === "string") {
43
+ return val
44
+ .replace(/^\[/, "")
45
+ .replace(/\]$/, "")
46
+ .replace(/'/g, "")
47
+ .split(",")
48
+ .map((s) => s.trim())
49
+ .filter(Boolean);
50
+ }
51
+ return [String(val)];
52
+ }
53
+ export function extractSubredditFromUrl(url) {
54
+ const m = url.match(/\/r\/([^/?#]+)/i);
55
+ return m ? m[1] : "unknown";
56
+ }
57
+ export function normalizeSubreddit(raw, permalink) {
58
+ const cleaned = raw.trim().replace(/^r\//i, "").trim();
59
+ return cleaned || extractSubredditFromUrl(permalink);
60
+ }
61
+ export function parseFeishuNumberField(value) {
62
+ if (value == null)
63
+ return undefined;
64
+ const str = String(value).trim();
65
+ if (!str || str === "-")
66
+ return undefined;
67
+ const parsed = Number(str);
68
+ if (!Number.isFinite(parsed))
69
+ return undefined;
70
+ return parsed;
71
+ }
72
+ function getField(fields, names) {
73
+ for (const name of names) {
74
+ const value = fields[name];
75
+ if (value !== undefined && value !== null && value !== "")
76
+ return value;
77
+ }
78
+ return undefined;
79
+ }
80
+ function rowToFields(fieldNames, row) {
81
+ const fields = {};
82
+ for (let i = 0; i < fieldNames.length; i += 1) {
83
+ fields[fieldNames[i]] = row[i];
84
+ }
85
+ return fields;
86
+ }
87
+ export function parseFeishuRecordListPayload(parsed) {
88
+ const data = parsed.data;
89
+ if (!data)
90
+ return [];
91
+ if (Array.isArray(data.items)) {
92
+ return data.items.map((item) => item.fields ?? {});
93
+ }
94
+ const fieldNames = data.fields ?? [];
95
+ const rows = data.data ?? [];
96
+ return rows.map((row) => rowToFields(fieldNames, row));
97
+ }
98
+ export function fetchFeishuRecordsViaLarkCli(input) {
99
+ const records = [];
100
+ let offset = 0;
101
+ const limit = 200;
102
+ while (true) {
103
+ const args = [
104
+ "base",
105
+ "+record-list",
106
+ "--base-token",
107
+ input.baseToken,
108
+ "--table-id",
109
+ input.tableId,
110
+ "--offset",
111
+ String(offset),
112
+ "--limit",
113
+ String(limit),
114
+ ];
115
+ if (input.viewId) {
116
+ args.push("--view-id", input.viewId);
117
+ }
118
+ const result = spawnSync("lark-cli", args, {
119
+ encoding: "utf8",
120
+ timeout: 60_000,
121
+ });
122
+ if (result.status !== 0) {
123
+ const message = [
124
+ result.stderr?.trim(),
125
+ result.stdout?.trim(),
126
+ result.error instanceof Error ? result.error.message.trim() : "",
127
+ ]
128
+ .filter(Boolean)
129
+ .join(" | ");
130
+ if (/not logged in|unauthorized|forbidden|token|auth/i.test(message)) {
131
+ throw new FeishuImportError("FEISHU_AUTH_REQUIRED", "飞书导入失败:lark-cli 未登录或无权限,请先执行 `lark-cli auth login` 并确认有表格访问权限。");
132
+ }
133
+ throw new FeishuImportError("FEISHU_IMPORT_COMMAND_FAILED", `飞书导入失败:lark-cli 命令执行失败(${message || "unknown error"})`);
134
+ }
135
+ let parsed;
136
+ try {
137
+ parsed = JSON.parse(result.stdout);
138
+ }
139
+ catch {
140
+ throw new FeishuImportError("FEISHU_IMPORT_PARSE_FAILED", "飞书导入失败:无法解析 lark-cli 输出(期望 JSON)。");
141
+ }
142
+ if (!parsed.ok) {
143
+ throw new FeishuImportError("FEISHU_IMPORT_CLI_ERROR", `飞书导入失败:lark-cli 返回错误(${JSON.stringify(parsed)})`);
144
+ }
145
+ const batch = parseFeishuRecordListPayload(parsed);
146
+ records.push(...batch);
147
+ if (!parsed.data?.has_more || batch.length === 0)
148
+ break;
149
+ offset += batch.length;
150
+ }
151
+ return records;
152
+ }
153
+ export function feishuFieldsToSnapshotInput(fields) {
154
+ const permalinkRaw = getField(fields, PERMALINK_FIELDS);
155
+ const permalink = extractFeishuPermalink(permalinkRaw);
156
+ if (!permalink)
157
+ return null;
158
+ const titleVal = getField(fields, TITLE_FIELDS);
159
+ const title = titleVal != null ? String(titleVal).trim() : undefined;
160
+ const subredditVal = getField(fields, SUBREDDIT_FIELDS);
161
+ const subredditRaw = subredditVal != null ? String(subredditVal) : "";
162
+ const subreddit = normalizeSubreddit(subredditRaw, permalink);
163
+ const postedAtRaw = getField(fields, POSTED_AT_FIELDS);
164
+ const postedAtDate = postedAtRaw ? new Date(String(postedAtRaw)) : undefined;
165
+ const postedAt = postedAtDate && !Number.isNaN(postedAtDate.getTime())
166
+ ? postedAtDate.toISOString()
167
+ : undefined;
168
+ const score = parseFeishuNumberField(getField(fields, SCORE_FIELDS));
169
+ const commentsCount = parseFeishuNumberField(getField(fields, COMMENT_FIELDS));
170
+ const bodyVal = getField(fields, BODY_FIELDS);
171
+ const postBody = bodyVal != null ? String(bodyVal) : null;
172
+ const opsStatus = parseFeishuArrayField(fields["运营状态"])[0] ?? null;
173
+ const draftStatus = parseFeishuArrayField(fields["稿子状态"])[0] ?? null;
174
+ const postType = parseFeishuArrayField(fields["发布类型"])[0] ?? null;
175
+ const accountType = parseFeishuArrayField(getField(fields, ["账号类型", "Account Type", "account_type"]))[0] ?? null;
176
+ return {
177
+ permalink,
178
+ subreddit,
179
+ title,
180
+ postedAt,
181
+ score,
182
+ commentsCount,
183
+ body: postBody,
184
+ opsStatus,
185
+ draftStatus,
186
+ postType,
187
+ accountType,
188
+ };
189
+ }
190
+ function extractTeamHint(fields) {
191
+ for (const name of TEAM_FIELD_ALIASES) {
192
+ const raw = fields[name];
193
+ if (raw == null || raw === "")
194
+ continue;
195
+ const values = parseFeishuArrayField(raw);
196
+ const candidate = (values[0] ?? String(raw)).trim();
197
+ if (candidate)
198
+ return candidate;
199
+ }
200
+ return null;
201
+ }
202
+ function normalizeTeamMapKey(raw) {
203
+ return raw.trim().toLowerCase();
204
+ }
205
+ export function buildTeamMap(explicit, teams) {
206
+ const map = {};
207
+ for (const team of teams) {
208
+ map[normalizeTeamMapKey(team.slug)] = team.id;
209
+ map[normalizeTeamMapKey(team.name)] = team.id;
210
+ }
211
+ if (explicit) {
212
+ for (const [key, teamId] of Object.entries(explicit)) {
213
+ map[normalizeTeamMapKey(key)] = teamId;
214
+ }
215
+ }
216
+ return map;
217
+ }
218
+ export function resolveTargetTeamId(input) {
219
+ const fieldNames = input.teamField
220
+ ? [input.teamField, ...TEAM_FIELD_ALIASES]
221
+ : TEAM_FIELD_ALIASES;
222
+ const raw = getField(input.fields, fieldNames);
223
+ const hint = raw != null
224
+ ? (parseFeishuArrayField(raw)[0] ?? String(raw)).trim()
225
+ : extractTeamHint(input.fields);
226
+ if (hint) {
227
+ const mapped = input.teamMap[normalizeTeamMapKey(hint)];
228
+ if (mapped)
229
+ return mapped;
230
+ }
231
+ return input.fallbackTeamId || null;
232
+ }
233
+ export function bumpTeamStats(byTeam, teamId, kind) {
234
+ if (!byTeam[teamId]) {
235
+ byTeam[teamId] = { imported: 0, updated: 0, skipped: 0 };
236
+ }
237
+ byTeam[teamId][kind] += 1;
238
+ }
239
+ //# sourceMappingURL=reddit-post-import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reddit-post-import.js","sourceRoot":"","sources":["../../src/feishu/reddit-post-import.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=reddit-post-import.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reddit-post-import.test.d.ts","sourceRoot":"","sources":["../../src/feishu/reddit-post-import.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,47 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { buildTeamMap, extractFeishuPermalink, feishuFieldsToSnapshotInput, parseFeishuRecordListPayload, resolveTargetTeamId, } from "./reddit-post-import.js";
3
+ describe("cli feishu reddit-post-import", () => {
4
+ it("parses markdown permalink and chinese fields", () => {
5
+ expect(extractFeishuPermalink("[link](https://www.reddit.com/r/eufy/comments/abc/post)")).toBe("https://www.reddit.com/r/eufy/comments/abc/post");
6
+ const snapshot = feishuFieldsToSnapshotInput({
7
+ 帖子链接: "https://www.reddit.com/r/test/comments/xyz/demo",
8
+ 帖子标题: "demo",
9
+ 板块社区: "r/test",
10
+ 品牌: "eufy",
11
+ 点赞量: "10",
12
+ 评论量: "2",
13
+ });
14
+ expect(snapshot).toMatchObject({
15
+ permalink: "https://www.reddit.com/r/test/comments/xyz/demo",
16
+ subreddit: "test",
17
+ score: 10,
18
+ commentsCount: 2,
19
+ });
20
+ });
21
+ it("maps brand field to team id", () => {
22
+ const teamMap = buildTeamMap(undefined, [
23
+ { id: "team-eufy", slug: "eufy", name: "Eufy" },
24
+ ]);
25
+ const teamId = resolveTargetTeamId({
26
+ fields: { 品牌: ["eufy"] },
27
+ teamField: "品牌",
28
+ teamMap,
29
+ fallbackTeamId: "fallback",
30
+ });
31
+ expect(teamId).toBe("team-eufy");
32
+ });
33
+ it("parses tabular lark-cli payload", () => {
34
+ const rows = parseFeishuRecordListPayload({
35
+ ok: true,
36
+ data: {
37
+ fields: ["帖子链接", "品牌"],
38
+ data: [["https://www.reddit.com/r/a/comments/1/a", ["eufy"]]],
39
+ },
40
+ });
41
+ expect(rows[0]).toMatchObject({
42
+ 帖子链接: "https://www.reddit.com/r/a/comments/1/a",
43
+ 品牌: ["eufy"],
44
+ });
45
+ });
46
+ });
47
+ //# sourceMappingURL=reddit-post-import.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reddit-post-import.test.js","sourceRoot":"","sources":["../../src/feishu/reddit-post-import.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,2BAA2B,EAC3B,4BAA4B,EAC5B,mBAAmB,GACpB,MAAM,yBAAyB,CAAC;AAEjC,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;IAC7C,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACtD,MAAM,CACJ,sBAAsB,CACpB,yDAAyD,CAC1D,CACF,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;QAE1D,MAAM,QAAQ,GAAG,2BAA2B,CAAC;YAC3C,IAAI,EAAE,iDAAiD;YACvD,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,QAAQ;YACd,EAAE,EAAE,MAAM;YACV,GAAG,EAAE,IAAI;YACT,GAAG,EAAE,GAAG;SACT,CAAC,CAAC;QACH,MAAM,CAAC,QAAQ,CAAC,CAAC,aAAa,CAAC;YAC7B,SAAS,EAAE,iDAAiD;YAC5D,SAAS,EAAE,MAAM;YACjB,KAAK,EAAE,EAAE;YACT,aAAa,EAAE,CAAC;SACjB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,EAAE;YACtC,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE;SAChD,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,mBAAmB,CAAC;YACjC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE;YACxB,SAAS,EAAE,IAAI;YACf,OAAO;YACP,cAAc,EAAE,UAAU;SAC3B,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,IAAI,GAAG,4BAA4B,CAAC;YACxC,EAAE,EAAE,IAAI;YACR,IAAI,EAAE;gBACJ,MAAM,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC;gBACtB,IAAI,EAAE,CAAC,CAAC,yCAAyC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;aAC9D;SACF,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;YAC5B,IAAI,EAAE,yCAAyC;YAC/C,EAAE,EAAE,CAAC,MAAM,CAAC;SACb,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { SocialHubClient } from "@geoly-ai/social-hub-sdk";
2
+ import { type FeishuImportOptions, type FeishuImportResult } from "./reddit-post-import.js";
3
+ export declare function syncFeishuPostsViaCli(client: SocialHubClient, fallbackTeamId: string, options?: FeishuImportOptions): Promise<FeishuImportResult>;
4
+ //# sourceMappingURL=sync-feishu-posts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-feishu-posts.d.ts","sourceRoot":"","sources":["../../src/feishu/sync-feishu-posts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAQL,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EAExB,MAAM,yBAAyB,CAAC;AA8BjC,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,eAAe,EACvB,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAmG7B"}
@@ -0,0 +1,112 @@
1
+ import { DEFAULT_FEISHU_BASE_TOKEN, DEFAULT_FEISHU_TABLE_ID, bumpTeamStats, buildTeamMap, feishuFieldsToSnapshotInput, fetchFeishuRecordsViaLarkCli, resolveTargetTeamId, } from "./reddit-post-import.js";
2
+ const BATCH_SIZE = 50;
3
+ function chunk(items, size) {
4
+ const batches = [];
5
+ for (let i = 0; i < items.length; i += size) {
6
+ batches.push(items.slice(i, i + size));
7
+ }
8
+ return batches;
9
+ }
10
+ function parseAgentTeams(raw) {
11
+ if (!raw || typeof raw !== "object")
12
+ return [];
13
+ const items = raw.items ?? [];
14
+ return items
15
+ .map((item) => {
16
+ if (!item || typeof item !== "object")
17
+ return null;
18
+ const row = item;
19
+ const id = typeof row.id === "string" ? row.id : undefined;
20
+ const slug = typeof row.slug === "string" ? row.slug : undefined;
21
+ const name = typeof row.name === "string" ? row.name : slug ?? id ?? "";
22
+ if (!id || !slug)
23
+ return null;
24
+ return { id, slug, name };
25
+ })
26
+ .filter((item) => item != null);
27
+ }
28
+ export async function syncFeishuPostsViaCli(client, fallbackTeamId, options = {}) {
29
+ const baseToken = options.baseToken ?? DEFAULT_FEISHU_BASE_TOKEN;
30
+ const tableId = options.tableId ?? DEFAULT_FEISHU_TABLE_ID;
31
+ const records = fetchFeishuRecordsViaLarkCli({
32
+ baseToken,
33
+ tableId,
34
+ viewId: options.viewId,
35
+ });
36
+ const teamsResponse = options.autoTeamMap
37
+ ? await client.listAgentTeams()
38
+ : { items: [] };
39
+ const teamMap = buildTeamMap(options.teamMap, options.autoTeamMap ? parseAgentTeams(teamsResponse) : []);
40
+ const result = {
41
+ imported: 0,
42
+ updated: 0,
43
+ skipped: 0,
44
+ skippedReasons: {},
45
+ byTeam: {},
46
+ dryRun: options.dryRun ?? false,
47
+ };
48
+ const bumpSkip = (reason, teamId) => {
49
+ result.skipped += 1;
50
+ result.skippedReasons[reason] = (result.skippedReasons[reason] ?? 0) + 1;
51
+ if (teamId)
52
+ bumpTeamStats(result.byTeam, teamId, "skipped");
53
+ };
54
+ const grouped = new Map();
55
+ for (const fields of records) {
56
+ const snapshot = feishuFieldsToSnapshotInput(fields);
57
+ if (!snapshot) {
58
+ bumpSkip("missing_permalink");
59
+ continue;
60
+ }
61
+ const targetTeamId = resolveTargetTeamId({
62
+ fields,
63
+ teamField: options.teamField,
64
+ teamMap,
65
+ fallbackTeamId,
66
+ });
67
+ if (!targetTeamId) {
68
+ bumpSkip("unmapped_team");
69
+ continue;
70
+ }
71
+ const payload = {
72
+ permalink: snapshot.permalink,
73
+ subreddit: snapshot.subreddit,
74
+ title: snapshot.title,
75
+ postedAt: snapshot.postedAt,
76
+ source: "feishu",
77
+ score: snapshot.score,
78
+ commentsCount: snapshot.commentsCount,
79
+ body: snapshot.body,
80
+ opsStatus: snapshot.opsStatus,
81
+ draftStatus: snapshot.draftStatus,
82
+ postType: snapshot.postType,
83
+ accountType: snapshot.accountType,
84
+ };
85
+ if (options.dryRun) {
86
+ result.imported += 1;
87
+ bumpTeamStats(result.byTeam, targetTeamId, "imported");
88
+ continue;
89
+ }
90
+ const bucket = grouped.get(targetTeamId) ?? [];
91
+ bucket.push(payload);
92
+ grouped.set(targetTeamId, bucket);
93
+ }
94
+ for (const [teamId, items] of grouped) {
95
+ let teamImported = 0;
96
+ let teamUpdated = 0;
97
+ for (const batch of chunk(items, BATCH_SIZE)) {
98
+ const upsert = await client.batchUpsertRedditPostSnapshotsByPermalink(teamId, batch);
99
+ result.imported += upsert.imported;
100
+ result.updated += upsert.updated;
101
+ teamImported += upsert.imported;
102
+ teamUpdated += upsert.updated;
103
+ }
104
+ result.byTeam[teamId] = {
105
+ imported: teamImported,
106
+ updated: teamUpdated,
107
+ skipped: result.byTeam[teamId]?.skipped ?? 0,
108
+ };
109
+ }
110
+ return result;
111
+ }
112
+ //# sourceMappingURL=sync-feishu-posts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-feishu-posts.js","sourceRoot":"","sources":["../../src/feishu/sync-feishu-posts.ts"],"names":[],"mappings":"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"}
@@ -137,7 +137,7 @@ describe("reddit subcommands", () => {
137
137
  expect(cmds).toContain("refresh");
138
138
  expect(cmds).toContain("update");
139
139
  expect(cmds).toContain("delete");
140
- expect(cmds).toContain("import-feishu");
140
+ expect(cmds).toContain("batch-upsert");
141
141
  });
142
142
  });
143
143
  describe("events subcommands", () => {