somtum 0.1.2

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 (194) hide show
  1. package/LICENSE +663 -0
  2. package/README.md +459 -0
  3. package/dist/cli/config_cmd.d.ts +10 -0
  4. package/dist/cli/config_cmd.d.ts.map +1 -0
  5. package/dist/cli/config_cmd.js +96 -0
  6. package/dist/cli/config_cmd.js.map +1 -0
  7. package/dist/cli/doctor.d.ts +17 -0
  8. package/dist/cli/doctor.d.ts.map +1 -0
  9. package/dist/cli/doctor.js +169 -0
  10. package/dist/cli/doctor.js.map +1 -0
  11. package/dist/cli/edit.d.ts +4 -0
  12. package/dist/cli/edit.d.ts.map +1 -0
  13. package/dist/cli/edit.js +63 -0
  14. package/dist/cli/edit.js.map +1 -0
  15. package/dist/cli/export.d.ts +19 -0
  16. package/dist/cli/export.d.ts.map +1 -0
  17. package/dist/cli/export.js +84 -0
  18. package/dist/cli/export.js.map +1 -0
  19. package/dist/cli/forget.d.ts +11 -0
  20. package/dist/cli/forget.d.ts.map +1 -0
  21. package/dist/cli/forget.js +32 -0
  22. package/dist/cli/forget.js.map +1 -0
  23. package/dist/cli/hook.d.ts +2 -0
  24. package/dist/cli/hook.d.ts.map +1 -0
  25. package/dist/cli/hook.js +66 -0
  26. package/dist/cli/hook.js.map +1 -0
  27. package/dist/cli/import.d.ts +18 -0
  28. package/dist/cli/import.d.ts.map +1 -0
  29. package/dist/cli/import.js +90 -0
  30. package/dist/cli/import.js.map +1 -0
  31. package/dist/cli/index.d.ts +3 -0
  32. package/dist/cli/index.d.ts.map +1 -0
  33. package/dist/cli/index.js +223 -0
  34. package/dist/cli/index.js.map +1 -0
  35. package/dist/cli/init.d.ts +24 -0
  36. package/dist/cli/init.d.ts.map +1 -0
  37. package/dist/cli/init.js +144 -0
  38. package/dist/cli/init.js.map +1 -0
  39. package/dist/cli/purge.d.ts +16 -0
  40. package/dist/cli/purge.d.ts.map +1 -0
  41. package/dist/cli/purge.js +69 -0
  42. package/dist/cli/purge.js.map +1 -0
  43. package/dist/cli/rebuild.d.ts +15 -0
  44. package/dist/cli/rebuild.d.ts.map +1 -0
  45. package/dist/cli/rebuild.js +41 -0
  46. package/dist/cli/rebuild.js.map +1 -0
  47. package/dist/cli/reindex.d.ts +6 -0
  48. package/dist/cli/reindex.d.ts.map +1 -0
  49. package/dist/cli/reindex.js +47 -0
  50. package/dist/cli/reindex.js.map +1 -0
  51. package/dist/cli/search.d.ts +16 -0
  52. package/dist/cli/search.d.ts.map +1 -0
  53. package/dist/cli/search.js +62 -0
  54. package/dist/cli/search.js.map +1 -0
  55. package/dist/cli/show.d.ts +12 -0
  56. package/dist/cli/show.d.ts.map +1 -0
  57. package/dist/cli/show.js +49 -0
  58. package/dist/cli/show.js.map +1 -0
  59. package/dist/cli/stats.d.ts +27 -0
  60. package/dist/cli/stats.d.ts.map +1 -0
  61. package/dist/cli/stats.js +80 -0
  62. package/dist/cli/stats.js.map +1 -0
  63. package/dist/cli/sync.d.ts +18 -0
  64. package/dist/cli/sync.d.ts.map +1 -0
  65. package/dist/cli/sync.js +138 -0
  66. package/dist/cli/sync.js.map +1 -0
  67. package/dist/config.d.ts +12 -0
  68. package/dist/config.d.ts.map +1 -0
  69. package/dist/config.js +52 -0
  70. package/dist/config.js.map +1 -0
  71. package/dist/core/cache.d.ts +29 -0
  72. package/dist/core/cache.d.ts.map +1 -0
  73. package/dist/core/cache.js +137 -0
  74. package/dist/core/cache.js.map +1 -0
  75. package/dist/core/db.d.ts +12 -0
  76. package/dist/core/db.d.ts.map +1 -0
  77. package/dist/core/db.js +80 -0
  78. package/dist/core/db.js.map +1 -0
  79. package/dist/core/embeddings.d.ts +15 -0
  80. package/dist/core/embeddings.d.ts.map +1 -0
  81. package/dist/core/embeddings.js +74 -0
  82. package/dist/core/embeddings.js.map +1 -0
  83. package/dist/core/embeddings_bootstrap.d.ts +3 -0
  84. package/dist/core/embeddings_bootstrap.d.ts.map +1 -0
  85. package/dist/core/embeddings_bootstrap.js +16 -0
  86. package/dist/core/embeddings_bootstrap.js.map +1 -0
  87. package/dist/core/embeddings_xenova.d.ts +3 -0
  88. package/dist/core/embeddings_xenova.d.ts.map +1 -0
  89. package/dist/core/embeddings_xenova.js +28 -0
  90. package/dist/core/embeddings_xenova.js.map +1 -0
  91. package/dist/core/extractor.d.ts +27 -0
  92. package/dist/core/extractor.d.ts.map +1 -0
  93. package/dist/core/extractor.js +133 -0
  94. package/dist/core/extractor.js.map +1 -0
  95. package/dist/core/file_summary.d.ts +33 -0
  96. package/dist/core/file_summary.d.ts.map +1 -0
  97. package/dist/core/file_summary.js +127 -0
  98. package/dist/core/file_summary.js.map +1 -0
  99. package/dist/core/fingerprint.d.ts +13 -0
  100. package/dist/core/fingerprint.d.ts.map +1 -0
  101. package/dist/core/fingerprint.js +36 -0
  102. package/dist/core/fingerprint.js.map +1 -0
  103. package/dist/core/index_gen.d.ts +16 -0
  104. package/dist/core/index_gen.d.ts.map +1 -0
  105. package/dist/core/index_gen.js +173 -0
  106. package/dist/core/index_gen.js.map +1 -0
  107. package/dist/core/memory_files.d.ts +4 -0
  108. package/dist/core/memory_files.d.ts.map +1 -0
  109. package/dist/core/memory_files.js +36 -0
  110. package/dist/core/memory_files.js.map +1 -0
  111. package/dist/core/privacy.d.ts +9 -0
  112. package/dist/core/privacy.d.ts.map +1 -0
  113. package/dist/core/privacy.js +32 -0
  114. package/dist/core/privacy.js.map +1 -0
  115. package/dist/core/project_id.d.ts +3 -0
  116. package/dist/core/project_id.d.ts.map +1 -0
  117. package/dist/core/project_id.js +31 -0
  118. package/dist/core/project_id.js.map +1 -0
  119. package/dist/core/reindex.d.ts +10 -0
  120. package/dist/core/reindex.d.ts.map +1 -0
  121. package/dist/core/reindex.js +40 -0
  122. package/dist/core/reindex.js.map +1 -0
  123. package/dist/core/retrieval_stats.d.ts +22 -0
  124. package/dist/core/retrieval_stats.d.ts.map +1 -0
  125. package/dist/core/retrieval_stats.js +56 -0
  126. package/dist/core/retrieval_stats.js.map +1 -0
  127. package/dist/core/retriever/bm25.d.ts +15 -0
  128. package/dist/core/retriever/bm25.d.ts.map +1 -0
  129. package/dist/core/retriever/bm25.js +51 -0
  130. package/dist/core/retriever/bm25.js.map +1 -0
  131. package/dist/core/retriever/embeddings.d.ts +9 -0
  132. package/dist/core/retriever/embeddings.d.ts.map +1 -0
  133. package/dist/core/retriever/embeddings.js +34 -0
  134. package/dist/core/retriever/embeddings.js.map +1 -0
  135. package/dist/core/retriever/factory.d.ts +6 -0
  136. package/dist/core/retriever/factory.d.ts.map +1 -0
  137. package/dist/core/retriever/factory.js +53 -0
  138. package/dist/core/retriever/factory.js.map +1 -0
  139. package/dist/core/retriever/hybrid.d.ts +14 -0
  140. package/dist/core/retriever/hybrid.d.ts.map +1 -0
  141. package/dist/core/retriever/hybrid.js +52 -0
  142. package/dist/core/retriever/hybrid.js.map +1 -0
  143. package/dist/core/retriever/llm_index.d.ts +18 -0
  144. package/dist/core/retriever/llm_index.d.ts.map +1 -0
  145. package/dist/core/retriever/llm_index.js +90 -0
  146. package/dist/core/retriever/llm_index.js.map +1 -0
  147. package/dist/core/retriever/types.d.ts +16 -0
  148. package/dist/core/retriever/types.d.ts.map +1 -0
  149. package/dist/core/retriever/types.js +2 -0
  150. package/dist/core/retriever/types.js.map +1 -0
  151. package/dist/core/schema.d.ts +470 -0
  152. package/dist/core/schema.d.ts.map +1 -0
  153. package/dist/core/schema.js +153 -0
  154. package/dist/core/schema.js.map +1 -0
  155. package/dist/core/store.d.ts +35 -0
  156. package/dist/core/store.d.ts.map +1 -0
  157. package/dist/core/store.js +172 -0
  158. package/dist/core/store.js.map +1 -0
  159. package/dist/core/tokens.d.ts +3 -0
  160. package/dist/core/tokens.d.ts.map +1 -0
  161. package/dist/core/tokens.js +12 -0
  162. package/dist/core/tokens.js.map +1 -0
  163. package/dist/core/transcript.d.ts +16 -0
  164. package/dist/core/transcript.d.ts.map +1 -0
  165. package/dist/core/transcript.js +128 -0
  166. package/dist/core/transcript.js.map +1 -0
  167. package/dist/db/migrations/001_init.sql +90 -0
  168. package/dist/db/migrations/002_cache_files.sql +6 -0
  169. package/dist/db/migrations/003_retrieval_stats.sql +17 -0
  170. package/dist/hooks/post_session.d.ts +65 -0
  171. package/dist/hooks/post_session.d.ts.map +1 -0
  172. package/dist/hooks/post_session.js +249 -0
  173. package/dist/hooks/post_session.js.map +1 -0
  174. package/dist/hooks/pre_prompt.d.ts +55 -0
  175. package/dist/hooks/pre_prompt.d.ts.map +1 -0
  176. package/dist/hooks/pre_prompt.js +98 -0
  177. package/dist/hooks/pre_prompt.js.map +1 -0
  178. package/dist/hooks/pre_read.d.ts +56 -0
  179. package/dist/hooks/pre_read.d.ts.map +1 -0
  180. package/dist/hooks/pre_read.js +77 -0
  181. package/dist/hooks/pre_read.js.map +1 -0
  182. package/dist/index.d.ts +15 -0
  183. package/dist/index.d.ts.map +1 -0
  184. package/dist/index.js +15 -0
  185. package/dist/index.js.map +1 -0
  186. package/dist/mcp/server.d.ts +20 -0
  187. package/dist/mcp/server.d.ts.map +1 -0
  188. package/dist/mcp/server.js +128 -0
  189. package/dist/mcp/server.js.map +1 -0
  190. package/dist/mcp/tools.d.ts +72 -0
  191. package/dist/mcp/tools.d.ts.map +1 -0
  192. package/dist/mcp/tools.js +153 -0
  193. package/dist/mcp/tools.js.map +1 -0
  194. package/package.json +79 -0
