xhs-operator 1.0.0-beta.1

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 (83) hide show
  1. package/README.md +100 -0
  2. package/dist/actions/account.d.ts +59 -0
  3. package/dist/actions/account.d.ts.map +1 -0
  4. package/dist/actions/account.js +142 -0
  5. package/dist/actions/account.js.map +1 -0
  6. package/dist/actions/interact.d.ts +37 -0
  7. package/dist/actions/interact.d.ts.map +1 -0
  8. package/dist/actions/interact.js +205 -0
  9. package/dist/actions/interact.js.map +1 -0
  10. package/dist/actions/publish.d.ts +18 -0
  11. package/dist/actions/publish.d.ts.map +1 -0
  12. package/dist/actions/publish.js +135 -0
  13. package/dist/actions/publish.js.map +1 -0
  14. package/dist/actions/scrape.d.ts +21 -0
  15. package/dist/actions/scrape.d.ts.map +1 -0
  16. package/dist/actions/scrape.js +145 -0
  17. package/dist/actions/scrape.js.map +1 -0
  18. package/dist/agents/copywriter.d.ts +21 -0
  19. package/dist/agents/copywriter.d.ts.map +1 -0
  20. package/dist/agents/copywriter.js +115 -0
  21. package/dist/agents/copywriter.js.map +1 -0
  22. package/dist/agents/image-composer.d.ts +26 -0
  23. package/dist/agents/image-composer.d.ts.map +1 -0
  24. package/dist/agents/image-composer.js +103 -0
  25. package/dist/agents/image-composer.js.map +1 -0
  26. package/dist/cli.d.ts +3 -0
  27. package/dist/cli.d.ts.map +1 -0
  28. package/dist/cli.js +204 -0
  29. package/dist/cli.js.map +1 -0
  30. package/dist/index.d.ts +5 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +6 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/plugin.d.ts +61 -0
  35. package/dist/plugin.d.ts.map +1 -0
  36. package/dist/plugin.js +182 -0
  37. package/dist/plugin.js.map +1 -0
  38. package/dist/risk/behavior-humanizer.d.ts +30 -0
  39. package/dist/risk/behavior-humanizer.d.ts.map +1 -0
  40. package/dist/risk/behavior-humanizer.js +105 -0
  41. package/dist/risk/behavior-humanizer.js.map +1 -0
  42. package/dist/risk/fingerprint-guard.d.ts +23 -0
  43. package/dist/risk/fingerprint-guard.d.ts.map +1 -0
  44. package/dist/risk/fingerprint-guard.js +127 -0
  45. package/dist/risk/fingerprint-guard.js.map +1 -0
  46. package/dist/risk/rate-guard.d.ts +33 -0
  47. package/dist/risk/rate-guard.d.ts.map +1 -0
  48. package/dist/risk/rate-guard.js +104 -0
  49. package/dist/risk/rate-guard.js.map +1 -0
  50. package/dist/runtime/standalone.d.ts +15 -0
  51. package/dist/runtime/standalone.d.ts.map +1 -0
  52. package/dist/runtime/standalone.js +199 -0
  53. package/dist/runtime/standalone.js.map +1 -0
  54. package/dist/scheduler.d.ts +42 -0
  55. package/dist/scheduler.d.ts.map +1 -0
  56. package/dist/scheduler.js +139 -0
  57. package/dist/scheduler.js.map +1 -0
  58. package/dist/storage/database.d.ts +23 -0
  59. package/dist/storage/database.d.ts.map +1 -0
  60. package/dist/storage/database.js +142 -0
  61. package/dist/storage/database.js.map +1 -0
  62. package/dist/storage/kv-store.d.ts +13 -0
  63. package/dist/storage/kv-store.d.ts.map +1 -0
  64. package/dist/storage/kv-store.js +60 -0
  65. package/dist/storage/kv-store.js.map +1 -0
  66. package/dist/types/index.d.ts +320 -0
  67. package/dist/types/index.d.ts.map +1 -0
  68. package/dist/types/index.js +5 -0
  69. package/dist/types/index.js.map +1 -0
  70. package/dist/utils/helpers.d.ts +63 -0
  71. package/dist/utils/helpers.d.ts.map +1 -0
  72. package/dist/utils/helpers.js +115 -0
  73. package/dist/utils/helpers.js.map +1 -0
  74. package/dist/workflows/content-campaign.d.ts +58 -0
  75. package/dist/workflows/content-campaign.d.ts.map +1 -0
  76. package/dist/workflows/content-campaign.js +155 -0
  77. package/dist/workflows/content-campaign.js.map +1 -0
  78. package/dist/workflows/daily-operate.d.ts +36 -0
  79. package/dist/workflows/daily-operate.d.ts.map +1 -0
  80. package/dist/workflows/daily-operate.js +222 -0
  81. package/dist/workflows/daily-operate.js.map +1 -0
  82. package/manifest.json +29 -0
  83. package/package.json +66 -0
