@fluxra-ai/fluxra-cli 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 (265) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +274 -0
  3. package/bin/fluxra +6 -0
  4. package/dist/cli/command-context.d.ts +17 -0
  5. package/dist/cli/command-context.d.ts.map +1 -0
  6. package/dist/cli/command-context.js +26 -0
  7. package/dist/cli/command-context.js.map +1 -0
  8. package/dist/cli/commands/auth/index.d.ts +3 -0
  9. package/dist/cli/commands/auth/index.d.ts.map +1 -0
  10. package/dist/cli/commands/auth/index.js +165 -0
  11. package/dist/cli/commands/auth/index.js.map +1 -0
  12. package/dist/cli/commands/chat/index.d.ts +3 -0
  13. package/dist/cli/commands/chat/index.d.ts.map +1 -0
  14. package/dist/cli/commands/chat/index.js +1201 -0
  15. package/dist/cli/commands/chat/index.js.map +1 -0
  16. package/dist/cli/commands/config/index.d.ts +3 -0
  17. package/dist/cli/commands/config/index.d.ts.map +1 -0
  18. package/dist/cli/commands/config/index.js +66 -0
  19. package/dist/cli/commands/config/index.js.map +1 -0
  20. package/dist/cli/commands/help.d.ts +7 -0
  21. package/dist/cli/commands/help.d.ts.map +1 -0
  22. package/dist/cli/commands/help.js +106 -0
  23. package/dist/cli/commands/help.js.map +1 -0
  24. package/dist/cli/commands/local/doctor.d.ts +26 -0
  25. package/dist/cli/commands/local/doctor.d.ts.map +1 -0
  26. package/dist/cli/commands/local/doctor.js +265 -0
  27. package/dist/cli/commands/local/doctor.js.map +1 -0
  28. package/dist/cli/commands/local/export.d.ts +41 -0
  29. package/dist/cli/commands/local/export.d.ts.map +1 -0
  30. package/dist/cli/commands/local/export.js +83 -0
  31. package/dist/cli/commands/local/export.js.map +1 -0
  32. package/dist/cli/commands/local/index.d.ts +6 -0
  33. package/dist/cli/commands/local/index.d.ts.map +1 -0
  34. package/dist/cli/commands/local/index.js +116 -0
  35. package/dist/cli/commands/local/index.js.map +1 -0
  36. package/dist/cli/commands/local/inspect.d.ts +42 -0
  37. package/dist/cli/commands/local/inspect.d.ts.map +1 -0
  38. package/dist/cli/commands/local/inspect.js +125 -0
  39. package/dist/cli/commands/local/inspect.js.map +1 -0
  40. package/dist/cli/commands/mcp.d.ts +8 -0
  41. package/dist/cli/commands/mcp.d.ts.map +1 -0
  42. package/dist/cli/commands/mcp.js +253 -0
  43. package/dist/cli/commands/mcp.js.map +1 -0
  44. package/dist/cli/commands/profile/index.d.ts +3 -0
  45. package/dist/cli/commands/profile/index.d.ts.map +1 -0
  46. package/dist/cli/commands/profile/index.js +114 -0
  47. package/dist/cli/commands/profile/index.js.map +1 -0
  48. package/dist/cli/commands/schema.d.ts +7 -0
  49. package/dist/cli/commands/schema.d.ts.map +1 -0
  50. package/dist/cli/commands/schema.js +33 -0
  51. package/dist/cli/commands/schema.js.map +1 -0
  52. package/dist/cli/errors.d.ts +16 -0
  53. package/dist/cli/errors.d.ts.map +1 -0
  54. package/dist/cli/errors.js +15 -0
  55. package/dist/cli/errors.js.map +1 -0
  56. package/dist/cli/fluxra.d.ts +9 -0
  57. package/dist/cli/fluxra.d.ts.map +1 -0
  58. package/dist/cli/fluxra.js +55 -0
  59. package/dist/cli/fluxra.js.map +1 -0
  60. package/dist/cli/helpers.d.ts +13 -0
  61. package/dist/cli/helpers.d.ts.map +1 -0
  62. package/dist/cli/helpers.js +32 -0
  63. package/dist/cli/helpers.js.map +1 -0
  64. package/dist/cli/output.d.ts +14 -0
  65. package/dist/cli/output.d.ts.map +1 -0
  66. package/dist/cli/output.js +55 -0
  67. package/dist/cli/output.js.map +1 -0
  68. package/dist/cli/version.d.ts +6 -0
  69. package/dist/cli/version.d.ts.map +1 -0
  70. package/dist/cli/version.js +8 -0
  71. package/dist/cli/version.js.map +1 -0
  72. package/dist/core/auth/auth-service.d.ts +35 -0
  73. package/dist/core/auth/auth-service.d.ts.map +1 -0
  74. package/dist/core/auth/auth-service.js +116 -0
  75. package/dist/core/auth/auth-service.js.map +1 -0
  76. package/dist/core/config/global-config.d.ts +38 -0
  77. package/dist/core/config/global-config.d.ts.map +1 -0
  78. package/dist/core/config/global-config.js +75 -0
  79. package/dist/core/config/global-config.js.map +1 -0
  80. package/dist/core/errors/error-model.d.ts +48 -0
  81. package/dist/core/errors/error-model.d.ts.map +1 -0
  82. package/dist/core/errors/error-model.js +152 -0
  83. package/dist/core/errors/error-model.js.map +1 -0
  84. package/dist/core/filesystem/paths.d.ts +45 -0
  85. package/dist/core/filesystem/paths.d.ts.map +1 -0
  86. package/dist/core/filesystem/paths.js +77 -0
  87. package/dist/core/filesystem/paths.js.map +1 -0
  88. package/dist/core/http/auth-api.d.ts +71 -0
  89. package/dist/core/http/auth-api.d.ts.map +1 -0
  90. package/dist/core/http/auth-api.js +91 -0
  91. package/dist/core/http/auth-api.js.map +1 -0
  92. package/dist/core/http/block-api.d.ts +37 -0
  93. package/dist/core/http/block-api.d.ts.map +1 -0
  94. package/dist/core/http/block-api.js +36 -0
  95. package/dist/core/http/block-api.js.map +1 -0
  96. package/dist/core/http/chat-api.d.ts +41 -0
  97. package/dist/core/http/chat-api.d.ts.map +1 -0
  98. package/dist/core/http/chat-api.js +88 -0
  99. package/dist/core/http/chat-api.js.map +1 -0
  100. package/dist/core/http/conversation-management-api.d.ts +65 -0
  101. package/dist/core/http/conversation-management-api.d.ts.map +1 -0
  102. package/dist/core/http/conversation-management-api.js +59 -0
  103. package/dist/core/http/conversation-management-api.js.map +1 -0
  104. package/dist/core/http/directory-api.d.ts +32 -0
  105. package/dist/core/http/directory-api.d.ts.map +1 -0
  106. package/dist/core/http/directory-api.js +36 -0
  107. package/dist/core/http/directory-api.js.map +1 -0
  108. package/dist/core/http/directory-profile-api.d.ts +32 -0
  109. package/dist/core/http/directory-profile-api.d.ts.map +1 -0
  110. package/dist/core/http/directory-profile-api.js +39 -0
  111. package/dist/core/http/directory-profile-api.js.map +1 -0
  112. package/dist/core/http/http-client.d.ts +41 -0
  113. package/dist/core/http/http-client.d.ts.map +1 -0
  114. package/dist/core/http/http-client.js +127 -0
  115. package/dist/core/http/http-client.js.map +1 -0
  116. package/dist/core/http/message-api.d.ts +55 -0
  117. package/dist/core/http/message-api.d.ts.map +1 -0
  118. package/dist/core/http/message-api.js +64 -0
  119. package/dist/core/http/message-api.js.map +1 -0
  120. package/dist/core/http/rate-limit.d.ts +22 -0
  121. package/dist/core/http/rate-limit.d.ts.map +1 -0
  122. package/dist/core/http/rate-limit.js +66 -0
  123. package/dist/core/http/rate-limit.js.map +1 -0
  124. package/dist/core/http/token-lifecycle.d.ts +18 -0
  125. package/dist/core/http/token-lifecycle.d.ts.map +1 -0
  126. package/dist/core/http/token-lifecycle.js +73 -0
  127. package/dist/core/http/token-lifecycle.js.map +1 -0
  128. package/dist/core/locking/profile-lock.d.ts +32 -0
  129. package/dist/core/locking/profile-lock.d.ts.map +1 -0
  130. package/dist/core/locking/profile-lock.js +104 -0
  131. package/dist/core/locking/profile-lock.js.map +1 -0
  132. package/dist/core/profiles/profile-service.d.ts +35 -0
  133. package/dist/core/profiles/profile-service.d.ts.map +1 -0
  134. package/dist/core/profiles/profile-service.js +119 -0
  135. package/dist/core/profiles/profile-service.js.map +1 -0
  136. package/dist/core/profiles/profile-types.d.ts +28 -0
  137. package/dist/core/profiles/profile-types.d.ts.map +1 -0
  138. package/dist/core/profiles/profile-types.js +13 -0
  139. package/dist/core/profiles/profile-types.js.map +1 -0
  140. package/dist/core/secrets/secrets-service.d.ts +25 -0
  141. package/dist/core/secrets/secrets-service.d.ts.map +1 -0
  142. package/dist/core/secrets/secrets-service.js +67 -0
  143. package/dist/core/secrets/secrets-service.js.map +1 -0
  144. package/dist/core/secrets/secrets-types.d.ts +29 -0
  145. package/dist/core/secrets/secrets-types.d.ts.map +1 -0
  146. package/dist/core/secrets/secrets-types.js +33 -0
  147. package/dist/core/secrets/secrets-types.js.map +1 -0
  148. package/dist/core/sqlite/chat-schema.d.ts +14 -0
  149. package/dist/core/sqlite/chat-schema.d.ts.map +1 -0
  150. package/dist/core/sqlite/chat-schema.js +172 -0
  151. package/dist/core/sqlite/chat-schema.js.map +1 -0
  152. package/dist/core/sqlite/core-schema.d.ts +14 -0
  153. package/dist/core/sqlite/core-schema.d.ts.map +1 -0
  154. package/dist/core/sqlite/core-schema.js +54 -0
  155. package/dist/core/sqlite/core-schema.js.map +1 -0
  156. package/dist/core/sqlite/database.d.ts +40 -0
  157. package/dist/core/sqlite/database.d.ts.map +1 -0
  158. package/dist/core/sqlite/database.js +68 -0
  159. package/dist/core/sqlite/database.js.map +1 -0
  160. package/dist/core/sqlite/migrations.d.ts +22 -0
  161. package/dist/core/sqlite/migrations.d.ts.map +1 -0
  162. package/dist/core/sqlite/migrations.js +64 -0
  163. package/dist/core/sqlite/migrations.js.map +1 -0
  164. package/dist/modules/chat/inbox/conversation-service.d.ts +35 -0
  165. package/dist/modules/chat/inbox/conversation-service.d.ts.map +1 -0
  166. package/dist/modules/chat/inbox/conversation-service.js +54 -0
  167. package/dist/modules/chat/inbox/conversation-service.js.map +1 -0
  168. package/dist/modules/chat/inbox/history-service.d.ts +25 -0
  169. package/dist/modules/chat/inbox/history-service.d.ts.map +1 -0
  170. package/dist/modules/chat/inbox/history-service.js +57 -0
  171. package/dist/modules/chat/inbox/history-service.js.map +1 -0
  172. package/dist/modules/chat/inbox/index.d.ts +9 -0
  173. package/dist/modules/chat/inbox/index.d.ts.map +1 -0
  174. package/dist/modules/chat/inbox/index.js +9 -0
  175. package/dist/modules/chat/inbox/index.js.map +1 -0
  176. package/dist/modules/chat/inbox/read-service.d.ts +36 -0
  177. package/dist/modules/chat/inbox/read-service.d.ts.map +1 -0
  178. package/dist/modules/chat/inbox/read-service.js +91 -0
  179. package/dist/modules/chat/inbox/read-service.js.map +1 -0
  180. package/dist/modules/chat/inbox/search-service.d.ts +20 -0
  181. package/dist/modules/chat/inbox/search-service.d.ts.map +1 -0
  182. package/dist/modules/chat/inbox/search-service.js +23 -0
  183. package/dist/modules/chat/inbox/search-service.js.map +1 -0
  184. package/dist/modules/chat/inbox/unread-service.d.ts +38 -0
  185. package/dist/modules/chat/inbox/unread-service.d.ts.map +1 -0
  186. package/dist/modules/chat/inbox/unread-service.js +65 -0
  187. package/dist/modules/chat/inbox/unread-service.js.map +1 -0
  188. package/dist/modules/chat/render/message-render.d.ts +35 -0
  189. package/dist/modules/chat/render/message-render.d.ts.map +1 -0
  190. package/dist/modules/chat/render/message-render.js +129 -0
  191. package/dist/modules/chat/render/message-render.js.map +1 -0
  192. package/dist/modules/chat/send/conversation-service.d.ts +53 -0
  193. package/dist/modules/chat/send/conversation-service.d.ts.map +1 -0
  194. package/dist/modules/chat/send/conversation-service.js +110 -0
  195. package/dist/modules/chat/send/conversation-service.js.map +1 -0
  196. package/dist/modules/chat/send/directory-cache-service.d.ts +37 -0
  197. package/dist/modules/chat/send/directory-cache-service.d.ts.map +1 -0
  198. package/dist/modules/chat/send/directory-cache-service.js +49 -0
  199. package/dist/modules/chat/send/directory-cache-service.js.map +1 -0
  200. package/dist/modules/chat/send/send-service.d.ts +36 -0
  201. package/dist/modules/chat/send/send-service.d.ts.map +1 -0
  202. package/dist/modules/chat/send/send-service.js +113 -0
  203. package/dist/modules/chat/send/send-service.js.map +1 -0
  204. package/dist/modules/chat/store/conversation-repo.d.ts +53 -0
  205. package/dist/modules/chat/store/conversation-repo.d.ts.map +1 -0
  206. package/dist/modules/chat/store/conversation-repo.js +75 -0
  207. package/dist/modules/chat/store/conversation-repo.js.map +1 -0
  208. package/dist/modules/chat/store/directory-cache-repo.d.ts +41 -0
  209. package/dist/modules/chat/store/directory-cache-repo.d.ts.map +1 -0
  210. package/dist/modules/chat/store/directory-cache-repo.js +64 -0
  211. package/dist/modules/chat/store/directory-cache-repo.js.map +1 -0
  212. package/dist/modules/chat/store/job-repo.d.ts +72 -0
  213. package/dist/modules/chat/store/job-repo.d.ts.map +1 -0
  214. package/dist/modules/chat/store/job-repo.js +140 -0
  215. package/dist/modules/chat/store/job-repo.js.map +1 -0
  216. package/dist/modules/chat/store/message-repo.d.ts +98 -0
  217. package/dist/modules/chat/store/message-repo.d.ts.map +1 -0
  218. package/dist/modules/chat/store/message-repo.js +231 -0
  219. package/dist/modules/chat/store/message-repo.js.map +1 -0
  220. package/dist/modules/chat/store/outbox-repo.d.ts +73 -0
  221. package/dist/modules/chat/store/outbox-repo.d.ts.map +1 -0
  222. package/dist/modules/chat/store/outbox-repo.js +112 -0
  223. package/dist/modules/chat/store/outbox-repo.js.map +1 -0
  224. package/dist/modules/chat/store/read-state-repo.d.ts +83 -0
  225. package/dist/modules/chat/store/read-state-repo.d.ts.map +1 -0
  226. package/dist/modules/chat/store/read-state-repo.js +210 -0
  227. package/dist/modules/chat/store/read-state-repo.js.map +1 -0
  228. package/dist/modules/chat/store/sync-state-repo.d.ts +45 -0
  229. package/dist/modules/chat/store/sync-state-repo.d.ts.map +1 -0
  230. package/dist/modules/chat/store/sync-state-repo.js +67 -0
  231. package/dist/modules/chat/store/sync-state-repo.js.map +1 -0
  232. package/dist/modules/chat/sync/backfill.d.ts +13 -0
  233. package/dist/modules/chat/sync/backfill.d.ts.map +1 -0
  234. package/dist/modules/chat/sync/backfill.js +37 -0
  235. package/dist/modules/chat/sync/backfill.js.map +1 -0
  236. package/dist/modules/chat/sync/cron-manager.d.ts +50 -0
  237. package/dist/modules/chat/sync/cron-manager.d.ts.map +1 -0
  238. package/dist/modules/chat/sync/cron-manager.js +164 -0
  239. package/dist/modules/chat/sync/cron-manager.js.map +1 -0
  240. package/dist/modules/chat/sync/index.d.ts +8 -0
  241. package/dist/modules/chat/sync/index.d.ts.map +1 -0
  242. package/dist/modules/chat/sync/index.js +7 -0
  243. package/dist/modules/chat/sync/index.js.map +1 -0
  244. package/dist/modules/chat/sync/job-logger.d.ts +44 -0
  245. package/dist/modules/chat/sync/job-logger.d.ts.map +1 -0
  246. package/dist/modules/chat/sync/job-logger.js +139 -0
  247. package/dist/modules/chat/sync/job-logger.js.map +1 -0
  248. package/dist/modules/chat/sync/sync-service.d.ts +14 -0
  249. package/dist/modules/chat/sync/sync-service.d.ts.map +1 -0
  250. package/dist/modules/chat/sync/sync-service.js +174 -0
  251. package/dist/modules/chat/sync/sync-service.js.map +1 -0
  252. package/dist/modules/chat/sync/sync-status.d.ts +14 -0
  253. package/dist/modules/chat/sync/sync-status.d.ts.map +1 -0
  254. package/dist/modules/chat/sync/sync-status.js +77 -0
  255. package/dist/modules/chat/sync/sync-status.js.map +1 -0
  256. package/dist/modules/chat/sync/sync-types.d.ts +80 -0
  257. package/dist/modules/chat/sync/sync-types.d.ts.map +1 -0
  258. package/dist/modules/chat/sync/sync-types.js +5 -0
  259. package/dist/modules/chat/sync/sync-types.js.map +1 -0
  260. package/dist/modules/chat/sync/watch-mode.d.ts +45 -0
  261. package/dist/modules/chat/sync/watch-mode.d.ts.map +1 -0
  262. package/dist/modules/chat/sync/watch-mode.js +161 -0
  263. package/dist/modules/chat/sync/watch-mode.js.map +1 -0
  264. package/package.json +67 -0
  265. package/tool-schema.json +1039 -0
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Cron manager - install/uninstall cron entries for background sync
3
+ */
4
+ import { execSync } from 'child_process';
5
+ import { upsertJob, deleteJob, getLatestJobByType } from '../store/job-repo.js';
6
+ const CRON_JOB_ID_PREFIX = 'fluxra-sync';
7
+ /**
8
+ * Generate cron entry for a profile
9
+ */
10
+ function generateCronEntry(options) {
11
+ const schedule = options.schedule || '*/5 * * * *';
12
+ const command = options.command || `cd ~ && fluxra chat sync once --profile ${options.profileName} >> ~/.fluxra/profiles/${options.profileName}/modules/chat/logs/cron-sync.log 2>&1`;
13
+ return `${schedule} ${command} # fluxra-sync-${options.profileName}`;
14
+ }
15
+ /**
16
+ * Extract profile name from cron comment
17
+ */
18
+ function extractProfileFromComment(line) {
19
+ const match = line.match(/# fluxra-sync-(.+)$/);
20
+ return match ? match[1] : null;
21
+ }
22
+ /**
23
+ * Get current crontab
24
+ */
25
+ function getCurrentCrontab() {
26
+ try {
27
+ return execSync('crontab -l', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
28
+ }
29
+ catch (error) {
30
+ // No crontab yet
31
+ return '';
32
+ }
33
+ }
34
+ /**
35
+ * Set crontab
36
+ */
37
+ function setCrontab(content) {
38
+ if (content.trim() === '') {
39
+ // Remove empty crontab
40
+ try {
41
+ execSync('crontab -r', { stdio: ['pipe', 'pipe', 'pipe'] });
42
+ }
43
+ catch {
44
+ // Already empty
45
+ }
46
+ }
47
+ else {
48
+ execSync(`echo '${content.replace(/'/g, "'\\''")}' | crontab -`, { stdio: ['pipe', 'pipe', 'pipe'] });
49
+ }
50
+ }
51
+ /**
52
+ * Check if cron is installed for a profile
53
+ */
54
+ export function isCronInstalled(db, profileName) {
55
+ const crontab = getCurrentCrontab();
56
+ return crontab.includes(`fluxra-sync-${profileName}`);
57
+ }
58
+ /**
59
+ * Install cron for a profile
60
+ */
61
+ export function installCron(db, options) {
62
+ // Check for conflicts
63
+ if (isCronInstalled(db, options.profileName)) {
64
+ throw new Error(`Cron already installed for profile '${options.profileName}'`);
65
+ }
66
+ // Get current crontab
67
+ const currentCrontab = getCurrentCrontab();
68
+ const cronEntry = generateCronEntry(options);
69
+ // Append new entry
70
+ const newCrontab = currentCrontab.trim() + '\n' + cronEntry;
71
+ // Install
72
+ setCrontab(newCrontab);
73
+ // Track in scheduler_jobs
74
+ const jobId = `${CRON_JOB_ID_PREFIX}-${options.profileName}`;
75
+ upsertJob(db, {
76
+ id: jobId,
77
+ jobType: 'cron-sync',
78
+ payload: {
79
+ profileName: options.profileName,
80
+ schedule: options.schedule || '*/5 * * * *',
81
+ installedAt: new Date().toISOString(),
82
+ },
83
+ scheduledAt: new Date().toISOString(),
84
+ });
85
+ return {
86
+ success: true,
87
+ schedule: options.schedule || '*/5 * * * *',
88
+ };
89
+ }
90
+ /**
91
+ * Uninstall cron for a profile
92
+ */
93
+ export function uninstallCron(db, profileName) {
94
+ const currentCrontab = getCurrentCrontab();
95
+ const lines = currentCrontab.split('\n');
96
+ // Filter out entries for this profile
97
+ const filteredLines = lines.filter(line => {
98
+ if (line.trim() === '' || line.startsWith('#')) {
99
+ return true;
100
+ }
101
+ const profile = extractProfileFromComment(line);
102
+ return profile !== profileName;
103
+ });
104
+ const newCrontab = filteredLines.filter(l => l.trim() !== '').join('\n');
105
+ setCrontab(newCrontab);
106
+ // Remove from scheduler_jobs
107
+ const jobId = `${CRON_JOB_ID_PREFIX}-${profileName}`;
108
+ deleteJob(db, jobId);
109
+ return { success: true };
110
+ }
111
+ /**
112
+ * Get cron status for a profile
113
+ */
114
+ export function getCronStatus(db, profileName) {
115
+ const installed = isCronInstalled(db, profileName);
116
+ const latestJob = getLatestJobByType(db, 'cron-sync');
117
+ return {
118
+ installed,
119
+ schedule: latestJob?.payload ? JSON.parse(latestJob.payload).schedule : '*/5 * * * *',
120
+ profileName,
121
+ lastRun: latestJob?.executed_at || null,
122
+ lastSuccess: latestJob?.status === 'completed' ? latestJob.executed_at : null,
123
+ lastError: latestJob?.last_error || null,
124
+ };
125
+ }
126
+ /**
127
+ * Detect cron conflicts (duplicate entries)
128
+ */
129
+ export function detectCronConflicts(db, profileName) {
130
+ const crontab = getCurrentCrontab();
131
+ const lines = crontab.split('\n').filter(l => l.trim() !== '' && !l.startsWith('#'));
132
+ const conflicts = [];
133
+ let count = 0;
134
+ for (const line of lines) {
135
+ const profile = extractProfileFromComment(line);
136
+ if (profile === profileName) {
137
+ count++;
138
+ if (count > 1) {
139
+ conflicts.push(line.trim());
140
+ }
141
+ }
142
+ }
143
+ return conflicts;
144
+ }
145
+ /**
146
+ * List all installed cron entries
147
+ */
148
+ export function listInstalledCrons() {
149
+ const crontab = getCurrentCrontab();
150
+ const lines = crontab.split('\n').filter(l => l.trim() !== '' && !l.startsWith('#'));
151
+ const crons = [];
152
+ for (const line of lines) {
153
+ const profile = extractProfileFromComment(line);
154
+ if (profile) {
155
+ const parts = line.trim().split(/\s+/);
156
+ crons.push({
157
+ profileName: profile,
158
+ schedule: parts.slice(0, 5).join(' '),
159
+ });
160
+ }
161
+ }
162
+ return crons;
163
+ }
164
+ //# sourceMappingURL=cron-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-manager.js","sourceRoot":"","sources":["../../../../src/modules/chat/sync/cron-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Chat sync module — public API
3
+ */
4
+ export { syncOnce, syncOnceLocked } from './sync-service.js';
5
+ export { getSyncStatus, formatSyncStatus } from './sync-status.js';
6
+ export { backfillConversation } from './backfill.js';
7
+ export type { SyncReport, SyncStatus, SyncOptions } from './sync-types.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/modules/chat/sync/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Chat sync module — public API
3
+ */
4
+ export { syncOnce, syncOnceLocked } from './sync-service.js';
5
+ export { getSyncStatus, formatSyncStatus } from './sync-status.js';
6
+ export { backfillConversation } from './backfill.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/modules/chat/sync/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Job logger - persistent lightweight job logs
3
+ */
4
+ export interface JobLogEntry {
5
+ timestamp: string;
6
+ level: 'info' | 'warn' | 'error';
7
+ jobType: string;
8
+ jobId?: string;
9
+ message: string;
10
+ details?: Record<string, any>;
11
+ }
12
+ /**
13
+ * Initialize log directory for a profile
14
+ */
15
+ export declare function initLogDir(profileName: string): string;
16
+ /**
17
+ * Append a log entry
18
+ */
19
+ export declare function appendJobLog(profileName: string, entry: JobLogEntry): void;
20
+ /**
21
+ * Get recent log entries
22
+ */
23
+ export declare function getRecentLogs(profileName: string, lines?: number): JobLogEntry[];
24
+ /**
25
+ * Rotate log file if too large
26
+ */
27
+ export declare function rotateLogs(logFile: string, maxSize?: number): void;
28
+ /**
29
+ * Format a log entry for display
30
+ */
31
+ export declare function formatLogEntry(entry: JobLogEntry): string;
32
+ /**
33
+ * Log a sync event
34
+ */
35
+ export declare function logSyncEvent(profileName: string, level: 'info' | 'warn' | 'error', message: string, details?: Record<string, any>): void;
36
+ /**
37
+ * Log a watch event
38
+ */
39
+ export declare function logWatchEvent(profileName: string, level: 'info' | 'warn' | 'error', message: string, details?: Record<string, any>): void;
40
+ /**
41
+ * Log a cron event
42
+ */
43
+ export declare function logCronEvent(profileName: string, level: 'info' | 'warn' | 'error', message: string, details?: Record<string, any>): void;
44
+ //# sourceMappingURL=job-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-logger.d.ts","sourceRoot":"","sources":["../../../../src/modules/chat/sync/job-logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC/B;AAMD;;GAEG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAStD;AAUD;;GAEG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,WAAW,GACjB,IAAI,CAaN;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,KAAK,GAAE,MAAW,GACjB,WAAW,EAAE,CAsBf;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAuBlE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAWzD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAChC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,IAAI,CAQN;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAChC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,IAAI,CAQN;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,EAChC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,IAAI,CAQN"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Job logger - persistent lightweight job logs
3
+ */
4
+ import { appendFileSync, readFileSync, existsSync, mkdirSync, renameSync } from 'fs';
5
+ import { join } from 'path';
6
+ import { getProfilePath } from '../../../core/filesystem/paths.js';
7
+ const LOG_DIR_NAME = 'modules/chat/logs';
8
+ const SYNC_LOG_FILE = 'sync.log';
9
+ const MAX_LOG_SIZE_BYTES = 10 * 1024 * 1024; // 10MB
10
+ /**
11
+ * Initialize log directory for a profile
12
+ */
13
+ export function initLogDir(profileName) {
14
+ const profilePath = getProfilePath(profileName);
15
+ const logDir = join(profilePath, LOG_DIR_NAME);
16
+ if (!existsSync(logDir)) {
17
+ mkdirSync(logDir, { recursive: true });
18
+ }
19
+ return logDir;
20
+ }
21
+ /**
22
+ * Get log file path
23
+ */
24
+ function getLogFilePath(profileName) {
25
+ const logDir = initLogDir(profileName);
26
+ return join(logDir, SYNC_LOG_FILE);
27
+ }
28
+ /**
29
+ * Append a log entry
30
+ */
31
+ export function appendJobLog(profileName, entry) {
32
+ const logFile = getLogFilePath(profileName);
33
+ // Rotate if too large
34
+ rotateLogs(logFile);
35
+ // Format as JSON line
36
+ const line = JSON.stringify({
37
+ ...entry,
38
+ timestamp: entry.timestamp || new Date().toISOString(),
39
+ });
40
+ appendFileSync(logFile, line + '\n', 'utf-8');
41
+ }
42
+ /**
43
+ * Get recent log entries
44
+ */
45
+ export function getRecentLogs(profileName, lines = 50) {
46
+ const logFile = getLogFilePath(profileName);
47
+ if (!existsSync(logFile)) {
48
+ return [];
49
+ }
50
+ try {
51
+ const content = readFileSync(logFile, 'utf-8');
52
+ const allLines = content.trim().split('\n').filter(l => l.trim() !== '');
53
+ const recentLines = allLines.slice(-lines);
54
+ return recentLines.map(line => {
55
+ try {
56
+ return JSON.parse(line);
57
+ }
58
+ catch {
59
+ return null;
60
+ }
61
+ }).filter((entry) => entry !== null);
62
+ }
63
+ catch {
64
+ return [];
65
+ }
66
+ }
67
+ /**
68
+ * Rotate log file if too large
69
+ */
70
+ export function rotateLogs(logFile, maxSize) {
71
+ const maxSizeBytes = maxSize || MAX_LOG_SIZE_BYTES;
72
+ if (!existsSync(logFile)) {
73
+ return;
74
+ }
75
+ try {
76
+ const stats = require('fs').statSync(logFile);
77
+ if (stats.size > maxSizeBytes) {
78
+ // Rename to .old
79
+ const oldFile = logFile + '.old';
80
+ // Remove old backup if exists
81
+ if (existsSync(oldFile)) {
82
+ require('fs').unlinkSync(oldFile);
83
+ }
84
+ renameSync(logFile, oldFile);
85
+ }
86
+ }
87
+ catch {
88
+ // Ignore rotation errors
89
+ }
90
+ }
91
+ /**
92
+ * Format a log entry for display
93
+ */
94
+ export function formatLogEntry(entry) {
95
+ const levelSymbol = entry.level === 'error' ? '✗' : entry.level === 'warn' ? '⚠' : '✓';
96
+ const timestamp = new Date(entry.timestamp).toLocaleString();
97
+ let output = `${timestamp} ${levelSymbol} [${entry.jobType}] ${entry.message}`;
98
+ if (entry.details) {
99
+ output += '\n ' + JSON.stringify(entry.details, null, 2).split('\n').join('\n ');
100
+ }
101
+ return output;
102
+ }
103
+ /**
104
+ * Log a sync event
105
+ */
106
+ export function logSyncEvent(profileName, level, message, details) {
107
+ appendJobLog(profileName, {
108
+ timestamp: new Date().toISOString(),
109
+ level,
110
+ jobType: 'sync',
111
+ message,
112
+ details,
113
+ });
114
+ }
115
+ /**
116
+ * Log a watch event
117
+ */
118
+ export function logWatchEvent(profileName, level, message, details) {
119
+ appendJobLog(profileName, {
120
+ timestamp: new Date().toISOString(),
121
+ level,
122
+ jobType: 'watch',
123
+ message,
124
+ details,
125
+ });
126
+ }
127
+ /**
128
+ * Log a cron event
129
+ */
130
+ export function logCronEvent(profileName, level, message, details) {
131
+ appendJobLog(profileName, {
132
+ timestamp: new Date().toISOString(),
133
+ level,
134
+ jobType: 'cron',
135
+ message,
136
+ details,
137
+ });
138
+ }
139
+ //# sourceMappingURL=job-logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-logger.js","sourceRoot":"","sources":["../../../../src/modules/chat/sync/job-logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Chat Sync Service — orchestrates remote-to-local synchronization
3
+ */
4
+ import Database from 'better-sqlite3';
5
+ import type { SyncReport, SyncOptions } from './sync-types.js';
6
+ /**
7
+ * Perform a one-shot chat synchronization
8
+ */
9
+ export declare function syncOnce(coreDb: Database.Database, chatDb: Database.Database, profileName: string, options?: SyncOptions): Promise<SyncReport>;
10
+ /**
11
+ * Run sync once with profile locking
12
+ */
13
+ export declare function syncOnceLocked(coreDb: Database.Database, chatDb: Database.Database, profileName: string, options?: SyncOptions): Promise<SyncReport>;
14
+ //# sourceMappingURL=sync-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-service.d.ts","sourceRoot":"","sources":["../../../../src/modules/chat/sync/sync-service.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAStC,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAiB,MAAM,iBAAiB,CAAC;AAE9E;;GAEG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,QAAQ,CAAC,QAAQ,EACzB,MAAM,EAAE,QAAQ,CAAC,QAAQ,EACzB,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CAoLrB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,QAAQ,CAAC,QAAQ,EACzB,MAAM,EAAE,QAAQ,CAAC,QAAQ,EACzB,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CAErB"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Chat Sync Service — orchestrates remote-to-local synchronization
3
+ */
4
+ import { ensureValidAccessToken } from '../../../core/http/token-lifecycle.js';
5
+ import { getMessages } from '../../../core/http/chat-api.js';
6
+ import { getSyncState, updateSyncState, initializeSyncState } from '../store/sync-state-repo.js';
7
+ import { upsertMessage, updateMessageStatus, getUnreadCount } from '../store/message-repo.js';
8
+ import { backfillConversation } from './backfill.js';
9
+ import { shouldBackoff, timeUntilNextPoll } from '../../../core/http/rate-limit.js';
10
+ import { withLock } from '../../../core/locking/profile-lock.js';
11
+ /**
12
+ * Perform a one-shot chat synchronization
13
+ */
14
+ export async function syncOnce(coreDb, chatDb, profileName, options = {}) {
15
+ const startedAt = new Date().toISOString();
16
+ const verbose = options.verbose || false;
17
+ const report = {
18
+ success: false,
19
+ startedAt,
20
+ completedAt: '',
21
+ messagesFetched: 0,
22
+ messagesInserted: 0,
23
+ messagesUpdated: 0,
24
+ conversationsInserted: 0,
25
+ conversationsUpdated: 0,
26
+ unreadDelta: 0,
27
+ rateLimit: null,
28
+ error: null,
29
+ };
30
+ try {
31
+ // Step 1: Ensure valid auth token
32
+ const accessToken = await ensureValidAccessToken(profileName);
33
+ if (verbose)
34
+ console.log('✓ Auth token validated');
35
+ // Step 2: Check rate limit (unless forced)
36
+ if (!options.force) {
37
+ const syncState = getSyncState(chatDb);
38
+ const now = new Date();
39
+ if (shouldBackoff(now, syncState.next_poll_after ? new Date(syncState.next_poll_after) : null)) {
40
+ const wait = timeUntilNextPoll(syncState.next_poll_after ? new Date(syncState.next_poll_after) : null, now);
41
+ report.error = `Rate limited. Next poll allowed in ${wait}s. Use --force to bypass.`;
42
+ report.completedAt = new Date().toISOString();
43
+ return report;
44
+ }
45
+ }
46
+ if (verbose)
47
+ console.log('✓ Rate limit check passed');
48
+ // Step 3: Read prior sync state
49
+ initializeSyncState(chatDb);
50
+ const syncState = getSyncState(chatDb);
51
+ const cursor = syncState.global_cursor || undefined;
52
+ if (verbose) {
53
+ console.log(` Cursor: ${cursor || '<initial sync>'}`);
54
+ }
55
+ // Step 4: Fetch latest remote messages (with pagination)
56
+ const unreadBefore = getUnreadCount(chatDb);
57
+ let currentCursor = cursor;
58
+ let hasMore = true;
59
+ const maxPages = options.limit ? Math.ceil(options.limit / 50) : 100; // Safety limit
60
+ let pageCount = 0;
61
+ const knownConversationIds = new Set();
62
+ while (hasMore && pageCount < maxPages) {
63
+ pageCount++;
64
+ const response = await getMessages(accessToken, {
65
+ cursor: currentCursor,
66
+ limit: 50,
67
+ });
68
+ const messages = response.data.messages || [];
69
+ hasMore = response.data.has_more || false;
70
+ currentCursor = response.data.cursor || undefined;
71
+ report.messagesFetched += messages.length;
72
+ report.rateLimit = response.rateLimit;
73
+ if (verbose) {
74
+ console.log(` Page ${pageCount}: ${messages.length} messages fetched`);
75
+ }
76
+ // Step 5: Upsert conversations and messages
77
+ for (const msg of messages) {
78
+ // Track conversations we've seen
79
+ if (!knownConversationIds.has(msg.conversation_id)) {
80
+ knownConversationIds.add(msg.conversation_id);
81
+ // Check if conversation exists locally
82
+ const existing = chatDb.prepare('SELECT conversation_id FROM conversations WHERE conversation_id = ?').get(msg.conversation_id);
83
+ if (!existing) {
84
+ // Backfill conversation metadata
85
+ try {
86
+ const result = await backfillConversation(accessToken, msg.conversation_id, chatDb);
87
+ if (result.inserted) {
88
+ report.conversationsInserted++;
89
+ }
90
+ else {
91
+ report.conversationsUpdated++;
92
+ }
93
+ }
94
+ catch (error) {
95
+ console.warn(`Warning: Could not backfill conversation ${msg.conversation_id}: ${error instanceof Error ? error.message : String(error)}`);
96
+ }
97
+ }
98
+ }
99
+ // Upsert message
100
+ const result = upsertMessage(chatDb, {
101
+ message_id: msg.message_id,
102
+ conversation_id: msg.conversation_id,
103
+ sender_id: msg.sender_id,
104
+ content: msg.content,
105
+ type: msg.type || 'text',
106
+ status: msg.status || 'sent',
107
+ in_reply_to: msg.in_reply_to || null,
108
+ mentions: msg.mention ? JSON.stringify(msg.mention) : null,
109
+ remote_created_at: msg.created_at,
110
+ remote_updated_at: msg.updated_at || null,
111
+ });
112
+ if (result.inserted) {
113
+ report.messagesInserted++;
114
+ }
115
+ else {
116
+ report.messagesUpdated++;
117
+ }
118
+ // Handle edited/withdrawn/deleted status
119
+ if (msg.status && ['edited', 'withdrawn', 'deleted'].includes(msg.status)) {
120
+ updateMessageStatus(chatDb, msg.message_id, msg.status);
121
+ }
122
+ // Detect mentions — mark as mentioned if current agent is in the mention list
123
+ // Note: We need agent_id from profile — for now, store the mention data
124
+ // The actual agent_id matching will happen when we know the profile's agent_id
125
+ }
126
+ }
127
+ // Step 6: Update sync state
128
+ const now = new Date();
129
+ const nextPollAfter = report.rateLimit?.nextPollAfter;
130
+ const minPollInterval = report.rateLimit?.minPollInterval || 1;
131
+ updateSyncState(chatDb, {
132
+ success: true,
133
+ globalCursor: currentCursor || undefined,
134
+ nextPollAfter: nextPollAfter?.toISOString(),
135
+ minPollInterval,
136
+ messagesSynced: report.messagesFetched,
137
+ conversationsSynced: report.conversationsInserted + report.conversationsUpdated,
138
+ });
139
+ // Step 7: Calculate unread delta
140
+ const unreadAfter = getUnreadCount(chatDb);
141
+ report.unreadDelta = Math.max(0, unreadAfter - unreadBefore);
142
+ report.success = true;
143
+ if (verbose) {
144
+ console.log(`✓ Sync complete: ${report.messagesFetched} fetched, ${report.messagesInserted} new, ${report.messagesUpdated} updated`);
145
+ console.log(` Unread: ${report.unreadDelta} new`);
146
+ }
147
+ }
148
+ catch (error) {
149
+ report.success = false;
150
+ report.error = error instanceof Error ? error.message : String(error);
151
+ // Record failed attempt in sync state
152
+ try {
153
+ updateSyncState(chatDb, {
154
+ success: false,
155
+ error: report.error,
156
+ });
157
+ }
158
+ catch {
159
+ // Ignore secondary error
160
+ }
161
+ if (verbose) {
162
+ console.error(`✗ Sync failed: ${report.error}`);
163
+ }
164
+ }
165
+ report.completedAt = new Date().toISOString();
166
+ return report;
167
+ }
168
+ /**
169
+ * Run sync once with profile locking
170
+ */
171
+ export async function syncOnceLocked(coreDb, chatDb, profileName, options = {}) {
172
+ return withLock(profileName, () => syncOnce(coreDb, chatDb, profileName, options));
173
+ }
174
+ //# sourceMappingURL=sync-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-service.js","sourceRoot":"","sources":["../../../../src/modules/chat/sync/sync-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Sync Status Service — read and format sync state for display
3
+ */
4
+ import Database from 'better-sqlite3';
5
+ import type { SyncStatus } from './sync-types.js';
6
+ /**
7
+ * Get the current sync status for a profile
8
+ */
9
+ export declare function getSyncStatus(chatDb: Database.Database): SyncStatus;
10
+ /**
11
+ * Format sync status for plain-text display
12
+ */
13
+ export declare function formatSyncStatus(status: SyncStatus): string;
14
+ //# sourceMappingURL=sync-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-status.d.ts","sourceRoot":"","sources":["../../../../src/modules/chat/sync/sync-status.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAGtC,OAAO,KAAK,EAAE,UAAU,EAA6B,MAAM,iBAAiB,CAAC;AAE7E;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,GAAG,UAAU,CAwBnE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA0C3D"}