@@ -0,0 +1,16 @@
1
+ import type { RetrievalResult } from '../core/retriever/types.js';
2
+ export declare function runSearch(opts: {
3
+ query: string;
4
+ k?: number;
5
+ strategy?: string;
6
+ cwd?: string;
7
+ dbPath?: string;
8
+ projectId?: string;
9
+ }): Promise<RetrievalResult[]>;
10
+ export declare function searchCommand(query: string, options?: {
11
+ strategy?: string;
12
+ k?: number;
13
+ json?: boolean;
14
+ cwd?: string;
15
+ }): Promise<number>;
16
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/cli/search.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AASlE,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAuB7B;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5E,OAAO,CAAC,MAAM,CAAC,CAkCjB"}
@@ -0,0 +1,62 @@
1
+ import { join } from 'node:path';
2
+ import { openDb } from '../core/db.js';
3
+ import { resolveProjectId } from '../core/project_id.js';
4
+ import { loadConfig, projectDir } from '../config.js';
5
+ import { makeRetriever } from '../core/retriever/factory.js';
6
+ import { RetrievalStrategy as RetrievalStrategyEnum } from '../core/schema.js';
7
+ function snippet(body, max = 160) {
8
+ const single = body.replace(/\s+/g, ' ').trim();
9
+ return single.length <= max ? single : `${single.slice(0, max - 1)}…`;
10
+ }
11
+ export async function runSearch(opts) {
12
+ const cwd = opts.cwd ?? process.cwd();
13
+ const config = loadConfig({ cwd });
14
+ const k = opts.k ?? config.retrieval.k;
15
+ const projectId = opts.projectId ?? resolveProjectId(cwd);
16
+ const dbPath = opts.dbPath ?? join(projectDir(projectId), 'db.sqlite');
17
+ // Resolve strategy: prefer explicit arg → config default
18
+ const strategyRaw = opts.strategy ?? config.retrieval.strategy;
19
+ const strategyParsed = RetrievalStrategyEnum.safeParse(strategyRaw);
20
+ const strategy = strategyParsed.success ? strategyParsed.data : 'bm25';
21
+ if (strategyParsed.success && strategyRaw !== strategy) {
22
+ console.warn(`[somtum] unknown strategy "${strategyRaw}", falling back to bm25`);
23
+ }
24
+ const db = openDb({ path: dbPath });
25
+ try {
26
+ const retriever = makeRetriever(strategy, db, config);
27
+ return await retriever.search(opts.query, { k, projectId });
28
+ }
29
+ finally {
30
+ db.close();
31
+ }
32
+ }
33
+ export async function searchCommand(query, options = {}) {
34
+ const cwd = options.cwd ?? process.cwd();
35
+ const searchOpts = { query, cwd };
36
+ if (options.k !== undefined)
37
+ searchOpts.k = options.k;
38
+ if (options.strategy !== undefined)
39
+ searchOpts.strategy = options.strategy;
40
+ const results = await runSearch(searchOpts);
41
+ if (options.json) {
42
+ console.log(JSON.stringify(results.map((r) => ({
43
+ id: r.id,
44
+ score: r.score,
45
+ source: r.source,
46
+ title: r.observation.title,
47
+ kind: r.observation.kind,
48
+ files: r.observation.files,
49
+ })), null, 2));
50
+ return 0;
51
+ }
52
+ if (results.length === 0) {
53
+ console.log('no matches');
54
+ return 0;
55
+ }
56
+ for (const r of results) {
57
+ console.log(`${r.id} [${r.observation.kind}] ${r.observation.title} (${r.source}: ${r.score.toFixed(3)})`);
58
+ console.log(` ${snippet(r.observation.body)}`);
59
+ }
60
+ return 0;
61
+ }
62
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/cli/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { Observation } from '../core/schema.js';
2
+ export declare function runShow(opts: {
3
+ id: string;
4
+ cwd?: string;
5
+ dbPath?: string;
6
+ projectId?: string;
7
+ }): Observation | null;
8
+ export declare function showCommand(id: string, options?: {
9
+ json?: boolean;
10
+ cwd?: string;
11
+ }): number;
12
+ //# sourceMappingURL=show.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"show.d.ts","sourceRoot":"","sources":["../../src/cli/show.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,wBAAgB,OAAO,CAAC,IAAI,EAAE;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,WAAW,GAAG,IAAI,CAWrB;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,CA4B9F"}
@@ -0,0 +1,49 @@
1
+ import { join } from 'node:path';
2
+ import { openDb } from '../core/db.js';
3
+ import { MemoryStore } from '../core/store.js';
4
+ import { resolveProjectId } from '../core/project_id.js';
5
+ import { projectDir } from '../config.js';
6
+ export function runShow(opts) {
7
+ const cwd = opts.cwd ?? process.cwd();
8
+ const projectId = opts.projectId ?? resolveProjectId(cwd);
9
+ const dbPath = opts.dbPath ?? join(projectDir(projectId), 'db.sqlite');
10
+ const db = openDb({ path: dbPath });
11
+ try {
12
+ const store = new MemoryStore(db);
13
+ return store.get(opts.id);
14
+ }
15
+ finally {
16
+ db.close();
17
+ }
18
+ }
19
+ export function showCommand(id, options = {}) {
20
+ const obs = runShow({ id, cwd: options.cwd ?? process.cwd() });
21
+ if (!obs) {
22
+ console.error(`no observation with id ${id}`);
23
+ return 1;
24
+ }
25
+ if (options.json) {
26
+ // embedding is a Buffer; serialize length not contents
27
+ const { embedding, ...rest } = obs;
28
+ const serializable = { ...rest, embedding_bytes: embedding ? embedding.length : null };
29
+ console.log(JSON.stringify(serializable, null, 2));
30
+ return 0;
31
+ }
32
+ console.log(`id: ${obs.id}`);
33
+ console.log(`project: ${obs.project_id}`);
34
+ console.log(`session: ${obs.session_id}`);
35
+ console.log(`kind: ${obs.kind}`);
36
+ console.log(`created: ${new Date(obs.created_at).toISOString()}`);
37
+ if (obs.files.length > 0)
38
+ console.log(`files: ${obs.files.join(', ')}`);
39
+ if (obs.tags.length > 0)
40
+ console.log(`tags: ${obs.tags.join(', ')}`);
41
+ console.log(`saved est: ${obs.tokens_saved} tokens`);
42
+ console.log(`spent est: ${obs.tokens_spent} tokens`);
43
+ console.log('');
44
+ console.log(`# ${obs.title}`);
45
+ console.log('');
46
+ console.log(obs.body);
47
+ return 0;
48
+ }
49
+ //# sourceMappingURL=show.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"show.js","sourceRoot":"","sources":["../../src/cli/show.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ export interface StatsSnapshot {
2
+ project_id: string;
3
+ memories: number;
4
+ by_kind: Record<string, number>;
5
+ cache_entries: number;
6
+ cache_hits: number;
7
+ cache_misses: number;
8
+ cache_hit_rate: number | null;
9
+ retrieval_by_strategy: Array<{
10
+ strategy: string;
11
+ call_count: number;
12
+ }>;
13
+ tokens_saved_estimated: number;
14
+ tokens_spent_estimated: number;
15
+ net_estimated: number;
16
+ breakeven_ratio_estimated: number | null;
17
+ }
18
+ export declare function collectStats(opts?: {
19
+ cwd?: string;
20
+ dbPath?: string;
21
+ projectId?: string;
22
+ }): StatsSnapshot;
23
+ export declare function statsCommand(options?: {
24
+ json?: boolean;
25
+ cwd?: string;
26
+ }): number;
27
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/cli/stats.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,qBAAqB,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvE,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,yBAAyB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1C;AAED,wBAAgB,YAAY,CAAC,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,aAAa,CA8B5G;AAiCD,wBAAgB,YAAY,CAAC,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,CAQnF"}
@@ -0,0 +1,80 @@
1
+ import { join } from 'node:path';
2
+ import { openDb } from '../core/db.js';
3
+ import { MemoryStore } from '../core/store.js';
4
+ import { PromptCache } from '../core/cache.js';
5
+ import { RetrievalStatsStore } from '../core/retrieval_stats.js';
6
+ import { resolveProjectId } from '../core/project_id.js';
7
+ import { projectDir } from '../config.js';
8
+ export function collectStats(opts = {}) {
9
+ const cwd = opts.cwd ?? process.cwd();
10
+ const projectId = opts.projectId ?? resolveProjectId(cwd);
11
+ const dbPath = opts.dbPath ?? join(projectDir(projectId), 'db.sqlite');
12
+ const db = openDb({ path: dbPath });
13
+ try {
14
+ const store = new MemoryStore(db);
15
+ const cache = new PromptCache(db);
16
+ const statsStore = new RetrievalStatsStore(db);
17
+ const saved = store.totalTokensSaved(projectId);
18
+ const spent = store.totalTokensSpent(projectId);
19
+ const cacheHits = statsStore.getCacheHitSummary(projectId);
20
+ const retrievalBreakdown = statsStore.getRetrievalBreakdown(projectId);
21
+ return {
22
+ project_id: projectId,
23
+ memories: store.countByProject(projectId),
24
+ by_kind: store.countByKind(projectId),
25
+ cache_entries: cache.count(),
26
+ cache_hits: cacheHits.hit_count,
27
+ cache_misses: cacheHits.miss_count,
28
+ cache_hit_rate: cacheHits.hit_rate,
29
+ retrieval_by_strategy: retrievalBreakdown,
30
+ tokens_saved_estimated: saved,
31
+ tokens_spent_estimated: spent,
32
+ net_estimated: saved - spent,
33
+ breakeven_ratio_estimated: spent > 0 ? Number((saved / spent).toFixed(2)) : null,
34
+ };
35
+ }
36
+ finally {
37
+ db.close();
38
+ }
39
+ }
40
+ function printHuman(s) {
41
+ console.log(`project ${s.project_id}`);
42
+ console.log(`memories ${s.memories}`);
43
+ for (const [k, n] of Object.entries(s.by_kind)) {
44
+ if (n > 0)
45
+ console.log(` ${k.padEnd(15)} ${n}`);
46
+ }
47
+ console.log(`cache entries ${s.cache_entries}`);
48
+ console.log(`cache hits ${s.cache_hits}`);
49
+ console.log(`cache misses ${s.cache_misses}`);
50
+ const hitRate = s.cache_hit_rate !== null ? `${(s.cache_hit_rate * 100).toFixed(1)}%` : 'n/a';
51
+ console.log(`cache hit rate ${hitRate}`);
52
+ if (s.retrieval_by_strategy.length > 0) {
53
+ console.log(`retrieval calls by strategy:`);
54
+ for (const r of s.retrieval_by_strategy) {
55
+ console.log(` ${r.strategy.padEnd(12)} ${r.call_count}`);
56
+ }
57
+ }
58
+ console.log(`tokens saved ${s.tokens_saved_estimated} (estimated)`);
59
+ console.log(`tokens spent ${s.tokens_spent_estimated} (estimated)`);
60
+ console.log(`net ${s.net_estimated} (estimated)`);
61
+ const br = s.breakeven_ratio_estimated;
62
+ if (br !== null) {
63
+ const warn = br < 1.5 ? ' — below 1.5x, check `somtum doctor`' : '';
64
+ console.log(`breakeven ${br}x (estimated)${warn}`);
65
+ }
66
+ else {
67
+ console.log(`breakeven n/a (no extraction cost recorded yet)`);
68
+ }
69
+ }
70
+ export function statsCommand(options = {}) {
71
+ const snap = collectStats({ cwd: options.cwd ?? process.cwd() });
72
+ if (options.json) {
73
+ console.log(JSON.stringify(snap, null, 2));
74
+ }
75
+ else {
76
+ printHuman(snap);
77
+ }
78
+ return 0;
79
+ }
80
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/cli/stats.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export interface SyncResult {
2
+ direction: 'push' | 'pull' | 'status';
3
+ local_count: number;
4
+ remote_count: number | null;
5
+ transferred: number;
6
+ remote: string;
7
+ }
8
+ export declare function runSync(opts: {
9
+ direction: 'push' | 'pull' | 'status';
10
+ cwd?: string;
11
+ remote?: string;
12
+ }): Promise<SyncResult>;
13
+ export declare function syncCommand(direction: 'push' | 'pull' | 'status', options?: {
14
+ remote?: string;
15
+ json?: boolean;
16
+ cwd?: string;
17
+ }): Promise<number>;
18
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/cli/sync.ts"],"names":[],"mappings":"AA0CA,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,UAAU,CAAC,CA0EtB;AAED,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,EACrC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9D,OAAO,CAAC,MAAM,CAAC,CA8BjB"}
@@ -0,0 +1,138 @@
1
+ // SSH-based push/pull sync (M6). Transfers observations as JSONL so we can
2
+ // merge rather than overwrite. Conflict rule: if the same ULID already exists
3
+ // locally the remote copy is skipped (ULIDs are unique across machines).
4
+ // Relies on `scp` being available in PATH.
5
+ import { execFileSync, execSync } from 'node:child_process';
6
+ import { unlinkSync, existsSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+ import { tmpdir } from 'node:os';
9
+ import { openDb } from '../core/db.js';
10
+ import { resolveProjectId } from '../core/project_id.js';
11
+ import { loadConfig, projectDir } from '../config.js';
12
+ import { runExport } from './export.js';
13
+ import { runImport } from './import.js';
14
+ // Parses "user@host:/remote/path" or "host:/remote/path"
15
+ function parseRemote(remote) {
16
+ const colonIdx = remote.indexOf(':');
17
+ if (colonIdx === -1)
18
+ throw new Error(`invalid sync.remote: "${remote}". Expected user@host:/path`);
19
+ return { userHost: remote.slice(0, colonIdx), path: remote.slice(colonIdx + 1) };
20
+ }
21
+ function scpTo(localPath, remote) {
22
+ execFileSync('scp', ['-q', localPath, remote], { stdio: ['ignore', 'ignore', 'pipe'] });
23
+ }
24
+ function scpFrom(remote, localPath) {
25
+ execFileSync('scp', ['-q', remote, localPath], { stdio: ['ignore', 'ignore', 'pipe'] });
26
+ }
27
+ function remoteCount(userHost, remotePath) {
28
+ try {
29
+ const out = execSync(`ssh -o BatchMode=yes -o ConnectTimeout=5 ${userHost} "wc -l < '${remotePath}' 2>/dev/null || echo 0"`, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
30
+ return Number.parseInt(out.trim(), 10);
31
+ }
32
+ catch {
33
+ return null;
34
+ }
35
+ }
36
+ export async function runSync(opts) {
37
+ const cwd = opts.cwd ?? process.cwd();
38
+ const config = loadConfig({ cwd });
39
+ const projectId = resolveProjectId(cwd);
40
+ const dbPath = join(projectDir(projectId), 'db.sqlite');
41
+ const remote = opts.remote ?? config.sync.remote;
42
+ if (!remote) {
43
+ throw new Error('sync.remote is not configured. Set it via `somtum config set sync.remote "user@host:/path/.somtum/projects/<id>"`');
44
+ }
45
+ const { userHost, path: remotePath } = parseRemote(remote);
46
+ const remoteJsonl = `${remotePath}/observations.jsonl`;
47
+ const localJsonl = join(projectDir(projectId), 'observations.jsonl');
48
+ const db = openDb({ path: dbPath });
49
+ let localCount;
50
+ try {
51
+ const { MemoryStore } = await import('../core/store.js');
52
+ localCount = new MemoryStore(db).countByProject(projectId);
53
+ }
54
+ finally {
55
+ db.close();
56
+ }
57
+ if (opts.direction === 'status') {
58
+ const remoteLineCount = remoteCount(userHost, remoteJsonl);
59
+ return {
60
+ direction: 'status',
61
+ local_count: localCount,
62
+ remote_count: remoteLineCount,
63
+ transferred: 0,
64
+ remote,
65
+ };
66
+ }
67
+ if (opts.direction === 'push') {
68
+ // Export local observations to JSONL then scp to remote.
69
+ runExport({ format: 'jsonl', output: localJsonl, cwd });
70
+ try {
71
+ // Ensure remote directory exists via SSH mkdir.
72
+ execSync(`ssh -o BatchMode=yes ${userHost} "mkdir -p '${remotePath}'"`, { stdio: ['ignore', 'ignore', 'pipe'] });
73
+ scpTo(localJsonl, `${userHost}:${remoteJsonl}`);
74
+ }
75
+ finally {
76
+ if (existsSync(localJsonl))
77
+ unlinkSync(localJsonl);
78
+ }
79
+ return {
80
+ direction: 'push',
81
+ local_count: localCount,
82
+ remote_count: localCount,
83
+ transferred: localCount,
84
+ remote,
85
+ };
86
+ }
87
+ // pull: copy remote JSONL locally and merge.
88
+ const tmpPath = join(tmpdir(), `somtum-pull-${projectId}.jsonl`);
89
+ try {
90
+ scpFrom(`${userHost}:${remoteJsonl}`, tmpPath);
91
+ const importResult = runImport({ input: tmpPath, format: 'jsonl', cwd });
92
+ return {
93
+ direction: 'pull',
94
+ local_count: localCount + importResult.imported,
95
+ remote_count: localCount + importResult.imported + importResult.skipped,
96
+ transferred: importResult.imported,
97
+ remote,
98
+ };
99
+ }
100
+ finally {
101
+ if (existsSync(tmpPath))
102
+ unlinkSync(tmpPath);
103
+ }
104
+ }
105
+ export async function syncCommand(direction, options = {}) {
106
+ let result;
107
+ try {
108
+ const syncOpts = {
109
+ direction,
110
+ cwd: options.cwd ?? process.cwd(),
111
+ };
112
+ if (options.remote !== undefined)
113
+ syncOpts.remote = options.remote;
114
+ result = await runSync(syncOpts);
115
+ }
116
+ catch (err) {
117
+ console.error(`sync error: ${err.message}`);
118
+ return 1;
119
+ }
120
+ if (options.json) {
121
+ console.log(JSON.stringify(result, null, 2));
122
+ return 0;
123
+ }
124
+ if (direction === 'status') {
125
+ console.log(`local ${result.local_count} observations`);
126
+ const remoteStr = result.remote_count !== null ? String(result.remote_count) : 'unreachable';
127
+ console.log(`remote ${remoteStr} observation lines`);
128
+ console.log(`remote ${result.remote}`);
129
+ }
130
+ else if (direction === 'push') {
131
+ console.log(`pushed ${result.transferred} observations to ${result.remote}`);
132
+ }
133
+ else {
134
+ console.log(`pulled ${result.transferred} new observations from ${result.remote}`);
135
+ }
136
+ return 0;
137
+ }
138
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/cli/sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { type Config } from './core/schema.js';
2
+ export declare const GLOBAL_DIR: string;
3
+ export declare const GLOBAL_CONFIG_PATH: string;
4
+ export declare const PROJECT_CONFIG_RELATIVE: string;
5
+ export interface LoadOptions {
6
+ cwd?: string;
7
+ global?: string;
8
+ }
9
+ export declare function loadConfig(options?: LoadOptions): Config;
10
+ export declare function ensureGlobalDir(): string;
11
+ export declare function projectDir(projectId: string): string;
12
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,KAAK,MAAM,EAAoB,MAAM,kBAAkB,CAAC;AAE/E,eAAO,MAAM,UAAU,QAA2D,CAAC;AACnF,eAAO,MAAM,kBAAkB,QAAkC,CAAC;AAClE,eAAO,MAAM,uBAAuB,QAAiC,CAAC;AA2BtE,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,UAAU,CAAC,OAAO,GAAE,WAAgB,GAAG,MAAM,CAS5D;AAED,wBAAgB,eAAe,IAAI,MAAM,CAKxC;AAED,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAIpD"}
package/dist/config.js ADDED
@@ -0,0 +1,52 @@
1
+ import { readFileSync, existsSync, mkdirSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { ConfigSchema } from './core/schema.js';
5
+ export const GLOBAL_DIR = process.env['SOMTUM_HOME'] ?? join(homedir(), '.somtum');
6
+ export const GLOBAL_CONFIG_PATH = join(GLOBAL_DIR, 'config.json');
7
+ export const PROJECT_CONFIG_RELATIVE = join('.somtum', 'config.json');
8
+ function readJsonIfExists(path) {
9
+ if (!existsSync(path))
10
+ return undefined;
11
+ const raw = readFileSync(path, 'utf8');
12
+ if (raw.trim() === '')
13
+ return undefined;
14
+ return JSON.parse(raw);
15
+ }
16
+ function deepMerge(base, over) {
17
+ if (over === undefined || over === null)
18
+ return base;
19
+ if (typeof base !== 'object' ||
20
+ base === null ||
21
+ Array.isArray(base) ||
22
+ typeof over !== 'object' ||
23
+ Array.isArray(over)) {
24
+ return over;
25
+ }
26
+ const out = { ...base };
27
+ for (const [k, v] of Object.entries(over)) {
28
+ out[k] = deepMerge(base[k], v);
29
+ }
30
+ return out;
31
+ }
32
+ export function loadConfig(options = {}) {
33
+ const cwd = options.cwd ?? process.cwd();
34
+ const globalPath = options.global ?? GLOBAL_CONFIG_PATH;
35
+ const globalRaw = (readJsonIfExists(globalPath) ?? {});
36
+ const projectRaw = (readJsonIfExists(join(cwd, PROJECT_CONFIG_RELATIVE)) ?? {});
37
+ const merged = deepMerge(globalRaw, projectRaw);
38
+ return ConfigSchema.parse(merged);
39
+ }
40
+ export function ensureGlobalDir() {
41
+ if (!existsSync(GLOBAL_DIR)) {
42
+ mkdirSync(GLOBAL_DIR, { recursive: true });
43
+ }
44
+ return GLOBAL_DIR;
45
+ }
46
+ export function projectDir(projectId) {
47
+ const dir = join(GLOBAL_DIR, 'projects', projectId);
48
+ if (!existsSync(dir))
49
+ mkdirSync(dir, { recursive: true });
50
+ return dir;
51
+ }
52
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { DB } from './db.js';
2
+ import { type CacheEntry, type CacheEntryInput } from './schema.js';
3
+ import { type Embedder } from './embeddings.js';
4
+ export declare const CACHE_FINGERPRINT_VERSION = 1;
5
+ export declare function normalizePrompt(prompt: string): string;
6
+ export declare function hashPrompt(prompt: string): string;
7
+ export declare class PromptCache {
8
+ private readonly db;
9
+ constructor(db: DB);
10
+ lookupByHash(promptHash: string): CacheEntry | null;
11
+ put(input: CacheEntryInput & {
12
+ prompt_embedding?: Buffer;
13
+ }): CacheEntry;
14
+ lookupFuzzy(prompt: string, embedder: Embedder, threshold: number): Promise<{
15
+ entry: CacheEntry;
16
+ similarity: number;
17
+ } | null>;
18
+ getById(id: string): CacheEntry | null;
19
+ setPromptEmbedding(id: string, v: Float32Array): void;
20
+ listMissingPromptEmbeddings(): {
21
+ id: string;
22
+ prompt_text: string;
23
+ }[];
24
+ recordFalseHit(id: string): void;
25
+ touch(id: string): void;
26
+ invalidate(id: string): void;
27
+ count(): number;
28
+ }
29
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/core/cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAoB,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,EAIL,KAAK,QAAQ,EACd,MAAM,iBAAiB,CAAC;AAIzB,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAsC3C,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKtD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,qBAAa,WAAW;IACV,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,EAAE;IAEnC,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAUnD,GAAG,CAAC,KAAK,EAAE,eAAe,GAAG;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,UAAU;IA2CjE,WAAW,CACf,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IA4B5D,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAOtC,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,YAAY,GAAG,IAAI;IAMrD,2BAA2B,IAAI;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE;IASpE,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAMhC,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAQvB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI5B,KAAK,IAAI,MAAM;CAMhB"}