om-memory-system 3.0.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 (221) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +587 -0
  3. package/dist/adapters/opencode/auto-capture-host.d.ts +3 -0
  4. package/dist/adapters/opencode/auto-capture-host.js +29 -0
  5. package/dist/adapters/opencode/auto-capture-summary.d.ts +4 -0
  6. package/dist/adapters/opencode/auto-capture-summary.js +147 -0
  7. package/dist/adapters/opencode/conversation.d.ts +2 -0
  8. package/dist/adapters/opencode/conversation.js +50 -0
  9. package/dist/adapters/opencode/user-prompt.d.ts +9 -0
  10. package/dist/adapters/opencode/user-prompt.js +26 -0
  11. package/dist/adapters/pi/capture.d.ts +41 -0
  12. package/dist/adapters/pi/capture.js +91 -0
  13. package/dist/adapters/pi/conversation.d.ts +38 -0
  14. package/dist/adapters/pi/conversation.js +118 -0
  15. package/dist/adapters/pi/extension.d.ts +18 -0
  16. package/dist/adapters/pi/extension.js +234 -0
  17. package/dist/adapters/pi/import-command.d.ts +29 -0
  18. package/dist/adapters/pi/import-command.js +232 -0
  19. package/dist/adapters/pi/profile.d.ts +39 -0
  20. package/dist/adapters/pi/profile.js +148 -0
  21. package/dist/adapters/pi/provider.d.ts +50 -0
  22. package/dist/adapters/pi/provider.js +77 -0
  23. package/dist/config.d.ts +290 -0
  24. package/dist/config.js +742 -0
  25. package/dist/core/capture-context.d.ts +4 -0
  26. package/dist/core/capture-context.js +132 -0
  27. package/dist/core/capture.d.ts +15 -0
  28. package/dist/core/capture.js +68 -0
  29. package/dist/core/extraction.d.ts +80 -0
  30. package/dist/core/extraction.js +140 -0
  31. package/dist/core/host.d.ts +52 -0
  32. package/dist/core/host.js +1 -0
  33. package/dist/core/memory-operations.d.ts +27 -0
  34. package/dist/core/memory-operations.js +247 -0
  35. package/dist/core/retrieval.d.ts +12 -0
  36. package/dist/core/retrieval.js +72 -0
  37. package/dist/importer/discovery.d.ts +31 -0
  38. package/dist/importer/discovery.js +88 -0
  39. package/dist/importer/importer.d.ts +87 -0
  40. package/dist/importer/importer.js +260 -0
  41. package/dist/importer/ledger.d.ts +44 -0
  42. package/dist/importer/ledger.js +137 -0
  43. package/dist/importer/session-loader.d.ts +19 -0
  44. package/dist/importer/session-loader.js +12 -0
  45. package/dist/index.d.ts +24 -0
  46. package/dist/index.js +601 -0
  47. package/dist/plugin.d.ts +9 -0
  48. package/dist/plugin.js +11 -0
  49. package/dist/services/ai/ai-provider-factory.d.ts +7 -0
  50. package/dist/services/ai/ai-provider-factory.js +41 -0
  51. package/dist/services/ai/api-key-placeholder.d.ts +1 -0
  52. package/dist/services/ai/api-key-placeholder.js +14 -0
  53. package/dist/services/ai/internal-capture-sessions.d.ts +6 -0
  54. package/dist/services/ai/internal-capture-sessions.js +33 -0
  55. package/dist/services/ai/opencode-diagnostics.d.ts +7 -0
  56. package/dist/services/ai/opencode-diagnostics.js +36 -0
  57. package/dist/services/ai/opencode-host-config.d.ts +10 -0
  58. package/dist/services/ai/opencode-host-config.js +51 -0
  59. package/dist/services/ai/opencode-provider-loader.d.ts +3 -0
  60. package/dist/services/ai/opencode-provider-loader.js +4 -0
  61. package/dist/services/ai/opencode-provider.d.ts +92 -0
  62. package/dist/services/ai/opencode-provider.js +419 -0
  63. package/dist/services/ai/opencode-sdk-client.d.ts +6 -0
  64. package/dist/services/ai/opencode-sdk-client.js +38 -0
  65. package/dist/services/ai/profile-llm-client.d.ts +2 -0
  66. package/dist/services/ai/profile-llm-client.js +27 -0
  67. package/dist/services/ai/provider-config.d.ts +17 -0
  68. package/dist/services/ai/provider-config.js +30 -0
  69. package/dist/services/ai/providers/anthropic-messages.d.ts +34 -0
  70. package/dist/services/ai/providers/anthropic-messages.js +220 -0
  71. package/dist/services/ai/providers/base-provider.d.ts +24 -0
  72. package/dist/services/ai/providers/base-provider.js +24 -0
  73. package/dist/services/ai/providers/google-gemini.d.ts +15 -0
  74. package/dist/services/ai/providers/google-gemini.js +228 -0
  75. package/dist/services/ai/providers/minimax.d.ts +35 -0
  76. package/dist/services/ai/providers/minimax.js +55 -0
  77. package/dist/services/ai/providers/openai-chat-completion.d.ts +22 -0
  78. package/dist/services/ai/providers/openai-chat-completion.js +387 -0
  79. package/dist/services/ai/providers/openai-responses.d.ts +13 -0
  80. package/dist/services/ai/providers/openai-responses.js +182 -0
  81. package/dist/services/ai/providers/orcarouter.d.ts +51 -0
  82. package/dist/services/ai/providers/orcarouter.js +66 -0
  83. package/dist/services/ai/session/ai-session-manager.d.ts +24 -0
  84. package/dist/services/ai/session/ai-session-manager.js +211 -0
  85. package/dist/services/ai/session/session-types.d.ts +42 -0
  86. package/dist/services/ai/session/session-types.js +1 -0
  87. package/dist/services/ai/tools/tool-schema.d.ts +40 -0
  88. package/dist/services/ai/tools/tool-schema.js +24 -0
  89. package/dist/services/ai/validators/user-profile-validator.d.ts +12 -0
  90. package/dist/services/ai/validators/user-profile-validator.js +114 -0
  91. package/dist/services/api-handlers.d.ts +186 -0
  92. package/dist/services/api-handlers.js +1284 -0
  93. package/dist/services/auth-token.d.ts +14 -0
  94. package/dist/services/auth-token.js +59 -0
  95. package/dist/services/auto-capture.d.ts +3 -0
  96. package/dist/services/auto-capture.js +127 -0
  97. package/dist/services/cleanup-service.d.ts +22 -0
  98. package/dist/services/cleanup-service.js +109 -0
  99. package/dist/services/client.d.ts +134 -0
  100. package/dist/services/client.js +327 -0
  101. package/dist/services/context.d.ts +10 -0
  102. package/dist/services/context.js +27 -0
  103. package/dist/services/cors.d.ts +12 -0
  104. package/dist/services/cors.js +52 -0
  105. package/dist/services/deduplication-service.d.ts +28 -0
  106. package/dist/services/deduplication-service.js +111 -0
  107. package/dist/services/embedding.d.ts +36 -0
  108. package/dist/services/embedding.js +200 -0
  109. package/dist/services/jsonc.d.ts +6 -0
  110. package/dist/services/jsonc.js +76 -0
  111. package/dist/services/language-detector.d.ts +2 -0
  112. package/dist/services/language-detector.js +33 -0
  113. package/dist/services/legacy-migration.d.ts +77 -0
  114. package/dist/services/legacy-migration.js +343 -0
  115. package/dist/services/logger.d.ts +1 -0
  116. package/dist/services/logger.js +119 -0
  117. package/dist/services/memory-portability-service.d.ts +37 -0
  118. package/dist/services/memory-portability-service.js +340 -0
  119. package/dist/services/memory-scope.d.ts +16 -0
  120. package/dist/services/memory-scope.js +43 -0
  121. package/dist/services/migration-service.d.ts +42 -0
  122. package/dist/services/migration-service.js +307 -0
  123. package/dist/services/onnxruntime-resolve.d.ts +24 -0
  124. package/dist/services/onnxruntime-resolve.js +174 -0
  125. package/dist/services/privacy.d.ts +26 -0
  126. package/dist/services/privacy.js +69 -0
  127. package/dist/services/request-timeouts.d.ts +9 -0
  128. package/dist/services/request-timeouts.js +11 -0
  129. package/dist/services/runtime-require.d.ts +17 -0
  130. package/dist/services/runtime-require.js +75 -0
  131. package/dist/services/secret-resolver.d.ts +1 -0
  132. package/dist/services/secret-resolver.js +65 -0
  133. package/dist/services/shard-inventory-service.d.ts +69 -0
  134. package/dist/services/shard-inventory-service.js +315 -0
  135. package/dist/services/shard-path-migration-service.d.ts +31 -0
  136. package/dist/services/shard-path-migration-service.js +367 -0
  137. package/dist/services/tag-prefix-migration.d.ts +60 -0
  138. package/dist/services/tag-prefix-migration.js +439 -0
  139. package/dist/services/tag-prefix-scan.d.ts +26 -0
  140. package/dist/services/tag-prefix-scan.js +91 -0
  141. package/dist/services/tags.d.ts +29 -0
  142. package/dist/services/tags.js +251 -0
  143. package/dist/services/turso/connection-manager.d.ts +15 -0
  144. package/dist/services/turso/connection-manager.js +163 -0
  145. package/dist/services/turso/cross-process-write-lock.d.ts +1 -0
  146. package/dist/services/turso/cross-process-write-lock.js +89 -0
  147. package/dist/services/turso/legacy-migrator.d.ts +1 -0
  148. package/dist/services/turso/legacy-migrator.js +540 -0
  149. package/dist/services/turso/lifecycle.d.ts +1 -0
  150. package/dist/services/turso/lifecycle.js +14 -0
  151. package/dist/services/turso/operation-lock.d.ts +2 -0
  152. package/dist/services/turso/operation-lock.js +61 -0
  153. package/dist/services/turso/ready.d.ts +2 -0
  154. package/dist/services/turso/ready.js +36 -0
  155. package/dist/services/turso/shard-manager.d.ts +38 -0
  156. package/dist/services/turso/shard-manager.js +496 -0
  157. package/dist/services/turso/sqlite-handle-release.d.ts +16 -0
  158. package/dist/services/turso/sqlite-handle-release.js +56 -0
  159. package/dist/services/turso/turso-db.d.ts +18 -0
  160. package/dist/services/turso/turso-db.js +53 -0
  161. package/dist/services/turso/types.d.ts +42 -0
  162. package/dist/services/turso/types.js +1 -0
  163. package/dist/services/turso/vector-search.d.ts +41 -0
  164. package/dist/services/turso/vector-search.js +384 -0
  165. package/dist/services/turso/vector-utils.d.ts +7 -0
  166. package/dist/services/turso/vector-utils.js +67 -0
  167. package/dist/services/user-memory-learning.d.ts +97 -0
  168. package/dist/services/user-memory-learning.js +673 -0
  169. package/dist/services/user-profile/ai-cleanup.d.ts +58 -0
  170. package/dist/services/user-profile/ai-cleanup.js +486 -0
  171. package/dist/services/user-profile/profile-context.d.ts +1 -0
  172. package/dist/services/user-profile/profile-context.js +105 -0
  173. package/dist/services/user-profile/profile-utils.d.ts +2 -0
  174. package/dist/services/user-profile/profile-utils.js +45 -0
  175. package/dist/services/user-profile/types.d.ts +92 -0
  176. package/dist/services/user-profile/types.js +1 -0
  177. package/dist/services/user-profile/user-profile-manager.d.ts +65 -0
  178. package/dist/services/user-profile/user-profile-manager.js +1660 -0
  179. package/dist/services/user-prompt/user-prompt-manager.d.ts +53 -0
  180. package/dist/services/user-prompt/user-prompt-manager.js +303 -0
  181. package/dist/services/web-api-auth.d.ts +3 -0
  182. package/dist/services/web-api-auth.js +25 -0
  183. package/dist/services/web-auth.d.ts +46 -0
  184. package/dist/services/web-auth.js +105 -0
  185. package/dist/services/web-server.d.ts +57 -0
  186. package/dist/services/web-server.js +659 -0
  187. package/dist/shared/api/index.d.ts +4 -0
  188. package/dist/shared/api/index.js +2 -0
  189. package/dist/shared/api/portability-schemas.d.ts +56 -0
  190. package/dist/shared/api/portability-schemas.js +39 -0
  191. package/dist/shared/api/schemas.d.ts +295 -0
  192. package/dist/shared/api/schemas.js +134 -0
  193. package/dist/shared/api/types.d.ts +28 -0
  194. package/dist/shared/api/types.js +1 -0
  195. package/dist/types/index.d.ts +27 -0
  196. package/dist/types/index.js +1 -0
  197. package/dist/utils/context-limit.d.ts +10 -0
  198. package/dist/utils/context-limit.js +43 -0
  199. package/dist/utils/math.d.ts +7 -0
  200. package/dist/utils/math.js +48 -0
  201. package/dist/utils/profile.d.ts +2 -0
  202. package/dist/utils/profile.js +15 -0
  203. package/dist/v2/adapter.d.ts +5 -0
  204. package/dist/v2/adapter.js +218 -0
  205. package/dist/v2/legacy-client.d.ts +15 -0
  206. package/dist/v2/legacy-client.js +257 -0
  207. package/dist/v2/memory-bridge.d.ts +18 -0
  208. package/dist/v2/memory-bridge.js +29 -0
  209. package/dist/v2/plugin.d.ts +3 -0
  210. package/dist/v2/plugin.js +24 -0
  211. package/dist/web/assets/index-DPjEpD1h.css +2 -0
  212. package/dist/web/assets/index-do26c4JJ.js +122 -0
  213. package/dist/web/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  214. package/dist/web/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  215. package/dist/web/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  216. package/dist/web/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  217. package/dist/web/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  218. package/dist/web/favicon.ico +0 -0
  219. package/dist/web/index.html +14 -0
  220. package/dist/web/omms-icon.png +0 -0
  221. package/package.json +138 -0
