wikimem 0.3.0 → 0.8.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 (228) hide show
  1. package/CHANGELOG.md +138 -29
  2. package/README.md +171 -309
  3. package/dist/cli/commands/ask.d.ts +3 -0
  4. package/dist/cli/commands/ask.d.ts.map +1 -0
  5. package/dist/cli/commands/ask.js +63 -0
  6. package/dist/cli/commands/ask.js.map +1 -0
  7. package/dist/cli/commands/export.d.ts +3 -0
  8. package/dist/cli/commands/export.d.ts.map +1 -0
  9. package/dist/cli/commands/export.js +108 -0
  10. package/dist/cli/commands/export.js.map +1 -0
  11. package/dist/cli/commands/history.d.ts +3 -0
  12. package/dist/cli/commands/history.d.ts.map +1 -0
  13. package/dist/cli/commands/history.js +61 -0
  14. package/dist/cli/commands/history.js.map +1 -0
  15. package/dist/cli/commands/improve.d.ts.map +1 -1
  16. package/dist/cli/commands/improve.js +4 -3
  17. package/dist/cli/commands/improve.js.map +1 -1
  18. package/dist/cli/commands/ingest.d.ts.map +1 -1
  19. package/dist/cli/commands/ingest.js +5 -4
  20. package/dist/cli/commands/ingest.js.map +1 -1
  21. package/dist/cli/commands/init.d.ts.map +1 -1
  22. package/dist/cli/commands/init.js +337 -81
  23. package/dist/cli/commands/init.js.map +1 -1
  24. package/dist/cli/commands/lint.d.ts.map +1 -1
  25. package/dist/cli/commands/lint.js +4 -3
  26. package/dist/cli/commands/lint.js.map +1 -1
  27. package/dist/cli/commands/mcp.d.ts +3 -0
  28. package/dist/cli/commands/mcp.d.ts.map +1 -0
  29. package/dist/cli/commands/mcp.js +11 -0
  30. package/dist/cli/commands/mcp.js.map +1 -0
  31. package/dist/cli/commands/open.d.ts +3 -0
  32. package/dist/cli/commands/open.d.ts.map +1 -0
  33. package/dist/cli/commands/open.js +36 -0
  34. package/dist/cli/commands/open.js.map +1 -0
  35. package/dist/cli/commands/query.d.ts.map +1 -1
  36. package/dist/cli/commands/query.js +5 -4
  37. package/dist/cli/commands/query.js.map +1 -1
  38. package/dist/cli/commands/search.d.ts +3 -0
  39. package/dist/cli/commands/search.d.ts.map +1 -0
  40. package/dist/cli/commands/search.js +61 -0
  41. package/dist/cli/commands/search.js.map +1 -0
  42. package/dist/cli/commands/serve.d.ts.map +1 -1
  43. package/dist/cli/commands/serve.js +41 -2
  44. package/dist/cli/commands/serve.js.map +1 -1
  45. package/dist/cli/commands/watch.d.ts.map +1 -1
  46. package/dist/cli/commands/watch.js +4 -3
  47. package/dist/cli/commands/watch.js.map +1 -1
  48. package/dist/cli/index.d.ts.map +1 -1
  49. package/dist/cli/index.js +27 -1
  50. package/dist/cli/index.js.map +1 -1
  51. package/dist/core/audit-trail.d.ts +15 -0
  52. package/dist/core/audit-trail.d.ts.map +1 -0
  53. package/dist/core/audit-trail.js +43 -0
  54. package/dist/core/audit-trail.js.map +1 -0
  55. package/dist/core/claude-code.d.ts +10 -0
  56. package/dist/core/claude-code.d.ts.map +1 -0
  57. package/dist/core/claude-code.js +81 -0
  58. package/dist/core/claude-code.js.map +1 -0
  59. package/dist/core/config.d.ts +23 -0
  60. package/dist/core/config.d.ts.map +1 -1
  61. package/dist/core/config.js.map +1 -1
  62. package/dist/core/connectors.d.ts +58 -0
  63. package/dist/core/connectors.d.ts.map +1 -0
  64. package/dist/core/connectors.js +189 -0
  65. package/dist/core/connectors.js.map +1 -0
  66. package/dist/core/folder-scanner.d.ts +10 -0
  67. package/dist/core/folder-scanner.d.ts.map +1 -0
  68. package/dist/core/folder-scanner.js +84 -0
  69. package/dist/core/folder-scanner.js.map +1 -0
  70. package/dist/core/git.d.ts +137 -0
  71. package/dist/core/git.d.ts.map +1 -0
  72. package/dist/core/git.js +520 -0
  73. package/dist/core/git.js.map +1 -0
  74. package/dist/core/history.d.ts +21 -0
  75. package/dist/core/history.d.ts.map +1 -0
  76. package/dist/core/history.js +107 -0
  77. package/dist/core/history.js.map +1 -0
  78. package/dist/core/improve.d.ts.map +1 -1
  79. package/dist/core/improve.js +9 -0
  80. package/dist/core/improve.js.map +1 -1
  81. package/dist/core/ingest.d.ts +1 -0
  82. package/dist/core/ingest.d.ts.map +1 -1
  83. package/dist/core/ingest.js +151 -7
  84. package/dist/core/ingest.js.map +1 -1
  85. package/dist/core/lint.d.ts.map +1 -1
  86. package/dist/core/lint.js +23 -4
  87. package/dist/core/lint.js.map +1 -1
  88. package/dist/core/oauth-defaults.d.ts +31 -0
  89. package/dist/core/oauth-defaults.d.ts.map +1 -0
  90. package/dist/core/oauth-defaults.js +77 -0
  91. package/dist/core/oauth-defaults.js.map +1 -0
  92. package/dist/core/observer.d.ts +94 -0
  93. package/dist/core/observer.d.ts.map +1 -0
  94. package/dist/core/observer.js +492 -0
  95. package/dist/core/observer.js.map +1 -0
  96. package/dist/core/pipeline-events.d.ts +63 -0
  97. package/dist/core/pipeline-events.d.ts.map +1 -0
  98. package/dist/core/pipeline-events.js +109 -0
  99. package/dist/core/pipeline-events.js.map +1 -0
  100. package/dist/core/query.d.ts.map +1 -1
  101. package/dist/core/query.js +16 -8
  102. package/dist/core/query.js.map +1 -1
  103. package/dist/core/scraper.d.ts +41 -0
  104. package/dist/core/scraper.d.ts.map +1 -0
  105. package/dist/core/scraper.js +277 -0
  106. package/dist/core/scraper.js.map +1 -0
  107. package/dist/core/sync/gdrive.d.ts +14 -0
  108. package/dist/core/sync/gdrive.d.ts.map +1 -0
  109. package/dist/core/sync/gdrive.js +205 -0
  110. package/dist/core/sync/gdrive.js.map +1 -0
  111. package/dist/core/sync/github.d.ts +20 -0
  112. package/dist/core/sync/github.d.ts.map +1 -0
  113. package/dist/core/sync/github.js +206 -0
  114. package/dist/core/sync/github.js.map +1 -0
  115. package/dist/core/sync/gmail.d.ts +15 -0
  116. package/dist/core/sync/gmail.d.ts.map +1 -0
  117. package/dist/core/sync/gmail.js +159 -0
  118. package/dist/core/sync/gmail.js.map +1 -0
  119. package/dist/core/sync/index.d.ts +47 -0
  120. package/dist/core/sync/index.d.ts.map +1 -0
  121. package/dist/core/sync/index.js +100 -0
  122. package/dist/core/sync/index.js.map +1 -0
  123. package/dist/core/sync/jira.d.ts +15 -0
  124. package/dist/core/sync/jira.d.ts.map +1 -0
  125. package/dist/core/sync/jira.js +176 -0
  126. package/dist/core/sync/jira.js.map +1 -0
  127. package/dist/core/sync/linear.d.ts +15 -0
  128. package/dist/core/sync/linear.d.ts.map +1 -0
  129. package/dist/core/sync/linear.js +111 -0
  130. package/dist/core/sync/linear.js.map +1 -0
  131. package/dist/core/sync/notion.d.ts +14 -0
  132. package/dist/core/sync/notion.d.ts.map +1 -0
  133. package/dist/core/sync/notion.js +168 -0
  134. package/dist/core/sync/notion.js.map +1 -0
  135. package/dist/core/sync/rss.d.ts +20 -0
  136. package/dist/core/sync/rss.d.ts.map +1 -0
  137. package/dist/core/sync/rss.js +165 -0
  138. package/dist/core/sync/rss.js.map +1 -0
  139. package/dist/core/sync/scheduler.d.ts +31 -0
  140. package/dist/core/sync/scheduler.d.ts.map +1 -0
  141. package/dist/core/sync/scheduler.js +129 -0
  142. package/dist/core/sync/scheduler.js.map +1 -0
  143. package/dist/core/sync/slack.d.ts +16 -0
  144. package/dist/core/sync/slack.d.ts.map +1 -0
  145. package/dist/core/sync/slack.js +173 -0
  146. package/dist/core/sync/slack.js.map +1 -0
  147. package/dist/core/vault.d.ts +22 -0
  148. package/dist/core/vault.d.ts.map +1 -1
  149. package/dist/core/vault.js +65 -0
  150. package/dist/core/vault.js.map +1 -1
  151. package/dist/core/webhooks.d.ts +13 -0
  152. package/dist/core/webhooks.d.ts.map +1 -0
  153. package/dist/core/webhooks.js +206 -0
  154. package/dist/core/webhooks.js.map +1 -0
  155. package/dist/index.js +3 -2
  156. package/dist/index.js.map +1 -1
  157. package/dist/mcp-entry.d.ts +10 -0
  158. package/dist/mcp-entry.d.ts.map +1 -0
  159. package/dist/mcp-entry.js +21 -0
  160. package/dist/mcp-entry.js.map +1 -0
  161. package/dist/mcp-server.d.ts +20 -0
  162. package/dist/mcp-server.d.ts.map +1 -0
  163. package/dist/mcp-server.js +483 -0
  164. package/dist/mcp-server.js.map +1 -0
  165. package/dist/mcp-tools-extended.d.ts +15 -0
  166. package/dist/mcp-tools-extended.d.ts.map +1 -0
  167. package/dist/mcp-tools-extended.js +277 -0
  168. package/dist/mcp-tools-extended.js.map +1 -0
  169. package/dist/processors/audio.d.ts.map +1 -1
  170. package/dist/processors/audio.js +42 -4
  171. package/dist/processors/audio.js.map +1 -1
  172. package/dist/processors/csv.d.ts +18 -0
  173. package/dist/processors/csv.d.ts.map +1 -0
  174. package/dist/processors/csv.js +230 -0
  175. package/dist/processors/csv.js.map +1 -0
  176. package/dist/processors/image.d.ts.map +1 -1
  177. package/dist/processors/image.js +55 -27
  178. package/dist/processors/image.js.map +1 -1
  179. package/dist/processors/pdf.d.ts.map +1 -1
  180. package/dist/processors/pdf.js +6 -3
  181. package/dist/processors/pdf.js.map +1 -1
  182. package/dist/processors/pptx.d.ts +3 -1
  183. package/dist/processors/pptx.d.ts.map +1 -1
  184. package/dist/processors/pptx.js +236 -95
  185. package/dist/processors/pptx.js.map +1 -1
  186. package/dist/processors/url.js +4 -1
  187. package/dist/processors/url.js.map +1 -1
  188. package/dist/processors/xlsx.d.ts +2 -0
  189. package/dist/processors/xlsx.d.ts.map +1 -1
  190. package/dist/processors/xlsx.js +182 -46
  191. package/dist/processors/xlsx.js.map +1 -1
  192. package/dist/providers/claude.d.ts +1 -0
  193. package/dist/providers/claude.d.ts.map +1 -1
  194. package/dist/providers/claude.js +5 -3
  195. package/dist/providers/claude.js.map +1 -1
  196. package/dist/providers/index.d.ts +17 -1
  197. package/dist/providers/index.d.ts.map +1 -1
  198. package/dist/providers/index.js +144 -0
  199. package/dist/providers/index.js.map +1 -1
  200. package/dist/providers/openai.d.ts +1 -0
  201. package/dist/providers/openai.d.ts.map +1 -1
  202. package/dist/providers/openai.js +5 -3
  203. package/dist/providers/openai.js.map +1 -1
  204. package/dist/providers/types.d.ts +18 -0
  205. package/dist/providers/types.d.ts.map +1 -1
  206. package/dist/templates/config-yaml.d.ts.map +1 -1
  207. package/dist/templates/config-yaml.js +12 -1
  208. package/dist/templates/config-yaml.js.map +1 -1
  209. package/dist/templates/source-types.d.ts +33 -0
  210. package/dist/templates/source-types.d.ts.map +1 -0
  211. package/dist/templates/source-types.js +178 -0
  212. package/dist/templates/source-types.js.map +1 -0
  213. package/dist/web/public/index.html +9836 -742
  214. package/dist/web/server.d.ts.map +1 -1
  215. package/dist/web/server.js +2823 -43
  216. package/dist/web/server.js.map +1 -1
  217. package/package.json +10 -4
  218. package/scripts/install.sh +54 -0
  219. package/src/web/public/index.html +9836 -742
  220. package/templates/mcp-config.json +9 -0
  221. package/templates/source-types/article.md +21 -0
  222. package/templates/source-types/book.md +21 -0
  223. package/templates/source-types/paper.md +23 -0
  224. package/templates/source-types/podcast.md +21 -0
  225. package/templates/source-types/raw-notes.md +17 -0
  226. package/templates/source-types/tweet-thread.md +19 -0
  227. package/templates/source-types/video.md +21 -0
  228. package/dist/web/public/public/index.html +0 -946
