inkdrift 0.1.0

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 (107) hide show
  1. package/.env.example +23 -0
  2. package/README.md +119 -0
  3. package/dist/index-once.d.ts +8 -0
  4. package/dist/index-once.d.ts.map +1 -0
  5. package/dist/index-once.js +45 -0
  6. package/dist/index-once.js.map +1 -0
  7. package/dist/index.d.ts +9 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +72 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/modules/bot/index.d.ts +11 -0
  12. package/dist/modules/bot/index.d.ts.map +1 -0
  13. package/dist/modules/bot/index.js +60 -0
  14. package/dist/modules/bot/index.js.map +1 -0
  15. package/dist/modules/bot/test.d.ts +13 -0
  16. package/dist/modules/bot/test.d.ts.map +1 -0
  17. package/dist/modules/bot/test.js +37 -0
  18. package/dist/modules/bot/test.js.map +1 -0
  19. package/dist/modules/distiller/index.d.ts +24 -0
  20. package/dist/modules/distiller/index.d.ts.map +1 -0
  21. package/dist/modules/distiller/index.js +124 -0
  22. package/dist/modules/distiller/index.js.map +1 -0
  23. package/dist/modules/distiller/test.d.ts +10 -0
  24. package/dist/modules/distiller/test.d.ts.map +1 -0
  25. package/dist/modules/distiller/test.js +92 -0
  26. package/dist/modules/distiller/test.js.map +1 -0
  27. package/dist/modules/extractor/index.d.ts +52 -0
  28. package/dist/modules/extractor/index.d.ts.map +1 -0
  29. package/dist/modules/extractor/index.js +114 -0
  30. package/dist/modules/extractor/index.js.map +1 -0
  31. package/dist/modules/extractor/test.d.ts +10 -0
  32. package/dist/modules/extractor/test.d.ts.map +1 -0
  33. package/dist/modules/extractor/test.js +80 -0
  34. package/dist/modules/extractor/test.js.map +1 -0
  35. package/dist/modules/fetcher/index.d.ts +2 -0
  36. package/dist/modules/fetcher/index.d.ts.map +1 -0
  37. package/dist/modules/fetcher/index.js +3 -0
  38. package/dist/modules/fetcher/index.js.map +1 -0
  39. package/dist/modules/fetcher/test.d.ts +2 -0
  40. package/dist/modules/fetcher/test.d.ts.map +1 -0
  41. package/dist/modules/fetcher/test.js +3 -0
  42. package/dist/modules/fetcher/test.js.map +1 -0
  43. package/dist/modules/flowus-source/index.d.ts +55 -0
  44. package/dist/modules/flowus-source/index.d.ts.map +1 -0
  45. package/dist/modules/flowus-source/index.js +195 -0
  46. package/dist/modules/flowus-source/index.js.map +1 -0
  47. package/dist/modules/flowus-source/test.d.ts +14 -0
  48. package/dist/modules/flowus-source/test.d.ts.map +1 -0
  49. package/dist/modules/flowus-source/test.js +63 -0
  50. package/dist/modules/flowus-source/test.js.map +1 -0
  51. package/dist/modules/flowus-source/types.d.ts +93 -0
  52. package/dist/modules/flowus-source/types.d.ts.map +1 -0
  53. package/dist/modules/flowus-source/types.js +5 -0
  54. package/dist/modules/flowus-source/types.js.map +1 -0
  55. package/dist/modules/memorizer/index.d.ts +29 -0
  56. package/dist/modules/memorizer/index.d.ts.map +1 -0
  57. package/dist/modules/memorizer/index.js +72 -0
  58. package/dist/modules/memorizer/index.js.map +1 -0
  59. package/dist/modules/memorizer/test.d.ts +10 -0
  60. package/dist/modules/memorizer/test.d.ts.map +1 -0
  61. package/dist/modules/memorizer/test.js +69 -0
  62. package/dist/modules/memorizer/test.js.map +1 -0
  63. package/dist/modules/queue/index.d.ts +45 -0
  64. package/dist/modules/queue/index.d.ts.map +1 -0
  65. package/dist/modules/queue/index.js +161 -0
  66. package/dist/modules/queue/index.js.map +1 -0
  67. package/dist/modules/queue/test.d.ts +2 -0
  68. package/dist/modules/queue/test.d.ts.map +1 -0
  69. package/dist/modules/queue/test.js +3 -0
  70. package/dist/modules/queue/test.js.map +1 -0
  71. package/dist/modules/webhook/index.d.ts +8 -0
  72. package/dist/modules/webhook/index.d.ts.map +1 -0
  73. package/dist/modules/webhook/index.js +8 -0
  74. package/dist/modules/webhook/index.js.map +1 -0
  75. package/dist/modules/webhook/test.d.ts +12 -0
  76. package/dist/modules/webhook/test.d.ts.map +1 -0
  77. package/dist/modules/webhook/test.js +14 -0
  78. package/dist/modules/webhook/test.js.map +1 -0
  79. package/dist/modules/wechat-client/index.d.ts +8 -0
  80. package/dist/modules/wechat-client/index.d.ts.map +1 -0
  81. package/dist/modules/wechat-client/index.js +8 -0
  82. package/dist/modules/wechat-client/index.js.map +1 -0
  83. package/dist/modules/wechat-client/test.d.ts +12 -0
  84. package/dist/modules/wechat-client/test.d.ts.map +1 -0
  85. package/dist/modules/wechat-client/test.js +14 -0
  86. package/dist/modules/wechat-client/test.js.map +1 -0
  87. package/dist/modules/wechat-fetcher/index.d.ts +18 -0
  88. package/dist/modules/wechat-fetcher/index.d.ts.map +1 -0
  89. package/dist/modules/wechat-fetcher/index.js +75 -0
  90. package/dist/modules/wechat-fetcher/index.js.map +1 -0
  91. package/dist/scripts/reset-one.d.ts +6 -0
  92. package/dist/scripts/reset-one.d.ts.map +1 -0
  93. package/dist/scripts/reset-one.js +40 -0
  94. package/dist/scripts/reset-one.js.map +1 -0
  95. package/dist/utils/config.d.ts +24 -0
  96. package/dist/utils/config.d.ts.map +1 -0
  97. package/dist/utils/config.js +35 -0
  98. package/dist/utils/config.js.map +1 -0
  99. package/dist/utils/logger.d.ts +2 -0
  100. package/dist/utils/logger.d.ts.map +1 -0
  101. package/dist/utils/logger.js +3 -0
  102. package/dist/utils/logger.js.map +1 -0
  103. package/dist/web/server.d.ts +2 -0
  104. package/dist/web/server.d.ts.map +1 -0
  105. package/dist/web/server.js +3 -0
  106. package/dist/web/server.js.map +1 -0
  107. package/package.json +61 -0