@@ -0,0 +1,200 @@
1
+ import { CONFIG } from "../config.js";
2
+ import { log } from "./logger.js";
3
+ import { join } from "node:path";
4
+ import { formatOnnxruntimeInitError, prepareOnnxruntimeForTransformers, } from "./onnxruntime-resolve.js";
5
+ import { createRuntimeRequire } from "./runtime-require.js";
6
+ const requireFromHere = createRuntimeRequire(import.meta);
7
+ const TIMEOUT_MS = 30000;
8
+ const GLOBAL_EMBEDDING_KEY = Symbol.for("omms.embedding.instance");
9
+ const MAX_CACHE_SIZE = 100;
10
+ const TASK_PREFIXES = {
11
+ document: "search_document: ",
12
+ query: "search_query: ",
13
+ };
14
+ /**
15
+ * Apply Nomic-style task prefixes when enabled.
16
+ * Cache keys and API/local inputs should use the returned string.
17
+ */
18
+ export function applyEmbeddingTaskPrefix(text, options, useTaskPrefixes = CONFIG.embeddingUseTaskPrefixes) {
19
+ if (!useTaskPrefixes || !options?.task)
20
+ return text;
21
+ const prefix = TASK_PREFIXES[options.task];
22
+ if (text.startsWith(prefix))
23
+ return text;
24
+ return `${prefix}${text}`;
25
+ }
26
+ let _transformers = null;
27
+ function getTransformersPackageSpecifier() {
28
+ // Keep this non-literal so OpenCode/Bun plugin-loader bundling does not eagerly
29
+ // traverse @huggingface/transformers internals during plugin startup. The package
30
+ // is only needed for the local embedding backend, and should stay lazy.
31
+ return ["@huggingface", "transformers"].join("/");
32
+ }
33
+ async function ensureTransformersLoaded() {
34
+ if (_transformers !== null)
35
+ return _transformers;
36
+ // Pin onnxruntime-node (+ common) to our direct 1.20.1 stack before transformers
37
+ // resolves them (#184 / #210 / #225). Load the CJS export so Module._resolveFilename
38
+ // shim applies — the ESM entry's static import bypasses it under OpenCode nested installs.
39
+ //
40
+ // Critical ordering for OpenCode's Bun --compile host (#210 follow-up):
41
+ // resolve the transformers absolute path BEFORE installOnnxruntimeResolveShim().
42
+ // After the shim is installed, non-onnx Module._resolveFilename fallbacks fail with
43
+ // `Cannot find module '@huggingface/transformers' from ''` even though the package
44
+ // exists. Loading via the pre-resolved absolute path keeps the onnx pin shim active
45
+ // for transformers' nested requires without needing a post-shim package resolve.
46
+ const transformersSpecifier = getTransformersPackageSpecifier();
47
+ let transformersEntry;
48
+ try {
49
+ transformersEntry = requireFromHere.resolve(transformersSpecifier);
50
+ }
51
+ catch (error) {
52
+ throw new Error(`Cannot resolve ${transformersSpecifier} before installing the onnxruntime pin shim. ` +
53
+ `Original error: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
54
+ }
55
+ prepareOnnxruntimeForTransformers();
56
+ const mod = requireFromHere(transformersEntry);
57
+ mod.env.allowLocalModels = true;
58
+ mod.env.allowRemoteModels = true;
59
+ mod.env.cacheDir = join(CONFIG.storagePath, ".cache");
60
+ // Keep ONNX WASM single-threaded for Bun/Node runtimes without SharedArrayBuffer.
61
+ try {
62
+ mod.env.backends.onnx.wasm.numThreads = 1;
63
+ }
64
+ catch (e) {
65
+ log("Failed to set wasm.numThreads", { error: String(e) });
66
+ }
67
+ _transformers = mod;
68
+ return _transformers;
69
+ }
70
+ /**
71
+ * Production transformers load path used by nested OpenCode install fixtures (#210).
72
+ * Prefer this over a separately anchored createRequire() so empty-referrer hosts are covered.
73
+ */
74
+ export async function loadLocalTransformersBackend() {
75
+ return ensureTransformersLoaded();
76
+ }
77
+ function withTimeout(promise, ms) {
78
+ return Promise.race([
79
+ promise,
80
+ new Promise((_, reject) => setTimeout(() => reject(new Error(`Timeout after ${ms}ms`)), ms)),
81
+ ]);
82
+ }
83
+ export class EmbeddingService {
84
+ pipe = null;
85
+ initPromise = null;
86
+ isWarmedUp = false;
87
+ /** Set when warmup fails permanently; prevents "initializing forever" (#184). */
88
+ initError = null;
89
+ cache = new Map();
90
+ cachedModelName = null;
91
+ static getInstance() {
92
+ if (!globalThis[GLOBAL_EMBEDDING_KEY]) {
93
+ globalThis[GLOBAL_EMBEDDING_KEY] = new EmbeddingService();
94
+ }
95
+ return globalThis[GLOBAL_EMBEDDING_KEY];
96
+ }
97
+ async warmup(progressCallback) {
98
+ if (this.isWarmedUp)
99
+ return;
100
+ if (this.initError)
101
+ throw new Error(this.initError);
102
+ if (this.initPromise)
103
+ return this.initPromise;
104
+ this.initPromise = this.initializeModel(progressCallback);
105
+ return this.initPromise;
106
+ }
107
+ async initializeModel(progressCallback) {
108
+ try {
109
+ if (CONFIG.embeddingApiUrl && CONFIG.embeddingApiKey) {
110
+ // Send a probe request to verify the API endpoint is actually reachable
111
+ // Uses a minimal embedding of "ping" to test the full request pipeline
112
+ const probeResponse = await withTimeout(fetch(`${CONFIG.embeddingApiUrl}/embeddings`, {
113
+ method: "POST",
114
+ headers: {
115
+ "Content-Type": "application/json",
116
+ Authorization: `Bearer ${CONFIG.embeddingApiKey}`,
117
+ },
118
+ body: JSON.stringify({
119
+ input: "ping",
120
+ model: CONFIG.embeddingModel,
121
+ }),
122
+ }), TIMEOUT_MS);
123
+ if (!probeResponse.ok) {
124
+ throw new Error(`Embedding API health check failed: ${probeResponse.status} ${probeResponse.statusText}`);
125
+ }
126
+ this.isWarmedUp = true;
127
+ this.initError = null;
128
+ return;
129
+ }
130
+ // Local model path
131
+ const { pipeline } = await ensureTransformersLoaded();
132
+ this.pipe = await pipeline("feature-extraction", CONFIG.embeddingModel, {
133
+ progress_callback: progressCallback,
134
+ });
135
+ this.isWarmedUp = true;
136
+ this.initError = null;
137
+ log("Embedding model warmed up", { model: CONFIG.embeddingModel });
138
+ }
139
+ catch (error) {
140
+ const rewritten = formatOnnxruntimeInitError(error);
141
+ this.initPromise = null;
142
+ this.initError = rewritten.message;
143
+ log("Failed to initialize embedding model", { error: rewritten.message });
144
+ throw rewritten;
145
+ }
146
+ }
147
+ async embed(text, options) {
148
+ if (this.cachedModelName !== CONFIG.embeddingModel) {
149
+ this.clearCache();
150
+ this.cachedModelName = CONFIG.embeddingModel;
151
+ }
152
+ const input = applyEmbeddingTaskPrefix(text, options);
153
+ const cached = this.cache.get(input);
154
+ if (cached)
155
+ return cached;
156
+ if (!this.isWarmedUp && !this.initPromise) {
157
+ await this.warmup();
158
+ }
159
+ if (this.initPromise) {
160
+ await this.initPromise;
161
+ }
162
+ let result;
163
+ if (CONFIG.embeddingApiUrl && CONFIG.embeddingApiKey) {
164
+ const response = await fetch(`${CONFIG.embeddingApiUrl}/embeddings`, {
165
+ method: "POST",
166
+ headers: {
167
+ "Content-Type": "application/json",
168
+ Authorization: `Bearer ${CONFIG.embeddingApiKey}`,
169
+ },
170
+ body: JSON.stringify({
171
+ input,
172
+ model: CONFIG.embeddingModel,
173
+ }),
174
+ });
175
+ if (!response.ok) {
176
+ throw new Error(`API embedding failed: ${response.statusText}`);
177
+ }
178
+ const data = await response.json();
179
+ result = new Float32Array(data.data[0].embedding);
180
+ }
181
+ else {
182
+ const output = await this.pipe(input, { pooling: "mean", normalize: true });
183
+ result = new Float32Array(output.data);
184
+ }
185
+ if (this.cache.size >= MAX_CACHE_SIZE) {
186
+ const firstKey = this.cache.keys().next().value;
187
+ if (firstKey !== undefined)
188
+ this.cache.delete(firstKey);
189
+ }
190
+ this.cache.set(input, result);
191
+ return result;
192
+ }
193
+ async embedWithTimeout(text, options) {
194
+ return withTimeout(this.embed(text, options), TIMEOUT_MS);
195
+ }
196
+ clearCache() {
197
+ this.cache.clear();
198
+ }
199
+ }
200
+ export const embeddingService = EmbeddingService.getInstance();
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Strips comments from JSONC content while respecting string boundaries.
3
+ * Handles // and /* comments, URLs in strings, and escaped quotes.
4
+ * Also removes trailing commas to support more relaxed JSONC format.
5
+ */
6
+ export declare function stripJsoncComments(content: string): string;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Strips comments from JSONC content while respecting string boundaries.
3
+ * Handles // and /* comments, URLs in strings, and escaped quotes.
4
+ * Also removes trailing commas to support more relaxed JSONC format.
5
+ */
6
+ export function stripJsoncComments(content) {
7
+ let result = "";
8
+ let i = 0;
9
+ let inString = false;
10
+ let inSingleLineComment = false;
11
+ let inMultiLineComment = false;
12
+ while (i < content.length) {
13
+ const char = content[i];
14
+ const nextChar = content[i + 1];
15
+ if (!inSingleLineComment && !inMultiLineComment) {
16
+ if (char === '"') {
17
+ // Count consecutive backslashes before this quote
18
+ let backslashCount = 0;
19
+ let j = i - 1;
20
+ while (j >= 0 && content[j] === "\\") {
21
+ backslashCount++;
22
+ j--;
23
+ }
24
+ // Quote is escaped only if preceded by ODD number of backslashes
25
+ // e.g., \" = escaped, \\" = not escaped (escaped backslash + quote)
26
+ if (backslashCount % 2 === 0) {
27
+ inString = !inString;
28
+ }
29
+ result += char;
30
+ i++;
31
+ continue;
32
+ }
33
+ }
34
+ if (inString) {
35
+ result += char;
36
+ i++;
37
+ continue;
38
+ }
39
+ if (!inSingleLineComment && !inMultiLineComment) {
40
+ if (char === "/" && nextChar === "/") {
41
+ inSingleLineComment = true;
42
+ i += 2;
43
+ continue;
44
+ }
45
+ if (char === "/" && nextChar === "*") {
46
+ inMultiLineComment = true;
47
+ i += 2;
48
+ continue;
49
+ }
50
+ }
51
+ if (inSingleLineComment) {
52
+ if (char === "\n") {
53
+ inSingleLineComment = false;
54
+ result += char;
55
+ }
56
+ i++;
57
+ continue;
58
+ }
59
+ if (inMultiLineComment) {
60
+ if (char === "*" && nextChar === "/") {
61
+ inMultiLineComment = false;
62
+ i += 2;
63
+ continue;
64
+ }
65
+ if (char === "\n") {
66
+ result += char;
67
+ }
68
+ i++;
69
+ continue;
70
+ }
71
+ result += char;
72
+ i++;
73
+ }
74
+ // Remove trailing commas before } or ]
75
+ return result.replace(/,\s*([}\]])/g, "$1");
76
+ }
@@ -0,0 +1,2 @@
1
+ export declare function detectLanguage(text: string): string;
2
+ export declare function getLanguageName(code: string): string;
@@ -0,0 +1,33 @@
1
+ import { franc } from "franc-min";
2
+ import { iso6393, iso6393To1 } from "iso-639-3";
3
+ // 3-letter codes without ISO 639-1 equivalents
4
+ const FALLBACK_MAP = {
5
+ cmn: "zh", // Mandarin Chinese
6
+ yue: "zh", // Cantonese
7
+ arz: "ar", // Egyptian Arabic
8
+ hbs: "sr", // Serbo-Croatian
9
+ };
10
+ export function detectLanguage(text) {
11
+ if (!text || text.trim().length === 0) {
12
+ return "en";
13
+ }
14
+ const detected = franc(text, { minLength: 5 });
15
+ if (detected === "und") {
16
+ return "en";
17
+ }
18
+ // Try 2-letter mapping first
19
+ const twoLetter = iso6393To1[detected];
20
+ if (twoLetter)
21
+ return twoLetter;
22
+ // Fallback for 3-letter codes without 2-letter equivalent
23
+ return FALLBACK_MAP[detected] || "en";
24
+ }
25
+ export function getLanguageName(code) {
26
+ // Try 2-letter lookup first
27
+ let lang = iso6393.find((l) => l.iso6391 === code);
28
+ // Fallback to 3-letter lookup
29
+ if (!lang) {
30
+ lang = iso6393.find((l) => l.iso6393 === code);
31
+ }
32
+ return lang?.name || "English";
33
+ }
@@ -0,0 +1,77 @@
1
+ export interface LegacyMigrationPaths {
2
+ legacyDir: string;
3
+ legacyDataDir: string;
4
+ ommsDir: string;
5
+ ommsDataDir: string;
6
+ backupsDir: string;
7
+ markerPath: string;
8
+ lockPath: string;
9
+ }
10
+ export interface LegacyMigrationMarker {
11
+ version: 1;
12
+ status: "migrated" | "failed";
13
+ source: string;
14
+ destination: string;
15
+ backupPath?: string;
16
+ fileCount?: number;
17
+ startedAt: string;
18
+ completedAt?: string;
19
+ /** Which stage failed, when status is "failed". */
20
+ stage?: "backup" | "copy";
21
+ error?: string;
22
+ }
23
+ export type LegacyMigrationResult = {
24
+ kind: "migrated";
25
+ marker: LegacyMigrationMarker;
26
+ } | {
27
+ kind: "already-migrated";
28
+ marker: LegacyMigrationMarker;
29
+ } | {
30
+ kind: "failed-marker";
31
+ marker: LegacyMigrationMarker;
32
+ } | {
33
+ kind: "failed";
34
+ marker: LegacyMigrationMarker;
35
+ } | {
36
+ kind: "fresh";
37
+ } | {
38
+ kind: "destination-exists";
39
+ } | {
40
+ kind: "in-progress";
41
+ };
42
+ interface BackupManifestEntry {
43
+ path: string;
44
+ size: number;
45
+ sha256: string;
46
+ }
47
+ export type { BackupManifestEntry };
48
+ export declare function legacyMigrationPaths(home?: string): LegacyMigrationPaths;
49
+ export declare function readLegacyMigrationMarker(home?: string): LegacyMigrationMarker | null;
50
+ /**
51
+ * Default storage resolution shared with config.ts. While a legacy store
52
+ * exists and the migration has not succeeded, storage keeps resolving to the
53
+ * legacy layout (covering both "migration pending" and "migration failed").
54
+ * After a successful migration, or on a fresh install, the omms path wins.
55
+ */
56
+ export declare function resolveDefaultStoragePath(home?: string): string;
57
+ export interface TreeWalk {
58
+ files: string[];
59
+ dirs: string[];
60
+ }
61
+ export declare function walkTree(root: string): TreeWalk;
62
+ declare function timestampSlug(date?: Date): string;
63
+ export { timestampSlug };
64
+ /**
65
+ * Copy the listed files from `sourceRoot` into `destRoot` (mirroring their
66
+ * relative paths), producing a checksum manifest, then verify every copied
67
+ * file by re-reading it and comparing size and sha256. Throws on any failure.
68
+ * The caller is responsible for creating any missing parent directories and
69
+ * for holding any locks that keep the source quiescent during the copy.
70
+ */
71
+ export declare function copyFilesWithVerification(sourceRoot: string, destRoot: string, relPaths: string[]): BackupManifestEntry[];
72
+ /**
73
+ * Run the one-time legacy store migration for the given home directory.
74
+ * Pure module: no environment-variable switches, no CONFIG dependency.
75
+ * Hosts integrate it through initConfigWithLegacyMigration in config.ts.
76
+ */
77
+ export declare function runLegacyStoreMigration(home?: string): LegacyMigrationResult;