context-mem 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 (208) hide show
  1. package/.context-mem.json.example +22 -0
  2. package/LICENSE +21 -0
  3. package/README.md +213 -0
  4. package/dist/cli/commands/dashboard.d.ts +2 -0
  5. package/dist/cli/commands/dashboard.d.ts.map +1 -0
  6. package/dist/cli/commands/dashboard.js +55 -0
  7. package/dist/cli/commands/dashboard.js.map +1 -0
  8. package/dist/cli/commands/doctor.d.ts +2 -0
  9. package/dist/cli/commands/doctor.d.ts.map +1 -0
  10. package/dist/cli/commands/doctor.js +49 -0
  11. package/dist/cli/commands/doctor.js.map +1 -0
  12. package/dist/cli/commands/init.d.ts +2 -0
  13. package/dist/cli/commands/init.d.ts.map +1 -0
  14. package/dist/cli/commands/init.js +43 -0
  15. package/dist/cli/commands/init.js.map +1 -0
  16. package/dist/cli/commands/serve.d.ts +2 -0
  17. package/dist/cli/commands/serve.d.ts.map +1 -0
  18. package/dist/cli/commands/serve.js +47 -0
  19. package/dist/cli/commands/serve.js.map +1 -0
  20. package/dist/cli/commands/status.d.ts +2 -0
  21. package/dist/cli/commands/status.d.ts.map +1 -0
  22. package/dist/cli/commands/status.js +29 -0
  23. package/dist/cli/commands/status.js.map +1 -0
  24. package/dist/cli/index.d.ts +3 -0
  25. package/dist/cli/index.d.ts.map +1 -0
  26. package/dist/cli/index.js +39 -0
  27. package/dist/cli/index.js.map +1 -0
  28. package/dist/core/budget.d.ts +11 -0
  29. package/dist/core/budget.d.ts.map +1 -0
  30. package/dist/core/budget.js +60 -0
  31. package/dist/core/budget.js.map +1 -0
  32. package/dist/core/config.d.ts +4 -0
  33. package/dist/core/config.d.ts.map +1 -0
  34. package/dist/core/config.js +41 -0
  35. package/dist/core/config.js.map +1 -0
  36. package/dist/core/events.d.ts +19 -0
  37. package/dist/core/events.d.ts.map +1 -0
  38. package/dist/core/events.js +101 -0
  39. package/dist/core/events.js.map +1 -0
  40. package/dist/core/kernel.d.ts +46 -0
  41. package/dist/core/kernel.d.ts.map +1 -0
  42. package/dist/core/kernel.js +228 -0
  43. package/dist/core/kernel.js.map +1 -0
  44. package/dist/core/lifecycle.d.ts +19 -0
  45. package/dist/core/lifecycle.d.ts.map +1 -0
  46. package/dist/core/lifecycle.js +35 -0
  47. package/dist/core/lifecycle.js.map +1 -0
  48. package/dist/core/observe-queue.d.ts +18 -0
  49. package/dist/core/observe-queue.d.ts.map +1 -0
  50. package/dist/core/observe-queue.js +56 -0
  51. package/dist/core/observe-queue.js.map +1 -0
  52. package/dist/core/pipeline.d.ts +15 -0
  53. package/dist/core/pipeline.d.ts.map +1 -0
  54. package/dist/core/pipeline.js +114 -0
  55. package/dist/core/pipeline.js.map +1 -0
  56. package/dist/core/plugin-registry.d.ts +13 -0
  57. package/dist/core/plugin-registry.d.ts.map +1 -0
  58. package/dist/core/plugin-registry.js +67 -0
  59. package/dist/core/plugin-registry.js.map +1 -0
  60. package/dist/core/session.d.ts +14 -0
  61. package/dist/core/session.d.ts.map +1 -0
  62. package/dist/core/session.js +95 -0
  63. package/dist/core/session.js.map +1 -0
  64. package/dist/core/truncation.d.ts +11 -0
  65. package/dist/core/truncation.d.ts.map +1 -0
  66. package/dist/core/truncation.js +143 -0
  67. package/dist/core/truncation.js.map +1 -0
  68. package/dist/core/types.d.ts +230 -0
  69. package/dist/core/types.d.ts.map +1 -0
  70. package/dist/core/types.js +50 -0
  71. package/dist/core/types.js.map +1 -0
  72. package/dist/core/utils.d.ts +4 -0
  73. package/dist/core/utils.d.ts.map +1 -0
  74. package/dist/core/utils.js +57 -0
  75. package/dist/core/utils.js.map +1 -0
  76. package/dist/index.d.ts +12 -0
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +27 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/mcp-server/server.d.ts +5 -0
  81. package/dist/mcp-server/server.d.ts.map +1 -0
  82. package/dist/mcp-server/server.js +101 -0
  83. package/dist/mcp-server/server.js.map +1 -0
  84. package/dist/mcp-server/tools.d.ts +201 -0
  85. package/dist/mcp-server/tools.d.ts.map +1 -0
  86. package/dist/mcp-server/tools.js +618 -0
  87. package/dist/mcp-server/tools.js.map +1 -0
  88. package/dist/plugins/knowledge/knowledge-base.d.ts +23 -0
  89. package/dist/plugins/knowledge/knowledge-base.d.ts.map +1 -0
  90. package/dist/plugins/knowledge/knowledge-base.js +165 -0
  91. package/dist/plugins/knowledge/knowledge-base.js.map +1 -0
  92. package/dist/plugins/platforms/claude-code.d.ts +14 -0
  93. package/dist/plugins/platforms/claude-code.d.ts.map +1 -0
  94. package/dist/plugins/platforms/claude-code.js +52 -0
  95. package/dist/plugins/platforms/claude-code.js.map +1 -0
  96. package/dist/plugins/privacy/privacy-engine.d.ts +18 -0
  97. package/dist/plugins/privacy/privacy-engine.d.ts.map +1 -0
  98. package/dist/plugins/privacy/privacy-engine.js +72 -0
  99. package/dist/plugins/privacy/privacy-engine.js.map +1 -0
  100. package/dist/plugins/runtimes/javascript.d.ts +13 -0
  101. package/dist/plugins/runtimes/javascript.d.ts.map +1 -0
  102. package/dist/plugins/runtimes/javascript.js +102 -0
  103. package/dist/plugins/runtimes/javascript.js.map +1 -0
  104. package/dist/plugins/runtimes/python.d.ts +14 -0
  105. package/dist/plugins/runtimes/python.d.ts.map +1 -0
  106. package/dist/plugins/runtimes/python.js +127 -0
  107. package/dist/plugins/runtimes/python.js.map +1 -0
  108. package/dist/plugins/runtimes/shell.d.ts +13 -0
  109. package/dist/plugins/runtimes/shell.d.ts.map +1 -0
  110. package/dist/plugins/runtimes/shell.js +55 -0
  111. package/dist/plugins/runtimes/shell.js.map +1 -0
  112. package/dist/plugins/search/bm25.d.ts +16 -0
  113. package/dist/plugins/search/bm25.d.ts.map +1 -0
  114. package/dist/plugins/search/bm25.js +61 -0
  115. package/dist/plugins/search/bm25.js.map +1 -0
  116. package/dist/plugins/search/fts5-utils.d.ts +2 -0
  117. package/dist/plugins/search/fts5-utils.d.ts.map +1 -0
  118. package/dist/plugins/search/fts5-utils.js +12 -0
  119. package/dist/plugins/search/fts5-utils.js.map +1 -0
  120. package/dist/plugins/search/fusion.d.ts +9 -0
  121. package/dist/plugins/search/fusion.d.ts.map +1 -0
  122. package/dist/plugins/search/fusion.js +45 -0
  123. package/dist/plugins/search/fusion.js.map +1 -0
  124. package/dist/plugins/search/intent.d.ts +5 -0
  125. package/dist/plugins/search/intent.d.ts.map +1 -0
  126. package/dist/plugins/search/intent.js +49 -0
  127. package/dist/plugins/search/intent.js.map +1 -0
  128. package/dist/plugins/search/levenshtein.d.ts +17 -0
  129. package/dist/plugins/search/levenshtein.d.ts.map +1 -0
  130. package/dist/plugins/search/levenshtein.js +99 -0
  131. package/dist/plugins/search/levenshtein.js.map +1 -0
  132. package/dist/plugins/search/trigram.d.ts +16 -0
  133. package/dist/plugins/search/trigram.d.ts.map +1 -0
  134. package/dist/plugins/search/trigram.js +63 -0
  135. package/dist/plugins/search/trigram.js.map +1 -0
  136. package/dist/plugins/storage/better-sqlite3.d.ts +19 -0
  137. package/dist/plugins/storage/better-sqlite3.d.ts.map +1 -0
  138. package/dist/plugins/storage/better-sqlite3.js +82 -0
  139. package/dist/plugins/storage/better-sqlite3.js.map +1 -0
  140. package/dist/plugins/storage/content-store.d.ts +20 -0
  141. package/dist/plugins/storage/content-store.d.ts.map +1 -0
  142. package/dist/plugins/storage/content-store.js +187 -0
  143. package/dist/plugins/storage/content-store.js.map +1 -0
  144. package/dist/plugins/storage/migrations.d.ts +8 -0
  145. package/dist/plugins/storage/migrations.d.ts.map +1 -0
  146. package/dist/plugins/storage/migrations.js +252 -0
  147. package/dist/plugins/storage/migrations.js.map +1 -0
  148. package/dist/plugins/summarizers/binary-summarizer.d.ts +12 -0
  149. package/dist/plugins/summarizers/binary-summarizer.d.ts.map +1 -0
  150. package/dist/plugins/summarizers/binary-summarizer.js +43 -0
  151. package/dist/plugins/summarizers/binary-summarizer.js.map +1 -0
  152. package/dist/plugins/summarizers/build-output-summarizer.d.ts +12 -0
  153. package/dist/plugins/summarizers/build-output-summarizer.d.ts.map +1 -0
  154. package/dist/plugins/summarizers/build-output-summarizer.js +68 -0
  155. package/dist/plugins/summarizers/build-output-summarizer.js.map +1 -0
  156. package/dist/plugins/summarizers/code-summarizer.d.ts +12 -0
  157. package/dist/plugins/summarizers/code-summarizer.d.ts.map +1 -0
  158. package/dist/plugins/summarizers/code-summarizer.js +179 -0
  159. package/dist/plugins/summarizers/code-summarizer.js.map +1 -0
  160. package/dist/plugins/summarizers/csv-summarizer.d.ts +12 -0
  161. package/dist/plugins/summarizers/csv-summarizer.d.ts.map +1 -0
  162. package/dist/plugins/summarizers/csv-summarizer.js +60 -0
  163. package/dist/plugins/summarizers/csv-summarizer.js.map +1 -0
  164. package/dist/plugins/summarizers/error-summarizer.d.ts +15 -0
  165. package/dist/plugins/summarizers/error-summarizer.d.ts.map +1 -0
  166. package/dist/plugins/summarizers/error-summarizer.js +111 -0
  167. package/dist/plugins/summarizers/error-summarizer.js.map +1 -0
  168. package/dist/plugins/summarizers/git-log-summarizer.d.ts +12 -0
  169. package/dist/plugins/summarizers/git-log-summarizer.d.ts.map +1 -0
  170. package/dist/plugins/summarizers/git-log-summarizer.js +76 -0
  171. package/dist/plugins/summarizers/git-log-summarizer.js.map +1 -0
  172. package/dist/plugins/summarizers/html-summarizer.d.ts +12 -0
  173. package/dist/plugins/summarizers/html-summarizer.d.ts.map +1 -0
  174. package/dist/plugins/summarizers/html-summarizer.js +69 -0
  175. package/dist/plugins/summarizers/html-summarizer.js.map +1 -0
  176. package/dist/plugins/summarizers/json-summarizer.d.ts +12 -0
  177. package/dist/plugins/summarizers/json-summarizer.d.ts.map +1 -0
  178. package/dist/plugins/summarizers/json-summarizer.js +132 -0
  179. package/dist/plugins/summarizers/json-summarizer.js.map +1 -0
  180. package/dist/plugins/summarizers/log-summarizer.d.ts +12 -0
  181. package/dist/plugins/summarizers/log-summarizer.d.ts.map +1 -0
  182. package/dist/plugins/summarizers/log-summarizer.js +173 -0
  183. package/dist/plugins/summarizers/log-summarizer.js.map +1 -0
  184. package/dist/plugins/summarizers/markdown-summarizer.d.ts +12 -0
  185. package/dist/plugins/summarizers/markdown-summarizer.d.ts.map +1 -0
  186. package/dist/plugins/summarizers/markdown-summarizer.js +75 -0
  187. package/dist/plugins/summarizers/markdown-summarizer.js.map +1 -0
  188. package/dist/plugins/summarizers/network-summarizer.d.ts +12 -0
  189. package/dist/plugins/summarizers/network-summarizer.d.ts.map +1 -0
  190. package/dist/plugins/summarizers/network-summarizer.js +74 -0
  191. package/dist/plugins/summarizers/network-summarizer.js.map +1 -0
  192. package/dist/plugins/summarizers/shell-summarizer.d.ts +12 -0
  193. package/dist/plugins/summarizers/shell-summarizer.d.ts.map +1 -0
  194. package/dist/plugins/summarizers/shell-summarizer.js +50 -0
  195. package/dist/plugins/summarizers/shell-summarizer.js.map +1 -0
  196. package/dist/plugins/summarizers/test-output-summarizer.d.ts +12 -0
  197. package/dist/plugins/summarizers/test-output-summarizer.d.ts.map +1 -0
  198. package/dist/plugins/summarizers/test-output-summarizer.js +77 -0
  199. package/dist/plugins/summarizers/test-output-summarizer.js.map +1 -0
  200. package/dist/plugins/summarizers/typescript-error-summarizer.d.ts +12 -0
  201. package/dist/plugins/summarizers/typescript-error-summarizer.d.ts.map +1 -0
  202. package/dist/plugins/summarizers/typescript-error-summarizer.js +67 -0
  203. package/dist/plugins/summarizers/typescript-error-summarizer.js.map +1 -0
  204. package/hooks/context-mem-hook.js +77 -0
  205. package/hooks/dashboard-autostart.js +92 -0
  206. package/hooks/dashboard-stop.js +32 -0
  207. package/hooks/hooks.json +40 -0
  208. package/package.json +32 -0