@@ -0,0 +1,135 @@
1
+ // ============================================================
2
+ // Publish Action — Note publishing to XHS Creator Center
3
+ // ============================================================
4
+ import { BehaviorHumanizer } from '../risk/behavior-humanizer.js';
5
+ import { QuotaExceededError } from '../risk/rate-guard.js';
6
+ import { randomBetween } from '../utils/helpers.js';
7
+ const CREATOR_PUBLISH_URL = 'https://creator.xiaohongshu.com/publish/publish';
8
+ export class PublishAction {
9
+ runtime;
10
+ fingerprintGuard;
11
+ rateGuard;
12
+ humanizer;
13
+ constructor(runtime, fingerprintGuard, rateGuard) {
14
+ this.runtime = runtime;
15
+ this.fingerprintGuard = fingerprintGuard;
16
+ this.rateGuard = rateGuard;
17
+ this.humanizer = new BehaviorHumanizer();
18
+ }
19
+ /**
20
+ * Publish a note with images to XHS.
21
+ */
22
+ async publishNote(account, note, images) {
23
+ // Check publish quota
24
+ const quota = this.rateGuard.checkQuota(account.id, 'publish');
25
+ if (!quota.allowed) {
26
+ throw new QuotaExceededError(quota.resetAt);
27
+ }
28
+ const page = await this.runtime.browser.newPage({
29
+ cookieFile: account.sessionFile,
30
+ proxy: account.proxy,
31
+ });
32
+ try {
33
+ // Apply fingerprint
34
+ await this.fingerprintGuard.applyFingerprint(page, account.id);
35
+ // Navigate to creator center
36
+ await page.navigate(CREATOR_PUBLISH_URL);
37
+ await this.humanizer.waitRandom(2000, 4000);
38
+ // Upload images
39
+ await this.uploadImages(page, images);
40
+ // Fill title
41
+ await this.humanizer.typeHuman(page, '#title-input', note.title, {
42
+ wpm: randomBetween(60, 120),
43
+ });
44
+ await this.humanizer.waitRandom(500, 1000);
45
+ // Fill body
46
+ await this.humanizer.typeHuman(page, '#content-textarea', note.body, {
47
+ wpm: randomBetween(50, 100),
48
+ });
49
+ await this.humanizer.waitRandom(800, 1500);
50
+ // Add hashtags
51
+ for (const tag of note.hashtags) {
52
+ await this.addHashtag(page, tag);
53
+ await this.humanizer.waitRandom(300, 800);
54
+ }
55
+ // Preview and submit
56
+ await this.humanizer.waitRandom(1000, 2000);
57
+ await this.humanizer.clickNatural(page, '[data-testid="publish-btn"]');
58
+ // Wait for publish confirmation
59
+ const result = await this.waitForPublishSuccess(page);
60
+ // Record action
61
+ this.rateGuard.recordAction(account.id, 'publish', result.noteId);
62
+ return result;
63
+ }
64
+ catch (error) {
65
+ this.rateGuard.recordFailure(account.id);
66
+ return {
67
+ success: false,
68
+ error: error instanceof Error ? error.message : String(error),
69
+ };
70
+ }
71
+ finally {
72
+ await page.close();
73
+ }
74
+ }
75
+ async uploadImages(page, images) {
76
+ for (const [idx, _img] of images.entries()) {
77
+ // Find upload input and trigger file selection
78
+ // In a real implementation, this would use the file chooser API
79
+ await page.waitForSelector('input[type="file"]', { timeout: 10000 });
80
+ // Simulated: openclaw browser API handles file buffer upload
81
+ await page.evaluate(`
82
+ document.querySelector('input[type="file"]').dispatchEvent(new Event('change'));
83
+ `);
84
+ if (idx < images.length - 1) {
85
+ await this.humanizer.waitRandom(800, 1500);
86
+ }
87
+ }
88
+ // Wait for upload completion
89
+ await this.humanizer.waitRandom(2000, 4000);
90
+ }
91
+ async addHashtag(page, tag) {
92
+ // Type # to trigger hashtag picker
93
+ await page.keyboard.type('#');
94
+ await this.humanizer.waitRandom(200, 500);
95
+ // Type tag name
96
+ for (const char of tag) {
97
+ await page.keyboard.type(char);
98
+ await this.humanizer.waitRandom(50, 150);
99
+ }
100
+ await this.humanizer.waitRandom(500, 1000);
101
+ // Select first suggestion
102
+ const suggestion = await page.$('.hashtag-suggestion-item');
103
+ if (suggestion) {
104
+ await suggestion.click();
105
+ }
106
+ else {
107
+ await page.keyboard.press('Enter');
108
+ }
109
+ }
110
+ async waitForPublishSuccess(page, timeoutMs = 30000) {
111
+ const start = Date.now();
112
+ while (Date.now() - start < timeoutMs) {
113
+ const url = page.url();
114
+ // Check for success redirect
115
+ if (url.includes('/publish/success') || url.includes('noteId=')) {
116
+ const noteIdMatch = url.match(/noteId=([a-f0-9]+)/);
117
+ return {
118
+ success: true,
119
+ noteId: noteIdMatch?.[1],
120
+ url: noteIdMatch ? `https://www.xiaohongshu.com/explore/${noteIdMatch[1]}` : undefined,
121
+ publishedAt: new Date(),
122
+ };
123
+ }
124
+ // Check for error messages
125
+ const errorEl = await page.$('.publish-error, .error-message');
126
+ if (errorEl) {
127
+ const errorText = await errorEl.textContent();
128
+ return { success: false, error: errorText || 'Unknown publish error' };
129
+ }
130
+ await this.humanizer.waitRandom(500, 1000);
131
+ }
132
+ return { success: false, error: 'Publish timeout' };
133
+ }
134
+ }
135
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/actions/publish.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { OpenClawRuntime, Account, AccountMetrics, NoteMetric } from '../types/index.js';
2
+ import { FingerprintGuard } from '../risk/fingerprint-guard.js';
3
+ export declare class ScrapeAction {
4
+ private runtime;
5
+ private fingerprintGuard;
6
+ private humanizer;
7
+ constructor(runtime: OpenClawRuntime, fingerprintGuard: FingerprintGuard);
8
+ /**
9
+ * Scrape complete account metrics from the Creator Center.
10
+ */
11
+ scrapeAccountMetrics(account: Account): Promise<AccountMetrics>;
12
+ /**
13
+ * Scrape a single note's detailed metrics.
14
+ */
15
+ scrapeNoteDetail(account: Account, noteId: string): Promise<NoteMetric | null>;
16
+ private scrapeOverview;
17
+ private scrapeNotesList;
18
+ private extractNoteMetricFromCard;
19
+ private scrapeNoteMetric;
20
+ }
21
+ //# sourceMappingURL=scrape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrape.d.ts","sourceRoot":"","sources":["../../src/actions/scrape.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EACf,OAAO,EACP,cAAc,EACd,UAAU,EAEX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAMhE,qBAAa,YAAY;IAIrB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,gBAAgB;IAJ1B,OAAO,CAAC,SAAS,CAAoB;gBAG3B,OAAO,EAAE,eAAe,EACxB,gBAAgB,EAAE,gBAAgB;IAK5C;;OAEG;IACG,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC;IAgCrE;;OAEG;IACG,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;YAiBtE,cAAc;YAiBd,eAAe;YAsBf,yBAAyB;YAyBzB,gBAAgB;CA0B/B"}
@@ -0,0 +1,145 @@
1
+ // ============================================================
2
+ // Scrape Action — Data collection from XHS Creator Center
3
+ // ============================================================
4
+ import { BehaviorHumanizer } from '../risk/behavior-humanizer.js';
5
+ import { sanitizePageContent } from '../utils/helpers.js';
6
+ const CREATOR_HOME_URL = 'https://creator.xiaohongshu.com/creator/home';
7
+ const CREATOR_NOTES_URL = 'https://creator.xiaohongshu.com/creator/notes';
8
+ export class ScrapeAction {
9
+ runtime;
10
+ fingerprintGuard;
11
+ humanizer;
12
+ constructor(runtime, fingerprintGuard) {
13
+ this.runtime = runtime;
14
+ this.fingerprintGuard = fingerprintGuard;
15
+ this.humanizer = new BehaviorHumanizer();
16
+ }
17
+ /**
18
+ * Scrape complete account metrics from the Creator Center.
19
+ */
20
+ async scrapeAccountMetrics(account) {
21
+ const page = await this.runtime.browser.newPage({
22
+ cookieFile: account.sessionFile,
23
+ proxy: account.proxy,
24
+ });
25
+ try {
26
+ await this.fingerprintGuard.applyFingerprint(page, account.id);
27
+ // Navigate to creator home
28
+ await page.navigate(CREATOR_HOME_URL);
29
+ await this.humanizer.waitRandom(2000, 4000);
30
+ // Scrape overview metrics
31
+ const overview = await this.scrapeOverview(page);
32
+ // Navigate to notes list
33
+ await page.navigate(CREATOR_NOTES_URL);
34
+ await this.humanizer.waitRandom(2000, 4000);
35
+ // Scrape individual note metrics
36
+ const notes = await this.scrapeNotesList(page);
37
+ return {
38
+ ...overview,
39
+ notes,
40
+ };
41
+ }
42
+ finally {
43
+ await page.close();
44
+ }
45
+ }
46
+ /**
47
+ * Scrape a single note's detailed metrics.
48
+ */
49
+ async scrapeNoteDetail(account, noteId) {
50
+ const page = await this.runtime.browser.newPage({
51
+ cookieFile: account.sessionFile,
52
+ proxy: account.proxy,
53
+ });
54
+ try {
55
+ await this.fingerprintGuard.applyFingerprint(page, account.id);
56
+ await page.navigate(`https://creator.xiaohongshu.com/creator/notes/${noteId}`);
57
+ await this.humanizer.waitRandom(2000, 4000);
58
+ return this.scrapeNoteMetric(page, noteId);
59
+ }
60
+ finally {
61
+ await page.close();
62
+ }
63
+ }
64
+ async scrapeOverview(page) {
65
+ // Try to extract from the page DOM
66
+ const extractNumber = async (selector) => {
67
+ const el = await page.$(selector);
68
+ if (!el)
69
+ return 0;
70
+ const text = sanitizePageContent((await el.textContent()) || '0');
71
+ return parseInt(text.replace(/[^0-9]/g, ''), 10) || 0;
72
+ };
73
+ return {
74
+ fans: await extractNumber('.fans-count, [data-type="fans"]'),
75
+ follows: await extractNumber('.follows-count, [data-type="follows"]'),
76
+ likes: await extractNumber('.likes-count, [data-type="likes"]'),
77
+ collects: await extractNumber('.collects-count, [data-type="collects"]'),
78
+ };
79
+ }
80
+ async scrapeNotesList(page) {
81
+ const notes = [];
82
+ // Scroll to load notes
83
+ for (let i = 0; i < 3; i++) {
84
+ const cards = await page.$$('.note-item, [data-type="note-row"]');
85
+ for (const card of cards) {
86
+ const noteId = await card.getAttribute('data-note-id');
87
+ if (!noteId || notes.some((n) => n.noteId === noteId))
88
+ continue;
89
+ const metric = await this.extractNoteMetricFromCard(card, noteId);
90
+ if (metric)
91
+ notes.push(metric);
92
+ }
93
+ // Scroll for more
94
+ await this.humanizer.browseRandomly(page, 2);
95
+ }
96
+ return notes;
97
+ }
98
+ async extractNoteMetricFromCard(card, noteId) {
99
+ try {
100
+ const rawText = sanitizePageContent((await card.textContent()) || '');
101
+ // Parse numbers from the card text (simplified extraction)
102
+ const numbers = rawText.match(/\d+/g)?.map(Number) || [];
103
+ return {
104
+ noteId,
105
+ title: rawText.slice(0, 50),
106
+ views: numbers[0] || 0,
107
+ likes: numbers[1] || 0,
108
+ comments: numbers[2] || 0,
109
+ collects: numbers[3] || 0,
110
+ publishedAt: new Date(),
111
+ ctr: numbers[0] && numbers[4] ? numbers[0] / numbers[4] : 0,
112
+ };
113
+ }
114
+ catch {
115
+ return null;
116
+ }
117
+ }
118
+ async scrapeNoteMetric(page, noteId) {
119
+ try {
120
+ const extractNumber = async (selector) => {
121
+ const el = await page.$(selector);
122
+ if (!el)
123
+ return 0;
124
+ const text = sanitizePageContent((await el.textContent()) || '0');
125
+ return parseInt(text.replace(/[^0-9]/g, ''), 10) || 0;
126
+ };
127
+ const titleEl = await page.$('.note-title, h1');
128
+ const title = sanitizePageContent((await titleEl?.textContent()) || '');
129
+ return {
130
+ noteId,
131
+ title,
132
+ views: await extractNumber('.views-count, [data-type="views"]'),
133
+ likes: await extractNumber('.likes-count, [data-type="likes"]'),
134
+ comments: await extractNumber('.comments-count, [data-type="comments"]'),
135
+ collects: await extractNumber('.collects-count, [data-type="collects"]'),
136
+ publishedAt: new Date(),
137
+ ctr: 0,
138
+ };
139
+ }
140
+ catch {
141
+ return null;
142
+ }
143
+ }
144
+ }
145
+ //# sourceMappingURL=scrape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrape.js","sourceRoot":"","sources":["../../src/actions/scrape.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { OpenClawRuntime, NoteGenerateRequest, NoteContent, NoteMetric } from '../types/index.js';
2
+ export declare class Copywriter {
3
+ private runtime;
4
+ constructor(runtime: OpenClawRuntime);
5
+ /**
6
+ * Generate a complete XHS note (title, body, hashtags, cover text).
7
+ */
8
+ generateNote(req: NoteGenerateRequest): Promise<NoteContent>;
9
+ /**
10
+ * Generate a personalized comment for an interaction task.
11
+ */
12
+ generateComment(noteTitle: string, noteExcerpt: string): Promise<string>;
13
+ /**
14
+ * Analyze past note performance to suggest the best topic.
15
+ */
16
+ analyzeTopPerformingTopics(notes: NoteMetric[]): Promise<string>;
17
+ private buildSystemPrompt;
18
+ private buildContentPrompt;
19
+ private parseNoteContent;
20
+ }
21
+ //# sourceMappingURL=copywriter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copywriter.d.ts","sourceRoot":"","sources":["../../src/agents/copywriter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACnB,WAAW,EAGX,UAAU,EACX,MAAM,mBAAmB,CAAC;AAgB3B,qBAAa,UAAU;IACT,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,eAAe;IAE5C;;OAEG;IACG,YAAY,CAAC,GAAG,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,CAAC;IAclE;;OAEG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAoB9E;;OAEG;IACG,0BAA0B,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAqBtE,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,gBAAgB;CAmBzB"}
@@ -0,0 +1,115 @@
1
+ // ============================================================
2
+ // Copywriter Agent — AI-powered content generation for XHS
3
+ // ============================================================
4
+ import { sanitizePageContent } from '../utils/helpers.js';
5
+ const STYLE_PROMPTS = {
6
+ lifestyle: `你是小红书生活方式博主。标题要有场景感+情绪词,正文结构:HOOK开头 → 故事 → 产品/体验 → CTA互动引导。结尾用评论区提问引发互动。`,
7
+ tutorial: `你是小红书教程类博主。标题用数字列表+结果导向,正文结构:痛点引入 → 分步骤教程 → Tips补充。结尾提醒收藏备用。`,
8
+ review: `你是小红书测评博主。标题用对比型/结论先行,正文结构:开箱体验 → 详细测评 → 优缺点总结。结尾引导点赞收藏。`,
9
+ vlog: `你是小红书vlog博主。标题用地点/事件型,正文按时间线叙事。结尾引导关注看后续。`,
10
+ };
11
+ const TONE_MODIFIERS = {
12
+ casual: '语气轻松活泼,像朋友聊天一样自然。适当使用口语化表达。',
13
+ professional: '语气专业可信,数据支撑观点。保持权威但不生硬。',
14
+ trendy: '紧跟潮流热梗,使用当下流行语和网络用语。活泼有趣。',
15
+ };
16
+ export class Copywriter {
17
+ runtime;
18
+ constructor(runtime) {
19
+ this.runtime = runtime;
20
+ }
21
+ /**
22
+ * Generate a complete XHS note (title, body, hashtags, cover text).
23
+ */
24
+ async generateNote(req) {
25
+ const systemPrompt = this.buildSystemPrompt(req.style, req.tone);
26
+ const userPrompt = this.buildContentPrompt(req);
27
+ const result = await this.runtime.ai.completion({
28
+ model: 'claude-sonnet-4-20250514',
29
+ system: systemPrompt,
30
+ prompt: userPrompt,
31
+ responseFormat: 'json',
32
+ });
33
+ return this.parseNoteContent(result);
34
+ }
35
+ /**
36
+ * Generate a personalized comment for an interaction task.
37
+ */
38
+ async generateComment(noteTitle, noteExcerpt) {
39
+ const sanitizedTitle = sanitizePageContent(noteTitle);
40
+ const sanitizedExcerpt = sanitizePageContent(noteExcerpt);
41
+ const result = await this.runtime.ai.completion({
42
+ model: 'claude-sonnet-4-20250514',
43
+ system: `你是一个真实的小红书用户。根据笔记内容生成一条自然、真诚的评论。
44
+ 要求:
45
+ - 10-50字之间
46
+ - 表达真实感受或提问
47
+ - 不要用模板化语言
48
+ - 可以适当用emoji但不要过多
49
+ - 不要用"博主"这样的称呼`,
50
+ prompt: `笔记标题:${sanitizedTitle}\n笔记内容摘要:${sanitizedExcerpt}\n\n请生成一条评论:`,
51
+ responseFormat: 'text',
52
+ });
53
+ return result.trim();
54
+ }
55
+ /**
56
+ * Analyze past note performance to suggest the best topic.
57
+ */
58
+ async analyzeTopPerformingTopics(notes) {
59
+ if (notes.length === 0)
60
+ return '日常分享';
61
+ // Sort by engagement (likes + comments + collects)
62
+ const sorted = [...notes].sort((a, b) => (b.likes + b.comments + b.collects) - (a.likes + a.comments + a.collects));
63
+ const topNotes = sorted.slice(0, 5);
64
+ const titles = topNotes.map((n) => n.title).join('\n');
65
+ const result = await this.runtime.ai.completion({
66
+ model: 'claude-sonnet-4-20250514',
67
+ system: '你是数据分析师,根据历史高互动笔记标题分析内容方向。',
68
+ prompt: `以下是近期互动最高的笔记标题:\n${titles}\n\n请推荐一个今天适合发布的话题方向(只输出话题关键词,不要其他内容):`,
69
+ responseFormat: 'text',
70
+ });
71
+ return result.trim();
72
+ }
73
+ buildSystemPrompt(style, tone) {
74
+ return `${STYLE_PROMPTS[style]}\n${TONE_MODIFIERS[tone]}\n\n请以JSON格式返回,包含以下字段:
75
+ {
76
+ "title": "笔记标题(≤20字,含关键词)",
77
+ "body": "笔记正文",
78
+ "hashtags": ["话题标签1", "话题标签2", ...],
79
+ "coverText": "封面文字(≤10字)"
80
+ }`;
81
+ }
82
+ buildContentPrompt(req) {
83
+ const parts = [
84
+ `主题:${req.topic}`,
85
+ `关键词:${req.keywords.join('、')}`,
86
+ `字数范围:${req.wordCount[0]}-${req.wordCount[1]}字`,
87
+ ];
88
+ if (req.includeEmoji)
89
+ parts.push('正文中适当使用emoji');
90
+ if (req.includeHashtags)
91
+ parts.push('生成3-5个相关话题标签');
92
+ return parts.join('\n');
93
+ }
94
+ parseNoteContent(raw) {
95
+ try {
96
+ const parsed = JSON.parse(raw);
97
+ return {
98
+ title: String(parsed.title || '').slice(0, 20),
99
+ body: String(parsed.body || ''),
100
+ hashtags: Array.isArray(parsed.hashtags) ? parsed.hashtags.map(String) : [],
101
+ coverText: String(parsed.coverText || '').slice(0, 10),
102
+ };
103
+ }
104
+ catch {
105
+ // Fallback: treat the whole response as the body
106
+ return {
107
+ title: raw.slice(0, 20),
108
+ body: raw,
109
+ hashtags: [],
110
+ coverText: '',
111
+ };
112
+ }
113
+ }
114
+ }
115
+ //# sourceMappingURL=copywriter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copywriter.js","sourceRoot":"","sources":["../../src/agents/copywriter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { OpenClawRuntime, NoteContent, ImageComposerConfig } from '../types/index.js';
2
+ export declare class ImageComposer {
3
+ private runtime;
4
+ constructor(runtime: OpenClawRuntime);
5
+ /**
6
+ * Compose a cover image for a note.
7
+ */
8
+ composeCoverImage(content: NoteContent, config: ImageComposerConfig): Promise<Buffer>;
9
+ /**
10
+ * Generate an AI image based on note content.
11
+ */
12
+ generateAIImage(content: NoteContent): Promise<Buffer>;
13
+ /**
14
+ * Fetch base image from configured source.
15
+ */
16
+ private fetchBaseImage;
17
+ /**
18
+ * Overlay text on the image using Sharp.
19
+ */
20
+ private overlayText;
21
+ /**
22
+ * Add a subtle brand watermark.
23
+ */
24
+ private addWatermark;
25
+ }
26
+ //# sourceMappingURL=image-composer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-composer.d.ts","sourceRoot":"","sources":["../../src/agents/image-composer.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,mBAAmB,EAEpB,MAAM,mBAAmB,CAAC;AAE3B,qBAAa,aAAa;IACZ,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,eAAe;IAE5C;;OAEG;IACG,iBAAiB,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC;IAe3F;;OAEG;IACG,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAS5D;;OAEG;YACW,cAAc;IAK5B;;OAEG;YACW,WAAW;IA0CzB;;OAEG;YACW,YAAY;CAiB3B"}
@@ -0,0 +1,103 @@
1
+ // ============================================================
2
+ // Image Composer — Cover image generation and composition
3
+ // ============================================================
4
+ export class ImageComposer {
5
+ runtime;
6
+ constructor(runtime) {
7
+ this.runtime = runtime;
8
+ }
9
+ /**
10
+ * Compose a cover image for a note.
11
+ */
12
+ async composeCoverImage(content, config) {
13
+ // Step 1: Get base image
14
+ const baseImage = await this.fetchBaseImage(content, config);
15
+ // Step 2: Overlay text (cover text)
16
+ const composed = await this.overlayText(baseImage, content.coverText, config);
17
+ // Step 3: Add watermark if brand colors are configured
18
+ if (config.brandColors.length > 0) {
19
+ return this.addWatermark(composed, config);
20
+ }
21
+ return composed;
22
+ }
23
+ /**
24
+ * Generate an AI image based on note content.
25
+ */
26
+ async generateAIImage(content) {
27
+ const prompt = `小红书风格封面图,主题:${content.title},风格清新自然,高质量`;
28
+ return this.runtime.ai.imageGeneration({
29
+ prompt,
30
+ size: '1080x1440', // 3:4 ratio for XHS
31
+ style: 'natural',
32
+ });
33
+ }
34
+ /**
35
+ * Fetch base image from configured source.
36
+ */
37
+ async fetchBaseImage(content, config) {
38
+ // Default: generate with AI
39
+ return this.generateAIImage(content);
40
+ }
41
+ /**
42
+ * Overlay text on the image using Sharp.
43
+ */
44
+ async overlayText(imageBuffer, text, config) {
45
+ // Dynamic import for sharp (heavy dependency)
46
+ const sharp = (await import('sharp')).default;
47
+ if (!text || !config.textOverlay)
48
+ return imageBuffer;
49
+ const { position, textColor, backgroundColor, padding } = config.textOverlay;
50
+ const fontSize = config.coverTemplate?.fontSize ?? 48;
51
+ // Create text SVG overlay
52
+ const svgWidth = 1080;
53
+ const svgHeight = 200;
54
+ const y = position === 'top' ? padding : position === 'center' ? 600 : 1200;
55
+ const bgRect = backgroundColor
56
+ ? `<rect x="0" y="0" width="${svgWidth}" height="${svgHeight}" fill="${backgroundColor}" opacity="0.7"/>`
57
+ : '';
58
+ const svg = `
59
+ <svg width="${svgWidth}" height="${svgHeight}">
60
+ ${bgRect}
61
+ <text x="${svgWidth / 2}" y="${svgHeight / 2 + fontSize / 3}"
62
+ font-size="${fontSize}" fill="${textColor}"
63
+ text-anchor="middle" font-family="sans-serif" font-weight="bold">
64
+ ${escapeXml(text)}
65
+ </text>
66
+ </svg>
67
+ `;
68
+ return sharp(imageBuffer)
69
+ .composite([{
70
+ input: Buffer.from(svg),
71
+ top: y,
72
+ left: 0,
73
+ }])
74
+ .toBuffer();
75
+ }
76
+ /**
77
+ * Add a subtle brand watermark.
78
+ */
79
+ async addWatermark(imageBuffer, config) {
80
+ const sharp = (await import('sharp')).default;
81
+ const color = config.brandColors[0] || '#ffffff';
82
+ const svg = `
83
+ <svg width="200" height="40">
84
+ <rect x="0" y="0" width="200" height="40" fill="${color}" opacity="0.3" rx="8"/>
85
+ </svg>
86
+ `;
87
+ return sharp(imageBuffer)
88
+ .composite([{
89
+ input: Buffer.from(svg),
90
+ gravity: 'southeast',
91
+ }])
92
+ .toBuffer();
93
+ }
94
+ }
95
+ function escapeXml(text) {
96
+ return text
97
+ .replace(/&/g, '&amp;')
98
+ .replace(/</g, '&lt;')
99
+ .replace(/>/g, '&gt;')
100
+ .replace(/"/g, '&quot;')
101
+ .replace(/'/g, '&apos;');
102
+ }
103
+ //# sourceMappingURL=image-composer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-composer.js","sourceRoot":"","sources":["../../src/agents/image-composer.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}