@@ -0,0 +1,205 @@
1
+ /**
2
+ * Google Drive sync module — fetches recent files and exports Google Workspace
3
+ * documents as markdown wiki pages under wiki/sources/.
4
+ */
5
+ import { mkdirSync, writeFileSync, existsSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ const API = 'https://www.googleapis.com/drive/v3';
8
+ /** Google Workspace MIME types we can export as text */
9
+ const EXPORT_MAP = {
10
+ 'application/vnd.google-apps.document': { mimeType: 'text/plain', label: 'Google Doc' },
11
+ 'application/vnd.google-apps.spreadsheet': { mimeType: 'text/csv', label: 'Google Sheet' },
12
+ 'application/vnd.google-apps.presentation': { mimeType: 'text/plain', label: 'Google Slides' },
13
+ };
14
+ /** MIME types we can download directly as text */
15
+ const TEXT_MIME_TYPES = new Set([
16
+ 'text/plain',
17
+ 'text/markdown',
18
+ 'text/csv',
19
+ 'text/html',
20
+ 'application/json',
21
+ 'text/x-python',
22
+ 'text/javascript',
23
+ 'application/x-yaml',
24
+ ]);
25
+ function sanitizeFilename(raw) {
26
+ return (raw
27
+ .toLowerCase()
28
+ .replace(/[^a-z0-9]+/g, '-')
29
+ .replace(/-+/g, '-')
30
+ .replace(/^-|-$/g, '')
31
+ .slice(0, 120) || 'untitled');
32
+ }
33
+ function errorHint(status, message) {
34
+ if (status === 401)
35
+ return 'Token expired — re-authenticate with Google OAuth';
36
+ if (status === 403)
37
+ return 'Insufficient permissions — ensure drive.readonly scope';
38
+ if (status === 429)
39
+ return 'Rate limited — try again later';
40
+ return `HTTP ${status}: ${message}`;
41
+ }
42
+ function recentTimestamp() {
43
+ const d = new Date();
44
+ d.setDate(d.getDate() - 30);
45
+ return d.toISOString();
46
+ }
47
+ async function driveFetch(url, token) {
48
+ const res = await fetch(url, {
49
+ headers: { Authorization: `Bearer ${token}` },
50
+ });
51
+ if (!res.ok) {
52
+ const body = await res.text().catch(() => '');
53
+ return { ok: false, status: res.status, message: body };
54
+ }
55
+ return { ok: true, data: (await res.json()) };
56
+ }
57
+ async function driveFetchText(url, token) {
58
+ const res = await fetch(url, {
59
+ headers: { Authorization: `Bearer ${token}` },
60
+ });
61
+ if (!res.ok) {
62
+ const body = await res.text().catch(() => '');
63
+ return { ok: false, status: res.status, message: body };
64
+ }
65
+ return { ok: true, data: await res.text() };
66
+ }
67
+ async function listFiles(token, maxFiles, folderId) {
68
+ const errors = [];
69
+ const allFiles = [];
70
+ let pageToken;
71
+ const since = recentTimestamp();
72
+ do {
73
+ const params = new URLSearchParams({
74
+ orderBy: 'modifiedTime desc',
75
+ pageSize: String(Math.min(50, maxFiles - allFiles.length)),
76
+ fields: 'nextPageToken,files(id,name,mimeType,modifiedTime,webViewLink)',
77
+ });
78
+ const queryParts = [`modifiedTime > '${since}'`, 'trashed = false'];
79
+ if (folderId) {
80
+ queryParts.push(`'${folderId}' in parents`);
81
+ }
82
+ params.set('q', queryParts.join(' and '));
83
+ if (pageToken) {
84
+ params.set('pageToken', pageToken);
85
+ }
86
+ const result = await driveFetch(`${API}/files?${params.toString()}`, token);
87
+ if (!result.ok) {
88
+ errors.push(`listFiles: ${errorHint(result.status, result.message)}`);
89
+ break;
90
+ }
91
+ allFiles.push(...result.data.files);
92
+ pageToken = result.data.nextPageToken;
93
+ } while (pageToken && allFiles.length < maxFiles);
94
+ return { files: allFiles.slice(0, maxFiles), errors };
95
+ }
96
+ async function exportFile(token, fileId, exportMimeType) {
97
+ const result = await driveFetchText(`${API}/files/${fileId}/export?mimeType=${encodeURIComponent(exportMimeType)}`, token);
98
+ if (!result.ok) {
99
+ return { content: null, error: `export(${fileId}): ${errorHint(result.status, result.message)}` };
100
+ }
101
+ return { content: result.data, error: null };
102
+ }
103
+ async function downloadFile(token, fileId) {
104
+ const result = await driveFetchText(`${API}/files/${fileId}?alt=media`, token);
105
+ if (!result.ok) {
106
+ return { content: null, error: `download(${fileId}): ${errorHint(result.status, result.message)}` };
107
+ }
108
+ return { content: result.data, error: null };
109
+ }
110
+ function fileToMarkdown(file, body, sourceLabel) {
111
+ const esc = (s) => s.replace(/'/g, "''");
112
+ const frontmatter = [
113
+ '---',
114
+ `type: source`,
115
+ `source-type: gdrive`,
116
+ `title: '${esc(file.name)}'`,
117
+ `gdrive-id: '${file.id}'`,
118
+ `mime-type: '${file.mimeType}'`,
119
+ `modified: '${file.modifiedTime}'`,
120
+ `created: '${new Date().toISOString()}'`,
121
+ file.webViewLink ? `link: '${file.webViewLink}'` : null,
122
+ `tags: [gdrive, ${sourceLabel.toLowerCase().replace(/\s+/g, '-')}]`,
123
+ '---',
124
+ ]
125
+ .filter(Boolean)
126
+ .join('\n');
127
+ const links = file.webViewLink
128
+ ? `\n## Links\n\n- [Open in Google Drive](${file.webViewLink})\n`
129
+ : '';
130
+ return {
131
+ filename: `gdrive-${sanitizeFilename(file.name)}.md`,
132
+ content: `${frontmatter}\n\n# ${file.name}\n\n> Source: ${sourceLabel} via Google Drive sync\n\n${body.trim()}\n${links}`,
133
+ };
134
+ }
135
+ export async function syncGDrive(options) {
136
+ const start = Date.now();
137
+ const errors = [];
138
+ let filesWritten = 0;
139
+ const maxFiles = options.maxFiles ?? 50;
140
+ const outDir = join(options.vaultRoot, 'wiki', 'sources');
141
+ if (!existsSync(outDir))
142
+ mkdirSync(outDir, { recursive: true });
143
+ const { files, errors: listErrors } = await listFiles(options.token, maxFiles, options.folderId);
144
+ errors.push(...listErrors);
145
+ if (files.length === 0 && listErrors.length > 0) {
146
+ return { provider: 'gdrive', filesWritten: 0, errors, duration: Date.now() - start };
147
+ }
148
+ for (const file of files) {
149
+ const exportInfo = EXPORT_MAP[file.mimeType];
150
+ if (exportInfo) {
151
+ // Google Workspace file — export via /export endpoint
152
+ const { content, error } = await exportFile(options.token, file.id, exportInfo.mimeType);
153
+ if (error) {
154
+ errors.push(error);
155
+ continue;
156
+ }
157
+ if (!content)
158
+ continue;
159
+ const { filename, content: md } = fileToMarkdown(file, content, exportInfo.label);
160
+ try {
161
+ writeFileSync(join(outDir, filename), md, 'utf-8');
162
+ filesWritten++;
163
+ }
164
+ catch (err) {
165
+ const msg = err instanceof Error ? err.message : String(err);
166
+ errors.push(`Write failed (${filename}): ${msg}`);
167
+ }
168
+ }
169
+ else if (TEXT_MIME_TYPES.has(file.mimeType)) {
170
+ // Plain text file — download directly
171
+ const { content, error } = await downloadFile(options.token, file.id);
172
+ if (error) {
173
+ errors.push(error);
174
+ continue;
175
+ }
176
+ if (!content)
177
+ continue;
178
+ const label = file.mimeType.split('/').pop() ?? 'text';
179
+ const { filename, content: md } = fileToMarkdown(file, content, label);
180
+ try {
181
+ writeFileSync(join(outDir, filename), md, 'utf-8');
182
+ filesWritten++;
183
+ }
184
+ catch (err) {
185
+ const msg = err instanceof Error ? err.message : String(err);
186
+ errors.push(`Write failed (${filename}): ${msg}`);
187
+ }
188
+ }
189
+ else {
190
+ // Binary file (PDF, image, etc.) — note existence but skip content
191
+ const body = `_Binary file (${file.mimeType}) — content not exported. Open in Google Drive to view._`;
192
+ const { filename, content: md } = fileToMarkdown(file, body, 'binary');
193
+ try {
194
+ writeFileSync(join(outDir, filename), md, 'utf-8');
195
+ filesWritten++;
196
+ }
197
+ catch (err) {
198
+ const msg = err instanceof Error ? err.message : String(err);
199
+ errors.push(`Write failed (${filename}): ${msg}`);
200
+ }
201
+ }
202
+ }
203
+ return { provider: 'gdrive', filesWritten, errors, duration: Date.now() - start };
204
+ }
205
+ //# sourceMappingURL=gdrive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gdrive.js","sourceRoot":"","sources":["../../../src/core/sync/gdrive.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * GitHub Sync — fetches repos, issues, PRs, and READMEs into raw/ for wiki ingest.
3
+ * Uses GitHub REST API v3 with OAuth access_token from .wikimem/tokens.json.
4
+ */
5
+ export interface GitHubSyncOptions {
6
+ token: string;
7
+ vaultRoot: string;
8
+ repos?: string[];
9
+ maxRepos?: number;
10
+ maxIssuesPerRepo?: number;
11
+ maxPRsPerRepo?: number;
12
+ }
13
+ export interface PlatformSyncResult {
14
+ provider: string;
15
+ filesWritten: number;
16
+ errors: string[];
17
+ duration: number;
18
+ }
19
+ export declare function syncGitHub(options: GitHubSyncOptions): Promise<PlatformSyncResult>;
20
+ //# sourceMappingURL=github.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../../src/core/sync/github.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AA6JD,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAqGxF"}
@@ -0,0 +1,206 @@
1
+ /**
2
+ * GitHub Sync — fetches repos, issues, PRs, and READMEs into raw/ for wiki ingest.
3
+ * Uses GitHub REST API v3 with OAuth access_token from .wikimem/tokens.json.
4
+ */
5
+ import { mkdirSync, writeFileSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ const API_BASE = 'https://api.github.com';
8
+ const MAX_TOTAL_CALLS = 200;
9
+ let callCount = 0;
10
+ async function ghFetch(path, token) {
11
+ if (callCount >= MAX_TOTAL_CALLS) {
12
+ return { data: null, error: `API call cap reached (${MAX_TOTAL_CALLS})` };
13
+ }
14
+ callCount++;
15
+ try {
16
+ const res = await fetch(`${API_BASE}${path}`, {
17
+ headers: {
18
+ Authorization: `Bearer ${token}`,
19
+ Accept: 'application/vnd.github.v3+json',
20
+ 'User-Agent': 'wikimem-sync',
21
+ },
22
+ });
23
+ const remaining = res.headers.get('X-RateLimit-Remaining');
24
+ if (remaining !== null && parseInt(remaining, 10) < 10) {
25
+ const resetAt = res.headers.get('X-RateLimit-Reset');
26
+ const resetTime = resetAt ? new Date(parseInt(resetAt, 10) * 1000).toISOString() : 'unknown';
27
+ return { data: null, error: `Rate limit nearly exhausted (${remaining} left, resets ${resetTime})` };
28
+ }
29
+ if (!res.ok) {
30
+ return { data: null, error: `GitHub API ${res.status}: ${res.statusText} for ${path}` };
31
+ }
32
+ const data = (await res.json());
33
+ return { data, error: null };
34
+ }
35
+ catch (err) {
36
+ const msg = err instanceof Error ? err.message : String(err);
37
+ return { data: null, error: `Fetch failed for ${path}: ${msg}` };
38
+ }
39
+ }
40
+ function todayDate() {
41
+ return new Date().toISOString().slice(0, 10);
42
+ }
43
+ function frontmatter(fields) {
44
+ const lines = ['---'];
45
+ for (const [key, val] of Object.entries(fields)) {
46
+ if (Array.isArray(val)) {
47
+ lines.push(`${key}: [${val.map((v) => `"${v}"`).join(', ')}]`);
48
+ }
49
+ else if (typeof val === 'string') {
50
+ lines.push(`${key}: "${val.replace(/"/g, '\\"')}"`);
51
+ }
52
+ else {
53
+ lines.push(`${key}: ${String(val)}`);
54
+ }
55
+ }
56
+ lines.push('---');
57
+ return lines.join('\n');
58
+ }
59
+ function sanitizeFilename(name) {
60
+ return name.replace(/[^a-zA-Z0-9._-]/g, '-').slice(0, 100);
61
+ }
62
+ function writeMarkdown(dir, filename, content) {
63
+ mkdirSync(dir, { recursive: true });
64
+ writeFileSync(join(dir, filename), content, 'utf-8');
65
+ }
66
+ function buildRepoPage(repo) {
67
+ const fm = frontmatter({
68
+ title: repo.full_name, addedBy: 'connector', source: 'github', type: 'repository',
69
+ url: repo.html_url, language: repo.language ?? 'unknown',
70
+ stars: repo.stargazers_count, forks: repo.forks_count, syncedAt: new Date().toISOString(),
71
+ });
72
+ const topics = repo.topics.length > 0 ? `\n**Topics:** ${repo.topics.join(', ')}` : '';
73
+ return `${fm}\n\n# ${repo.full_name}\n\n${repo.description ?? '_No description._'}\n
74
+ | Stat | Value |
75
+ |------|-------|
76
+ | Language | ${repo.language ?? 'N/A'} |
77
+ | Stars | ${repo.stargazers_count} |
78
+ | Forks | ${repo.forks_count} |
79
+ | Open Issues | ${repo.open_issues_count} |
80
+ | Updated | ${repo.updated_at} |
81
+ | Private | ${repo.private ? 'Yes' : 'No'} |
82
+ ${topics}\n\n[View on GitHub](${repo.html_url})\n`;
83
+ }
84
+ function buildIssuePage(repo, issue) {
85
+ const fm = frontmatter({
86
+ title: `#${issue.number} ${issue.title}`, addedBy: 'connector', source: 'github',
87
+ type: 'issue', repo, url: issue.html_url, state: issue.state,
88
+ author: issue.user?.login ?? 'unknown', labels: issue.labels.map((l) => l.name),
89
+ createdAt: issue.created_at, syncedAt: new Date().toISOString(),
90
+ });
91
+ const body = issue.body ? issue.body.slice(0, 5000) : '_No description._';
92
+ return `${fm}\n\n# ${issue.title}\n\n**Issue #${issue.number}** in \`${repo}\` | ${issue.state} | by ${issue.user?.login ?? 'unknown'}\n\n${body}\n`;
93
+ }
94
+ function buildPRPage(repo, pr) {
95
+ const fm = frontmatter({
96
+ title: `PR #${pr.number} ${pr.title}`, addedBy: 'connector', source: 'github',
97
+ type: 'pull-request', repo, url: pr.html_url, state: pr.state,
98
+ author: pr.user?.login ?? 'unknown', branch: `${pr.head.ref} -> ${pr.base.ref}`,
99
+ createdAt: pr.created_at, syncedAt: new Date().toISOString(),
100
+ });
101
+ const body = pr.body ? pr.body.slice(0, 5000) : '_No description._';
102
+ return `${fm}\n\n# ${pr.title}\n\n**PR #${pr.number}** in \`${repo}\` | ${pr.state} | \`${pr.head.ref}\` -> \`${pr.base.ref}\` | by ${pr.user?.login ?? 'unknown'}\n\n${body}\n`;
103
+ }
104
+ function buildReadmePage(repo, content, htmlUrl) {
105
+ const fm = frontmatter({
106
+ title: `${repo} README`, addedBy: 'connector', source: 'github',
107
+ type: 'readme', repo, url: htmlUrl, syncedAt: new Date().toISOString(),
108
+ });
109
+ return `${fm}\n\n${content.slice(0, 10000)}\n`;
110
+ }
111
+ export async function syncGitHub(options) {
112
+ const start = Date.now();
113
+ callCount = 0;
114
+ const errors = [];
115
+ let filesWritten = 0;
116
+ const date = todayDate();
117
+ const outDir = join(options.vaultRoot, 'raw', date);
118
+ mkdirSync(outDir, { recursive: true });
119
+ const maxRepos = options.maxRepos ?? 30;
120
+ const maxIssues = options.maxIssuesPerRepo ?? 20;
121
+ const maxPRs = options.maxPRsPerRepo ?? 10;
122
+ // Step 1: Get repos
123
+ let repos = [];
124
+ if (options.repos && options.repos.length > 0) {
125
+ for (const fullName of options.repos.slice(0, maxRepos)) {
126
+ const { data, error } = await ghFetch(`/repos/${fullName}`, options.token);
127
+ if (error) {
128
+ errors.push(error);
129
+ continue;
130
+ }
131
+ if (data)
132
+ repos.push(data);
133
+ }
134
+ }
135
+ else {
136
+ const { data, error } = await ghFetch(`/user/repos?sort=updated&per_page=${maxRepos}&type=owner`, options.token);
137
+ if (error)
138
+ errors.push(error);
139
+ if (data)
140
+ repos = data;
141
+ }
142
+ // Step 2: Write repo summaries and fetch details
143
+ for (const repo of repos) {
144
+ const repoDir = join(outDir, 'github', sanitizeFilename(repo.full_name));
145
+ // Repo summary page
146
+ writeMarkdown(repoDir, 'repo.md', buildRepoPage(repo));
147
+ filesWritten++;
148
+ // README
149
+ const { data: readmeData, error: readmeErr } = await ghFetch(`/repos/${repo.full_name}/readme`, options.token);
150
+ if (readmeErr) {
151
+ if (!readmeErr.includes('404'))
152
+ errors.push(readmeErr);
153
+ }
154
+ else if (readmeData) {
155
+ try {
156
+ const decoded = Buffer.from(readmeData.content, 'base64').toString('utf-8');
157
+ writeMarkdown(repoDir, 'README.md', buildReadmePage(repo.full_name, decoded, readmeData.html_url));
158
+ filesWritten++;
159
+ }
160
+ catch (decodeErr) {
161
+ errors.push(`Failed to decode README for ${repo.full_name}`);
162
+ }
163
+ }
164
+ // Issues
165
+ if (repo.open_issues_count > 0) {
166
+ const { data: issues, error: issueErr } = await ghFetch(`/repos/${repo.full_name}/issues?state=open&per_page=${maxIssues}&sort=updated`, options.token);
167
+ if (issueErr) {
168
+ errors.push(issueErr);
169
+ }
170
+ if (issues) {
171
+ const issueDir = join(repoDir, 'issues');
172
+ for (const issue of issues) {
173
+ // The issues endpoint includes PRs; skip them
174
+ if ('pull_request' in issue)
175
+ continue;
176
+ writeMarkdown(issueDir, `issue-${issue.number}.md`, buildIssuePage(repo.full_name, issue));
177
+ filesWritten++;
178
+ }
179
+ }
180
+ }
181
+ // PRs
182
+ const { data: prs, error: prErr } = await ghFetch(`/repos/${repo.full_name}/pulls?state=open&per_page=${maxPRs}&sort=updated`, options.token);
183
+ if (prErr) {
184
+ errors.push(prErr);
185
+ }
186
+ if (prs) {
187
+ const prDir = join(repoDir, 'prs');
188
+ for (const pr of prs) {
189
+ writeMarkdown(prDir, `pr-${pr.number}.md`, buildPRPage(repo.full_name, pr));
190
+ filesWritten++;
191
+ }
192
+ }
193
+ // Bail early if hitting call cap
194
+ if (callCount >= MAX_TOTAL_CALLS) {
195
+ errors.push(`Stopped after ${repos.indexOf(repo) + 1} repos — API call cap reached`);
196
+ break;
197
+ }
198
+ }
199
+ return {
200
+ provider: 'github',
201
+ filesWritten,
202
+ errors,
203
+ duration: Date.now() - start,
204
+ };
205
+ }
206
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../../src/core/sync/github.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export interface GmailSyncOptions {
2
+ token: string;
3
+ vaultRoot: string;
4
+ maxThreads?: number;
5
+ query?: string;
6
+ labelIds?: string[];
7
+ }
8
+ export interface PlatformSyncResult {
9
+ provider: string;
10
+ filesWritten: number;
11
+ errors: string[];
12
+ duration: number;
13
+ }
14
+ export declare function syncGmail(options: GmailSyncOptions): Promise<PlatformSyncResult>;
15
+ //# sourceMappingURL=gmail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gmail.d.ts","sourceRoot":"","sources":["../../../src/core/sync/gmail.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AA8KD,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAkCtF"}
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Gmail sync module — fetches recent threads and writes them as markdown
3
+ * into the wiki vault's raw/{date}/ directory.
4
+ */
5
+ import { mkdirSync, writeFileSync, existsSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ const API = 'https://gmail.googleapis.com/gmail/v1/users/me';
8
+ function getHeader(headers, name) {
9
+ return headers.find((h) => h.name.toLowerCase() === name.toLowerCase())?.value ?? '';
10
+ }
11
+ function decode64(data) {
12
+ return Buffer.from(data, 'base64url').toString('utf-8');
13
+ }
14
+ function extractPlainText(part) {
15
+ if (part.mimeType === 'text/plain' && part.body.data)
16
+ return decode64(part.body.data);
17
+ if (part.parts) {
18
+ for (const sub of part.parts) {
19
+ const text = extractPlainText(sub);
20
+ if (text)
21
+ return text;
22
+ }
23
+ }
24
+ return '';
25
+ }
26
+ function extractBody(msg) {
27
+ const { payload } = msg;
28
+ if (payload.body.data)
29
+ return decode64(payload.body.data);
30
+ if (payload.parts) {
31
+ const plain = payload.parts.find((p) => p.mimeType === 'text/plain');
32
+ if (plain?.body.data)
33
+ return decode64(plain.body.data);
34
+ for (const part of payload.parts) {
35
+ const text = extractPlainText(part);
36
+ if (text)
37
+ return text;
38
+ }
39
+ const html = payload.parts.find((p) => p.mimeType === 'text/html');
40
+ if (html?.body.data)
41
+ return decode64(html.body.data);
42
+ }
43
+ return '(no body content)';
44
+ }
45
+ function sanitizeFilename(raw) {
46
+ return (raw.replace(/[/\\:*?"<>|]/g, '-').replace(/\s+/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '').slice(0, 120) ||
47
+ 'untitled');
48
+ }
49
+ function formatDate(internalDate) {
50
+ const ms = parseInt(internalDate, 10);
51
+ return Number.isNaN(ms) ? new Date().toISOString() : new Date(ms).toISOString();
52
+ }
53
+ function todayStr() {
54
+ const n = new Date();
55
+ return `${n.getFullYear()}-${String(n.getMonth() + 1).padStart(2, '0')}-${String(n.getDate()).padStart(2, '0')}`;
56
+ }
57
+ function errorHint(status, message) {
58
+ if (status === 401)
59
+ return 'Token expired — re-authenticate with Google OAuth';
60
+ if (status === 429)
61
+ return 'Rate limited — try again later';
62
+ return `HTTP ${status}: ${message}`;
63
+ }
64
+ async function gmailFetch(endpoint, token) {
65
+ const res = await fetch(`${API}${endpoint}`, {
66
+ headers: { Authorization: `Bearer ${token}` },
67
+ });
68
+ if (!res.ok) {
69
+ const body = await res.text().catch(() => '');
70
+ return { ok: false, status: res.status, message: body };
71
+ }
72
+ return { ok: true, data: (await res.json()) };
73
+ }
74
+ async function listThreads(token, maxResults, query, labelIds) {
75
+ const params = new URLSearchParams({ maxResults: String(maxResults) });
76
+ if (query)
77
+ params.set('q', query);
78
+ if (labelIds?.length) {
79
+ for (const lid of labelIds)
80
+ params.append('labelIds', lid);
81
+ }
82
+ const result = await gmailFetch(`/threads?${params.toString()}`, token);
83
+ if (result.ok === false) {
84
+ return { threads: [], errors: [`listThreads: ${errorHint(result.status, result.message)}`] };
85
+ }
86
+ return { threads: result.data.threads ?? [], errors: [] };
87
+ }
88
+ async function getThread(token, threadId) {
89
+ const result = await gmailFetch(`/threads/${threadId}?format=full`, token);
90
+ if (result.ok === false) {
91
+ return { thread: null, error: `getThread(${threadId}): ${errorHint(result.status, result.message)}` };
92
+ }
93
+ return { thread: result.data, error: null };
94
+ }
95
+ function threadToMarkdown(thread) {
96
+ const messages = thread.messages ?? [];
97
+ const firstMsg = messages[0];
98
+ const headers = firstMsg?.payload.headers ?? [];
99
+ const subject = getHeader(headers, 'Subject') || '(no subject)';
100
+ const from = getHeader(headers, 'From');
101
+ const date = firstMsg ? formatDate(firstMsg.internalDate) : new Date().toISOString();
102
+ const esc = (s) => s.replace(/'/g, "''");
103
+ const frontmatter = [
104
+ '---',
105
+ `addedBy: 'connector'`,
106
+ `source: 'gmail'`,
107
+ `subject: '${esc(subject)}'`,
108
+ `from: '${esc(from)}'`,
109
+ `date: '${date}'`,
110
+ `threadId: '${thread.id}'`,
111
+ `messageCount: ${messages.length}`,
112
+ '---',
113
+ ].join('\n');
114
+ const body = messages
115
+ .map((msg) => {
116
+ const mFrom = getHeader(msg.payload.headers, 'From');
117
+ const mDate = formatDate(msg.internalDate);
118
+ return `## From: ${mFrom}\n_${mDate}_\n\n${extractBody(msg).trim()}`;
119
+ })
120
+ .join('\n\n---\n\n');
121
+ return {
122
+ filename: `gmail-${sanitizeFilename(subject)}.md`,
123
+ content: `${frontmatter}\n\n# ${subject}\n\n${body}\n`,
124
+ };
125
+ }
126
+ export async function syncGmail(options) {
127
+ const start = Date.now();
128
+ const errors = [];
129
+ let filesWritten = 0;
130
+ const maxThreads = options.maxThreads ?? 50;
131
+ const outDir = join(options.vaultRoot, 'raw', todayStr());
132
+ if (!existsSync(outDir))
133
+ mkdirSync(outDir, { recursive: true });
134
+ const { threads, errors: listErrors } = await listThreads(options.token, maxThreads, options.query, options.labelIds);
135
+ errors.push(...listErrors);
136
+ if (threads.length === 0 && listErrors.length > 0) {
137
+ return { provider: 'gmail', filesWritten: 0, errors, duration: Date.now() - start };
138
+ }
139
+ for (const stub of threads) {
140
+ const { thread, error } = await getThread(options.token, stub.id);
141
+ if (error) {
142
+ errors.push(error);
143
+ continue;
144
+ }
145
+ if (!thread)
146
+ continue;
147
+ const { filename, content } = threadToMarkdown(thread);
148
+ try {
149
+ writeFileSync(join(outDir, filename), content, 'utf-8');
150
+ filesWritten++;
151
+ }
152
+ catch (err) {
153
+ const msg = err instanceof Error ? err.message : String(err);
154
+ errors.push(`Write failed (${filename}): ${msg}`);
155
+ }
156
+ }
157
+ return { provider: 'gmail', filesWritten, errors, duration: Date.now() - start };
158
+ }
159
+ //# sourceMappingURL=gmail.js.map