@@ -0,0 +1,195 @@
1
+ /**
2
+ * flowus-source module
3
+ *
4
+ * FlowUs API client for reading articles from a multi-dimensional table.
5
+ * Replaces the wechaty bot as the article source in Phase 1.
6
+ */
7
+ import got from 'got';
8
+ const STATUS_PROP = 'status';
9
+ export class FlowUsClient {
10
+ baseUrl;
11
+ token;
12
+ databaseId;
13
+ headers;
14
+ constructor(config) {
15
+ this.baseUrl = config.baseUrl.replace(/\/+$/, '');
16
+ this.token = config.token;
17
+ this.databaseId = config.databaseId;
18
+ this.headers = {
19
+ Authorization: `Bearer ${this.token}`,
20
+ 'Content-Type': 'application/json',
21
+ };
22
+ }
23
+ /**
24
+ * Query all unprocessed articles from the database.
25
+ * Returns articles where "处理状态" is empty or "未处理".
26
+ */
27
+ async queryNewArticles() {
28
+ const allPages = [];
29
+ let cursor;
30
+ do {
31
+ const body = { page_size: 100 };
32
+ if (cursor)
33
+ body.start_cursor = cursor;
34
+ const res = await got
35
+ .post(`${this.baseUrl}/v1/databases/${this.databaseId}/query`, {
36
+ headers: this.headers,
37
+ json: body,
38
+ })
39
+ .json();
40
+ allPages.push(...res.results);
41
+ cursor = res.has_more ? res.next_cursor ?? undefined : undefined;
42
+ } while (cursor);
43
+ // Filter: keep articles where status is empty, null, or "未处理"
44
+ return allPages.filter((page) => {
45
+ const status = page.properties[STATUS_PROP];
46
+ if (!status)
47
+ return true;
48
+ if (status.type === 'select') {
49
+ const sel = status.select;
50
+ return !sel || sel.name === '未处理';
51
+ }
52
+ return true;
53
+ });
54
+ }
55
+ /**
56
+ * Read article content (all child blocks) and return as plain text/Markdown.
57
+ */
58
+ async getArticleContent(pageId) {
59
+ const blocks = await this.fetchAllBlocks(pageId);
60
+ return blocks.map((block) => this.blockToMarkdown(block)).filter(Boolean).join('\n\n');
61
+ }
62
+ /**
63
+ * Fetch all blocks for a page (raw, for inspection/testing).
64
+ */
65
+ async getBlocks(pageId) {
66
+ return this.fetchAllBlocks(pageId);
67
+ }
68
+ /**
69
+ * Mark an article as "处理中".
70
+ */
71
+ async markProcessing(pageId) {
72
+ await this.setStatus(pageId, '处理中');
73
+ }
74
+ /**
75
+ * Mark an article as "已完成".
76
+ */
77
+ async markAsProcessed(pageId) {
78
+ await this.setStatus(pageId, '已完成');
79
+ }
80
+ /**
81
+ * Mark an article as "失败".
82
+ */
83
+ async markAsFailed(pageId, error) {
84
+ await this.setStatus(pageId, '失败');
85
+ }
86
+ async setStatus(pageId, status) {
87
+ await got
88
+ .patch(`${this.baseUrl}/v1/pages/${pageId}`, {
89
+ headers: this.headers,
90
+ json: {
91
+ properties: {
92
+ [STATUS_PROP]: {
93
+ type: 'select',
94
+ select: { name: status },
95
+ },
96
+ },
97
+ },
98
+ })
99
+ .json();
100
+ }
101
+ /**
102
+ * Convenience: get a full article with content from a page record.
103
+ */
104
+ async getFullArticle(page) {
105
+ const titleProp = page.properties['title'];
106
+ const title = titleProp && 'title' in titleProp
107
+ ? titleProp.title
108
+ .map((t) => t.plain_text)
109
+ .join('')
110
+ : '';
111
+ const urlProp = page.properties['网址链接'];
112
+ const url = urlProp && 'url' in urlProp ? urlProp.url : '';
113
+ const authorProp = page.properties['作者'];
114
+ const author = authorProp && 'select' in authorProp
115
+ ? authorProp.select?.name ?? ''
116
+ : '';
117
+ const tagsProp = page.properties['标签'];
118
+ const tags = tagsProp && 'multi_select' in tagsProp
119
+ ? tagsProp.multi_select.map((t) => t.name)
120
+ : [];
121
+ const content = await this.getArticleContent(page.id);
122
+ return { pageId: page.id, title, url, author, tags, content };
123
+ }
124
+ /**
125
+ * Recursively fetch all blocks for a page, including nested children.
126
+ */
127
+ async fetchAllBlocks(pageId) {
128
+ const allBlocks = [];
129
+ let cursor;
130
+ do {
131
+ const res = await got
132
+ .get(`${this.baseUrl}/v1/blocks/${pageId}/children`, {
133
+ headers: this.headers,
134
+ searchParams: {
135
+ page_size: 100,
136
+ ...(cursor ? { start_cursor: cursor } : {}),
137
+ },
138
+ })
139
+ .json();
140
+ allBlocks.push(...res.results);
141
+ cursor = res.has_more ? res.next_cursor ?? undefined : undefined;
142
+ } while (cursor);
143
+ // Recursively fetch children for blocks that have them
144
+ for (const block of allBlocks) {
145
+ if (block.has_children) {
146
+ const children = await this.fetchAllBlocks(block.id);
147
+ block._children = children;
148
+ }
149
+ }
150
+ return allBlocks;
151
+ }
152
+ /**
153
+ * Convert a single block to Markdown string.
154
+ * FlowUs uses block.data (unlike Notion's block[block.type]).
155
+ */
156
+ blockToMarkdown(block) {
157
+ const data = block.data;
158
+ const text = data?.rich_text?.map((rt) => rt.plain_text).join('') ?? '';
159
+ switch (block.type) {
160
+ case 'heading_1':
161
+ return `# ${text}`;
162
+ case 'heading_2':
163
+ return `## ${text}`;
164
+ case 'heading_3':
165
+ return `### ${text}`;
166
+ case 'paragraph':
167
+ return text;
168
+ case 'bulleted_list_item':
169
+ return `- ${text}`;
170
+ case 'numbered_list_item':
171
+ return `1. ${text}`;
172
+ case 'quote':
173
+ return `> ${text}`;
174
+ case 'code':
175
+ return `\`\`\`\n${text}\n\`\`\``;
176
+ case 'divider':
177
+ return '---';
178
+ case 'image': {
179
+ const imgUrl = data?.external?.url ?? data?.file?.url ?? '';
180
+ return imgUrl ? `![](${imgUrl})` : '[image]';
181
+ }
182
+ case 'bookmark': {
183
+ const url = data?.url ?? '';
184
+ return url ? `[${url}](${url})` : '';
185
+ }
186
+ case 'file': {
187
+ const fileUrl = data?.file?.url ?? '';
188
+ return fileUrl ? `[file](${fileUrl})` : '[file]';
189
+ }
190
+ default:
191
+ return text;
192
+ }
193
+ }
194
+ }
195
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/modules/flowus-source/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * flowus-source module standalone test
3
+ *
4
+ * Usage: npx tsx src/modules/flowus-source/test.ts
5
+ *
6
+ * Validation:
7
+ * 1. Query articles from the 垃圾堆 database
8
+ * 2. Read article content (blocks → markdown)
9
+ * 3. Verify block structure (heading_1, paragraph, image, etc.)
10
+ *
11
+ * Note: Does NOT call markAsProcessed to avoid side effects.
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../../src/modules/flowus-source/test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * flowus-source module standalone test
3
+ *
4
+ * Usage: npx tsx src/modules/flowus-source/test.ts
5
+ *
6
+ * Validation:
7
+ * 1. Query articles from the 垃圾堆 database
8
+ * 2. Read article content (blocks → markdown)
9
+ * 3. Verify block structure (heading_1, paragraph, image, etc.)
10
+ *
11
+ * Note: Does NOT call markAsProcessed to avoid side effects.
12
+ */
13
+ import { config } from '../../utils/config.js';
14
+ import { FlowUsClient } from './index.js';
15
+ const { token, databaseId } = config.flowus;
16
+ if (!token || !databaseId) {
17
+ console.error('Missing FLOWUS_TOKEN or FLOWUS_DATABASE_ID in .env');
18
+ process.exit(1);
19
+ }
20
+ const client = new FlowUsClient({
21
+ baseUrl: config.flowus.baseUrl,
22
+ token,
23
+ databaseId,
24
+ });
25
+ console.log('=== flowus-source module test ===\n');
26
+ // Step 1: Query unprocessed articles
27
+ console.log('[1] Querying articles from 垃圾堆 database...');
28
+ const pages = await client.queryNewArticles();
29
+ console.log(` Found ${pages.length} unprocessed article(s)\n`);
30
+ if (pages.length === 0) {
31
+ console.log(' No unprocessed articles. Test passed (empty result is valid).');
32
+ process.exit(0);
33
+ }
34
+ // Step 2: Show article metadata
35
+ for (const page of pages.slice(0, 3)) {
36
+ console.log(`[2] Article: ${page.id}`);
37
+ const article = await client.getFullArticle(page);
38
+ console.log(` Title: ${article.title}`);
39
+ console.log(` URL: ${article.url}`);
40
+ console.log(` Author: ${article.author}`);
41
+ console.log(` Tags: ${article.tags.join(', ') || '(none)'}`);
42
+ console.log(` Content length: ${article.content.length} chars`);
43
+ console.log(` Content preview: ${article.content.substring(0, 200).replace(/\n/g, '\\n')}`);
44
+ console.log();
45
+ }
46
+ // Step 3: Verify block structure of the first article
47
+ if (pages.length > 0) {
48
+ console.log('[3] Verifying block structure of first article...');
49
+ const blocks = await client.getBlocks(pages[0].id);
50
+ const typeCounts = {};
51
+ for (const block of blocks) {
52
+ typeCounts[block.type] = (typeCounts[block.type] ?? 0) + 1;
53
+ }
54
+ console.log(' Block types:', JSON.stringify(typeCounts, null, 2));
55
+ if (Object.keys(typeCounts).length > 0) {
56
+ console.log(' PASS: Found structured blocks');
57
+ }
58
+ else {
59
+ console.log(' WARN: No blocks found (article may be empty)');
60
+ }
61
+ }
62
+ console.log('\n=== Test complete ===');
63
+ //# sourceMappingURL=test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.js","sourceRoot":"","sources":["../../../src/modules/flowus-source/test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * FlowUs API types
3
+ */
4
+ export interface FlowUsConfig {
5
+ baseUrl: string;
6
+ token: string;
7
+ databaseId: string;
8
+ }
9
+ /** Rich text item within a block */
10
+ export interface RichTextItem {
11
+ type: 'text' | 'mention' | 'equation';
12
+ plain_text: string;
13
+ href?: string;
14
+ }
15
+ /** Block data payload (FlowUs uses `data` field, unlike Notion's `block[type]`) */
16
+ export interface FlowUsBlockData {
17
+ rich_text?: Array<{
18
+ plain_text: string;
19
+ }>;
20
+ text_color?: string;
21
+ background_color?: string;
22
+ external?: {
23
+ url: string;
24
+ };
25
+ file?: {
26
+ url: string;
27
+ };
28
+ url?: string;
29
+ [key: string]: unknown;
30
+ }
31
+ /** A single FlowUs block (paragraph, heading, image, etc.) */
32
+ export interface FlowUsBlock {
33
+ id: string;
34
+ type: string;
35
+ has_children?: boolean;
36
+ data?: FlowUsBlockData;
37
+ [key: string]: unknown;
38
+ }
39
+ /** A page/record from a FlowUs database query */
40
+ export interface FlowUsPage {
41
+ id: string;
42
+ object: 'page';
43
+ created_time: string;
44
+ properties: {
45
+ title?: {
46
+ type: 'title';
47
+ title: Array<{
48
+ plain_text: string;
49
+ }>;
50
+ };
51
+ url?: {
52
+ type: 'url';
53
+ url: string;
54
+ };
55
+ 标签?: {
56
+ type: 'multi_select';
57
+ multi_select: Array<{
58
+ name: string;
59
+ }>;
60
+ };
61
+ 作者?: {
62
+ type: 'select';
63
+ select: {
64
+ name: string;
65
+ } | null;
66
+ };
67
+ [key: string]: unknown;
68
+ };
69
+ }
70
+ /** Query database response */
71
+ export interface QueryDatabaseResponse {
72
+ object: 'list';
73
+ results: FlowUsPage[];
74
+ next_cursor: string | null;
75
+ has_more: boolean;
76
+ }
77
+ /** Get block children response */
78
+ export interface GetBlockChildrenResponse {
79
+ object: 'list';
80
+ results: FlowUsBlock[];
81
+ next_cursor: string | null;
82
+ has_more: boolean;
83
+ }
84
+ /** Article extracted from FlowUs database record */
85
+ export interface FlowUsArticle {
86
+ pageId: string;
87
+ title: string;
88
+ url: string;
89
+ author: string;
90
+ tags: string[];
91
+ content: string;
92
+ }
93
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/modules/flowus-source/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,oCAAoC;AACpC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,mFAAmF;AACnF,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,KAAK,CAAC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3B,IAAI,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,8DAA8D;AAC9D,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,iDAAiD;AACjD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE;QACV,KAAK,CAAC,EAAE;YAAE,IAAI,EAAE,OAAO,CAAC;YAAC,KAAK,EAAE,KAAK,CAAC;gBAAE,UAAU,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,CAAC;QAChE,GAAG,CAAC,EAAE;YAAE,IAAI,EAAE,KAAK,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;QACnC,EAAE,CAAC,EAAE;YAAE,IAAI,EAAE,cAAc,CAAC;YAAC,YAAY,EAAE,KAAK,CAAC;gBAAE,IAAI,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,CAAC;QACrE,EAAE,CAAC,EAAE;YAAE,IAAI,EAAE,QAAQ,CAAC;YAAC,MAAM,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAA;aAAE,GAAG,IAAI,CAAA;SAAE,CAAC;QACzD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAED,8BAA8B;AAC9B,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,kCAAkC;AAClC,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,oDAAoD;AACpD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * FlowUs API types
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/modules/flowus-source/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * memorizer module
3
+ *
4
+ * Saves knowledge points to nmem via CLI (`nmem m add`).
5
+ * Checks service availability first, then saves points one by one.
6
+ * Individual failures don't block remaining points.
7
+ */
8
+ export interface MemorizerResult {
9
+ saved: number;
10
+ failed: number;
11
+ errors: string[];
12
+ }
13
+ /**
14
+ * Check if nmem service is available.
15
+ */
16
+ export declare function checkNmemAvailable(): Promise<boolean>;
17
+ /**
18
+ * Save knowledge points to nmem, one by one.
19
+ * Maps: title → -t, content → positional arg, tags → -l, importance → -i
20
+ *
21
+ * Single failure doesn't block remaining points.
22
+ */
23
+ export declare function saveMemories(points: Array<{
24
+ title: string;
25
+ content: string;
26
+ tags: string[];
27
+ importance: number;
28
+ }>, logDir?: string): Promise<MemorizerResult>;
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/memorizer/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAID;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO3D;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,KAAK,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC,EACF,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,eAAe,CAAC,CAqC1B"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * memorizer module
3
+ *
4
+ * Saves knowledge points to nmem via CLI (`nmem m add`).
5
+ * Checks service availability first, then saves points one by one.
6
+ * Individual failures don't block remaining points.
7
+ */
8
+ import { execFile } from 'node:child_process';
9
+ import { promisify } from 'node:util';
10
+ import { appendFile, mkdir } from 'node:fs/promises';
11
+ import { join } from 'node:path';
12
+ const execFileAsync = promisify(execFile);
13
+ // ---- API ----
14
+ /**
15
+ * Check if nmem service is available.
16
+ */
17
+ export async function checkNmemAvailable() {
18
+ try {
19
+ const { stdout } = await execFileAsync('nmem', ['status']);
20
+ return stdout.includes('ok');
21
+ }
22
+ catch {
23
+ return false;
24
+ }
25
+ }
26
+ /**
27
+ * Save knowledge points to nmem, one by one.
28
+ * Maps: title → -t, content → positional arg, tags → -l, importance → -i
29
+ *
30
+ * Single failure doesn't block remaining points.
31
+ */
32
+ export async function saveMemories(points, logDir) {
33
+ let saved = 0;
34
+ let failed = 0;
35
+ const errors = [];
36
+ for (const point of points) {
37
+ try {
38
+ const tagsArg = point.tags.join(',');
39
+ await execFileAsync('nmem', [
40
+ 'm', 'add',
41
+ point.content,
42
+ '-t', point.title,
43
+ '-l', tagsArg,
44
+ '-i', String(point.importance),
45
+ ]);
46
+ saved++;
47
+ // Append JSONL log on success
48
+ if (logDir) {
49
+ await appendLog(logDir, {
50
+ ts: new Date().toISOString(),
51
+ title: point.title,
52
+ summary: point.content.substring(0, 200),
53
+ tags: point.tags,
54
+ importance: point.importance,
55
+ });
56
+ }
57
+ }
58
+ catch (err) {
59
+ failed++;
60
+ const msg = err instanceof Error ? err.message : String(err);
61
+ errors.push(`[${point.title}]: ${msg}`);
62
+ }
63
+ }
64
+ return { saved, failed, errors };
65
+ }
66
+ async function appendLog(logDir, entry) {
67
+ const date = new Date().toISOString().slice(0, 10);
68
+ const filePath = join(logDir, `save-${date}.jsonl`);
69
+ await mkdir(logDir, { recursive: true });
70
+ await appendFile(filePath, JSON.stringify(entry) + '\n');
71
+ }
72
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/modules/memorizer/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAU1C,gBAAgB;AAEhB;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC3D,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAKE,EACF,MAAe;IAEf,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAErC,MAAM,aAAa,CAAC,MAAM,EAAE;gBAC1B,GAAG,EAAE,KAAK;gBACV,KAAK,CAAC,OAAO;gBACb,IAAI,EAAE,KAAK,CAAC,KAAK;gBACjB,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;aAC/B,CAAC,CAAC;YAEH,KAAK,EAAE,CAAC;YAER,8BAA8B;YAC9B,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,SAAS,CAAC,MAAM,EAAE;oBACtB,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;oBAC5B,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC;oBACxC,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,UAAU,EAAE,KAAK,CAAC,UAAU;iBAC7B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,EAAE,CAAC;YACT,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACnC,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,MAAc,EAAE,KAA8B;IACrE,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,QAAQ,IAAI,QAAQ,CAAC,CAAC;IACpD,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * memorizer module standalone test
3
+ *
4
+ * Usage: npx tsx src/modules/memorizer/test.ts
5
+ *
6
+ * Uses mock data to verify nmem save works.
7
+ * Tests: availability check + batch save + partial failure resilience.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../../src/modules/memorizer/test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * memorizer module standalone test
3
+ *
4
+ * Usage: npx tsx src/modules/memorizer/test.ts
5
+ *
6
+ * Uses mock data to verify nmem save works.
7
+ * Tests: availability check + batch save + partial failure resilience.
8
+ */
9
+ import { checkNmemAvailable, saveMemories } from './index.js';
10
+ console.log('=== memorizer module test ===\n');
11
+ // Step 1: Check nmem availability
12
+ console.log('[1] Checking nmem availability...');
13
+ const available = await checkNmemAvailable();
14
+ console.log(` nmem available: ${available}\n`);
15
+ if (!available) {
16
+ console.log(' nmem service is not running. Cannot test save.');
17
+ console.log(' Start with: nmem serve');
18
+ process.exit(1);
19
+ }
20
+ // Step 2: Prepare mock knowledge points
21
+ const mockPoints = [
22
+ {
23
+ title: 'inkdrift test: TypeScript satisfies 运算符',
24
+ content: 'TypeScript 4.9 引入 satisfies 运算符,用于在不拓宽类型的情况下检查表达式是否满足某个类型。与类型断言不同,它保留了更窄的推断类型。\n\n来源:https://example.com/ts-satisfies',
25
+ tags: ['TypeScript', '类型系统', 'inkdrift-test'],
26
+ importance: 0.7,
27
+ },
28
+ {
29
+ title: 'inkdrift test: Node.js test runner',
30
+ content: 'Node.js 20 内置了 node:test 模块,无需第三方测试框架即可运行测试。支持 describe/it 语法、assert、mock 和测试报告。\n\n来源:https://example.com/node-test',
31
+ tags: ['Node.js', '测试', 'inkdrift-test'],
32
+ importance: 0.6,
33
+ },
34
+ {
35
+ title: 'inkdrift test: memorizer integration check',
36
+ content: '这是一条测试知识点,用于验证 memorizer 模块的写入功能。如果看到这条记录说明 nmem 集成工作正常。\n\n来源:https://example.com/test',
37
+ tags: ['测试', 'inkdrift', 'inkdrift-test'],
38
+ importance: 0.3,
39
+ },
40
+ ];
41
+ console.log(`[2] Saving ${mockPoints.length} mock knowledge points...`);
42
+ const result = await saveMemories(mockPoints);
43
+ console.log(` Saved: ${result.saved}`);
44
+ console.log(` Failed: ${result.failed}`);
45
+ if (result.errors.length > 0) {
46
+ console.log(' Errors:');
47
+ for (const e of result.errors) {
48
+ console.log(` - ${e}`);
49
+ }
50
+ }
51
+ // Step 3: Validate results
52
+ console.log('\n[3] Validating...');
53
+ const checks = [];
54
+ if (result.saved === mockPoints.length) {
55
+ checks.push('PASS: All points saved');
56
+ }
57
+ else {
58
+ checks.push(`FAIL: Expected ${mockPoints.length} saved, got ${result.saved}`);
59
+ }
60
+ if (result.failed === 0) {
61
+ checks.push('PASS: No failures');
62
+ }
63
+ else {
64
+ checks.push(`FAIL: ${result.failed} point(s) failed`);
65
+ }
66
+ for (const c of checks)
67
+ console.log(` ${c}`);
68
+ console.log('\n=== Test complete ===');
69
+ //# sourceMappingURL=test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.js","sourceRoot":"","sources":["../../../src/modules/memorizer/test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE9D,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;AAE/C,kCAAkC;AAClC,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;AACjD,MAAM,SAAS,GAAG,MAAM,kBAAkB,EAAE,CAAC;AAC7C,OAAO,CAAC,GAAG,CAAC,uBAAuB,SAAS,IAAI,CAAC,CAAC;AAElD,IAAI,CAAC,SAAS,EAAE,CAAC;IACf,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,wCAAwC;AACxC,MAAM,UAAU,GAAG;IACjB;QACE,KAAK,EAAE,yCAAyC;QAChD,OAAO,EACL,uHAAuH;QACzH,IAAI,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,eAAe,CAAC;QAC7C,UAAU,EAAE,GAAG;KAChB;IACD;QACE,KAAK,EAAE,oCAAoC;QAC3C,OAAO,EACL,sHAAsH;QACxH,IAAI,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,eAAe,CAAC;QACxC,UAAU,EAAE,GAAG;KAChB;IACD;QACE,KAAK,EAAE,4CAA4C;QACnD,OAAO,EACL,yFAAyF;QAC3F,IAAI,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,eAAe,CAAC;QACzC,UAAU,EAAE,GAAG;KAChB;CACF,CAAC;AAEF,OAAO,CAAC,GAAG,CAAC,cAAc,UAAU,CAAC,MAAM,2BAA2B,CAAC,CAAC;AAExE,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,UAAU,CAAC,CAAC;AAE9C,OAAO,CAAC,GAAG,CAAC,cAAc,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;AAC1C,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAE5C,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;IAC7B,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC;AAED,2BAA2B;AAC3B,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;AACnC,MAAM,MAAM,GAAa,EAAE,CAAC;AAE5B,IAAI,MAAM,CAAC,KAAK,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC;IACvC,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;AACxC,CAAC;KAAM,CAAC;IACN,MAAM,CAAC,IAAI,CAAC,kBAAkB,UAAU,CAAC,MAAM,eAAe,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;AAChF,CAAC;AAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;IACxB,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;AACnC,CAAC;KAAM,CAAC;IACN,MAAM,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,MAAM,kBAAkB,CAAC,CAAC;AACxD,CAAC;AAED,KAAK,MAAM,CAAC,IAAI,MAAM;IAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAEhD,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * queue module - serial task queue
3
+ *
4
+ * Processes FlowUs articles one at a time through the full pipeline:
5
+ * fetch content → extract → distill → memorize → update status.
6
+ */
7
+ import { type DistillConfig } from '../distiller/index.js';
8
+ export interface QueueTask {
9
+ type: 'flowus_article';
10
+ pageId: string;
11
+ url: string;
12
+ title: string;
13
+ }
14
+ export interface QueueConfig {
15
+ flowus: {
16
+ baseUrl: string;
17
+ token: string;
18
+ databaseId: string;
19
+ };
20
+ distill: DistillConfig;
21
+ logDir?: string;
22
+ }
23
+ export interface ProcessResult {
24
+ task: QueueTask;
25
+ success: boolean;
26
+ pointsCount: number;
27
+ savedCount: number;
28
+ error?: string;
29
+ }
30
+ export declare class SerialQueue {
31
+ private client;
32
+ private distillConfig;
33
+ private logDir?;
34
+ constructor(config: QueueConfig);
35
+ /**
36
+ * Fetch new articles from FlowUs and process them one by one.
37
+ * Returns results for each processed article.
38
+ */
39
+ processAll(): Promise<ProcessResult[]>;
40
+ /**
41
+ * Process a single article through the full pipeline.
42
+ */
43
+ private processPage;
44
+ }
45
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/queue/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAgC,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAMzF,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,gBAAgB,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAID,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEZ,MAAM,EAAE,WAAW;IAU/B;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAwC5C;;OAEG;YACW,WAAW;CAqG1B"}