@stackmemoryai/stackmemory 0.2.9 → 0.3.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 (575) hide show
  1. package/dist/agents/core/agent-task-manager.js +512 -0
  2. package/dist/agents/core/agent-task-manager.js.map +7 -0
  3. package/dist/agents/verifiers/base-verifier.js +129 -0
  4. package/dist/agents/verifiers/base-verifier.js.map +7 -0
  5. package/dist/agents/verifiers/formatter-verifier.js +126 -0
  6. package/dist/agents/verifiers/formatter-verifier.js.map +7 -0
  7. package/dist/agents/verifiers/llm-judge.js +248 -0
  8. package/dist/agents/verifiers/llm-judge.js.map +7 -0
  9. package/dist/cli/__tests__/index.test.js +290 -0
  10. package/dist/cli/__tests__/index.test.js.map +7 -0
  11. package/dist/cli/auto-detect.js +317 -0
  12. package/dist/cli/auto-detect.js.map +7 -0
  13. package/dist/cli/browser-test.js +29 -0
  14. package/dist/cli/browser-test.js.map +7 -0
  15. package/dist/cli/claude-sm.js +369 -0
  16. package/dist/cli/claude-sm.js.map +7 -0
  17. package/dist/cli/codex-sm.js +283 -0
  18. package/dist/cli/codex-sm.js.map +7 -0
  19. package/dist/cli/commands/agent.js +286 -0
  20. package/dist/cli/commands/agent.js.map +7 -0
  21. package/dist/cli/commands/config.js +199 -0
  22. package/dist/cli/commands/config.js.map +7 -0
  23. package/dist/cli/commands/context.js +327 -0
  24. package/dist/cli/commands/context.js.map +7 -0
  25. package/dist/cli/commands/handoff.js +191 -0
  26. package/dist/cli/commands/handoff.js.map +7 -0
  27. package/dist/cli/commands/linear-test.js +115 -0
  28. package/dist/cli/commands/linear-test.js.map +7 -0
  29. package/dist/cli/commands/linear.js +378 -0
  30. package/dist/cli/commands/linear.js.map +7 -0
  31. package/dist/cli/commands/log.js +165 -0
  32. package/dist/cli/commands/log.js.map +7 -0
  33. package/dist/cli/commands/onboard.js +349 -0
  34. package/dist/cli/commands/onboard.js.map +7 -0
  35. package/dist/cli/commands/projects.js +195 -0
  36. package/dist/cli/commands/projects.js.map +7 -0
  37. package/dist/cli/commands/search.js +152 -0
  38. package/dist/cli/commands/search.js.map +7 -0
  39. package/dist/cli/commands/session.js +179 -0
  40. package/dist/cli/commands/session.js.map +7 -0
  41. package/dist/cli/commands/tasks.js +205 -0
  42. package/dist/cli/commands/tasks.js.map +7 -0
  43. package/dist/cli/commands/webhook.js +131 -0
  44. package/dist/cli/commands/webhook.js.map +7 -0
  45. package/dist/cli/commands/worktree.js +276 -0
  46. package/dist/cli/commands/worktree.js.map +7 -0
  47. package/dist/cli/index.js +953 -0
  48. package/dist/cli/index.js.map +7 -0
  49. package/dist/cli/utils/viewer.js +92 -0
  50. package/dist/cli/utils/viewer.js.map +7 -0
  51. package/dist/core/config/__tests__/config-manager.test.js +248 -0
  52. package/dist/core/config/__tests__/config-manager.test.js.map +7 -0
  53. package/dist/core/config/config-manager.js +368 -0
  54. package/dist/core/config/config-manager.js.map +7 -0
  55. package/dist/core/config/types.js +140 -0
  56. package/dist/core/config/types.js.map +7 -0
  57. package/dist/core/context/__tests__/frame-manager.test.js +879 -0
  58. package/dist/core/context/__tests__/frame-manager.test.js.map +7 -0
  59. package/dist/core/context/auto-context.js +72 -0
  60. package/dist/core/context/auto-context.js.map +7 -0
  61. package/dist/core/context/compaction-handler.js +326 -0
  62. package/dist/core/context/compaction-handler.js.map +7 -0
  63. package/dist/core/context/frame-database.js +376 -0
  64. package/dist/core/context/frame-database.js.map +7 -0
  65. package/dist/core/context/frame-digest.js +239 -0
  66. package/dist/core/context/frame-digest.js.map +7 -0
  67. package/dist/core/context/frame-manager.js +682 -0
  68. package/dist/core/context/frame-manager.js.map +7 -0
  69. package/dist/core/context/frame-stack.js +270 -0
  70. package/dist/core/context/frame-stack.js.map +7 -0
  71. package/dist/core/context/frame-types.js +1 -0
  72. package/dist/core/context/frame-types.js.map +7 -0
  73. package/dist/core/context/index.js +33 -0
  74. package/dist/core/context/index.js.map +7 -0
  75. package/dist/core/context/model-aware-compaction.js +619 -0
  76. package/dist/core/context/model-aware-compaction.js.map +7 -0
  77. package/dist/core/context/refactored-frame-manager.js +393 -0
  78. package/dist/core/context/refactored-frame-manager.js.map +7 -0
  79. package/dist/core/database/batch-operations.js +329 -0
  80. package/dist/core/database/batch-operations.js.map +7 -0
  81. package/dist/core/database/connection-pool.js +224 -0
  82. package/dist/core/database/connection-pool.js.map +7 -0
  83. package/dist/core/database/query-cache.js +284 -0
  84. package/dist/core/database/query-cache.js.map +7 -0
  85. package/dist/core/digest/__tests__/enhanced-hybrid-digest.test.js +379 -0
  86. package/dist/core/digest/__tests__/enhanced-hybrid-digest.test.js.map +7 -0
  87. package/dist/core/digest/__tests__/frame-digest-integration.test.js +230 -0
  88. package/dist/core/digest/__tests__/frame-digest-integration.test.js.map +7 -0
  89. package/dist/core/digest/enhanced-hybrid-digest.js +267 -0
  90. package/dist/core/digest/enhanced-hybrid-digest.js.map +7 -0
  91. package/dist/core/digest/frame-digest-integration.js +172 -0
  92. package/dist/core/digest/frame-digest-integration.js.map +7 -0
  93. package/dist/core/digest/hybrid-digest-generator.js +549 -0
  94. package/dist/core/digest/hybrid-digest-generator.js.map +7 -0
  95. package/dist/core/digest/index.js +5 -0
  96. package/dist/core/digest/index.js.map +7 -0
  97. package/dist/core/digest/types.js +21 -0
  98. package/dist/core/digest/types.js.map +7 -0
  99. package/dist/core/errors/__tests__/error-handling.test.js +270 -0
  100. package/dist/core/errors/__tests__/error-handling.test.js.map +7 -0
  101. package/dist/core/errors/index.js +239 -0
  102. package/dist/core/errors/index.js.map +7 -0
  103. package/dist/core/errors/recovery.js +258 -0
  104. package/dist/core/errors/recovery.js.map +7 -0
  105. package/dist/core/merge/__tests__/conflict-scenarios.test.js +414 -0
  106. package/dist/core/merge/__tests__/conflict-scenarios.test.js.map +7 -0
  107. package/dist/core/merge/conflict-detector.js +424 -0
  108. package/dist/core/merge/conflict-detector.js.map +7 -0
  109. package/dist/core/merge/index.js +5 -0
  110. package/dist/core/merge/index.js.map +7 -0
  111. package/dist/core/merge/resolution-engine.js +565 -0
  112. package/dist/core/merge/resolution-engine.js.map +7 -0
  113. package/dist/core/merge/stack-diff.js +528 -0
  114. package/dist/core/merge/stack-diff.js.map +7 -0
  115. package/dist/core/merge/types.js +1 -0
  116. package/dist/core/merge/types.js.map +7 -0
  117. package/dist/core/monitoring/error-handler.js +278 -0
  118. package/dist/core/monitoring/error-handler.js.map +7 -0
  119. package/dist/core/monitoring/logger.js +115 -0
  120. package/dist/core/monitoring/logger.js.map +7 -0
  121. package/dist/core/monitoring/metrics.js +157 -0
  122. package/dist/core/monitoring/metrics.js.map +7 -0
  123. package/dist/core/monitoring/progress-tracker.js +174 -0
  124. package/dist/core/monitoring/progress-tracker.js.map +7 -0
  125. package/dist/core/performance/context-cache.js +269 -0
  126. package/dist/core/performance/context-cache.js.map +7 -0
  127. package/dist/core/performance/index.js +7 -0
  128. package/dist/core/performance/index.js.map +7 -0
  129. package/dist/core/performance/lazy-context-loader.js +319 -0
  130. package/dist/core/performance/lazy-context-loader.js.map +7 -0
  131. package/dist/core/performance/monitor.js +217 -0
  132. package/dist/core/performance/monitor.js.map +7 -0
  133. package/dist/core/performance/optimized-frame-context.js +326 -0
  134. package/dist/core/performance/optimized-frame-context.js.map +7 -0
  135. package/dist/core/performance/performance-benchmark.js +269 -0
  136. package/dist/core/performance/performance-benchmark.js.map +7 -0
  137. package/dist/core/performance/performance-profiler.js +318 -0
  138. package/dist/core/performance/performance-profiler.js.map +7 -0
  139. package/dist/core/performance/streaming-jsonl-parser.js +187 -0
  140. package/dist/core/performance/streaming-jsonl-parser.js.map +7 -0
  141. package/dist/core/persistence/postgres-adapter.js +345 -0
  142. package/dist/core/persistence/postgres-adapter.js.map +7 -0
  143. package/dist/core/projects/project-manager.js +699 -0
  144. package/dist/core/projects/project-manager.js.map +7 -0
  145. package/dist/core/query/__tests__/query-parser.test.js +301 -0
  146. package/dist/core/query/__tests__/query-parser.test.js.map +7 -0
  147. package/dist/core/query/__tests__/query-templates.test.js +210 -0
  148. package/dist/core/query/__tests__/query-templates.test.js.map +7 -0
  149. package/dist/core/query/query-parser.js +366 -0
  150. package/dist/core/query/query-parser.js.map +7 -0
  151. package/dist/core/query/query-templates.js +317 -0
  152. package/dist/core/query/query-templates.js.map +7 -0
  153. package/dist/core/retrieval/index.js +4 -0
  154. package/dist/core/retrieval/index.js.map +7 -0
  155. package/dist/core/retrieval/llm-context-retrieval.js +577 -0
  156. package/dist/core/retrieval/llm-context-retrieval.js.map +7 -0
  157. package/dist/core/retrieval/summary-generator.js +585 -0
  158. package/dist/core/retrieval/summary-generator.js.map +7 -0
  159. package/dist/core/retrieval/types.js +17 -0
  160. package/dist/core/retrieval/types.js.map +7 -0
  161. package/dist/core/session/index.js +11 -0
  162. package/dist/core/session/index.js.map +7 -0
  163. package/dist/core/session/session-manager.js +297 -0
  164. package/dist/core/session/session-manager.js.map +7 -0
  165. package/dist/core/trace/cli-trace-wrapper.js +110 -0
  166. package/dist/core/trace/cli-trace-wrapper.js.map +7 -0
  167. package/dist/core/trace/db-trace-wrapper.js +215 -0
  168. package/dist/core/trace/db-trace-wrapper.js.map +7 -0
  169. package/dist/core/trace/debug-trace.js +385 -0
  170. package/dist/core/trace/debug-trace.js.map +7 -0
  171. package/dist/core/trace/index.js +158 -0
  172. package/dist/core/trace/index.js.map +7 -0
  173. package/dist/core/trace/linear-api-wrapper.js +169 -0
  174. package/dist/core/trace/linear-api-wrapper.js.map +7 -0
  175. package/dist/core/trace/trace-demo.js +135 -0
  176. package/dist/core/trace/trace-demo.js.map +7 -0
  177. package/dist/core/trace/trace-detector.demo.js +138 -0
  178. package/dist/core/trace/trace-detector.demo.js.map +7 -0
  179. package/dist/core/trace/trace-detector.js +386 -0
  180. package/dist/core/trace/trace-detector.js.map +7 -0
  181. package/dist/core/trace/trace-detector.test.js +401 -0
  182. package/dist/core/trace/trace-detector.test.js.map +7 -0
  183. package/dist/core/trace/trace-store.js +341 -0
  184. package/dist/core/trace/trace-store.js.map +7 -0
  185. package/dist/core/trace/types.js +73 -0
  186. package/dist/core/trace/types.js.map +7 -0
  187. package/dist/core/types.js +1 -0
  188. package/dist/core/types.js.map +7 -0
  189. package/dist/core/utils/update-checker.js +214 -0
  190. package/dist/core/utils/update-checker.js.map +7 -0
  191. package/dist/core/worktree/worktree-manager.js +450 -0
  192. package/dist/core/worktree/worktree-manager.js.map +7 -0
  193. package/dist/features/analytics/api/analytics-api.js +283 -0
  194. package/dist/features/analytics/api/analytics-api.js.map +7 -0
  195. package/dist/features/analytics/core/analytics-service.js +267 -0
  196. package/dist/features/analytics/core/analytics-service.js.map +7 -0
  197. package/dist/features/analytics/index.js +14 -0
  198. package/dist/features/analytics/index.js.map +7 -0
  199. package/dist/features/analytics/queries/metrics-queries.js +273 -0
  200. package/dist/features/analytics/queries/metrics-queries.js.map +7 -0
  201. package/dist/features/analytics/types/metrics.js +1 -0
  202. package/dist/features/analytics/types/metrics.js.map +7 -0
  203. package/dist/features/browser/browser-mcp.js +488 -0
  204. package/dist/features/browser/browser-mcp.js.map +7 -0
  205. package/dist/features/tasks/__tests__/pebbles-task-store.test.js +747 -0
  206. package/dist/features/tasks/__tests__/pebbles-task-store.test.js.map +7 -0
  207. package/dist/features/tasks/pebbles-task-store.js +647 -0
  208. package/dist/features/tasks/pebbles-task-store.js.map +7 -0
  209. package/dist/features/tasks/task-aware-context.js +406 -0
  210. package/dist/features/tasks/task-aware-context.js.map +7 -0
  211. package/dist/index.js +21 -0
  212. package/dist/index.js.map +7 -0
  213. package/dist/integrations/linear/__tests__/auth.test.js +558 -0
  214. package/dist/integrations/linear/__tests__/auth.test.js.map +7 -0
  215. package/dist/integrations/linear/__tests__/sync-service.test.js +760 -0
  216. package/dist/integrations/linear/__tests__/sync-service.test.js.map +7 -0
  217. package/dist/integrations/linear/auth.js +308 -0
  218. package/dist/integrations/linear/auth.js.map +7 -0
  219. package/dist/integrations/linear/auto-sync.js +244 -0
  220. package/dist/integrations/linear/auto-sync.js.map +7 -0
  221. package/dist/integrations/linear/client.js +448 -0
  222. package/dist/integrations/linear/client.js.map +7 -0
  223. package/dist/integrations/linear/config.js +115 -0
  224. package/dist/integrations/linear/config.js.map +7 -0
  225. package/dist/integrations/linear/sync-manager.js +233 -0
  226. package/dist/integrations/linear/sync-manager.js.map +7 -0
  227. package/dist/integrations/linear/sync-service.js +214 -0
  228. package/dist/integrations/linear/sync-service.js.map +7 -0
  229. package/dist/integrations/linear/sync.js +565 -0
  230. package/dist/integrations/linear/sync.js.map +7 -0
  231. package/dist/integrations/linear/types.js +1 -0
  232. package/dist/integrations/linear/types.js.map +7 -0
  233. package/dist/integrations/linear/webhook-server.js +204 -0
  234. package/dist/integrations/linear/webhook-server.js.map +7 -0
  235. package/dist/integrations/linear/webhook.js +269 -0
  236. package/dist/integrations/linear/webhook.js.map +7 -0
  237. package/dist/integrations/mcp/__tests__/server.test.js +798 -0
  238. package/dist/integrations/mcp/__tests__/server.test.js.map +7 -0
  239. package/dist/integrations/mcp/handlers/context-handlers.js +253 -0
  240. package/dist/integrations/mcp/handlers/context-handlers.js.map +7 -0
  241. package/dist/integrations/mcp/handlers/index.js +134 -0
  242. package/dist/integrations/mcp/handlers/index.js.map +7 -0
  243. package/dist/integrations/mcp/handlers/linear-handlers.js +243 -0
  244. package/dist/integrations/mcp/handlers/linear-handlers.js.map +7 -0
  245. package/dist/integrations/mcp/handlers/task-handlers.js +235 -0
  246. package/dist/integrations/mcp/handlers/task-handlers.js.map +7 -0
  247. package/dist/integrations/mcp/handlers/trace-handlers.js +304 -0
  248. package/dist/integrations/mcp/handlers/trace-handlers.js.map +7 -0
  249. package/dist/integrations/mcp/index.js +19 -0
  250. package/dist/integrations/mcp/index.js.map +7 -0
  251. package/dist/integrations/mcp/refactored-server.js +331 -0
  252. package/dist/integrations/mcp/refactored-server.js.map +7 -0
  253. package/dist/integrations/mcp/server.js +1621 -0
  254. package/dist/integrations/mcp/server.js.map +7 -0
  255. package/dist/integrations/mcp/tool-definitions.js +562 -0
  256. package/dist/integrations/mcp/tool-definitions.js.map +7 -0
  257. package/dist/integrations/mcp/trace-test.js +44 -0
  258. package/dist/integrations/mcp/trace-test.js.map +7 -0
  259. package/dist/integrations/pg-aiguide/embedding-provider.js +174 -0
  260. package/dist/integrations/pg-aiguide/embedding-provider.js.map +7 -0
  261. package/dist/integrations/pg-aiguide/semantic-search.js +183 -0
  262. package/dist/integrations/pg-aiguide/semantic-search.js.map +7 -0
  263. package/dist/integrations/pg-aiguide/timescale-analytics.js +220 -0
  264. package/dist/integrations/pg-aiguide/timescale-analytics.js.map +7 -0
  265. package/dist/mcp/stackmemory-mcp-server.js +550 -0
  266. package/dist/mcp/stackmemory-mcp-server.js.map +7 -0
  267. package/dist/middleware/exponential-rate-limiter.js +285 -0
  268. package/dist/middleware/exponential-rate-limiter.js.map +7 -0
  269. package/dist/models/user.model.js +351 -0
  270. package/dist/models/user.model.js.map +7 -0
  271. package/dist/scripts/benchmark-performance.d.ts +7 -0
  272. package/dist/scripts/benchmark-performance.d.ts.map +1 -0
  273. package/dist/scripts/benchmark-performance.js +44 -0
  274. package/dist/scripts/benchmark-performance.js.map +1 -0
  275. package/dist/scripts/cleanup-duplicate-tasks.d.ts +12 -0
  276. package/dist/scripts/cleanup-duplicate-tasks.d.ts.map +1 -0
  277. package/dist/scripts/cleanup-duplicate-tasks.js +215 -0
  278. package/dist/scripts/cleanup-duplicate-tasks.js.map +1 -0
  279. package/dist/servers/production/auth-middleware.js +513 -0
  280. package/dist/servers/production/auth-middleware.js.map +7 -0
  281. package/dist/servers/railway/index.js +390 -0
  282. package/dist/servers/railway/index.js.map +7 -0
  283. package/dist/services/config-service.js +62 -0
  284. package/dist/services/config-service.js.map +7 -0
  285. package/dist/services/context-service.js +191 -0
  286. package/dist/services/context-service.js.map +7 -0
  287. package/dist/src/agents/core/agent-task-manager.d.ts +154 -0
  288. package/dist/src/agents/core/agent-task-manager.d.ts.map +1 -0
  289. package/dist/src/agents/core/agent-task-manager.js +504 -0
  290. package/dist/src/agents/core/agent-task-manager.js.map +1 -0
  291. package/dist/src/agents/verifiers/base-verifier.d.ts +112 -0
  292. package/dist/src/agents/verifiers/base-verifier.d.ts.map +1 -0
  293. package/dist/src/agents/verifiers/base-verifier.js +130 -0
  294. package/dist/src/agents/verifiers/base-verifier.js.map +1 -0
  295. package/dist/src/agents/verifiers/formatter-verifier.d.ts +14 -0
  296. package/dist/src/agents/verifiers/formatter-verifier.d.ts.map +1 -0
  297. package/dist/src/agents/verifiers/formatter-verifier.js +107 -0
  298. package/dist/src/agents/verifiers/formatter-verifier.js.map +1 -0
  299. package/dist/src/agents/verifiers/llm-judge.d.ts +46 -0
  300. package/dist/src/agents/verifiers/llm-judge.d.ts.map +1 -0
  301. package/dist/src/agents/verifiers/llm-judge.js +248 -0
  302. package/dist/src/agents/verifiers/llm-judge.js.map +1 -0
  303. package/dist/src/cli/claude-sm.js +55 -0
  304. package/dist/src/cli/claude-sm.js.map +1 -1
  305. package/dist/src/cli/commands/agent.d.ts +9 -0
  306. package/dist/src/cli/commands/agent.d.ts.map +1 -0
  307. package/dist/src/cli/commands/agent.js +303 -0
  308. package/dist/src/cli/commands/agent.js.map +1 -0
  309. package/dist/src/cli/commands/handoff.d.ts +6 -0
  310. package/dist/src/cli/commands/handoff.d.ts.map +1 -0
  311. package/dist/src/cli/commands/handoff.js +212 -0
  312. package/dist/src/cli/commands/handoff.js.map +1 -0
  313. package/dist/src/cli/index.d.ts.map +1 -1
  314. package/dist/src/cli/index.js +4 -0
  315. package/dist/src/cli/index.js.map +1 -1
  316. package/dist/src/core/context/frame-database.d.ts +59 -0
  317. package/dist/src/core/context/frame-database.d.ts.map +1 -0
  318. package/dist/src/core/context/frame-database.js +333 -0
  319. package/dist/src/core/context/frame-database.js.map +1 -0
  320. package/dist/src/core/context/frame-digest.d.ts +59 -0
  321. package/dist/src/core/context/frame-digest.d.ts.map +1 -0
  322. package/dist/src/core/context/frame-digest.js +264 -0
  323. package/dist/src/core/context/frame-digest.js.map +1 -0
  324. package/dist/src/core/context/frame-manager.d.ts +2 -0
  325. package/dist/src/core/context/frame-manager.d.ts.map +1 -1
  326. package/dist/src/core/context/frame-manager.js +7 -0
  327. package/dist/src/core/context/frame-manager.js.map +1 -1
  328. package/dist/src/core/context/frame-stack.d.ts +85 -0
  329. package/dist/src/core/context/frame-stack.d.ts.map +1 -0
  330. package/dist/src/core/context/frame-stack.js +287 -0
  331. package/dist/src/core/context/frame-stack.js.map +1 -0
  332. package/dist/src/core/context/frame-types.d.ts +67 -0
  333. package/dist/src/core/context/frame-types.d.ts.map +1 -0
  334. package/dist/src/core/context/frame-types.js +6 -0
  335. package/dist/src/core/context/frame-types.js.map +1 -0
  336. package/dist/src/core/context/index.d.ts +11 -0
  337. package/dist/src/core/context/index.d.ts.map +1 -0
  338. package/dist/src/core/context/index.js +14 -0
  339. package/dist/src/core/context/index.js.map +1 -0
  340. package/dist/src/core/context/refactored-frame-manager.d.ts +99 -0
  341. package/dist/src/core/context/refactored-frame-manager.d.ts.map +1 -0
  342. package/dist/src/core/context/refactored-frame-manager.js +340 -0
  343. package/dist/src/core/context/refactored-frame-manager.js.map +1 -0
  344. package/dist/src/core/database/batch-operations.d.ts +118 -0
  345. package/dist/src/core/database/batch-operations.d.ts.map +1 -0
  346. package/dist/src/core/database/batch-operations.js +339 -0
  347. package/dist/src/core/database/batch-operations.js.map +1 -0
  348. package/dist/src/core/database/connection-pool.d.ts +79 -0
  349. package/dist/src/core/database/connection-pool.d.ts.map +1 -0
  350. package/dist/src/core/database/connection-pool.js +236 -0
  351. package/dist/src/core/database/connection-pool.js.map +1 -0
  352. package/dist/src/core/database/query-cache.d.ts +135 -0
  353. package/dist/src/core/database/query-cache.d.ts.map +1 -0
  354. package/dist/src/core/database/query-cache.js +294 -0
  355. package/dist/src/core/database/query-cache.js.map +1 -0
  356. package/dist/src/core/digest/enhanced-hybrid-digest.d.ts +125 -0
  357. package/dist/src/core/digest/enhanced-hybrid-digest.d.ts.map +1 -0
  358. package/dist/src/core/digest/enhanced-hybrid-digest.js +282 -0
  359. package/dist/src/core/digest/enhanced-hybrid-digest.js.map +1 -0
  360. package/dist/src/core/digest/frame-digest-integration.d.ts +67 -0
  361. package/dist/src/core/digest/frame-digest-integration.d.ts.map +1 -0
  362. package/dist/src/core/digest/frame-digest-integration.js +198 -0
  363. package/dist/src/core/digest/frame-digest-integration.js.map +1 -0
  364. package/dist/src/core/digest/hybrid-digest-generator.d.ts +3 -3
  365. package/dist/src/core/digest/hybrid-digest-generator.d.ts.map +1 -1
  366. package/dist/src/core/digest/hybrid-digest-generator.js.map +1 -1
  367. package/dist/src/core/digest/index.d.ts +3 -1
  368. package/dist/src/core/digest/index.d.ts.map +1 -1
  369. package/dist/src/core/digest/index.js +3 -1
  370. package/dist/src/core/digest/index.js.map +1 -1
  371. package/dist/src/core/errors/index.d.ts +13 -5
  372. package/dist/src/core/errors/index.d.ts.map +1 -1
  373. package/dist/src/core/errors/index.js +13 -5
  374. package/dist/src/core/errors/index.js.map +1 -1
  375. package/dist/src/core/merge/conflict-detector.d.ts +122 -0
  376. package/dist/src/core/merge/conflict-detector.d.ts.map +1 -0
  377. package/dist/src/core/merge/conflict-detector.js +468 -0
  378. package/dist/src/core/merge/conflict-detector.js.map +1 -0
  379. package/dist/src/core/merge/index.d.ts +9 -0
  380. package/dist/src/core/merge/index.d.ts.map +1 -0
  381. package/dist/src/core/merge/index.js +9 -0
  382. package/dist/src/core/merge/index.js.map +1 -0
  383. package/dist/src/core/merge/resolution-engine.d.ts +120 -0
  384. package/dist/src/core/merge/resolution-engine.d.ts.map +1 -0
  385. package/dist/src/core/merge/resolution-engine.js +573 -0
  386. package/dist/src/core/merge/resolution-engine.js.map +1 -0
  387. package/dist/src/core/merge/stack-diff.d.ts +97 -0
  388. package/dist/src/core/merge/stack-diff.d.ts.map +1 -0
  389. package/dist/src/core/merge/stack-diff.js +516 -0
  390. package/dist/src/core/merge/stack-diff.js.map +1 -0
  391. package/dist/src/core/merge/types.d.ts +110 -0
  392. package/dist/src/core/merge/types.d.ts.map +1 -0
  393. package/dist/src/core/merge/types.js +6 -0
  394. package/dist/src/core/merge/types.js.map +1 -0
  395. package/dist/src/core/performance/context-cache.d.ts +109 -0
  396. package/dist/src/core/performance/context-cache.d.ts.map +1 -0
  397. package/dist/src/core/performance/context-cache.js +280 -0
  398. package/dist/src/core/performance/context-cache.js.map +1 -0
  399. package/dist/src/core/performance/index.d.ts +3 -0
  400. package/dist/src/core/performance/index.d.ts.map +1 -0
  401. package/dist/src/core/performance/index.js +3 -0
  402. package/dist/src/core/performance/index.js.map +1 -0
  403. package/dist/src/core/performance/lazy-context-loader.d.ts +93 -0
  404. package/dist/src/core/performance/lazy-context-loader.d.ts.map +1 -0
  405. package/dist/src/core/performance/lazy-context-loader.js +332 -0
  406. package/dist/src/core/performance/lazy-context-loader.js.map +1 -0
  407. package/dist/src/core/performance/monitor.d.ts +48 -0
  408. package/dist/src/core/performance/monitor.d.ts.map +1 -0
  409. package/dist/src/core/performance/monitor.js +226 -0
  410. package/dist/src/core/performance/monitor.js.map +1 -0
  411. package/dist/src/core/performance/optimized-frame-context.d.ts +74 -0
  412. package/dist/src/core/performance/optimized-frame-context.d.ts.map +1 -0
  413. package/dist/src/core/performance/optimized-frame-context.js +330 -0
  414. package/dist/src/core/performance/optimized-frame-context.js.map +1 -0
  415. package/dist/src/core/performance/performance-benchmark.d.ts +50 -0
  416. package/dist/src/core/performance/performance-benchmark.d.ts.map +1 -0
  417. package/dist/src/core/performance/performance-benchmark.js +290 -0
  418. package/dist/src/core/performance/performance-benchmark.js.map +1 -0
  419. package/dist/src/core/performance/performance-profiler.d.ts +151 -0
  420. package/dist/src/core/performance/performance-profiler.d.ts.map +1 -0
  421. package/dist/src/core/performance/performance-profiler.js +346 -0
  422. package/dist/src/core/performance/performance-profiler.js.map +1 -0
  423. package/dist/src/core/performance/streaming-jsonl-parser.d.ts +41 -0
  424. package/dist/src/core/performance/streaming-jsonl-parser.d.ts.map +1 -0
  425. package/dist/src/core/performance/streaming-jsonl-parser.js +193 -0
  426. package/dist/src/core/performance/streaming-jsonl-parser.js.map +1 -0
  427. package/dist/src/core/persistence/postgres-adapter.d.ts.map +1 -1
  428. package/dist/src/core/persistence/postgres-adapter.js +18 -4
  429. package/dist/src/core/persistence/postgres-adapter.js.map +1 -1
  430. package/dist/src/core/query/query-parser.d.ts +5 -0
  431. package/dist/src/core/query/query-parser.d.ts.map +1 -1
  432. package/dist/src/core/query/query-parser.js +86 -18
  433. package/dist/src/core/query/query-parser.js.map +1 -1
  434. package/dist/src/core/query/query-templates.d.ts +44 -0
  435. package/dist/src/core/query/query-templates.d.ts.map +1 -0
  436. package/dist/src/core/query/query-templates.js +326 -0
  437. package/dist/src/core/query/query-templates.js.map +1 -0
  438. package/dist/src/core/retrieval/llm-context-retrieval.d.ts +5 -3
  439. package/dist/src/core/retrieval/llm-context-retrieval.d.ts.map +1 -1
  440. package/dist/src/core/retrieval/llm-context-retrieval.js +73 -21
  441. package/dist/src/core/retrieval/llm-context-retrieval.js.map +1 -1
  442. package/dist/src/core/trace/cli-trace-wrapper.d.ts +23 -0
  443. package/dist/src/core/trace/cli-trace-wrapper.d.ts.map +1 -0
  444. package/dist/src/core/trace/cli-trace-wrapper.js +141 -0
  445. package/dist/src/core/trace/cli-trace-wrapper.js.map +1 -0
  446. package/dist/src/core/trace/db-trace-wrapper.d.ts +36 -0
  447. package/dist/src/core/trace/db-trace-wrapper.d.ts.map +1 -0
  448. package/dist/src/core/trace/db-trace-wrapper.js +252 -0
  449. package/dist/src/core/trace/db-trace-wrapper.js.map +1 -0
  450. package/dist/src/core/trace/debug-trace.d.ts +84 -0
  451. package/dist/src/core/trace/debug-trace.d.ts.map +1 -0
  452. package/dist/src/core/trace/debug-trace.js +402 -0
  453. package/dist/src/core/trace/debug-trace.js.map +1 -0
  454. package/dist/src/core/trace/error-test.d.ts +6 -0
  455. package/dist/src/core/trace/error-test.d.ts.map +1 -0
  456. package/dist/src/core/trace/error-test.js +128 -0
  457. package/dist/src/core/trace/error-test.js.map +1 -0
  458. package/dist/src/core/trace/index.d.ts +25 -0
  459. package/dist/src/core/trace/index.d.ts.map +1 -0
  460. package/dist/src/core/trace/index.js +121 -0
  461. package/dist/src/core/trace/index.js.map +1 -0
  462. package/dist/src/core/trace/linear-api-wrapper.d.ts +17 -0
  463. package/dist/src/core/trace/linear-api-wrapper.d.ts.map +1 -0
  464. package/dist/src/core/trace/linear-api-wrapper.js +205 -0
  465. package/dist/src/core/trace/linear-api-wrapper.js.map +1 -0
  466. package/dist/src/core/trace/performance-test.d.ts +6 -0
  467. package/dist/src/core/trace/performance-test.d.ts.map +1 -0
  468. package/dist/src/core/trace/performance-test.js +111 -0
  469. package/dist/src/core/trace/performance-test.js.map +1 -0
  470. package/dist/src/core/trace/trace-demo.d.ts +8 -0
  471. package/dist/src/core/trace/trace-demo.d.ts.map +1 -0
  472. package/dist/src/core/trace/trace-demo.js +154 -0
  473. package/dist/src/core/trace/trace-demo.js.map +1 -0
  474. package/dist/src/core/trace/trace-detector.d.ts +2 -2
  475. package/dist/src/core/trace/trace-detector.d.ts.map +1 -1
  476. package/dist/src/core/trace/trace-detector.demo.js +1 -1
  477. package/dist/src/core/trace/trace-detector.demo.js.map +1 -1
  478. package/dist/src/core/trace/trace-detector.js +3 -3
  479. package/dist/src/core/trace/trace-detector.js.map +1 -1
  480. package/dist/src/features/tasks/pebbles-task-store.d.ts +9 -2
  481. package/dist/src/features/tasks/pebbles-task-store.d.ts.map +1 -1
  482. package/dist/src/features/tasks/pebbles-task-store.js +97 -18
  483. package/dist/src/features/tasks/pebbles-task-store.js.map +1 -1
  484. package/dist/src/integrations/linear/auth.d.ts.map +1 -1
  485. package/dist/src/integrations/linear/auth.js.map +1 -1
  486. package/dist/src/integrations/linear/client.d.ts +15 -1
  487. package/dist/src/integrations/linear/client.d.ts.map +1 -1
  488. package/dist/src/integrations/linear/client.js +85 -3
  489. package/dist/src/integrations/linear/client.js.map +1 -1
  490. package/dist/src/integrations/linear/sync-manager.d.ts +2 -0
  491. package/dist/src/integrations/linear/sync-manager.d.ts.map +1 -1
  492. package/dist/src/integrations/linear/sync-manager.js +16 -4
  493. package/dist/src/integrations/linear/sync-manager.js.map +1 -1
  494. package/dist/src/integrations/linear/sync-service.d.ts +23 -2
  495. package/dist/src/integrations/linear/sync-service.d.ts.map +1 -1
  496. package/dist/src/integrations/linear/sync-service.js +44 -25
  497. package/dist/src/integrations/linear/sync-service.js.map +1 -1
  498. package/dist/src/integrations/linear/sync.d.ts +6 -0
  499. package/dist/src/integrations/linear/sync.d.ts.map +1 -1
  500. package/dist/src/integrations/linear/sync.js +27 -2
  501. package/dist/src/integrations/linear/sync.js.map +1 -1
  502. package/dist/src/integrations/linear/types.d.ts +16 -1
  503. package/dist/src/integrations/linear/types.d.ts.map +1 -1
  504. package/dist/src/integrations/linear/webhook-server.d.ts.map +1 -1
  505. package/dist/src/integrations/linear/webhook-server.js +10 -8
  506. package/dist/src/integrations/linear/webhook-server.js.map +1 -1
  507. package/dist/src/integrations/linear/webhook.d.ts +13 -0
  508. package/dist/src/integrations/linear/webhook.d.ts.map +1 -1
  509. package/dist/src/integrations/linear/webhook.js +101 -14
  510. package/dist/src/integrations/linear/webhook.js.map +1 -1
  511. package/dist/src/integrations/mcp/handlers/context-handlers.d.ts +39 -0
  512. package/dist/src/integrations/mcp/handlers/context-handlers.d.ts.map +1 -0
  513. package/dist/src/integrations/mcp/handlers/context-handlers.js +266 -0
  514. package/dist/src/integrations/mcp/handlers/context-handlers.js.map +1 -0
  515. package/dist/src/integrations/mcp/handlers/index.d.ts +37 -0
  516. package/dist/src/integrations/mcp/handlers/index.d.ts.map +1 -0
  517. package/dist/src/integrations/mcp/handlers/index.js +134 -0
  518. package/dist/src/integrations/mcp/handlers/index.js.map +1 -0
  519. package/dist/src/integrations/mcp/handlers/linear-handlers.d.ts +33 -0
  520. package/dist/src/integrations/mcp/handlers/linear-handlers.d.ts.map +1 -0
  521. package/dist/src/integrations/mcp/handlers/linear-handlers.js +251 -0
  522. package/dist/src/integrations/mcp/handlers/linear-handlers.js.map +1 -0
  523. package/dist/src/integrations/mcp/handlers/task-handlers.d.ts +42 -0
  524. package/dist/src/integrations/mcp/handlers/task-handlers.d.ts.map +1 -0
  525. package/dist/src/integrations/mcp/handlers/task-handlers.js +238 -0
  526. package/dist/src/integrations/mcp/handlers/task-handlers.js.map +1 -0
  527. package/dist/src/integrations/mcp/handlers/trace-handlers.d.ts +41 -0
  528. package/dist/src/integrations/mcp/handlers/trace-handlers.d.ts.map +1 -0
  529. package/dist/src/integrations/mcp/handlers/trace-handlers.js +298 -0
  530. package/dist/src/integrations/mcp/handlers/trace-handlers.js.map +1 -0
  531. package/dist/src/integrations/mcp/index.d.ts +13 -0
  532. package/dist/src/integrations/mcp/index.d.ts.map +1 -0
  533. package/dist/src/integrations/mcp/index.js +17 -0
  534. package/dist/src/integrations/mcp/index.js.map +1 -0
  535. package/dist/src/integrations/mcp/refactored-server.d.ts +76 -0
  536. package/dist/src/integrations/mcp/refactored-server.d.ts.map +1 -0
  537. package/dist/src/integrations/mcp/refactored-server.js +351 -0
  538. package/dist/src/integrations/mcp/refactored-server.js.map +1 -0
  539. package/dist/src/integrations/mcp/tool-definitions.d.ts +44 -0
  540. package/dist/src/integrations/mcp/tool-definitions.d.ts.map +1 -0
  541. package/dist/src/integrations/mcp/tool-definitions.js +563 -0
  542. package/dist/src/integrations/mcp/tool-definitions.js.map +1 -0
  543. package/dist/src/integrations/pg-aiguide/semantic-search.d.ts.map +1 -1
  544. package/dist/src/integrations/pg-aiguide/semantic-search.js +43 -21
  545. package/dist/src/integrations/pg-aiguide/semantic-search.js.map +1 -1
  546. package/dist/src/mcp/stackmemory-mcp-server.d.ts +9 -0
  547. package/dist/src/mcp/stackmemory-mcp-server.d.ts.map +1 -0
  548. package/dist/src/mcp/stackmemory-mcp-server.js +519 -0
  549. package/dist/src/mcp/stackmemory-mcp-server.js.map +1 -0
  550. package/dist/src/middleware/exponential-rate-limiter.d.ts +78 -0
  551. package/dist/src/middleware/exponential-rate-limiter.d.ts.map +1 -0
  552. package/dist/src/middleware/exponential-rate-limiter.js +293 -0
  553. package/dist/src/middleware/exponential-rate-limiter.js.map +1 -0
  554. package/dist/src/models/user.model.d.ts +8 -1
  555. package/dist/src/models/user.model.d.ts.map +1 -1
  556. package/dist/src/models/user.model.js +62 -14
  557. package/dist/src/models/user.model.js.map +1 -1
  558. package/dist/src/servers/production/auth-middleware.d.ts +5 -2
  559. package/dist/src/servers/production/auth-middleware.d.ts.map +1 -1
  560. package/dist/src/servers/production/auth-middleware.js +71 -34
  561. package/dist/src/servers/production/auth-middleware.js.map +1 -1
  562. package/dist/src/services/context-service.d.ts.map +1 -1
  563. package/dist/src/services/context-service.js +86 -1
  564. package/dist/src/services/context-service.js.map +1 -1
  565. package/dist/src/validation/schemas.d.ts +633 -0
  566. package/dist/src/validation/schemas.d.ts.map +1 -0
  567. package/dist/src/validation/schemas.js +347 -0
  568. package/dist/src/validation/schemas.js.map +1 -0
  569. package/dist/types/task.js +1 -0
  570. package/dist/types/task.js.map +7 -0
  571. package/dist/utils/logger.js +52 -0
  572. package/dist/utils/logger.js.map +7 -0
  573. package/dist/validation/schemas.js +218 -0
  574. package/dist/validation/schemas.js.map +7 -0
  575. package/package.json +7 -3