@@ -0,0 +1,12 @@
1
+ import type { SummarizerPlugin, PluginConfig, SummaryResult, SummarizeOpts } from '../../core/types.js';
2
+ export declare class ShellSummarizer implements SummarizerPlugin {
3
+ name: string;
4
+ version: string;
5
+ type: "summarizer";
6
+ contentTypes: string[];
7
+ init(_config: PluginConfig): Promise<void>;
8
+ destroy(): Promise<void>;
9
+ detect(content: string): boolean;
10
+ summarize(content: string, _opts: SummarizeOpts): Promise<SummaryResult>;
11
+ }
12
+ //# sourceMappingURL=shell-summarizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-summarizer.d.ts","sourceRoot":"","sources":["../../../src/plugins/summarizers/shell-summarizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAMxG,qBAAa,eAAgB,YAAW,gBAAgB;IACtD,IAAI,SAAsB;IAC1B,OAAO,SAAW;IAClB,IAAI,EAAG,YAAY,CAAU;IAC7B,YAAY,WAA+B;IAErC,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAC1C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAE9B,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAK1B,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;CAmC/E"}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ShellSummarizer = void 0;
4
+ const utils_js_1 = require("../../core/utils.js");
5
+ const KEEP_LINES = 10;
6
+ const MIN_LINES_TO_SUMMARIZE = 20;
7
+ class ShellSummarizer {
8
+ name = 'shell-summarizer';
9
+ version = '1.0.0';
10
+ type = 'summarizer';
11
+ contentTypes = ['shell', 'command-output'];
12
+ async init(_config) { }
13
+ async destroy() { }
14
+ detect(content) {
15
+ const lineCount = content.split('\n').length;
16
+ return lineCount >= MIN_LINES_TO_SUMMARIZE;
17
+ }
18
+ async summarize(content, _opts) {
19
+ const lines = content.split('\n');
20
+ const tokensOriginal = (0, utils_js_1.estimateTokens)(content);
21
+ if (lines.length < MIN_LINES_TO_SUMMARIZE) {
22
+ return {
23
+ summary: content,
24
+ tokens_original: tokensOriginal,
25
+ tokens_summarized: tokensOriginal,
26
+ savings_pct: 0,
27
+ content_type: 'shell',
28
+ };
29
+ }
30
+ const head = lines.slice(0, KEEP_LINES);
31
+ const tail = lines.slice(-KEEP_LINES);
32
+ const omitted = lines.length - KEEP_LINES * 2;
33
+ const summary = [
34
+ `[${lines.length} lines total]`,
35
+ ...head,
36
+ `... (${omitted} lines omitted) ...`,
37
+ ...tail,
38
+ ].join('\n');
39
+ const tokensSummarized = (0, utils_js_1.estimateTokens)(summary);
40
+ return {
41
+ summary,
42
+ tokens_original: tokensOriginal,
43
+ tokens_summarized: tokensSummarized,
44
+ savings_pct: tokensOriginal > 0 ? Math.round((1 - tokensSummarized / tokensOriginal) * 100) : 0,
45
+ content_type: 'shell',
46
+ };
47
+ }
48
+ }
49
+ exports.ShellSummarizer = ShellSummarizer;
50
+ //# sourceMappingURL=shell-summarizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-summarizer.js","sourceRoot":"","sources":["../../../src/plugins/summarizers/shell-summarizer.ts"],"names":[],"mappings":";;;AACA,kDAAqD;AAErD,MAAM,UAAU,GAAG,EAAE,CAAC;AACtB,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAElC,MAAa,eAAe;IAC1B,IAAI,GAAG,kBAAkB,CAAC;IAC1B,OAAO,GAAG,OAAO,CAAC;IAClB,IAAI,GAAG,YAAqB,CAAC;IAC7B,YAAY,GAAG,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAE3C,KAAK,CAAC,IAAI,CAAC,OAAqB,IAAkB,CAAC;IACnD,KAAK,CAAC,OAAO,KAAmB,CAAC;IAEjC,MAAM,CAAC,OAAe;QACpB,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;QAC7C,OAAO,SAAS,IAAI,sBAAsB,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,OAAe,EAAE,KAAoB;QACnD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,cAAc,GAAG,IAAA,yBAAc,EAAC,OAAO,CAAC,CAAC;QAE/C,IAAI,KAAK,CAAC,MAAM,GAAG,sBAAsB,EAAE,CAAC;YAC1C,OAAO;gBACL,OAAO,EAAE,OAAO;gBAChB,eAAe,EAAE,cAAc;gBAC/B,iBAAiB,EAAE,cAAc;gBACjC,WAAW,EAAE,CAAC;gBACd,YAAY,EAAE,OAAO;aACtB,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,GAAG,UAAU,GAAG,CAAC,CAAC;QAE9C,MAAM,OAAO,GAAG;YACd,IAAI,KAAK,CAAC,MAAM,eAAe;YAC/B,GAAG,IAAI;YACP,QAAQ,OAAO,qBAAqB;YACpC,GAAG,IAAI;SACR,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,MAAM,gBAAgB,GAAG,IAAA,yBAAc,EAAC,OAAO,CAAC,CAAC;QAEjD,OAAO;YACL,OAAO;YACP,eAAe,EAAE,cAAc;YAC/B,iBAAiB,EAAE,gBAAgB;YACnC,WAAW,EAAE,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,gBAAgB,GAAG,cAAc,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/F,YAAY,EAAE,OAAO;SACtB,CAAC;IACJ,CAAC;CACF;AAjDD,0CAiDC"}
@@ -0,0 +1,12 @@
1
+ import type { SummarizerPlugin, PluginConfig, SummaryResult, SummarizeOpts } from '../../core/types.js';
2
+ export declare class TestOutputSummarizer implements SummarizerPlugin {
3
+ name: string;
4
+ version: string;
5
+ type: "summarizer";
6
+ contentTypes: string[];
7
+ init(_config: PluginConfig): Promise<void>;
8
+ destroy(): Promise<void>;
9
+ detect(content: string): boolean;
10
+ summarize(content: string, _opts: SummarizeOpts): Promise<SummaryResult>;
11
+ }
12
+ //# sourceMappingURL=test-output-summarizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-output-summarizer.d.ts","sourceRoot":"","sources":["../../../src/plugins/summarizers/test-output-summarizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAaxG,qBAAa,oBAAqB,YAAW,gBAAgB;IAC3D,IAAI,SAA4B;IAChC,OAAO,SAAW;IAClB,IAAI,EAAG,YAAY,CAAU;IAC7B,YAAY,WAAmB;IAEzB,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAC1C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAE9B,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI1B,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;CA0D/E"}
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TestOutputSummarizer = void 0;
4
+ const utils_js_1 = require("../../core/utils.js");
5
+ const TEST_DETECT_PATTERN = /Tests:.*total|PASS\s|FAIL\s|test suites/i;
6
+ const TESTS_LINE_REGEX = /^Tests:\s*(.+)$/m;
7
+ const PASS_COUNT_REGEX = /(\d+)\s+passed/i;
8
+ const FAIL_COUNT_REGEX = /(\d+)\s+failed/i;
9
+ const SKIP_COUNT_REGEX = /(\d+)\s+(?:skipped|pending|todo)/i;
10
+ const TOTAL_COUNT_REGEX = /(\d+)\s+total/i;
11
+ const SUITE_COUNT_REGEX = /Test Suites:\s*.*?(\d+)\s+total/i;
12
+ const DURATION_REGEX = /Time:\s*([\d.]+\s*(?:ms|s|m))/i;
13
+ const FAILED_TEST_REGEX = /(?:FAIL|✕|✗|×)\s+(.+)/g;
14
+ class TestOutputSummarizer {
15
+ name = 'test-output-summarizer';
16
+ version = '1.0.0';
17
+ type = 'summarizer';
18
+ contentTypes = ['test-output'];
19
+ async init(_config) { }
20
+ async destroy() { }
21
+ detect(content) {
22
+ return TEST_DETECT_PATTERN.test(content);
23
+ }
24
+ async summarize(content, _opts) {
25
+ const tokensOriginal = (0, utils_js_1.estimateTokens)(content);
26
+ // Extract the "Tests:" line specifically to avoid matching "Test Suites:" counts
27
+ const testsLineMatch = content.match(TESTS_LINE_REGEX);
28
+ const testsLine = testsLineMatch ? testsLineMatch[1] : content;
29
+ const passMatch = testsLine.match(PASS_COUNT_REGEX);
30
+ const failMatch = testsLine.match(FAIL_COUNT_REGEX);
31
+ const skipMatch = testsLine.match(SKIP_COUNT_REGEX);
32
+ const totalMatch = testsLine.match(TOTAL_COUNT_REGEX);
33
+ const suiteMatch = content.match(SUITE_COUNT_REGEX);
34
+ const durationMatch = content.match(DURATION_REGEX);
35
+ const passed = passMatch ? parseInt(passMatch[1], 10) : 0;
36
+ const failed = failMatch ? parseInt(failMatch[1], 10) : 0;
37
+ const skipped = skipMatch ? parseInt(skipMatch[1], 10) : 0;
38
+ const total = totalMatch ? parseInt(totalMatch[1], 10) : passed + failed + skipped;
39
+ const suites = suiteMatch ? parseInt(suiteMatch[1], 10) : 0;
40
+ const duration = durationMatch ? durationMatch[1] : 'unknown';
41
+ // Extract failed test names (up to 10)
42
+ const failedTests = [];
43
+ let failedMatch;
44
+ const failedRegex = new RegExp(FAILED_TEST_REGEX.source, 'g');
45
+ while ((failedMatch = failedRegex.exec(content)) !== null && failedTests.length < 10) {
46
+ failedTests.push(failedMatch[1].trim());
47
+ }
48
+ const summaryParts = [
49
+ `# Test Results`,
50
+ '',
51
+ `## Counts`,
52
+ ` Passed: ${passed}`,
53
+ ` Failed: ${failed}`,
54
+ ` Skipped: ${skipped}`,
55
+ ` Total: ${total}`,
56
+ ` Suites: ${suites}`,
57
+ ` Duration: ${duration}`,
58
+ ];
59
+ if (failedTests.length > 0) {
60
+ summaryParts.push('', `## Failed tests (${failedTests.length})`);
61
+ for (const t of failedTests) {
62
+ summaryParts.push(` - ${t}`);
63
+ }
64
+ }
65
+ const summary = summaryParts.join('\n');
66
+ const tokensSummarized = (0, utils_js_1.estimateTokens)(summary);
67
+ return {
68
+ summary,
69
+ tokens_original: tokensOriginal,
70
+ tokens_summarized: tokensSummarized,
71
+ savings_pct: tokensOriginal > 0 ? Math.round((1 - tokensSummarized / tokensOriginal) * 100) : 0,
72
+ content_type: 'test-output',
73
+ };
74
+ }
75
+ }
76
+ exports.TestOutputSummarizer = TestOutputSummarizer;
77
+ //# sourceMappingURL=test-output-summarizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-output-summarizer.js","sourceRoot":"","sources":["../../../src/plugins/summarizers/test-output-summarizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { SummarizerPlugin, PluginConfig, SummaryResult, SummarizeOpts } from '../../core/types.js';
2
+ export declare class TypescriptErrorSummarizer implements SummarizerPlugin {
3
+ name: string;
4
+ version: string;
5
+ type: "summarizer";
6
+ contentTypes: string[];
7
+ init(_config: PluginConfig): Promise<void>;
8
+ destroy(): Promise<void>;
9
+ detect(content: string): boolean;
10
+ summarize(content: string, _opts: SummarizeOpts): Promise<SummaryResult>;
11
+ }
12
+ //# sourceMappingURL=typescript-error-summarizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typescript-error-summarizer.d.ts","sourceRoot":"","sources":["../../../src/plugins/summarizers/typescript-error-summarizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAMxG,qBAAa,yBAA0B,YAAW,gBAAgB;IAChE,IAAI,SAAiC;IACrC,OAAO,SAAW;IAClB,IAAI,EAAG,YAAY,CAAU;IAC7B,YAAY,WAAwB;IAE9B,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAC1C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAE9B,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAI1B,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;CAwD/E"}
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TypescriptErrorSummarizer = void 0;
4
+ const utils_js_1 = require("../../core/utils.js");
5
+ const TS_ERROR_PATTERN = /error TS\d+:/;
6
+ const TS_ERROR_LINE_REGEX = /^(.+?)\(\d+,\d+\):\s*error (TS\d+):\s*(.+)$/;
7
+ class TypescriptErrorSummarizer {
8
+ name = 'typescript-error-summarizer';
9
+ version = '1.0.0';
10
+ type = 'summarizer';
11
+ contentTypes = ['typescript-error'];
12
+ async init(_config) { }
13
+ async destroy() { }
14
+ detect(content) {
15
+ return TS_ERROR_PATTERN.test(content);
16
+ }
17
+ async summarize(content, _opts) {
18
+ const lines = content.split('\n');
19
+ const tokensOriginal = (0, utils_js_1.estimateTokens)(content);
20
+ const errorsPerFile = new Map();
21
+ const errorCodes = new Map();
22
+ const errorMessages = [];
23
+ for (const line of lines) {
24
+ const match = line.match(TS_ERROR_LINE_REGEX);
25
+ if (match) {
26
+ const [, file, code, message] = match;
27
+ errorsPerFile.set(file, (errorsPerFile.get(file) || 0) + 1);
28
+ errorCodes.set(code, (errorCodes.get(code) || 0) + 1);
29
+ if (errorMessages.length < 3) {
30
+ errorMessages.push(`${code}: ${message}`);
31
+ }
32
+ }
33
+ }
34
+ const totalErrors = Array.from(errorsPerFile.values()).reduce((a, b) => a + b, 0);
35
+ // Sort error codes by count descending
36
+ const sortedCodes = Array.from(errorCodes.entries())
37
+ .sort((a, b) => b[1] - a[1])
38
+ .slice(0, 10);
39
+ // Sort files by error count descending
40
+ const sortedFiles = Array.from(errorsPerFile.entries())
41
+ .sort((a, b) => b[1] - a[1])
42
+ .slice(0, 10);
43
+ const summaryParts = [
44
+ `# TypeScript Errors: ${totalErrors} total`,
45
+ '',
46
+ `## Errors per file (top ${sortedFiles.length})`,
47
+ ...sortedFiles.map(([file, count]) => ` ${file}: ${count}`),
48
+ '',
49
+ `## Error codes (top ${sortedCodes.length})`,
50
+ ...sortedCodes.map(([code, count]) => ` ${code}: ${count} occurrences`),
51
+ '',
52
+ `## First errors`,
53
+ ...errorMessages.map(m => ` - ${m}`),
54
+ ];
55
+ const summary = summaryParts.join('\n');
56
+ const tokensSummarized = (0, utils_js_1.estimateTokens)(summary);
57
+ return {
58
+ summary,
59
+ tokens_original: tokensOriginal,
60
+ tokens_summarized: tokensSummarized,
61
+ savings_pct: tokensOriginal > 0 ? Math.round((1 - tokensSummarized / tokensOriginal) * 100) : 0,
62
+ content_type: 'typescript-error',
63
+ };
64
+ }
65
+ }
66
+ exports.TypescriptErrorSummarizer = TypescriptErrorSummarizer;
67
+ //# sourceMappingURL=typescript-error-summarizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typescript-error-summarizer.js","sourceRoot":"","sources":["../../../src/plugins/summarizers/typescript-error-summarizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // Read stdin
5
+ let input = '';
6
+ try {
7
+ const fs = require('fs');
8
+ input = fs.readFileSync(0, 'utf8');
9
+ } catch { process.exit(0); }
10
+
11
+ if (!input.trim()) process.exit(0);
12
+
13
+ let data;
14
+ try {
15
+ data = JSON.parse(input);
16
+ } catch { process.exit(0); }
17
+
18
+ const toolName = data.tool_name;
19
+ const toolInput = data.tool_input || {};
20
+ const toolOutput = data.tool_output || {};
21
+
22
+ // Classify what to observe
23
+ function getObservation(name, inp, out) {
24
+ const stdout = out.stdout || out.content || out.output || '';
25
+ const content = typeof stdout === 'string' ? stdout : JSON.stringify(stdout);
26
+
27
+ if (!content || content.length < 10) return null;
28
+
29
+ switch (name) {
30
+ case 'Bash': return { content, type: 'log', source: 'Bash' };
31
+ case 'Read': return { content, type: 'code', source: 'Read', filePath: inp.file_path };
32
+ case 'Write':
33
+ case 'Edit': return { content: inp.content || content, type: 'code', source: name, filePath: inp.file_path };
34
+ case 'Grep':
35
+ case 'Glob': return { content, type: 'context', source: name };
36
+ default: return null;
37
+ }
38
+ }
39
+
40
+ const obs = getObservation(toolName, toolInput, toolOutput);
41
+ if (!obs) process.exit(0);
42
+
43
+ // Strip basic private tags before sending
44
+ let cleaned = obs.content;
45
+ cleaned = cleaned.replace(/<private>[\s\S]*?<\/private>/gi, '');
46
+ cleaned = cleaned.replace(/<redact>[\s\S]*?<\/redact>/gi, '[REDACTED]');
47
+
48
+ if (cleaned.length < 10) process.exit(0);
49
+
50
+ // Fire-and-forget POST to MCP server
51
+ const http = require('http');
52
+ const port = parseInt(process.env.CONTEXT_MEM_PORT || '51893', 10);
53
+ const payload = JSON.stringify({
54
+ jsonrpc: '2.0',
55
+ method: 'tools/call',
56
+ params: {
57
+ name: 'observe',
58
+ arguments: {
59
+ content: cleaned.slice(0, 50000), // Cap at 50KB
60
+ type: obs.type,
61
+ source: obs.source,
62
+ }
63
+ }
64
+ });
65
+
66
+ const req = http.request({
67
+ hostname: '127.0.0.1',
68
+ port,
69
+ path: '/',
70
+ method: 'POST',
71
+ headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) },
72
+ timeout: 500,
73
+ }, () => {});
74
+
75
+ req.on('error', () => {}); // Fire and forget
76
+ req.write(payload);
77
+ req.end();
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * context-mem dashboard auto-start hook
6
+ *
7
+ * Fires on SessionStart — starts the dashboard server as a background process
8
+ * if it's not already running.
9
+ *
10
+ * Hook type: SessionStart
11
+ */
12
+
13
+ const { spawn, execSync } = require('child_process');
14
+ const path = require('path');
15
+ const fs = require('fs');
16
+ const net = require('net');
17
+
18
+ const PORT = parseInt(process.env.CONTEXT_MEM_DASHBOARD_PORT || '51893', 10);
19
+ const PROJECT_DIR = process.cwd();
20
+ const DB_PATH = path.join(PROJECT_DIR, '.context-mem', 'store.db');
21
+ const PID_FILE = path.join(PROJECT_DIR, '.context-mem', 'dashboard.pid');
22
+ const SERVER_SCRIPT = path.join(__dirname, '..', 'dashboard', 'server.js');
23
+
24
+ // Skip if no database
25
+ if (!fs.existsSync(DB_PATH)) process.exit(0);
26
+
27
+ // Skip if server script missing
28
+ if (!fs.existsSync(SERVER_SCRIPT)) process.exit(0);
29
+
30
+ // Check if already running via PID file
31
+ function isRunning(pid) {
32
+ try {
33
+ process.kill(pid, 0);
34
+ return true;
35
+ } catch {
36
+ return false;
37
+ }
38
+ }
39
+
40
+ // Check if port is in use
41
+ function isPortInUse(port) {
42
+ return new Promise((resolve) => {
43
+ const s = net.createConnection({ port, host: '127.0.0.1' });
44
+ s.on('connect', () => { s.destroy(); resolve(true); });
45
+ s.on('error', () => resolve(false));
46
+ s.setTimeout(300, () => { s.destroy(); resolve(false); });
47
+ });
48
+ }
49
+
50
+ async function main() {
51
+ // Check PID file
52
+ if (fs.existsSync(PID_FILE)) {
53
+ const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8').trim(), 10);
54
+ if (pid && isRunning(pid)) {
55
+ // Already running
56
+ process.exit(0);
57
+ }
58
+ // Stale PID file
59
+ fs.unlinkSync(PID_FILE);
60
+ }
61
+
62
+ // Check if port is already in use (maybe started manually)
63
+ if (await isPortInUse(PORT)) {
64
+ process.exit(0);
65
+ }
66
+
67
+ // Start dashboard in background
68
+ const child = spawn('node', [
69
+ SERVER_SCRIPT,
70
+ '--port', String(PORT),
71
+ '--db', DB_PATH,
72
+ '--project', PROJECT_DIR,
73
+ '--no-open', // Don't auto-open browser on hook start
74
+ ], {
75
+ detached: true,
76
+ stdio: 'ignore',
77
+ env: { ...process.env },
78
+ });
79
+
80
+ child.unref();
81
+
82
+ // Write PID
83
+ fs.mkdirSync(path.dirname(PID_FILE), { recursive: true });
84
+ fs.writeFileSync(PID_FILE, String(child.pid));
85
+
86
+ // Output for hook feedback
87
+ console.log(JSON.stringify({
88
+ result: `Dashboard started on port ${PORT} (pid: ${child.pid})`
89
+ }));
90
+ }
91
+
92
+ main().catch(() => process.exit(0));
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * context-mem dashboard stop hook
6
+ *
7
+ * Fires on Stop — gracefully shuts down the dashboard server.
8
+ *
9
+ * Hook type: Stop
10
+ */
11
+
12
+ const path = require('path');
13
+ const fs = require('fs');
14
+
15
+ const PROJECT_DIR = process.cwd();
16
+ const PID_FILE = path.join(PROJECT_DIR, '.context-mem', 'dashboard.pid');
17
+
18
+ if (!fs.existsSync(PID_FILE)) process.exit(0);
19
+
20
+ const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8').trim(), 10);
21
+ if (!pid) {
22
+ fs.unlinkSync(PID_FILE);
23
+ process.exit(0);
24
+ }
25
+
26
+ try {
27
+ process.kill(pid, 'SIGTERM');
28
+ fs.unlinkSync(PID_FILE);
29
+ } catch {
30
+ // Process already dead
31
+ try { fs.unlinkSync(PID_FILE); } catch {}
32
+ }
@@ -0,0 +1,40 @@
1
+ {
2
+ "description": "context-mem hooks — observation capture and dashboard auto-start",
3
+ "hooks": {
4
+ "SessionStart": [
5
+ {
6
+ "matcher": "startup|clear|compact",
7
+ "hooks": [
8
+ {
9
+ "type": "command",
10
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/dashboard-autostart.js\"",
11
+ "timeout": 10
12
+ }
13
+ ]
14
+ }
15
+ ],
16
+ "PostToolUse": [
17
+ {
18
+ "matcher": "Bash|Read|Write|Edit|Grep|Glob",
19
+ "hooks": [
20
+ {
21
+ "type": "command",
22
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/context-mem-hook.js\"",
23
+ "timeout": 5
24
+ }
25
+ ]
26
+ }
27
+ ],
28
+ "Stop": [
29
+ {
30
+ "hooks": [
31
+ {
32
+ "type": "command",
33
+ "command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/dashboard-stop.js\"",
34
+ "timeout": 5
35
+ }
36
+ ]
37
+ }
38
+ ]
39
+ }
40
+ }
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "context-mem",
3
+ "version": "0.1.0",
4
+ "description": "Context optimization for AI coding assistants — 90%+ token savings via summarization, search, and progressive disclosure",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "bin": {
8
+ "context-mem": "./dist/cli/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "test": "node --test 'dist/tests/**/*.test.js'",
14
+ "test:watch": "tsc --watch & node --test --watch 'dist/tests/**/*.test.js'",
15
+ "lint": "tsc --noEmit",
16
+ "prepublishOnly": "npm run build && npm test"
17
+ },
18
+ "keywords": ["mcp", "context", "llm", "token-optimization", "claude-code", "ai-coding"],
19
+ "author": "Juba Kitiashvili",
20
+ "license": "MIT",
21
+ "files": ["dist", "!dist/tests", "hooks", ".context-mem.json.example"],
22
+ "engines": { "node": ">=18" },
23
+ "dependencies": {
24
+ "@modelcontextprotocol/sdk": "^1.0.0",
25
+ "better-sqlite3": "^11.0.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/better-sqlite3": "^7.6.0",
29
+ "@types/node": "^20.0.0",
30
+ "typescript": "^5.5.0"
31
+ }
32
+ }