@@ -0,0 +1,174 @@
1
+ import { logger } from "../../core/monitoring/logger.js";
2
+ import crypto from "crypto";
3
+ class OpenAIEmbeddingProvider {
4
+ apiKey;
5
+ model;
6
+ dimensions;
7
+ constructor(model = "text-embedding-ada-002") {
8
+ this.apiKey = process.env.OPENAI_API_KEY;
9
+ this.model = model;
10
+ this.dimensions = model === "text-embedding-ada-002" ? 1536 : 3072;
11
+ }
12
+ async createEmbedding(text) {
13
+ if (!this.apiKey) {
14
+ throw new Error("OPENAI_API_KEY environment variable is not set");
15
+ }
16
+ try {
17
+ const response = await fetch("https://api.openai.com/v1/embeddings", {
18
+ method: "POST",
19
+ headers: {
20
+ "Content-Type": "application/json",
21
+ Authorization: `Bearer ${this.apiKey}`
22
+ },
23
+ body: JSON.stringify({
24
+ input: text,
25
+ model: this.model
26
+ })
27
+ });
28
+ if (!response.ok) {
29
+ throw new Error(`OpenAI API error: ${response.statusText}`);
30
+ }
31
+ const data = await response.json();
32
+ return data.data[0].embedding;
33
+ } catch (error) {
34
+ logger.error(
35
+ "Failed to create OpenAI embedding",
36
+ error instanceof Error ? error : new Error(String(error))
37
+ );
38
+ throw error;
39
+ }
40
+ }
41
+ getDimensions() {
42
+ return this.dimensions;
43
+ }
44
+ getName() {
45
+ return `OpenAI-${this.model}`;
46
+ }
47
+ }
48
+ class LocalEmbeddingProvider {
49
+ dimensions;
50
+ vocabulary = /* @__PURE__ */ new Map();
51
+ idf = /* @__PURE__ */ new Map();
52
+ documentCount = 0;
53
+ constructor(dimensions = 384) {
54
+ this.dimensions = dimensions;
55
+ }
56
+ tokenize(text) {
57
+ return text.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((token) => token.length > 2);
58
+ }
59
+ getWordVector(word) {
60
+ const hash = crypto.createHash("sha256").update(word).digest();
61
+ const vector = new Array(this.dimensions).fill(0);
62
+ for (let i = 0; i < Math.min(hash.length, this.dimensions); i++) {
63
+ const value = (hash[i] - 128) / 128;
64
+ vector[i] = value;
65
+ }
66
+ return vector;
67
+ }
68
+ async createEmbedding(text) {
69
+ const tokens = this.tokenize(text);
70
+ const vector = new Array(this.dimensions).fill(0);
71
+ if (tokens.length === 0) {
72
+ return vector;
73
+ }
74
+ const termFreq = /* @__PURE__ */ new Map();
75
+ for (const token of tokens) {
76
+ termFreq.set(token, (termFreq.get(token) || 0) + 1);
77
+ }
78
+ this.documentCount++;
79
+ for (const token of new Set(tokens)) {
80
+ if (!this.vocabulary.has(token)) {
81
+ this.vocabulary.set(token, this.vocabulary.size);
82
+ }
83
+ this.idf.set(token, (this.idf.get(token) || 0) + 1);
84
+ }
85
+ let totalWeight = 0;
86
+ for (const [token, freq] of termFreq.entries()) {
87
+ const tf = freq / tokens.length;
88
+ const docFreq = this.idf.get(token) || 1;
89
+ const idf = Math.log((this.documentCount + 1) / (docFreq + 1));
90
+ const weight = tf * idf;
91
+ const wordVector = this.getWordVector(token);
92
+ for (let i = 0; i < this.dimensions; i++) {
93
+ vector[i] += wordVector[i] * weight;
94
+ }
95
+ totalWeight += weight;
96
+ }
97
+ if (totalWeight > 0) {
98
+ const magnitude = Math.sqrt(
99
+ vector.reduce((sum, val) => sum + val * val, 0)
100
+ );
101
+ if (magnitude > 0) {
102
+ for (let i = 0; i < this.dimensions; i++) {
103
+ vector[i] /= magnitude;
104
+ }
105
+ }
106
+ }
107
+ return vector;
108
+ }
109
+ getDimensions() {
110
+ return this.dimensions;
111
+ }
112
+ getName() {
113
+ return "Local-TFIDF";
114
+ }
115
+ }
116
+ class HybridEmbeddingProvider {
117
+ openai;
118
+ local;
119
+ useOpenAI;
120
+ constructor(dimensions = 1536) {
121
+ this.openai = new OpenAIEmbeddingProvider();
122
+ this.local = new LocalEmbeddingProvider(dimensions);
123
+ this.useOpenAI = !!process.env.OPENAI_API_KEY;
124
+ if (!this.useOpenAI) {
125
+ logger.warn("OPENAI_API_KEY not set, using local embeddings");
126
+ }
127
+ }
128
+ async createEmbedding(text) {
129
+ if (this.useOpenAI) {
130
+ try {
131
+ return await this.openai.createEmbedding(text);
132
+ } catch (error) {
133
+ logger.warn(
134
+ "OpenAI embedding failed, falling back to local",
135
+ error instanceof Error ? error : void 0
136
+ );
137
+ this.useOpenAI = false;
138
+ }
139
+ }
140
+ const localEmbedding = await this.local.createEmbedding(text);
141
+ const targetDimensions = this.getDimensions();
142
+ if (localEmbedding.length < targetDimensions) {
143
+ return [
144
+ ...localEmbedding,
145
+ ...new Array(targetDimensions - localEmbedding.length).fill(0)
146
+ ];
147
+ }
148
+ return localEmbedding.slice(0, targetDimensions);
149
+ }
150
+ getDimensions() {
151
+ return this.useOpenAI ? this.openai.getDimensions() : this.local.getDimensions();
152
+ }
153
+ getName() {
154
+ return this.useOpenAI ? this.openai.getName() : `Hybrid-${this.local.getName()}`;
155
+ }
156
+ }
157
+ function createEmbeddingProvider(type) {
158
+ switch (type) {
159
+ case "openai":
160
+ return new OpenAIEmbeddingProvider();
161
+ case "local":
162
+ return new LocalEmbeddingProvider();
163
+ case "hybrid":
164
+ default:
165
+ return new HybridEmbeddingProvider();
166
+ }
167
+ }
168
+ export {
169
+ HybridEmbeddingProvider,
170
+ LocalEmbeddingProvider,
171
+ OpenAIEmbeddingProvider,
172
+ createEmbeddingProvider
173
+ };
174
+ //# sourceMappingURL=embedding-provider.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/integrations/pg-aiguide/embedding-provider.ts"],
4
+ "sourcesContent": ["import { logger } from '../../core/monitoring/logger.js';\nimport crypto from 'crypto';\n\nexport interface EmbeddingProvider {\n createEmbedding(text: string): Promise<number[]>;\n getDimensions(): number;\n getName(): string;\n}\n\n/**\n * OpenAI Embeddings Provider\n * Requires OPENAI_API_KEY environment variable\n */\nexport class OpenAIEmbeddingProvider implements EmbeddingProvider {\n private apiKey: string | undefined;\n private model: string;\n private dimensions: number;\n\n constructor(model = 'text-embedding-ada-002') {\n this.apiKey = process.env.OPENAI_API_KEY;\n this.model = model;\n this.dimensions = model === 'text-embedding-ada-002' ? 1536 : 3072; // ada-002 vs text-embedding-3-small\n }\n\n async createEmbedding(text: string): Promise<number[]> {\n if (!this.apiKey) {\n throw new Error('OPENAI_API_KEY environment variable is not set');\n }\n\n try {\n const response = await fetch('https://api.openai.com/v1/embeddings', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n input: text,\n model: this.model,\n }),\n });\n\n if (!response.ok) {\n throw new Error(`OpenAI API error: ${response.statusText}`);\n }\n\n const data = (await response.json()) as {\n data: Array<{ embedding: number[] }>;\n };\n return data.data[0].embedding;\n } catch (error) {\n logger.error(\n 'Failed to create OpenAI embedding',\n error instanceof Error ? error : new Error(String(error))\n );\n throw error;\n }\n }\n\n getDimensions(): number {\n return this.dimensions;\n }\n\n getName(): string {\n return `OpenAI-${this.model}`;\n }\n}\n\n/**\n * Local Embeddings Provider using simple TF-IDF-like approach\n * Deterministic and doesn't require external APIs\n */\nexport class LocalEmbeddingProvider implements EmbeddingProvider {\n private dimensions: number;\n private vocabulary: Map<string, number> = new Map();\n private idf: Map<string, number> = new Map();\n private documentCount = 0;\n\n constructor(dimensions = 384) {\n this.dimensions = dimensions;\n }\n\n private tokenize(text: string): string[] {\n return text\n .toLowerCase()\n .replace(/[^\\w\\s]/g, ' ')\n .split(/\\s+/)\n .filter((token) => token.length > 2);\n }\n\n private getWordVector(word: string): number[] {\n // Use deterministic hashing to create a vector for each word\n const hash = crypto.createHash('sha256').update(word).digest();\n const vector = new Array(this.dimensions).fill(0);\n\n // Use hash bytes to set vector components\n for (let i = 0; i < Math.min(hash.length, this.dimensions); i++) {\n const value = (hash[i] - 128) / 128; // Normalize to [-1, 1]\n vector[i] = value;\n }\n\n return vector;\n }\n\n async createEmbedding(text: string): Promise<number[]> {\n const tokens = this.tokenize(text);\n const vector = new Array(this.dimensions).fill(0);\n\n if (tokens.length === 0) {\n return vector;\n }\n\n // Calculate TF-IDF weighted average of word vectors\n const termFreq = new Map<string, number>();\n\n // Count term frequencies\n for (const token of tokens) {\n termFreq.set(token, (termFreq.get(token) || 0) + 1);\n }\n\n // Build vocabulary and update document frequency\n this.documentCount++;\n for (const token of new Set(tokens)) {\n if (!this.vocabulary.has(token)) {\n this.vocabulary.set(token, this.vocabulary.size);\n }\n this.idf.set(token, (this.idf.get(token) || 0) + 1);\n }\n\n // Calculate weighted vector\n let totalWeight = 0;\n\n for (const [token, freq] of termFreq.entries()) {\n const tf = freq / tokens.length;\n const docFreq = this.idf.get(token) || 1;\n const idf = Math.log((this.documentCount + 1) / (docFreq + 1));\n const weight = tf * idf;\n\n const wordVector = this.getWordVector(token);\n for (let i = 0; i < this.dimensions; i++) {\n vector[i] += wordVector[i] * weight;\n }\n totalWeight += weight;\n }\n\n // Normalize the vector\n if (totalWeight > 0) {\n const magnitude = Math.sqrt(\n vector.reduce((sum, val) => sum + val * val, 0)\n );\n if (magnitude > 0) {\n for (let i = 0; i < this.dimensions; i++) {\n vector[i] /= magnitude;\n }\n }\n }\n\n return vector;\n }\n\n getDimensions(): number {\n return this.dimensions;\n }\n\n getName(): string {\n return 'Local-TFIDF';\n }\n}\n\n/**\n * Hybrid provider that tries OpenAI first, falls back to local\n */\nexport class HybridEmbeddingProvider implements EmbeddingProvider {\n private openai: OpenAIEmbeddingProvider;\n private local: LocalEmbeddingProvider;\n private useOpenAI: boolean;\n\n constructor(dimensions = 1536) {\n this.openai = new OpenAIEmbeddingProvider();\n this.local = new LocalEmbeddingProvider(dimensions);\n this.useOpenAI = !!process.env.OPENAI_API_KEY;\n\n if (!this.useOpenAI) {\n logger.warn('OPENAI_API_KEY not set, using local embeddings');\n }\n }\n\n async createEmbedding(text: string): Promise<number[]> {\n if (this.useOpenAI) {\n try {\n return await this.openai.createEmbedding(text);\n } catch (error) {\n logger.warn(\n 'OpenAI embedding failed, falling back to local',\n error instanceof Error ? error : undefined\n );\n this.useOpenAI = false; // Disable for future calls\n }\n }\n\n const localEmbedding = await this.local.createEmbedding(text);\n\n // Pad or truncate to match expected dimensions\n const targetDimensions = this.getDimensions();\n if (localEmbedding.length < targetDimensions) {\n return [\n ...localEmbedding,\n ...new Array(targetDimensions - localEmbedding.length).fill(0),\n ];\n }\n return localEmbedding.slice(0, targetDimensions);\n }\n\n getDimensions(): number {\n return this.useOpenAI\n ? this.openai.getDimensions()\n : this.local.getDimensions();\n }\n\n getName(): string {\n return this.useOpenAI\n ? this.openai.getName()\n : `Hybrid-${this.local.getName()}`;\n }\n}\n\n// Factory function\nexport function createEmbeddingProvider(\n type?: 'openai' | 'local' | 'hybrid'\n): EmbeddingProvider {\n switch (type) {\n case 'openai':\n return new OpenAIEmbeddingProvider();\n case 'local':\n return new LocalEmbeddingProvider();\n case 'hybrid':\n default:\n return new HybridEmbeddingProvider();\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,183 @@
1
+ import { logger } from "../../core/monitoring/logger.js";
2
+ import {
3
+ createEmbeddingProvider
4
+ } from "./embedding-provider.js";
5
+ import { sanitizeSQLIdentifier } from "../../validation/schemas.js";
6
+ class SemanticSearch {
7
+ pool;
8
+ config;
9
+ embeddingProvider;
10
+ constructor(config) {
11
+ this.pool = config.pool;
12
+ this.config = config;
13
+ this.embeddingProvider = config.embeddingProvider || createEmbeddingProvider("hybrid");
14
+ if (this.embeddingProvider.getDimensions() !== config.vectorDimensions) {
15
+ logger.warn(
16
+ `Embedding provider dimensions (${this.embeddingProvider.getDimensions()}) don't match config (${config.vectorDimensions}). Using provider dimensions.`
17
+ );
18
+ this.config.vectorDimensions = this.embeddingProvider.getDimensions();
19
+ }
20
+ }
21
+ async createEmbedding(text) {
22
+ return this.embeddingProvider.createEmbedding(text);
23
+ }
24
+ async indexContent(id, content, metadata) {
25
+ const embedding = await this.createEmbedding(content);
26
+ const query = `
27
+ INSERT INTO ${this.config.tableName} (id, ${this.config.contentColumn}, ${this.config.embeddingColumn}, metadata)
28
+ VALUES ($1, $2, $3, $4)
29
+ ON CONFLICT (id) DO UPDATE
30
+ SET ${this.config.contentColumn} = $2,
31
+ ${this.config.embeddingColumn} = $3,
32
+ metadata = $4
33
+ `;
34
+ await this.pool.query(query, [
35
+ id,
36
+ content,
37
+ `[${embedding.join(",")}]`,
38
+ metadata ? JSON.stringify(metadata) : null
39
+ ]);
40
+ }
41
+ async search(query, limit = 10, threshold = 0.7) {
42
+ const queryEmbedding = await this.createEmbedding(query);
43
+ const sanitizedTable = sanitizeSQLIdentifier(this.config.tableName);
44
+ const sanitizedContent = sanitizeSQLIdentifier(this.config.contentColumn);
45
+ const sanitizedEmbedding = sanitizeSQLIdentifier(
46
+ this.config.embeddingColumn
47
+ );
48
+ const searchQuery = `
49
+ SELECT
50
+ id,
51
+ ${sanitizedContent} as content,
52
+ metadata,
53
+ 1 - (${sanitizedEmbedding} <=> $1::vector) as similarity
54
+ FROM ${sanitizedTable}
55
+ WHERE 1 - (${sanitizedEmbedding} <=> $1::vector) > $2
56
+ ORDER BY ${sanitizedEmbedding} <=> $1::vector
57
+ LIMIT $3
58
+ `;
59
+ const result = await this.pool.query(searchQuery, [
60
+ `[${queryEmbedding.join(",")}]`,
61
+ threshold,
62
+ limit
63
+ ]);
64
+ return result.rows.map((row) => ({
65
+ id: row.id,
66
+ content: row.content,
67
+ similarity: row.similarity,
68
+ metadata: row.metadata
69
+ }));
70
+ }
71
+ async findSimilar(id, limit = 10) {
72
+ const sanitizedTable = sanitizeSQLIdentifier(this.config.tableName);
73
+ const sanitizedContent = sanitizeSQLIdentifier(this.config.contentColumn);
74
+ const sanitizedEmbedding = sanitizeSQLIdentifier(
75
+ this.config.embeddingColumn
76
+ );
77
+ const query = `
78
+ WITH target AS (
79
+ SELECT ${sanitizedEmbedding} as embedding
80
+ FROM ${sanitizedTable}
81
+ WHERE id = $1
82
+ )
83
+ SELECT
84
+ t.id,
85
+ t.${sanitizedContent} as content,
86
+ t.metadata,
87
+ 1 - (t.${sanitizedEmbedding} <=> target.embedding) as similarity
88
+ FROM ${sanitizedTable} t, target
89
+ WHERE t.id != $1
90
+ ORDER BY t.${this.config.embeddingColumn} <=> target.embedding
91
+ LIMIT $2
92
+ `;
93
+ const result = await this.pool.query(query, [id, limit]);
94
+ return result.rows.map((row) => ({
95
+ id: row.id,
96
+ content: row.content,
97
+ similarity: row.similarity,
98
+ metadata: row.metadata
99
+ }));
100
+ }
101
+ async cluster(k, maxIterations = 10) {
102
+ const sanitizedTable = sanitizeSQLIdentifier(this.config.tableName);
103
+ const sanitizedContent = sanitizeSQLIdentifier(this.config.contentColumn);
104
+ const sanitizedEmbedding = sanitizeSQLIdentifier(
105
+ this.config.embeddingColumn
106
+ );
107
+ const query = `
108
+ WITH clusters AS (
109
+ SELECT
110
+ id,
111
+ ${sanitizedContent} as content,
112
+ metadata,
113
+ kmeans(${sanitizedEmbedding}, $1, $2) OVER () as cluster_id
114
+ FROM ${sanitizedTable}
115
+ )
116
+ SELECT * FROM clusters ORDER BY cluster_id
117
+ `;
118
+ const result = await this.pool.query(query, [k, maxIterations]);
119
+ const clusterMap = /* @__PURE__ */ new Map();
120
+ for (const row of result.rows) {
121
+ const clusterId = row.cluster_id;
122
+ if (!clusterMap.has(clusterId)) {
123
+ clusterMap.set(clusterId, []);
124
+ }
125
+ clusterMap.get(clusterId).push({
126
+ id: row.id,
127
+ content: row.content,
128
+ similarity: 1,
129
+ // Cluster membership
130
+ metadata: row.metadata
131
+ });
132
+ }
133
+ return clusterMap;
134
+ }
135
+ async reindex() {
136
+ const sanitizedTable = sanitizeSQLIdentifier(this.config.tableName);
137
+ const indexName = `idx_${sanitizedTable}_embedding`;
138
+ const sanitizedIndex = sanitizeSQLIdentifier(indexName);
139
+ const query = `REINDEX INDEX CONCURRENTLY ${sanitizedIndex}`;
140
+ try {
141
+ await this.pool.query(query);
142
+ logger.info(`Reindexed ${sanitizedTable} embeddings`);
143
+ } catch (error) {
144
+ logger.error(
145
+ "Failed to reindex embeddings",
146
+ error instanceof Error ? error : void 0
147
+ );
148
+ throw error;
149
+ }
150
+ }
151
+ async getStats() {
152
+ const sanitizedTable = sanitizeSQLIdentifier(this.config.tableName);
153
+ const sanitizedEmbedding = sanitizeSQLIdentifier(
154
+ this.config.embeddingColumn
155
+ );
156
+ const indexName = `idx_${sanitizedTable}_embedding`;
157
+ const statsQuery = `
158
+ SELECT
159
+ COUNT(*) as total,
160
+ AVG(
161
+ 1 - (${sanitizedEmbedding} <=> (
162
+ SELECT AVG(${sanitizedEmbedding})::vector
163
+ FROM ${sanitizedTable}
164
+ ))
165
+ ) as avg_similarity,
166
+ pg_size_pretty(
167
+ pg_relation_size($1::regclass)
168
+ ) as index_size
169
+ FROM ${sanitizedTable}
170
+ `;
171
+ const result = await this.pool.query(statsQuery, [indexName]);
172
+ const row = result.rows[0];
173
+ return {
174
+ totalDocuments: parseInt(row.total),
175
+ avgSimilarity: parseFloat(row.avg_similarity) || 0,
176
+ indexSize: row.index_size || "0 bytes"
177
+ };
178
+ }
179
+ }
180
+ export {
181
+ SemanticSearch
182
+ };
183
+ //# sourceMappingURL=semantic-search.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/integrations/pg-aiguide/semantic-search.ts"],
4
+ "sourcesContent": ["import { Pool } from 'pg';\nimport { logger } from '../../core/monitoring/logger.js';\nimport {\n EmbeddingProvider,\n createEmbeddingProvider,\n} from './embedding-provider.js';\nimport { sanitizeSQLIdentifier } from '../../validation/schemas.js';\n\nexport interface SemanticSearchConfig {\n pool: Pool;\n tableName: string;\n embeddingColumn: string;\n contentColumn: string;\n vectorDimensions: number;\n embeddingProvider?: EmbeddingProvider;\n}\n\nexport interface SearchResult {\n id: string;\n content: string;\n similarity: number;\n metadata?: Record<string, any>;\n}\n\nexport class SemanticSearch {\n private pool: Pool;\n private config: SemanticSearchConfig;\n private embeddingProvider: EmbeddingProvider;\n\n constructor(config: SemanticSearchConfig) {\n this.pool = config.pool;\n this.config = config;\n this.embeddingProvider =\n config.embeddingProvider || createEmbeddingProvider('hybrid');\n\n // Verify dimensions match\n if (this.embeddingProvider.getDimensions() !== config.vectorDimensions) {\n logger.warn(\n `Embedding provider dimensions (${this.embeddingProvider.getDimensions()}) ` +\n `don't match config (${config.vectorDimensions}). Using provider dimensions.`\n );\n this.config.vectorDimensions = this.embeddingProvider.getDimensions();\n }\n }\n\n async createEmbedding(text: string): Promise<number[]> {\n return this.embeddingProvider.createEmbedding(text);\n }\n\n async indexContent(\n id: string,\n content: string,\n metadata?: Record<string, any>\n ): Promise<void> {\n const embedding = await this.createEmbedding(content);\n\n const query = `\n INSERT INTO ${this.config.tableName} (id, ${this.config.contentColumn}, ${this.config.embeddingColumn}, metadata)\n VALUES ($1, $2, $3, $4)\n ON CONFLICT (id) DO UPDATE\n SET ${this.config.contentColumn} = $2,\n ${this.config.embeddingColumn} = $3,\n metadata = $4\n `;\n\n await this.pool.query(query, [\n id,\n content,\n `[${embedding.join(',')}]`,\n metadata ? JSON.stringify(metadata) : null,\n ]);\n }\n\n async search(\n query: string,\n limit = 10,\n threshold = 0.7\n ): Promise<SearchResult[]> {\n const queryEmbedding = await this.createEmbedding(query);\n\n // Sanitize all identifiers to prevent SQL injection\n const sanitizedTable = sanitizeSQLIdentifier(this.config.tableName);\n const sanitizedContent = sanitizeSQLIdentifier(this.config.contentColumn);\n const sanitizedEmbedding = sanitizeSQLIdentifier(\n this.config.embeddingColumn\n );\n\n const searchQuery = `\n SELECT \n id,\n ${sanitizedContent} as content,\n metadata,\n 1 - (${sanitizedEmbedding} <=> $1::vector) as similarity\n FROM ${sanitizedTable}\n WHERE 1 - (${sanitizedEmbedding} <=> $1::vector) > $2\n ORDER BY ${sanitizedEmbedding} <=> $1::vector\n LIMIT $3\n `;\n\n const result = await this.pool.query(searchQuery, [\n `[${queryEmbedding.join(',')}]`,\n threshold,\n limit,\n ]);\n\n return result.rows.map((row: any) => ({\n id: row.id,\n content: row.content,\n similarity: row.similarity,\n metadata: row.metadata,\n }));\n }\n\n async findSimilar(id: string, limit = 10): Promise<SearchResult[]> {\n // Sanitize all identifiers to prevent SQL injection\n const sanitizedTable = sanitizeSQLIdentifier(this.config.tableName);\n const sanitizedContent = sanitizeSQLIdentifier(this.config.contentColumn);\n const sanitizedEmbedding = sanitizeSQLIdentifier(\n this.config.embeddingColumn\n );\n\n const query = `\n WITH target AS (\n SELECT ${sanitizedEmbedding} as embedding\n FROM ${sanitizedTable}\n WHERE id = $1\n )\n SELECT \n t.id,\n t.${sanitizedContent} as content,\n t.metadata,\n 1 - (t.${sanitizedEmbedding} <=> target.embedding) as similarity\n FROM ${sanitizedTable} t, target\n WHERE t.id != $1\n ORDER BY t.${this.config.embeddingColumn} <=> target.embedding\n LIMIT $2\n `;\n\n const result = await this.pool.query(query, [id, limit]);\n\n return result.rows.map((row: any) => ({\n id: row.id,\n content: row.content,\n similarity: row.similarity,\n metadata: row.metadata,\n }));\n }\n\n async cluster(\n k: number,\n maxIterations = 10\n ): Promise<Map<number, SearchResult[]>> {\n // Sanitize all identifiers to prevent SQL injection\n const sanitizedTable = sanitizeSQLIdentifier(this.config.tableName);\n const sanitizedContent = sanitizeSQLIdentifier(this.config.contentColumn);\n const sanitizedEmbedding = sanitizeSQLIdentifier(\n this.config.embeddingColumn\n );\n\n // K-means clustering using pgvector\n const query = `\n WITH clusters AS (\n SELECT \n id,\n ${sanitizedContent} as content,\n metadata,\n kmeans(${sanitizedEmbedding}, $1, $2) OVER () as cluster_id\n FROM ${sanitizedTable}\n )\n SELECT * FROM clusters ORDER BY cluster_id\n `;\n\n const result = await this.pool.query(query, [k, maxIterations]);\n\n const clusterMap = new Map<number, SearchResult[]>();\n\n for (const row of result.rows) {\n const clusterId = row.cluster_id;\n if (!clusterMap.has(clusterId)) {\n clusterMap.set(clusterId, []);\n }\n\n clusterMap.get(clusterId)!.push({\n id: row.id,\n content: row.content,\n similarity: 1.0, // Cluster membership\n metadata: row.metadata,\n });\n }\n\n return clusterMap;\n }\n\n async reindex(): Promise<void> {\n // Sanitize table name to prevent SQL injection\n const sanitizedTable = sanitizeSQLIdentifier(this.config.tableName);\n\n // Rebuild the IVFFlat index for better performance\n // Using sanitized identifier prevents SQL injection\n const indexName = `idx_${sanitizedTable}_embedding`;\n const sanitizedIndex = sanitizeSQLIdentifier(indexName);\n\n const query = `REINDEX INDEX CONCURRENTLY ${sanitizedIndex}`;\n\n try {\n await this.pool.query(query);\n logger.info(`Reindexed ${sanitizedTable} embeddings`);\n } catch (error) {\n logger.error(\n 'Failed to reindex embeddings',\n error instanceof Error ? error : undefined\n );\n throw error;\n }\n }\n\n async getStats(): Promise<{\n totalDocuments: number;\n avgSimilarity: number;\n indexSize: string;\n }> {\n // Sanitize all identifiers to prevent SQL injection\n const sanitizedTable = sanitizeSQLIdentifier(this.config.tableName);\n const sanitizedEmbedding = sanitizeSQLIdentifier(\n this.config.embeddingColumn\n );\n const indexName = `idx_${sanitizedTable}_embedding`;\n\n const statsQuery = `\n SELECT \n COUNT(*) as total,\n AVG(\n 1 - (${sanitizedEmbedding} <=> (\n SELECT AVG(${sanitizedEmbedding})::vector \n FROM ${sanitizedTable}\n ))\n ) as avg_similarity,\n pg_size_pretty(\n pg_relation_size($1::regclass)\n ) as index_size\n FROM ${sanitizedTable}\n `;\n\n const result = await this.pool.query(statsQuery, [indexName]);\n const row: any = result.rows[0];\n\n return {\n totalDocuments: parseInt(row.total),\n avgSimilarity: parseFloat(row.avg_similarity) || 0,\n indexSize: row.index_size || '0 bytes',\n };\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,220 @@
1
+ import { logger } from "../../core/monitoring/logger.js";
2
+ class TimescaleAnalytics {
3
+ pool;
4
+ config;
5
+ constructor(config) {
6
+ this.pool = config.pool;
7
+ this.config = config;
8
+ }
9
+ async createContinuousAggregate(name, interval, columns) {
10
+ const aggregates = columns.map(
11
+ (col) => `
12
+ AVG(${col}) as avg_${col},
13
+ MIN(${col}) as min_${col},
14
+ MAX(${col}) as max_${col},
15
+ SUM(${col}) as sum_${col}
16
+ `
17
+ ).join(",\n ");
18
+ const query = `
19
+ CREATE MATERIALIZED VIEW IF NOT EXISTS ${name}
20
+ WITH (timescaledb.continuous) AS
21
+ SELECT
22
+ time_bucket('${interval}', ${this.config.timeColumn}) as bucket,
23
+ COUNT(*) as count,
24
+ ${aggregates}
25
+ FROM ${this.config.tableName}
26
+ GROUP BY bucket
27
+ WITH NO DATA
28
+ `;
29
+ await this.pool.query(query);
30
+ await this.pool.query(`
31
+ SELECT add_continuous_aggregate_policy('${name}',
32
+ start_offset => INTERVAL '1 month',
33
+ end_offset => INTERVAL '1 hour',
34
+ schedule_interval => INTERVAL '1 hour',
35
+ if_not_exists => TRUE
36
+ )
37
+ `);
38
+ logger.info(`Created continuous aggregate: ${name}`);
39
+ }
40
+ async getTimeSeries(startTime, endTime, interval, columns) {
41
+ const selectedColumns = columns || this.config.valueColumns;
42
+ const aggregates = selectedColumns.map(
43
+ (col) => `
44
+ AVG(${col})::float as avg_${col},
45
+ MIN(${col})::float as min_${col},
46
+ MAX(${col})::float as max_${col},
47
+ SUM(${col})::float as sum_${col}
48
+ `
49
+ ).join(",\n ");
50
+ const query = `
51
+ SELECT
52
+ time_bucket($1, ${this.config.timeColumn}) as period,
53
+ COUNT(*)::int as count,
54
+ ${aggregates}
55
+ FROM ${this.config.tableName}
56
+ WHERE ${this.config.timeColumn} >= $2
57
+ AND ${this.config.timeColumn} <= $3
58
+ GROUP BY period
59
+ ORDER BY period
60
+ `;
61
+ const result = await this.pool.query(query, [interval, startTime, endTime]);
62
+ return result.rows.map((row) => {
63
+ const avg = {};
64
+ const min = {};
65
+ const max = {};
66
+ const sum = {};
67
+ selectedColumns.forEach((col) => {
68
+ avg[col] = row[`avg_${col}`];
69
+ min[col] = row[`min_${col}`];
70
+ max[col] = row[`max_${col}`];
71
+ sum[col] = row[`sum_${col}`];
72
+ });
73
+ return {
74
+ period: row.period,
75
+ count: row.count,
76
+ avg,
77
+ min,
78
+ max,
79
+ sum
80
+ };
81
+ });
82
+ }
83
+ async detectAnomalies(column, sensitivity = 2.5, lookback = "7 days") {
84
+ const query = `
85
+ WITH stats AS (
86
+ SELECT
87
+ AVG(${column})::float as mean,
88
+ STDDEV(${column})::float as stddev
89
+ FROM ${this.config.tableName}
90
+ WHERE ${this.config.timeColumn} >= NOW() - INTERVAL '${lookback}'
91
+ ),
92
+ anomalies AS (
93
+ SELECT
94
+ ${this.config.timeColumn} as timestamp,
95
+ ${column} as value,
96
+ metadata,
97
+ ABS(${column} - stats.mean) / NULLIF(stats.stddev, 0) as z_score
98
+ FROM ${this.config.tableName}, stats
99
+ WHERE ${this.config.timeColumn} >= NOW() - INTERVAL '${lookback}'
100
+ AND ABS(${column} - stats.mean) / NULLIF(stats.stddev, 0) > $1
101
+ )
102
+ SELECT * FROM anomalies
103
+ ORDER BY z_score DESC
104
+ `;
105
+ const result = await this.pool.query(query, [sensitivity]);
106
+ return result.rows.map((row) => ({
107
+ timestamp: row.timestamp,
108
+ values: { [column]: row.value, z_score: row.z_score },
109
+ metadata: row.metadata
110
+ }));
111
+ }
112
+ async forecast(column, periods, method = "linear") {
113
+ if (method === "linear") {
114
+ const query = `
115
+ WITH regression AS (
116
+ SELECT
117
+ regr_slope(${column}, EXTRACT(EPOCH FROM ${this.config.timeColumn}))::float as slope,
118
+ regr_intercept(${column}, EXTRACT(EPOCH FROM ${this.config.timeColumn}))::float as intercept,
119
+ MAX(${this.config.timeColumn}) as last_time,
120
+ EXTRACT(EPOCH FROM MAX(${this.config.timeColumn})) as last_epoch
121
+ FROM ${this.config.tableName}
122
+ WHERE ${this.config.timeColumn} >= NOW() - INTERVAL '30 days'
123
+ ),
124
+ forecast_times AS (
125
+ SELECT
126
+ last_time + (INTERVAL '1 hour' * generate_series(1, $1)) as forecast_time
127
+ FROM regression
128
+ )
129
+ SELECT
130
+ forecast_time as timestamp,
131
+ (intercept + slope * EXTRACT(EPOCH FROM forecast_time))::float as forecast_value
132
+ FROM forecast_times, regression
133
+ `;
134
+ const result = await this.pool.query(query, [periods]);
135
+ return result.rows.map((row) => ({
136
+ timestamp: row.timestamp,
137
+ values: { [column]: row.forecast_value, forecast: true }
138
+ }));
139
+ }
140
+ logger.warn("Seasonal forecasting not yet implemented");
141
+ return [];
142
+ }
143
+ async getRetentionPolicy() {
144
+ const query = `
145
+ SELECT
146
+ hypertable_name as table_name,
147
+ drop_after::text as retention_period,
148
+ schedule_interval IS NOT NULL as is_enabled
149
+ FROM timescaledb_information.retention_policies
150
+ WHERE hypertable_name = $1
151
+ `;
152
+ const result = await this.pool.query(query, [this.config.tableName]);
153
+ return result.rows.map((row) => ({
154
+ tableName: row.table_name,
155
+ retentionPeriod: row.retention_period,
156
+ isEnabled: row.is_enabled
157
+ }));
158
+ }
159
+ async setRetentionPolicy(retentionPeriod) {
160
+ const query = `
161
+ SELECT add_retention_policy($1,
162
+ drop_after => INTERVAL '${retentionPeriod}',
163
+ if_not_exists => TRUE
164
+ )
165
+ `;
166
+ await this.pool.query(query, [this.config.tableName]);
167
+ logger.info(
168
+ `Set retention policy for ${this.config.tableName}: ${retentionPeriod}`
169
+ );
170
+ }
171
+ async compress(olderThan) {
172
+ await this.pool.query(`
173
+ ALTER TABLE ${this.config.tableName}
174
+ SET (timescaledb.compress,
175
+ timescaledb.compress_segmentby = 'type',
176
+ timescaledb.compress_orderby = '${this.config.timeColumn} DESC')
177
+ `);
178
+ await this.pool.query(
179
+ `
180
+ SELECT add_compression_policy($1,
181
+ compress_after => INTERVAL '${olderThan}',
182
+ if_not_exists => TRUE
183
+ )
184
+ `,
185
+ [this.config.tableName]
186
+ );
187
+ logger.info(
188
+ `Enabled compression for ${this.config.tableName} older than ${olderThan}`
189
+ );
190
+ }
191
+ async getChunkStats() {
192
+ const query = `
193
+ SELECT
194
+ COUNT(*) as total_chunks,
195
+ COUNT(*) FILTER (WHERE is_compressed) as compressed_chunks,
196
+ pg_size_pretty(SUM(total_bytes)) as total_size,
197
+ pg_size_pretty(SUM(total_bytes) FILTER (WHERE is_compressed)) as compressed_size,
198
+ CASE
199
+ WHEN SUM(uncompressed_total_bytes) > 0
200
+ THEN (1 - SUM(total_bytes)::float / SUM(uncompressed_total_bytes))::numeric(4,2)
201
+ ELSE 0
202
+ END as compression_ratio
203
+ FROM timescaledb_information.chunks
204
+ WHERE hypertable_name = $1
205
+ `;
206
+ const result = await this.pool.query(query, [this.config.tableName]);
207
+ const row = result.rows[0];
208
+ return {
209
+ totalChunks: parseInt(row.total_chunks) || 0,
210
+ compressedChunks: parseInt(row.compressed_chunks) || 0,
211
+ totalSize: row.total_size || "0 bytes",
212
+ compressedSize: row.compressed_size || "0 bytes",
213
+ compressionRatio: parseFloat(row.compression_ratio) || 0
214
+ };
215
+ }
216
+ }
217
+ export {
218
+ TimescaleAnalytics
219
+ };
220
+ //# sourceMappingURL=timescale-analytics.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/integrations/pg-aiguide/timescale-analytics.ts"],
4
+ "sourcesContent": ["import { Pool } from 'pg';\nimport { logger } from '../../core/monitoring/logger.js';\n\nexport interface TimeSeriesConfig {\n pool: Pool;\n tableName: string;\n timeColumn: string;\n valueColumns: string[];\n}\n\nexport interface TimeSeriesData {\n timestamp: Date;\n values: Record<string, any>;\n metadata?: Record<string, any>;\n}\n\nexport interface AggregateResult {\n period: Date;\n count: number;\n avg: Record<string, number>;\n min: Record<string, number>;\n max: Record<string, number>;\n sum: Record<string, number>;\n}\n\nexport class TimescaleAnalytics {\n private pool: Pool;\n private config: TimeSeriesConfig;\n\n constructor(config: TimeSeriesConfig) {\n this.pool = config.pool;\n this.config = config;\n }\n\n async createContinuousAggregate(\n name: string,\n interval: string,\n columns: string[]\n ): Promise<void> {\n const aggregates = columns\n .map(\n (col) => `\n AVG(${col}) as avg_${col},\n MIN(${col}) as min_${col},\n MAX(${col}) as max_${col},\n SUM(${col}) as sum_${col}\n `\n )\n .join(',\\n ');\n\n const query = `\n CREATE MATERIALIZED VIEW IF NOT EXISTS ${name}\n WITH (timescaledb.continuous) AS\n SELECT \n time_bucket('${interval}', ${this.config.timeColumn}) as bucket,\n COUNT(*) as count,\n ${aggregates}\n FROM ${this.config.tableName}\n GROUP BY bucket\n WITH NO DATA\n `;\n\n await this.pool.query(query);\n\n // Add refresh policy\n await this.pool.query(`\n SELECT add_continuous_aggregate_policy('${name}',\n start_offset => INTERVAL '1 month',\n end_offset => INTERVAL '1 hour',\n schedule_interval => INTERVAL '1 hour',\n if_not_exists => TRUE\n )\n `);\n\n logger.info(`Created continuous aggregate: ${name}`);\n }\n\n async getTimeSeries(\n startTime: Date,\n endTime: Date,\n interval: string,\n columns?: string[]\n ): Promise<AggregateResult[]> {\n const selectedColumns = columns || this.config.valueColumns;\n\n const aggregates = selectedColumns\n .map(\n (col) => `\n AVG(${col})::float as avg_${col},\n MIN(${col})::float as min_${col},\n MAX(${col})::float as max_${col},\n SUM(${col})::float as sum_${col}\n `\n )\n .join(',\\n ');\n\n const query = `\n SELECT \n time_bucket($1, ${this.config.timeColumn}) as period,\n COUNT(*)::int as count,\n ${aggregates}\n FROM ${this.config.tableName}\n WHERE ${this.config.timeColumn} >= $2\n AND ${this.config.timeColumn} <= $3\n GROUP BY period\n ORDER BY period\n `;\n\n const result = await this.pool.query(query, [interval, startTime, endTime]);\n\n return result.rows.map((row: any) => {\n const avg: Record<string, number> = {};\n const min: Record<string, number> = {};\n const max: Record<string, number> = {};\n const sum: Record<string, number> = {};\n\n selectedColumns.forEach((col) => {\n avg[col] = row[`avg_${col}`];\n min[col] = row[`min_${col}`];\n max[col] = row[`max_${col}`];\n sum[col] = row[`sum_${col}`];\n });\n\n return {\n period: row.period,\n count: row.count,\n avg,\n min,\n max,\n sum,\n };\n });\n }\n\n async detectAnomalies(\n column: string,\n sensitivity = 2.5,\n lookback = '7 days'\n ): Promise<TimeSeriesData[]> {\n const query = `\n WITH stats AS (\n SELECT \n AVG(${column})::float as mean,\n STDDEV(${column})::float as stddev\n FROM ${this.config.tableName}\n WHERE ${this.config.timeColumn} >= NOW() - INTERVAL '${lookback}'\n ),\n anomalies AS (\n SELECT \n ${this.config.timeColumn} as timestamp,\n ${column} as value,\n metadata,\n ABS(${column} - stats.mean) / NULLIF(stats.stddev, 0) as z_score\n FROM ${this.config.tableName}, stats\n WHERE ${this.config.timeColumn} >= NOW() - INTERVAL '${lookback}'\n AND ABS(${column} - stats.mean) / NULLIF(stats.stddev, 0) > $1\n )\n SELECT * FROM anomalies\n ORDER BY z_score DESC\n `;\n\n const result = await this.pool.query(query, [sensitivity]);\n\n return result.rows.map((row) => ({\n timestamp: row.timestamp,\n values: { [column]: row.value, z_score: row.z_score },\n metadata: row.metadata,\n }));\n }\n\n async forecast(\n column: string,\n periods: number,\n method: 'linear' | 'seasonal' = 'linear'\n ): Promise<TimeSeriesData[]> {\n // Simple linear regression forecast\n if (method === 'linear') {\n const query = `\n WITH regression AS (\n SELECT \n regr_slope(${column}, EXTRACT(EPOCH FROM ${this.config.timeColumn}))::float as slope,\n regr_intercept(${column}, EXTRACT(EPOCH FROM ${this.config.timeColumn}))::float as intercept,\n MAX(${this.config.timeColumn}) as last_time,\n EXTRACT(EPOCH FROM MAX(${this.config.timeColumn})) as last_epoch\n FROM ${this.config.tableName}\n WHERE ${this.config.timeColumn} >= NOW() - INTERVAL '30 days'\n ),\n forecast_times AS (\n SELECT \n last_time + (INTERVAL '1 hour' * generate_series(1, $1)) as forecast_time\n FROM regression\n )\n SELECT \n forecast_time as timestamp,\n (intercept + slope * EXTRACT(EPOCH FROM forecast_time))::float as forecast_value\n FROM forecast_times, regression\n `;\n\n const result = await this.pool.query(query, [periods]);\n\n return result.rows.map((row) => ({\n timestamp: row.timestamp,\n values: { [column]: row.forecast_value, forecast: true },\n }));\n }\n\n // Seasonal decomposition would require more complex logic\n logger.warn('Seasonal forecasting not yet implemented');\n return [];\n }\n\n async getRetentionPolicy(): Promise<\n {\n tableName: string;\n retentionPeriod: string;\n isEnabled: boolean;\n }[]\n > {\n const query = `\n SELECT \n hypertable_name as table_name,\n drop_after::text as retention_period,\n schedule_interval IS NOT NULL as is_enabled\n FROM timescaledb_information.retention_policies\n WHERE hypertable_name = $1\n `;\n\n const result = await this.pool.query(query, [this.config.tableName]);\n\n return result.rows.map((row) => ({\n tableName: row.table_name,\n retentionPeriod: row.retention_period,\n isEnabled: row.is_enabled,\n }));\n }\n\n async setRetentionPolicy(retentionPeriod: string): Promise<void> {\n const query = `\n SELECT add_retention_policy($1, \n drop_after => INTERVAL '${retentionPeriod}',\n if_not_exists => TRUE\n )\n `;\n\n await this.pool.query(query, [this.config.tableName]);\n logger.info(\n `Set retention policy for ${this.config.tableName}: ${retentionPeriod}`\n );\n }\n\n async compress(olderThan: string): Promise<void> {\n // Enable compression\n await this.pool.query(`\n ALTER TABLE ${this.config.tableName} \n SET (timescaledb.compress, \n timescaledb.compress_segmentby = 'type',\n timescaledb.compress_orderby = '${this.config.timeColumn} DESC')\n `);\n\n // Add compression policy\n await this.pool.query(\n `\n SELECT add_compression_policy($1,\n compress_after => INTERVAL '${olderThan}',\n if_not_exists => TRUE\n )\n `,\n [this.config.tableName]\n );\n\n logger.info(\n `Enabled compression for ${this.config.tableName} older than ${olderThan}`\n );\n }\n\n async getChunkStats(): Promise<{\n totalChunks: number;\n compressedChunks: number;\n totalSize: string;\n compressedSize: string;\n compressionRatio: number;\n }> {\n const query = `\n SELECT \n COUNT(*) as total_chunks,\n COUNT(*) FILTER (WHERE is_compressed) as compressed_chunks,\n pg_size_pretty(SUM(total_bytes)) as total_size,\n pg_size_pretty(SUM(total_bytes) FILTER (WHERE is_compressed)) as compressed_size,\n CASE \n WHEN SUM(uncompressed_total_bytes) > 0 \n THEN (1 - SUM(total_bytes)::float / SUM(uncompressed_total_bytes))::numeric(4,2)\n ELSE 0\n END as compression_ratio\n FROM timescaledb_information.chunks\n WHERE hypertable_name = $1\n `;\n\n const result = await this.pool.query(query, [this.config.tableName]);\n const row = result.rows[0];\n\n return {\n totalChunks: parseInt(row.total_chunks) || 0,\n compressedChunks: parseInt(row.compressed_chunks) || 0,\n totalSize: row.total_size || '0 bytes',\n compressedSize: row.compressed_size || '0 bytes',\n compressionRatio: parseFloat(row.compression_ratio) || 0,\n };\n }\n}\n"],
5
+ "mappings": "AACA,SAAS,cAAc;AAwBhB,MAAM,mBAAmB;AAAA,EACtB;AAAA,EACA;AAAA,EAER,YAAY,QAA0B;AACpC,SAAK,OAAO,OAAO;AACnB,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,MAAM,0BACJ,MACA,UACA,SACe;AACf,UAAM,aAAa,QAChB;AAAA,MACC,CAAC,QAAQ;AAAA,YACL,GAAG,YAAY,GAAG;AAAA,YAClB,GAAG,YAAY,GAAG;AAAA,YAClB,GAAG,YAAY,GAAG;AAAA,YAClB,GAAG,YAAY,GAAG;AAAA;AAAA,IAExB,EACC,KAAK,WAAW;AAEnB,UAAM,QAAQ;AAAA,+CAC6B,IAAI;AAAA;AAAA;AAAA,uBAG5B,QAAQ,MAAM,KAAK,OAAO,UAAU;AAAA;AAAA,UAEjD,UAAU;AAAA,aACP,KAAK,OAAO,SAAS;AAAA;AAAA;AAAA;AAK9B,UAAM,KAAK,KAAK,MAAM,KAAK;AAG3B,UAAM,KAAK,KAAK,MAAM;AAAA,gDACsB,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAM/C;AAED,WAAO,KAAK,iCAAiC,IAAI,EAAE;AAAA,EACrD;AAAA,EAEA,MAAM,cACJ,WACA,SACA,UACA,SAC4B;AAC5B,UAAM,kBAAkB,WAAW,KAAK,OAAO;AAE/C,UAAM,aAAa,gBAChB;AAAA,MACC,CAAC,QAAQ;AAAA,YACL,GAAG,mBAAmB,GAAG;AAAA,YACzB,GAAG,mBAAmB,GAAG;AAAA,YACzB,GAAG,mBAAmB,GAAG;AAAA,YACzB,GAAG,mBAAmB,GAAG;AAAA;AAAA,IAE/B,EACC,KAAK,WAAW;AAEnB,UAAM,QAAQ;AAAA;AAAA,0BAEQ,KAAK,OAAO,UAAU;AAAA;AAAA,UAEtC,UAAU;AAAA,aACP,KAAK,OAAO,SAAS;AAAA,cACpB,KAAK,OAAO,UAAU;AAAA,cACtB,KAAK,OAAO,UAAU;AAAA;AAAA;AAAA;AAKhC,UAAM,SAAS,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,UAAU,WAAW,OAAO,CAAC;AAE1E,WAAO,OAAO,KAAK,IAAI,CAAC,QAAa;AACnC,YAAM,MAA8B,CAAC;AACrC,YAAM,MAA8B,CAAC;AACrC,YAAM,MAA8B,CAAC;AACrC,YAAM,MAA8B,CAAC;AAErC,sBAAgB,QAAQ,CAAC,QAAQ;AAC/B,YAAI,GAAG,IAAI,IAAI,OAAO,GAAG,EAAE;AAC3B,YAAI,GAAG,IAAI,IAAI,OAAO,GAAG,EAAE;AAC3B,YAAI,GAAG,IAAI,IAAI,OAAO,GAAG,EAAE;AAC3B,YAAI,GAAG,IAAI,IAAI,OAAO,GAAG,EAAE;AAAA,MAC7B,CAAC;AAED,aAAO;AAAA,QACL,QAAQ,IAAI;AAAA,QACZ,OAAO,IAAI;AAAA,QACX;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,gBACJ,QACA,cAAc,KACd,WAAW,UACgB;AAC3B,UAAM,QAAQ;AAAA;AAAA;AAAA,gBAGF,MAAM;AAAA,mBACH,MAAM;AAAA,eACV,KAAK,OAAO,SAAS;AAAA,gBACpB,KAAK,OAAO,UAAU,yBAAyB,QAAQ;AAAA;AAAA;AAAA;AAAA,YAI3D,KAAK,OAAO,UAAU;AAAA,YACtB,MAAM;AAAA;AAAA,gBAEF,MAAM;AAAA,eACP,KAAK,OAAO,SAAS;AAAA,gBACpB,KAAK,OAAO,UAAU,yBAAyB,QAAQ;AAAA,oBACnD,MAAM;AAAA;AAAA;AAAA;AAAA;AAMtB,UAAM,SAAS,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,WAAW,CAAC;AAEzD,WAAO,OAAO,KAAK,IAAI,CAAC,SAAS;AAAA,MAC/B,WAAW,IAAI;AAAA,MACf,QAAQ,EAAE,CAAC,MAAM,GAAG,IAAI,OAAO,SAAS,IAAI,QAAQ;AAAA,MACpD,UAAU,IAAI;AAAA,IAChB,EAAE;AAAA,EACJ;AAAA,EAEA,MAAM,SACJ,QACA,SACA,SAAgC,UACL;AAE3B,QAAI,WAAW,UAAU;AACvB,YAAM,QAAQ;AAAA;AAAA;AAAA,yBAGK,MAAM,wBAAwB,KAAK,OAAO,UAAU;AAAA,6BAChD,MAAM,wBAAwB,KAAK,OAAO,UAAU;AAAA,kBAC/D,KAAK,OAAO,UAAU;AAAA,qCACH,KAAK,OAAO,UAAU;AAAA,iBAC1C,KAAK,OAAO,SAAS;AAAA,kBACpB,KAAK,OAAO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAalC,YAAM,SAAS,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,OAAO,CAAC;AAErD,aAAO,OAAO,KAAK,IAAI,CAAC,SAAS;AAAA,QAC/B,WAAW,IAAI;AAAA,QACf,QAAQ,EAAE,CAAC,MAAM,GAAG,IAAI,gBAAgB,UAAU,KAAK;AAAA,MACzD,EAAE;AAAA,IACJ;AAGA,WAAO,KAAK,0CAA0C;AACtD,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,MAAM,qBAMJ;AACA,UAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASd,UAAM,SAAS,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,KAAK,OAAO,SAAS,CAAC;AAEnE,WAAO,OAAO,KAAK,IAAI,CAAC,SAAS;AAAA,MAC/B,WAAW,IAAI;AAAA,MACf,iBAAiB,IAAI;AAAA,MACrB,WAAW,IAAI;AAAA,IACjB,EAAE;AAAA,EACJ;AAAA,EAEA,MAAM,mBAAmB,iBAAwC;AAC/D,UAAM,QAAQ;AAAA;AAAA,kCAEgB,eAAe;AAAA;AAAA;AAAA;AAK7C,UAAM,KAAK,KAAK,MAAM,OAAO,CAAC,KAAK,OAAO,SAAS,CAAC;AACpD,WAAO;AAAA,MACL,4BAA4B,KAAK,OAAO,SAAS,KAAK,eAAe;AAAA,IACvE;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,WAAkC;AAE/C,UAAM,KAAK,KAAK,MAAM;AAAA,oBACN,KAAK,OAAO,SAAS;AAAA;AAAA;AAAA,6CAGI,KAAK,OAAO,UAAU;AAAA,KAC9D;AAGD,UAAM,KAAK,KAAK;AAAA,MACd;AAAA;AAAA,sCAEgC,SAAS;AAAA;AAAA;AAAA;AAAA,MAIzC,CAAC,KAAK,OAAO,SAAS;AAAA,IACxB;AAEA,WAAO;AAAA,MACL,2BAA2B,KAAK,OAAO,SAAS,eAAe,SAAS;AAAA,IAC1E;AAAA,EACF;AAAA,EAEA,MAAM,gBAMH;AACD,UAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAed,UAAM,SAAS,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,KAAK,OAAO,SAAS,CAAC;AACnE,UAAM,MAAM,OAAO,KAAK,CAAC;AAEzB,WAAO;AAAA,MACL,aAAa,SAAS,IAAI,YAAY,KAAK;AAAA,MAC3C,kBAAkB,SAAS,IAAI,iBAAiB,KAAK;AAAA,MACrD,WAAW,IAAI,cAAc;AAAA,MAC7B,gBAAgB,IAAI,mBAAmB;AAAA,MACvC,kBAAkB,WAAW,IAAI,iBAAiB,KAAK;AAAA,IACzD;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }