profclaw 2.0.0 → 2.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 (477) hide show
  1. package/.env.example +14 -2
  2. package/CHANGELOG.md +37 -0
  3. package/CONTRIBUTING.md +20 -0
  4. package/Dockerfile +39 -23
  5. package/README.md +174 -40
  6. package/dist/agents/agent-summary.d.ts +44 -0
  7. package/dist/agents/agent-summary.js +176 -0
  8. package/dist/agents/auto-memory.d.ts +59 -0
  9. package/dist/agents/auto-memory.js +310 -0
  10. package/dist/agents/checkpoint-manager.d.ts +76 -0
  11. package/dist/agents/checkpoint-manager.js +156 -0
  12. package/dist/agents/circuit-breaker.d.ts +54 -0
  13. package/dist/agents/circuit-breaker.js +153 -0
  14. package/dist/agents/context-compactor.d.ts +70 -0
  15. package/dist/agents/context-compactor.js +361 -0
  16. package/dist/agents/conversation-branch.d.ts +55 -0
  17. package/dist/agents/conversation-branch.js +115 -0
  18. package/dist/agents/error-recovery.d.ts +44 -0
  19. package/dist/agents/error-recovery.js +197 -0
  20. package/dist/agents/events.d.ts +76 -0
  21. package/dist/agents/events.js +8 -0
  22. package/dist/agents/executor.d.ts +35 -1
  23. package/dist/agents/executor.js +573 -124
  24. package/dist/agents/file-snapshots.d.ts +72 -0
  25. package/dist/agents/file-snapshots.js +182 -0
  26. package/dist/agents/index.d.ts +2 -0
  27. package/dist/agents/orchestrator.d.ts +183 -0
  28. package/dist/agents/orchestrator.js +495 -0
  29. package/dist/agents/permissions.d.ts +63 -0
  30. package/dist/agents/permissions.js +138 -0
  31. package/dist/agents/plan-mode.d.ts +71 -0
  32. package/dist/agents/plan-mode.js +186 -0
  33. package/dist/agents/prompt-suggestions.d.ts +33 -0
  34. package/dist/agents/prompt-suggestions.js +208 -0
  35. package/dist/agents/rate-limit-monitor.d.ts +56 -0
  36. package/dist/agents/rate-limit-monitor.js +224 -0
  37. package/dist/agents/result-store.d.ts +37 -0
  38. package/dist/agents/result-store.js +104 -0
  39. package/dist/agents/session-diff.d.ts +43 -0
  40. package/dist/agents/session-diff.js +258 -0
  41. package/dist/agents/tool-loader.d.ts +65 -0
  42. package/dist/agents/tool-loader.js +273 -0
  43. package/dist/agents/transcript.d.ts +96 -0
  44. package/dist/agents/transcript.js +267 -0
  45. package/dist/agents/worktree-manager.d.ts +80 -0
  46. package/dist/agents/worktree-manager.js +203 -0
  47. package/dist/auth/middleware.js +14 -0
  48. package/dist/chat/agentic-executor.d.ts +7 -0
  49. package/dist/chat/agentic-executor.js +253 -30
  50. package/dist/chat/conversations.d.ts +2 -0
  51. package/dist/chat/conversations.js +8 -0
  52. package/dist/chat/execution/executor.d.ts +8 -0
  53. package/dist/chat/execution/executor.js +157 -103
  54. package/dist/chat/execution/index.js +5 -1
  55. package/dist/chat/execution/tool-router.js +40 -14
  56. package/dist/chat/execution/tools/canvas.d.ts +2 -2
  57. package/dist/chat/execution/tools/code-tools.d.ts +66 -0
  58. package/dist/chat/execution/tools/code-tools.js +353 -0
  59. package/dist/chat/execution/tools/complete-task.d.ts +2 -2
  60. package/dist/chat/execution/tools/cron-tool.d.ts +26 -10
  61. package/dist/chat/execution/tools/cron-tool.js +48 -3
  62. package/dist/chat/execution/tools/decompose-task.d.ts +58 -0
  63. package/dist/chat/execution/tools/decompose-task.js +166 -0
  64. package/dist/chat/execution/tools/exec.d.ts +5 -2
  65. package/dist/chat/execution/tools/exec.js +294 -155
  66. package/dist/chat/execution/tools/feed-tools.d.ts +77 -0
  67. package/dist/chat/execution/tools/feed-tools.js +142 -0
  68. package/dist/chat/execution/tools/file-ops.d.ts +1 -1
  69. package/dist/chat/execution/tools/github.d.ts +2 -2
  70. package/dist/chat/execution/tools/index.d.ts +14 -2
  71. package/dist/chat/execution/tools/index.js +86 -12
  72. package/dist/chat/execution/tools/integrations.d.ts +8 -8
  73. package/dist/chat/execution/tools/multi-patch.d.ts +53 -0
  74. package/dist/chat/execution/tools/multi-patch.js +373 -0
  75. package/dist/chat/execution/tools/openai-image-gen.d.ts +2 -2
  76. package/dist/chat/execution/tools/plan-tools.d.ts +80 -0
  77. package/dist/chat/execution/tools/plan-tools.js +134 -0
  78. package/dist/chat/execution/tools/profclaw-ops.d.ts +6 -6
  79. package/dist/chat/execution/tools/repl-tool.d.ts +46 -0
  80. package/dist/chat/execution/tools/repl-tool.js +207 -0
  81. package/dist/chat/execution/tools/sessions-send.d.ts +2 -2
  82. package/dist/chat/execution/tools/slack-actions.d.ts +2 -2
  83. package/dist/chat/execution/tools/system.d.ts +4 -4
  84. package/dist/chat/execution/tools/todo-tool.d.ts +72 -0
  85. package/dist/chat/execution/tools/todo-tool.js +152 -0
  86. package/dist/chat/execution/tools/tool-search.d.ts +50 -0
  87. package/dist/chat/execution/tools/tool-search.js +155 -0
  88. package/dist/chat/execution/types.d.ts +21 -14
  89. package/dist/chat/execution/workflows/executor.d.ts +11 -0
  90. package/dist/chat/execution/workflows/executor.js +99 -1
  91. package/dist/chat/execution/workflows/types.d.ts +35 -2
  92. package/dist/chat/format/index.d.ts +1 -0
  93. package/dist/chat/format/index.js +1 -0
  94. package/dist/chat/format/markdown-convert.d.ts +23 -0
  95. package/dist/chat/format/markdown-convert.js +149 -0
  96. package/dist/chat/index.d.ts +1 -1
  97. package/dist/chat/index.js +1 -1
  98. package/dist/chat/message-handler.js +58 -6
  99. package/dist/chat/proactive/index.d.ts +62 -0
  100. package/dist/chat/proactive/index.js +147 -0
  101. package/dist/chat/prompt-adapter.js +2 -0
  102. package/dist/chat/providers/irc/index.d.ts +2 -2
  103. package/dist/chat/providers/telegram/index.d.ts +2 -0
  104. package/dist/chat/providers/telegram/index.js +21 -2
  105. package/dist/chat/system-prompts.d.ts +3 -3
  106. package/dist/chat/system-prompts.js +116 -61
  107. package/dist/chat/tools.d.ts +6 -6
  108. package/dist/cli/commands/auth.js +64 -1
  109. package/dist/cli/commands/chat.js +1327 -138
  110. package/dist/cli/commands/doctor.js +222 -16
  111. package/dist/cli/commands/history.d.ts +3 -0
  112. package/dist/cli/commands/history.js +138 -0
  113. package/dist/cli/commands/import.d.ts +44 -0
  114. package/dist/cli/commands/import.js +526 -0
  115. package/dist/cli/commands/init.d.ts +13 -0
  116. package/dist/cli/commands/init.js +381 -0
  117. package/dist/cli/commands/onboard.js +210 -30
  118. package/dist/cli/commands/plan.d.ts +13 -0
  119. package/dist/cli/commands/plan.js +184 -0
  120. package/dist/cli/commands/serve.d.ts +7 -0
  121. package/dist/cli/commands/serve.js +77 -18
  122. package/dist/cli/commands/setup.js +84 -3
  123. package/dist/cli/commands/status.js +54 -0
  124. package/dist/cli/commands/tools.js +13 -13
  125. package/dist/cli/commands/tui.js +26 -1
  126. package/dist/cli/index.js +19 -0
  127. package/dist/cli/ink/App.d.ts +13 -0
  128. package/dist/cli/ink/App.js +6 -0
  129. package/dist/cli/ink/ChatApp.d.ts +60 -0
  130. package/dist/cli/ink/ChatApp.js +325 -0
  131. package/dist/cli/ink/DashboardApp.d.ts +3 -0
  132. package/dist/cli/ink/DashboardApp.js +143 -0
  133. package/dist/cli/ink/components/AgentStatus.d.ts +17 -0
  134. package/dist/cli/ink/components/AgentStatus.js +33 -0
  135. package/dist/cli/ink/components/ChannelList.d.ts +17 -0
  136. package/dist/cli/ink/components/ChannelList.js +33 -0
  137. package/dist/cli/ink/components/ConnectionStatus.d.ts +19 -0
  138. package/dist/cli/ink/components/ConnectionStatus.js +50 -0
  139. package/dist/cli/ink/components/CostBar.d.ts +19 -0
  140. package/dist/cli/ink/components/CostBar.js +35 -0
  141. package/dist/cli/ink/components/HookStatus.d.ts +15 -0
  142. package/dist/cli/ink/components/HookStatus.js +7 -0
  143. package/dist/cli/ink/components/PermissionPrompt.d.ts +21 -0
  144. package/dist/cli/ink/components/PermissionPrompt.js +51 -0
  145. package/dist/cli/ink/components/PlanView.d.ts +23 -0
  146. package/dist/cli/ink/components/PlanView.js +26 -0
  147. package/dist/cli/ink/components/ProviderList.d.ts +16 -0
  148. package/dist/cli/ink/components/ProviderList.js +16 -0
  149. package/dist/cli/ink/components/SessionHeader.d.ts +15 -0
  150. package/dist/cli/ink/components/SessionHeader.js +15 -0
  151. package/dist/cli/ink/components/StreamingMessage.d.ts +20 -0
  152. package/dist/cli/ink/components/StreamingMessage.js +27 -0
  153. package/dist/cli/ink/components/SuggestionBar.d.ts +15 -0
  154. package/dist/cli/ink/components/SuggestionBar.js +28 -0
  155. package/dist/cli/ink/components/SystemHealth.d.ts +20 -0
  156. package/dist/cli/ink/components/SystemHealth.js +39 -0
  157. package/dist/cli/ink/components/TaskList.d.ts +17 -0
  158. package/dist/cli/ink/components/TaskList.js +59 -0
  159. package/dist/cli/ink/components/ToolCall.d.ts +17 -0
  160. package/dist/cli/ink/components/ToolCall.js +43 -0
  161. package/dist/cli/ink/index.d.ts +23 -0
  162. package/dist/cli/ink/index.js +15 -0
  163. package/dist/cli/ink/keybindings.d.ts +35 -0
  164. package/dist/cli/ink/keybindings.js +105 -0
  165. package/dist/cli/ink/markdown-renderer.d.ts +47 -0
  166. package/dist/cli/ink/markdown-renderer.js +380 -0
  167. package/dist/cli/ink/output-styles.d.ts +39 -0
  168. package/dist/cli/ink/output-styles.js +119 -0
  169. package/dist/cli/interactive/auto-serve.d.ts +38 -0
  170. package/dist/cli/interactive/auto-serve.js +209 -0
  171. package/dist/cli/interactive/index.d.ts +25 -0
  172. package/dist/cli/interactive/index.js +23 -0
  173. package/dist/cli/interactive/picker.d.ts +28 -0
  174. package/dist/cli/interactive/picker.js +153 -0
  175. package/dist/cli/interactive/renderer.d.ts +26 -0
  176. package/dist/cli/interactive/renderer.js +555 -0
  177. package/dist/cli/interactive/repl.d.ts +14 -0
  178. package/dist/cli/interactive/repl.js +1516 -0
  179. package/dist/cli/interactive/stream-client.d.ts +59 -0
  180. package/dist/cli/interactive/stream-client.js +506 -0
  181. package/dist/cli/interactive/types.d.ts +121 -0
  182. package/dist/cli/interactive/types.js +10 -0
  183. package/dist/cli/utils/api.d.ts +9 -0
  184. package/dist/cli/utils/api.js +58 -2
  185. package/dist/cron/natural-language.d.ts +54 -0
  186. package/dist/cron/natural-language.js +569 -0
  187. package/dist/cron/scheduler.d.ts +34 -4
  188. package/dist/cron/scheduler.js +141 -9
  189. package/dist/cron/templates.d.ts +1 -1
  190. package/dist/cron/templates.js +219 -0
  191. package/dist/feeds/feed-engine.d.ts +149 -0
  192. package/dist/feeds/feed-engine.js +600 -0
  193. package/dist/feeds/index.d.ts +9 -0
  194. package/dist/feeds/index.js +8 -0
  195. package/dist/gateway/router.js +6 -1
  196. package/dist/hooks/built-in/audit-log.d.ts +11 -0
  197. package/dist/hooks/built-in/audit-log.js +84 -0
  198. package/dist/hooks/built-in/cost-warning.d.ts +10 -0
  199. package/dist/hooks/built-in/cost-warning.js +59 -0
  200. package/dist/hooks/built-in/dangerous-tool.d.ts +32 -0
  201. package/dist/hooks/built-in/dangerous-tool.js +80 -0
  202. package/dist/hooks/built-in/index.d.ts +14 -0
  203. package/dist/hooks/built-in/index.js +20 -0
  204. package/dist/hooks/index.d.ts +3 -0
  205. package/dist/hooks/index.js +6 -0
  206. package/dist/hooks/loader.d.ts +17 -0
  207. package/dist/hooks/loader.js +142 -0
  208. package/dist/hooks/registry.d.ts +62 -0
  209. package/dist/hooks/registry.js +127 -0
  210. package/dist/integrations/web-search.js +6 -3
  211. package/dist/memory/index.d.ts +1 -0
  212. package/dist/memory/index.js +2 -0
  213. package/dist/memory/memory-service.js +14 -13
  214. package/dist/memory/observational.d.ts +62 -0
  215. package/dist/memory/observational.js +396 -0
  216. package/dist/middleware/content-filter.d.ts +22 -0
  217. package/dist/middleware/content-filter.js +69 -0
  218. package/dist/middleware/request-validator.d.ts +159 -0
  219. package/dist/middleware/request-validator.js +93 -0
  220. package/dist/plugins/sdk.d.ts +22 -0
  221. package/dist/plugins/sdk.js +17 -1
  222. package/dist/projects/types.d.ts +10 -10
  223. package/dist/providers/ai-sdk.d.ts +11 -0
  224. package/dist/providers/ai-sdk.js +78 -19
  225. package/dist/providers/core/models.js +67 -1
  226. package/dist/providers/core/types.d.ts +3 -0
  227. package/dist/providers/index.d.ts +1 -0
  228. package/dist/providers/index.js +1 -0
  229. package/dist/providers/smart-router.d.ts +118 -0
  230. package/dist/providers/smart-router.js +685 -0
  231. package/dist/providers/types.d.ts +16 -16
  232. package/dist/routes/agents.js +50 -0
  233. package/dist/routes/auth.js +8 -1
  234. package/dist/routes/chat.js +259 -14
  235. package/dist/routes/costs.js +32 -0
  236. package/dist/routes/cron.js +80 -5
  237. package/dist/routes/feeds.d.ts +10 -0
  238. package/dist/routes/feeds.js +168 -0
  239. package/dist/routes/mcp.js +21 -0
  240. package/dist/routes/memory.js +130 -0
  241. package/dist/routes/skills.js +129 -0
  242. package/dist/routes/teams.d.ts +9 -0
  243. package/dist/routes/teams.js +210 -0
  244. package/dist/routes/tools.js +14 -0
  245. package/dist/routes/users.js +2 -0
  246. package/dist/server/route-loader.js +3 -1
  247. package/dist/server/stream-bridge.d.ts +19 -0
  248. package/dist/server/stream-bridge.js +38 -0
  249. package/dist/server.js +310 -36
  250. package/dist/skills/marketplace.d.ts +87 -0
  251. package/dist/skills/marketplace.js +268 -0
  252. package/dist/storage/index.d.ts +14 -0
  253. package/dist/storage/index.js +64 -3
  254. package/dist/storage/schema.d.ts +4 -4
  255. package/dist/storage/schema.js +1 -1
  256. package/dist/teams/index.d.ts +110 -0
  257. package/dist/teams/index.js +365 -0
  258. package/dist/tickets/types.d.ts +39 -39
  259. package/dist/types/summary.d.ts +5 -5
  260. package/dist/utils/auto-update.d.ts +23 -0
  261. package/dist/utils/auto-update.js +157 -0
  262. package/dist/utils/offline-detect.d.ts +55 -0
  263. package/dist/utils/offline-detect.js +121 -0
  264. package/dist/utils/pid-file.d.ts +36 -0
  265. package/dist/utils/pid-file.js +125 -0
  266. package/dist/utils/prevent-sleep.d.ts +27 -0
  267. package/dist/utils/prevent-sleep.js +95 -0
  268. package/dist/utils/sanitizer.d.ts +57 -0
  269. package/dist/utils/sanitizer.js +174 -0
  270. package/docker-compose.yml +13 -137
  271. package/package.json +31 -6
  272. package/skills/deploy-cloudflare/SKILL.md +62 -0
  273. package/skills/deploy-vercel/SKILL.md +67 -0
  274. package/skills/docker-deploy/SKILL.md +158 -0
  275. package/skills/full-stack-builder/SKILL.md +92 -0
  276. package/skills/humanizer/SKILL.md +488 -0
  277. package/skills/profclaw-assistant/SKILL.md +85 -56
  278. package/ui/dist/assets/ActivityView-Da6HQ8ws.js +1 -0
  279. package/ui/dist/assets/AgentList-H58R0kX3.js +1 -0
  280. package/ui/dist/assets/AnalyticsDashboard-B28AeRsc.js +1 -0
  281. package/ui/dist/assets/AreaChart-DwLzeAQ8.js +1 -0
  282. package/ui/dist/assets/CartesianChart-piKQsTAR.js +36 -0
  283. package/ui/dist/assets/ChatView-Dbj8rxU5.js +10 -0
  284. package/ui/dist/assets/CostsDashboard-C6F5df0F.js +1 -0
  285. package/ui/dist/assets/EstimateSelect-wga0rUKX.js +1 -0
  286. package/ui/dist/assets/FeedDashboard-Ef6FEzEf.js +1 -0
  287. package/ui/dist/assets/FloatingChatbot-0yhkUeCq.js +2 -0
  288. package/ui/dist/assets/InviteCodeManagement-tUXfx4Bc.js +2 -0
  289. package/ui/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  290. package/ui/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  291. package/ui/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  292. package/ui/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  293. package/ui/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  294. package/ui/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  295. package/ui/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  296. package/ui/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  297. package/ui/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  298. package/ui/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  299. package/ui/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  300. package/ui/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  301. package/ui/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  302. package/ui/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  303. package/ui/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  304. package/ui/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  305. package/ui/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  306. package/ui/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  307. package/ui/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  308. package/ui/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  309. package/ui/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  310. package/ui/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  311. package/ui/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  312. package/ui/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  313. package/ui/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  314. package/ui/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  315. package/ui/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  316. package/ui/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  317. package/ui/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  318. package/ui/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  319. package/ui/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  320. package/ui/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  321. package/ui/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  322. package/ui/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  323. package/ui/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  324. package/ui/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  325. package/ui/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  326. package/ui/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  327. package/ui/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  328. package/ui/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  329. package/ui/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  330. package/ui/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  331. package/ui/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  332. package/ui/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  333. package/ui/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  334. package/ui/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  335. package/ui/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  336. package/ui/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  337. package/ui/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  338. package/ui/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  339. package/ui/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  340. package/ui/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  341. package/ui/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  342. package/ui/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  343. package/ui/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  344. package/ui/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  345. package/ui/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  346. package/ui/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  347. package/ui/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  348. package/ui/dist/assets/MarketplacePage-DGrLtolR.js +1 -0
  349. package/ui/dist/assets/{ProjectDetail--gPfvATB.js → ProjectDetail-BgWvA6UP.js} +2 -2
  350. package/ui/dist/assets/ProjectIcon-TDuliqwg.js +1 -0
  351. package/ui/dist/assets/ProjectList-DXgM4187.js +1 -0
  352. package/ui/dist/assets/{Settings-1kaf7VHE.js → Settings-xA8Zhi3p.js} +3 -3
  353. package/ui/dist/assets/StatusIndicator-B8vfFAxg.js +1 -0
  354. package/ui/dist/assets/{SummaryDetail-DV3AmONk.js → SummaryDetail-eedRfTtF.js} +2 -2
  355. package/ui/dist/assets/SummaryList-CLNX2P84.js +1 -0
  356. package/ui/dist/assets/TaskDetail-BtWclNiR.js +1 -0
  357. package/ui/dist/assets/TaskList-JjODAgSc.js +1 -0
  358. package/ui/dist/assets/TeamsPage-CBK5iAyx.js +1 -0
  359. package/ui/dist/assets/TicketBoard-C9aJNNYp.js +1 -0
  360. package/ui/dist/assets/TicketDetail-CV5JmL31.js +1 -0
  361. package/ui/dist/assets/TicketList-68V4lzUz.js +1 -0
  362. package/ui/dist/assets/UserManagement-DKTb6UpE.js +2 -0
  363. package/ui/dist/assets/ViewSwitcher-BvdQht2Y.js +1 -0
  364. package/ui/dist/assets/alert-dialog-O6qBOv_f.js +1 -0
  365. package/ui/dist/assets/{archive-BsLa7brF.js → archive-CX7UvZpf.js} +1 -1
  366. package/ui/dist/assets/badge-BbfnwDJP.js +1 -0
  367. package/ui/dist/assets/{bug-CmZI7jqM.js → bug-3WX0394-.js} +1 -1
  368. package/ui/dist/assets/{calendar-Bf0t2B82.js → calendar-buq77TaS.js} +1 -1
  369. package/ui/dist/assets/{chevron-up-CoUsOvZj.js → chevron-up-4ymsBJRo.js} +1 -1
  370. package/ui/dist/assets/{circle-x-Dgw11LgT.js → circle-x-ByXtwR6Y.js} +1 -1
  371. package/ui/dist/assets/constants-CVdDh7p0.js +1 -0
  372. package/ui/dist/assets/{cpu-DiPMQICV.js → cpu-CiuoCeDY.js} +1 -1
  373. package/ui/dist/assets/{database-BwTfupDi.js → database-BWXSBg5a.js} +1 -1
  374. package/ui/dist/assets/dialog-lDg4NvMV.js +1 -0
  375. package/ui/dist/assets/dollar-sign-Dmijd6DP.js +1 -0
  376. package/ui/dist/assets/{ellipsis-UJx4Xnf6.js → ellipsis-vT-5SVIp.js} +1 -1
  377. package/ui/dist/assets/{ellipsis-vertical-DoULYEKn.js → ellipsis-vertical-B4tAX_bL.js} +1 -1
  378. package/ui/dist/assets/feature-markdown-DBo5Q7uq.js +289 -0
  379. package/ui/dist/assets/{file-code-B2UrJLwi.js → file-code-ChOWdKXf.js} +1 -1
  380. package/ui/dist/assets/{folder-open-BJi577JH.js → folder-open-CkOUbIiP.js} +1 -1
  381. package/ui/dist/assets/{funnel-PkaD_HSR.js → funnel-uZkoSPP-.js} +1 -1
  382. package/ui/dist/assets/{git-branch-C_K30am0.js → git-branch-CwvUxj7C.js} +1 -1
  383. package/ui/dist/assets/{git-commit-horizontal-IT6ecxWQ.js → git-commit-horizontal-lxPzCvhD.js} +1 -1
  384. package/ui/dist/assets/{globe-f-jjCa_g.js → globe-D_WpJdsj.js} +1 -1
  385. package/ui/dist/assets/{hash-DNEv8Elo.js → hash-CA0hJ7vh.js} +1 -1
  386. package/ui/dist/assets/{history-BQSBo_1Q.js → history-CEWMLELs.js} +1 -1
  387. package/ui/dist/assets/inbox-ehtOptTV.js +1 -0
  388. package/ui/dist/assets/{index-nS3EErDg.js → index-C1rhbml4.js} +3 -3
  389. package/ui/dist/assets/index-CR8gfCHv.js +1 -0
  390. package/ui/dist/assets/index-DVXMpWai.js +1 -0
  391. package/ui/dist/assets/index-DaDJMM2v.js +1 -0
  392. package/ui/dist/assets/index-Djdq_0xu.js +1 -0
  393. package/ui/dist/assets/index-M46Gcb8K.css +1 -0
  394. package/ui/dist/assets/index-sEBN7w8J.js +109 -0
  395. package/ui/dist/assets/layers-C6Mhf8Nk.js +1 -0
  396. package/ui/dist/assets/{layout-dashboard-CcKt1hXw.js → layout-dashboard-BRUM0kpT.js} +1 -1
  397. package/ui/dist/assets/{lightbulb-Jhp7FvbU.js → lightbulb-CN2q1O5l.js} +1 -1
  398. package/ui/dist/assets/{link-2-DdO7ostF.js → link-2-CC4E28yJ.js} +1 -1
  399. package/ui/dist/assets/markdown-renderer-C6ENbB0u.js +10 -0
  400. package/ui/dist/assets/markdown-renderer-CfVKi3_s.css +1 -0
  401. package/ui/dist/assets/{message-square-CBgH65X7.js → message-square-Bbb241am.js} +1 -1
  402. package/ui/dist/assets/package-CwT3IzFx.js +1 -0
  403. package/ui/dist/assets/{pencil-CYXCEPQh.js → pencil-CDmiHzoj.js} +1 -1
  404. package/ui/dist/assets/{play-d1ONaH0-.js → play-tjy5jMQX.js} +1 -1
  405. package/ui/dist/assets/popover-CFHZf3pE.js +1 -0
  406. package/ui/dist/assets/progress-BboUHuLf.js +1 -0
  407. package/ui/dist/assets/{rocket-DhvUetsk.js → rocket--8ZHgdXJ.js} +1 -1
  408. package/ui/dist/assets/select-n108rXny.js +1 -0
  409. package/ui/dist/assets/{send-P0r5D7td.js → send-Cu7MR2Qh.js} +1 -1
  410. package/ui/dist/assets/server-DmodxZp-.js +1 -0
  411. package/ui/dist/assets/{settings-2-ocj5uHGx.js → settings-2-CkRNqkxj.js} +1 -1
  412. package/ui/dist/assets/sheet-7aUJkyzU.js +1 -0
  413. package/ui/dist/assets/{shield-check-DfVdE34l.js → shield-check-ViI3nMKE.js} +1 -1
  414. package/ui/dist/assets/{shield-off-8l0J6R-8.js → shield-off-DN3tagkn.js} +1 -1
  415. package/ui/dist/assets/skeleton-C0E1Nfro.js +1 -0
  416. package/ui/dist/assets/{smartphone-77_g3SQn.js → smartphone-5FghiXpA.js} +1 -1
  417. package/ui/dist/assets/{square-Ckzsr3Rn.js → square-DiNSx8K7.js} +1 -1
  418. package/ui/dist/assets/star-DhdFVidS.js +1 -0
  419. package/ui/dist/assets/switch-CIgVbZqQ.js +1 -0
  420. package/ui/dist/assets/table-BC56FVMV.js +1 -0
  421. package/ui/dist/assets/{tag-C35mgoEv.js → tag-CH_vQliw.js} +1 -1
  422. package/ui/dist/assets/textarea-CxDiKFXZ.js +1 -0
  423. package/ui/dist/assets/{timer-DHJBS2w1.js → timer-CdGVTb60.js} +1 -1
  424. package/ui/dist/assets/tooltip-BuW9A5UO.js +1 -0
  425. package/ui/dist/assets/{trash-2-keO5tKPE.js → trash-2-CucZJL0N.js} +1 -1
  426. package/ui/dist/assets/trending-down-BCezC1z2.js +1 -0
  427. package/ui/dist/assets/{trending-up-BBv8KbrY.js → trending-up-C5OYX2k2.js} +1 -1
  428. package/ui/dist/assets/vendor-query-C0p7b53x.js +4 -0
  429. package/ui/dist/assets/vendor-react-Mc5_kfYG.js +12 -0
  430. package/ui/dist/assets/vendor-ui-CXPAUBFv.js +51 -0
  431. package/ui/dist/assets/{wand-sparkles-BusQ52ZK.js → wand-sparkles-BaH6pJnc.js} +1 -1
  432. package/ui/dist/assets/{wrench-02YaOSiK.js → wrench-CjxjP6ok.js} +1 -1
  433. package/ui/dist/index.html +5 -2
  434. package/ui/dist/assets/ActivityView-BeshZXmE.js +0 -1
  435. package/ui/dist/assets/AgentList-QVHeldPi.js +0 -1
  436. package/ui/dist/assets/AnalyticsDashboard-C9R97dXE.js +0 -1
  437. package/ui/dist/assets/AreaChart-B73gaiVQ.js +0 -1
  438. package/ui/dist/assets/CartesianChart-CXYL2R-A.js +0 -36
  439. package/ui/dist/assets/ChatView-qjZErlrp.js +0 -10
  440. package/ui/dist/assets/CostsDashboard-O4DCLy1i.js +0 -1
  441. package/ui/dist/assets/EstimateSelect-1hQf4Osk.js +0 -1
  442. package/ui/dist/assets/FloatingChatbot-BZBzrJxd.js +0 -2
  443. package/ui/dist/assets/InviteCodeManagement-LEoGqYeA.js +0 -2
  444. package/ui/dist/assets/ProjectIcon-Chd_ofsw.js +0 -1
  445. package/ui/dist/assets/ProjectList-BvUfVB6c.js +0 -4
  446. package/ui/dist/assets/StatusIndicator-pRfkNcdV.js +0 -1
  447. package/ui/dist/assets/SummaryList-B6kXiTxL.js +0 -1
  448. package/ui/dist/assets/TaskDetail-CV6CzbOS.js +0 -1
  449. package/ui/dist/assets/TaskList-DL7brQKd.js +0 -1
  450. package/ui/dist/assets/TicketBoard-CrkkFj7C.js +0 -1
  451. package/ui/dist/assets/TicketDetail-hnnYclpD.js +0 -1
  452. package/ui/dist/assets/TicketList-CsDAyQCL.js +0 -1
  453. package/ui/dist/assets/UserManagement-BGFQyTSr.js +0 -2
  454. package/ui/dist/assets/ViewSwitcher-CnL0OqA8.js +0 -1
  455. package/ui/dist/assets/alert-dialog-SKM6Gjz4.js +0 -7
  456. package/ui/dist/assets/badge-CVHH1a-v.js +0 -1
  457. package/ui/dist/assets/brain-6o_RHVpe.js +0 -1
  458. package/ui/dist/assets/constants-Q5Zivl-a.js +0 -1
  459. package/ui/dist/assets/dialog-BUqN9Psj.js +0 -1
  460. package/ui/dist/assets/index-BUmnwPQr.js +0 -1
  461. package/ui/dist/assets/index-BfF5G4Cw.js +0 -1
  462. package/ui/dist/assets/index-C8N375c2.js +0 -1
  463. package/ui/dist/assets/index-CuxnqVVz.css +0 -1
  464. package/ui/dist/assets/index-CzMM3QOk.js +0 -1
  465. package/ui/dist/assets/index-lJlNPFVJ.js +0 -67
  466. package/ui/dist/assets/layers-jFqVrWMD.js +0 -1
  467. package/ui/dist/assets/markdown-renderer-n1ToC4XQ.js +0 -36
  468. package/ui/dist/assets/popover-CrmZgoWu.js +0 -1
  469. package/ui/dist/assets/progress-uv4SPkL5.js +0 -1
  470. package/ui/dist/assets/select-CeQ8AHGy.js +0 -1
  471. package/ui/dist/assets/server-CVHTZB72.js +0 -1
  472. package/ui/dist/assets/sheet-DuQExSho.js +0 -1
  473. package/ui/dist/assets/skeleton-TFiFJ3nB.js +0 -1
  474. package/ui/dist/assets/switch-CAePkd6k.js +0 -1
  475. package/ui/dist/assets/table-ZjAZ7hkt.js +0 -1
  476. package/ui/dist/assets/textarea-DsVPnSgR.js +0 -1
  477. package/ui/dist/assets/tooltip-BYmQ331W.js +0 -1
@@ -110,7 +110,8 @@ async function searchSerper(query, apiKey, options = {}) {
110
110
  */
111
111
  async function searchSearxng(query, baseUrl, options = {}) {
112
112
  const headers = {
113
- Accept: 'application/json',
113
+ 'Accept': 'application/json',
114
+ 'User-Agent': 'profClaw/2.0 (search integration)',
114
115
  };
115
116
  if (options.apiKey) {
116
117
  headers['Authorization'] = `Bearer ${options.apiKey}`;
@@ -264,9 +265,11 @@ export function isWebSearchAvailable(config) {
264
265
  * Get default config from environment variables
265
266
  */
266
267
  export function getDefaultWebSearchConfig() {
267
- // Auto-detect provider from available env vars
268
+ // Auto-detect provider: prefer paid providers over public SearXNG
268
269
  let provider = 'brave';
269
- if (process.env.SERPER_API_KEY)
270
+ if (process.env.BRAVE_API_KEY)
271
+ provider = 'brave';
272
+ else if (process.env.SERPER_API_KEY)
270
273
  provider = 'serper';
271
274
  else if (process.env.TAVILY_API_KEY)
272
275
  provider = 'tavily';
@@ -5,4 +5,5 @@
5
5
  */
6
6
  export { DEFAULT_MEMORY_CONFIG, type MemoryConfig, type MemoryFile, type MemoryChunk, type SearchResult, type MemoryStats, type MemorySession, initMemoryTables, syncMemoryFiles, searchMemory, getMemoryContent, chunkText, estimateTokens, hashContent, getMemoryStats, listMemoryFiles, listFileChunks, deleteMemoryChunk, deleteMemoryFile, clearAllMemories, createMemorySession, listMemorySessions, updateSessionStats, archiveSession, } from './memory-service.js';
7
7
  export { MemoryWatcher, getMemoryWatcher, initMemoryWatcher, stopMemoryWatcher, type MemoryWatcherOptions, type MemoryWatcherState, } from './memory-watcher.js';
8
+ export { observeConversation, observeWindow, compressToDigest, type ConversationSnapshot, type Observation, type ObservationResult, type ObservationType, } from './observational.js';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -22,4 +22,6 @@ listMemoryFiles, listFileChunks, deleteMemoryChunk, deleteMemoryFile, clearAllMe
22
22
  createMemorySession, listMemorySessions, updateSessionStats, archiveSession, } from './memory-service.js';
23
23
  // Memory Watcher (automatic sync)
24
24
  export { MemoryWatcher, getMemoryWatcher, initMemoryWatcher, stopMemoryWatcher, } from './memory-watcher.js';
25
+ // Observational Memory
26
+ export { observeConversation, observeWindow, compressToDigest, } from './observational.js';
25
27
  //# sourceMappingURL=index.js.map
@@ -354,8 +354,8 @@ async function indexFile(path, content, fileStat, source, config, embeddingServi
354
354
  args: [chunk.text, chunkId, path, source, config.model, chunk.startLine, chunk.endLine],
355
355
  });
356
356
  }
357
- catch {
358
- // FTS5 might not be available
357
+ catch (err) {
358
+ logger.warn('[Memory] FTS5 insert failed (indexFile), text search may be degraded:', { error: err instanceof Error ? err.message : String(err) });
359
359
  }
360
360
  }
361
361
  }
@@ -408,8 +408,8 @@ async function reindexFile(path, content, fileStat, source, config, embeddingSer
408
408
  args: [chunk.text, chunkId, path, source, config.model, chunk.startLine, chunk.endLine],
409
409
  });
410
410
  }
411
- catch {
412
- // FTS5 might not be available
411
+ catch (err) {
412
+ logger.warn('[Memory] FTS5 insert failed (reindexFile), text search may be degraded:', { error: err instanceof Error ? err.message : String(err) });
413
413
  }
414
414
  }
415
415
  }
@@ -431,8 +431,8 @@ async function removeFileChunks(path) {
431
431
  args: [chunk.id],
432
432
  });
433
433
  }
434
- catch {
435
- // FTS might not be available
434
+ catch (err) {
435
+ logger.warn('[Memory] FTS5 delete failed (removeFileChunks):', { error: err instanceof Error ? err.message : String(err) });
436
436
  }
437
437
  }
438
438
  // Delete chunks
@@ -591,7 +591,8 @@ async function ftsSearch(query, limit) {
591
591
  }
592
592
  return chunks;
593
593
  }
594
- catch {
594
+ catch (err) {
595
+ logger.warn('[Memory] FTS5 search unavailable, falling back to LIKE search:', { error: err instanceof Error ? err.message : String(err) });
595
596
  // FTS5 not available, fall back to LIKE search
596
597
  const result = await client.execute({
597
598
  sql: `SELECT id, path, source, start_line, end_line, hash, text, model
@@ -732,8 +733,8 @@ export async function deleteMemoryChunk(chunkId) {
732
733
  args: [chunkId],
733
734
  });
734
735
  }
735
- catch {
736
- // FTS might not be available
736
+ catch (err) {
737
+ logger.warn('[Memory] FTS5 delete failed (deleteMemoryChunk):', { error: err instanceof Error ? err.message : String(err) });
737
738
  }
738
739
  // Delete from chunks
739
740
  const result = await client.execute({
@@ -762,8 +763,8 @@ export async function clearAllMemories() {
762
763
  try {
763
764
  await client.execute(`DELETE FROM memory_fts`);
764
765
  }
765
- catch {
766
- // FTS might not be available
766
+ catch (err) {
767
+ logger.warn('[Memory] FTS5 clear failed (clearAllMemories):', { error: err instanceof Error ? err.message : String(err) });
767
768
  }
768
769
  await client.execute(`DELETE FROM memory_chunks`);
769
770
  await client.execute(`DELETE FROM memory_files`);
@@ -998,8 +999,8 @@ export async function indexConversation(input, config = DEFAULT_MEMORY_CONFIG) {
998
999
  args: [chunk.text, chunkId, path, source, config.model, chunk.startLine, chunk.endLine],
999
1000
  });
1000
1001
  }
1001
- catch {
1002
- // FTS5 might not be available
1002
+ catch (err) {
1003
+ logger.warn('[Memory] FTS5 insert failed (indexConversation), text search may be degraded:', { error: err instanceof Error ? err.message : String(err) });
1003
1004
  }
1004
1005
  }
1005
1006
  logger.info(`[Memory] Indexed conversation ${input.conversationId}: ${chunks.length} chunks, ~${tokensEstimate} tokens`);
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Observational Memory Engine
3
+ *
4
+ * Background agent that compresses conversation history into structured
5
+ * observations. Instead of storing raw messages, it extracts:
6
+ * - Decisions made and their rationale
7
+ * - User preferences (language, framework, style, tools)
8
+ * - Problems solved and solution patterns
9
+ * - Project facts and context
10
+ *
11
+ * This is the "profClaw never forgets AND learns" story.
12
+ * Based on VentureBeat's observational memory pattern (10x cheaper than RAG).
13
+ */
14
+ export type ObservationType = 'decision' | 'preference' | 'solution' | 'fact' | 'error_pattern' | 'workflow';
15
+ export interface Observation {
16
+ id: string;
17
+ type: ObservationType;
18
+ summary: string;
19
+ details: Record<string, unknown>;
20
+ confidence: number;
21
+ source: {
22
+ conversationId: string;
23
+ messageRange: [number, number];
24
+ timestamp: number;
25
+ };
26
+ }
27
+ export interface ConversationSnapshot {
28
+ conversationId: string;
29
+ messages: Array<{
30
+ role: 'user' | 'assistant' | 'system';
31
+ content: string;
32
+ model?: string;
33
+ toolsUsed?: string[];
34
+ }>;
35
+ metadata?: {
36
+ provider?: string;
37
+ channel?: string;
38
+ userId?: string;
39
+ };
40
+ }
41
+ export interface ObservationResult {
42
+ observations: Observation[];
43
+ preferencesTracked: number;
44
+ experiencesRecorded: number;
45
+ processingTimeMs: number;
46
+ }
47
+ /**
48
+ * Process a conversation snapshot and extract observations.
49
+ * Call this after a conversation ends or at periodic intervals.
50
+ */
51
+ export declare function observeConversation(snapshot: ConversationSnapshot): Promise<ObservationResult>;
52
+ /**
53
+ * Process a batch of recent messages (sliding window).
54
+ * Use this for periodic observation without waiting for conversation end.
55
+ */
56
+ export declare function observeWindow(conversationId: string, messages: ConversationSnapshot['messages'], windowSize?: number, userId?: string): Promise<ObservationResult>;
57
+ /**
58
+ * Build a compressed summary of a conversation for long-term storage.
59
+ * Replaces raw message history with a structured digest.
60
+ */
61
+ export declare function compressToDigest(messages: ConversationSnapshot['messages'], observations: Observation[]): string;
62
+ //# sourceMappingURL=observational.d.ts.map
@@ -0,0 +1,396 @@
1
+ /**
2
+ * Observational Memory Engine
3
+ *
4
+ * Background agent that compresses conversation history into structured
5
+ * observations. Instead of storing raw messages, it extracts:
6
+ * - Decisions made and their rationale
7
+ * - User preferences (language, framework, style, tools)
8
+ * - Problems solved and solution patterns
9
+ * - Project facts and context
10
+ *
11
+ * This is the "profClaw never forgets AND learns" story.
12
+ * Based on VentureBeat's observational memory pattern (10x cheaper than RAG).
13
+ */
14
+ import { randomUUID } from 'node:crypto';
15
+ import { createContextualLogger } from '../utils/logger.js';
16
+ import { recordExperience, trackPreference, findSimilarExperiences, } from './experience-store.js';
17
+ const log = createContextualLogger('ObservationalMemory');
18
+ /**
19
+ * Extract decisions from conversation (user chose X over Y, agreed to approach).
20
+ */
21
+ const decisionExtractor = {
22
+ type: 'decision',
23
+ extract: (messages, ctx) => {
24
+ const observations = [];
25
+ const decisionPatterns = [
26
+ /\b(?:let's go with|decided to|choosing|we'll use|going with|picked|selected)\b\s+(.{10,80})/i,
27
+ /\b(?:yes|agreed|correct|that's right|exactly|perfect)\b.*\b(?:use|go with|pick|choose)\b\s+(.{5,60})/i,
28
+ /\b(?:instead of|rather than|not|don't)\b\s+(.{5,60})\b(?:use|go with|pick)\b\s+(.{5,60})/i,
29
+ ];
30
+ for (let i = 0; i < messages.length; i++) {
31
+ const msg = messages[i];
32
+ if (msg.role !== 'user' && msg.role !== 'assistant')
33
+ continue;
34
+ for (const pattern of decisionPatterns) {
35
+ const match = msg.content.match(pattern);
36
+ if (match) {
37
+ observations.push({
38
+ id: randomUUID(),
39
+ type: 'decision',
40
+ summary: `Decision: ${match[0].slice(0, 120)}`,
41
+ details: { matchedText: match[0], role: msg.role },
42
+ confidence: 0.7,
43
+ source: {
44
+ conversationId: ctx.conversationId,
45
+ messageRange: [ctx.startIdx + i, ctx.startIdx + i],
46
+ timestamp: Date.now(),
47
+ },
48
+ });
49
+ break; // one per message
50
+ }
51
+ }
52
+ }
53
+ return observations;
54
+ },
55
+ };
56
+ /**
57
+ * Extract user preferences (language, framework, tool, style choices).
58
+ */
59
+ const preferenceExtractor = {
60
+ type: 'preference',
61
+ extract: (messages, ctx) => {
62
+ const observations = [];
63
+ const prefPatterns = [
64
+ { pattern: /\b(?:I (?:use|prefer|like|want|always use|work with))\s+(\w[\w\s.-]{2,30})/i, category: 'tool' },
65
+ { pattern: /\b(?:write (?:it )?in|using|with)\s+(TypeScript|JavaScript|Python|Go|Rust|Java|C\+\+|Ruby|PHP|Swift|Kotlin)/i, category: 'language' },
66
+ { pattern: /\b(?:use|using|with)\s+(React|Vue|Angular|Svelte|Next\.?js|Nuxt|Express|Hono|FastAPI|Django|Spring|Rails)/i, category: 'framework' },
67
+ { pattern: /\b(?:style|format|convention).*\b(camelCase|snake_case|PascalCase|kebab-case)/i, category: 'style' },
68
+ { pattern: /\b(?:don't|never|avoid|skip|no)\s+(\w[\w\s]{2,30})/i, category: 'anti-preference' },
69
+ ];
70
+ for (const msg of messages) {
71
+ if (msg.role !== 'user')
72
+ continue;
73
+ for (const { pattern, category } of prefPatterns) {
74
+ const match = msg.content.match(pattern);
75
+ if (match && match[1]) {
76
+ observations.push({
77
+ id: randomUUID(),
78
+ type: 'preference',
79
+ summary: `Preference (${category}): ${match[1].trim()}`,
80
+ details: { category, value: match[1].trim(), fullMatch: match[0] },
81
+ confidence: 0.6,
82
+ source: {
83
+ conversationId: ctx.conversationId,
84
+ messageRange: [ctx.startIdx, ctx.startIdx + messages.length - 1],
85
+ timestamp: Date.now(),
86
+ },
87
+ });
88
+ }
89
+ }
90
+ }
91
+ return observations;
92
+ },
93
+ };
94
+ /**
95
+ * Extract solution patterns (problem -> tool chain -> outcome).
96
+ */
97
+ const solutionExtractor = {
98
+ type: 'solution',
99
+ extract: (messages, ctx) => {
100
+ const observations = [];
101
+ // Find messages with tool usage followed by success indicators
102
+ const toolMessages = messages.filter(m => m.toolsUsed && m.toolsUsed.length > 0);
103
+ if (toolMessages.length === 0)
104
+ return observations;
105
+ // Look for the user's original request
106
+ const firstUserMsg = messages.find(m => m.role === 'user');
107
+ if (!firstUserMsg)
108
+ return observations;
109
+ // Check if the conversation ended positively
110
+ const lastMessages = messages.slice(-3);
111
+ const endedPositively = lastMessages.some(m => m.role === 'user' && /\b(thanks|perfect|great|works|done|good|nice)\b/i.test(m.content)) || lastMessages.some(m => m.role === 'assistant' && /\b(completed|done|finished|success)\b/i.test(m.content));
112
+ if (endedPositively && toolMessages.length > 0) {
113
+ const allTools = [...new Set(toolMessages.flatMap(m => m.toolsUsed ?? []))];
114
+ observations.push({
115
+ id: randomUUID(),
116
+ type: 'solution',
117
+ summary: `Solved "${firstUserMsg.content.slice(0, 80)}" using ${allTools.join(' -> ')}`,
118
+ details: {
119
+ problem: firstUserMsg.content.slice(0, 200),
120
+ tools: allTools,
121
+ messageCount: messages.length,
122
+ },
123
+ confidence: endedPositively ? 0.85 : 0.5,
124
+ source: {
125
+ conversationId: ctx.conversationId,
126
+ messageRange: [ctx.startIdx, ctx.startIdx + messages.length - 1],
127
+ timestamp: Date.now(),
128
+ },
129
+ });
130
+ }
131
+ return observations;
132
+ },
133
+ };
134
+ /**
135
+ * Extract project facts (file paths, architecture, naming conventions).
136
+ */
137
+ const factExtractor = {
138
+ type: 'fact',
139
+ extract: (messages, ctx) => {
140
+ const observations = [];
141
+ const factPatterns = [
142
+ { pattern: /\b(?:the (?:project|repo|codebase) (?:uses|has|is|runs on))\s+(.{10,100})/i, category: 'architecture' },
143
+ { pattern: /\b(?:deployed (?:on|to|at|via))\s+(\S+)/i, category: 'deployment' },
144
+ { pattern: /\b(?:database|db) (?:is|uses)\s+(\w+)/i, category: 'database' },
145
+ { pattern: /\b(?:CI|CD|pipeline) (?:is|uses|runs on)\s+(\w[\w\s.-]+)/i, category: 'ci' },
146
+ ];
147
+ for (const msg of messages) {
148
+ if (msg.role !== 'user')
149
+ continue;
150
+ for (const { pattern, category } of factPatterns) {
151
+ const match = msg.content.match(pattern);
152
+ if (match) {
153
+ observations.push({
154
+ id: randomUUID(),
155
+ type: 'fact',
156
+ summary: `Project fact (${category}): ${match[0].slice(0, 100)}`,
157
+ details: { category, fact: match[0], value: match[1] },
158
+ confidence: 0.65,
159
+ source: {
160
+ conversationId: ctx.conversationId,
161
+ messageRange: [ctx.startIdx, ctx.startIdx + messages.length - 1],
162
+ timestamp: Date.now(),
163
+ },
164
+ });
165
+ }
166
+ }
167
+ }
168
+ return observations;
169
+ },
170
+ };
171
+ /**
172
+ * Extract error recovery patterns (what went wrong, how it was fixed).
173
+ */
174
+ const errorPatternExtractor = {
175
+ type: 'error_pattern',
176
+ extract: (messages, ctx) => {
177
+ const observations = [];
178
+ for (let i = 0; i < messages.length - 1; i++) {
179
+ const msg = messages[i];
180
+ const next = messages[i + 1];
181
+ // Look for error followed by fix
182
+ const isError = msg.role === 'assistant' &&
183
+ /\b(error|failed|exception|crash|bug|issue|problem)\b/i.test(msg.content);
184
+ const isFix = next && next.role === 'assistant' &&
185
+ /\b(fix|resolved|solved|workaround|updated|changed)\b/i.test(next.content);
186
+ if (isError && isFix) {
187
+ observations.push({
188
+ id: randomUUID(),
189
+ type: 'error_pattern',
190
+ summary: `Error recovery: ${msg.content.slice(0, 60)} -> ${next.content.slice(0, 60)}`,
191
+ details: {
192
+ error: msg.content.slice(0, 200),
193
+ fix: next.content.slice(0, 200),
194
+ toolsUsed: next.toolsUsed,
195
+ },
196
+ confidence: 0.75,
197
+ source: {
198
+ conversationId: ctx.conversationId,
199
+ messageRange: [ctx.startIdx + i, ctx.startIdx + i + 1],
200
+ timestamp: Date.now(),
201
+ },
202
+ });
203
+ }
204
+ }
205
+ return observations;
206
+ },
207
+ };
208
+ const ALL_EXTRACTORS = [
209
+ decisionExtractor,
210
+ preferenceExtractor,
211
+ solutionExtractor,
212
+ factExtractor,
213
+ errorPatternExtractor,
214
+ ];
215
+ // Core Engine
216
+ /**
217
+ * Process a conversation snapshot and extract observations.
218
+ * Call this after a conversation ends or at periodic intervals.
219
+ */
220
+ export async function observeConversation(snapshot) {
221
+ const start = Date.now();
222
+ const allObservations = [];
223
+ let preferencesTracked = 0;
224
+ let experiencesRecorded = 0;
225
+ const ctx = {
226
+ conversationId: snapshot.conversationId,
227
+ userId: snapshot.metadata?.userId,
228
+ startIdx: 0,
229
+ };
230
+ // Run all extractors
231
+ for (const extractor of ALL_EXTRACTORS) {
232
+ try {
233
+ const observations = extractor.extract(snapshot.messages, ctx);
234
+ allObservations.push(...observations);
235
+ }
236
+ catch (error) {
237
+ log.warn(`Extractor ${extractor.type} failed`, {
238
+ error: error instanceof Error ? error.message : String(error),
239
+ });
240
+ }
241
+ }
242
+ // Deduplicate by summary similarity
243
+ const seen = new Set();
244
+ const unique = allObservations.filter(obs => {
245
+ const key = obs.summary.toLowerCase().slice(0, 50);
246
+ if (seen.has(key))
247
+ return false;
248
+ seen.add(key);
249
+ return true;
250
+ });
251
+ // Check for duplicates against existing experiences
252
+ const deduplicated = [];
253
+ for (const obs of unique) {
254
+ const existing = await findSimilarExperiences(obs.summary, [], 1);
255
+ if (existing.length > 0 && existing[0].successScore >= obs.confidence) {
256
+ continue; // already know this
257
+ }
258
+ deduplicated.push(obs);
259
+ }
260
+ // Persist observations
261
+ for (const obs of deduplicated) {
262
+ try {
263
+ // Map observation type to experience type
264
+ const expType = obs.type === 'preference' ? 'user_preference'
265
+ : obs.type === 'solution' || obs.type === 'workflow' ? 'task_solution'
266
+ : obs.type === 'error_pattern' ? 'error_recovery'
267
+ : 'task_solution';
268
+ await recordExperience({
269
+ type: expType,
270
+ intent: obs.summary,
271
+ solution: obs.details,
272
+ successScore: obs.confidence,
273
+ tags: [obs.type, ...(obs.details['category'] ? [String(obs.details['category'])] : [])],
274
+ sourceConversationId: obs.source.conversationId,
275
+ userId: ctx.userId,
276
+ });
277
+ experiencesRecorded++;
278
+ // Track preferences specifically
279
+ if (obs.type === 'preference' && ctx.userId && obs.details['category'] && obs.details['value']) {
280
+ await trackPreference(ctx.userId, String(obs.details['category']), String(obs.details['value']));
281
+ preferencesTracked++;
282
+ }
283
+ }
284
+ catch (error) {
285
+ log.warn('Failed to persist observation', {
286
+ type: obs.type,
287
+ error: error instanceof Error ? error.message : String(error),
288
+ });
289
+ }
290
+ }
291
+ const result = {
292
+ observations: deduplicated,
293
+ preferencesTracked,
294
+ experiencesRecorded,
295
+ processingTimeMs: Date.now() - start,
296
+ };
297
+ if (deduplicated.length > 0) {
298
+ log.info('Observations extracted', {
299
+ conversationId: snapshot.conversationId,
300
+ total: deduplicated.length,
301
+ byType: countByType(deduplicated),
302
+ preferencesTracked,
303
+ experiencesRecorded,
304
+ processingTimeMs: result.processingTimeMs,
305
+ });
306
+ }
307
+ return result;
308
+ }
309
+ /**
310
+ * Process a batch of recent messages (sliding window).
311
+ * Use this for periodic observation without waiting for conversation end.
312
+ */
313
+ export async function observeWindow(conversationId, messages, windowSize = 20, userId) {
314
+ // Take last N messages
315
+ const window = messages.slice(-windowSize);
316
+ return observeConversation({
317
+ conversationId,
318
+ messages: window,
319
+ metadata: { userId },
320
+ });
321
+ }
322
+ /**
323
+ * Build a compressed summary of a conversation for long-term storage.
324
+ * Replaces raw message history with a structured digest.
325
+ */
326
+ export function compressToDigest(messages, observations) {
327
+ const sections = [];
328
+ // Conversation overview
329
+ const userMessages = messages.filter(m => m.role === 'user');
330
+ const assistantMessages = messages.filter(m => m.role === 'assistant');
331
+ sections.push(`Conversation: ${userMessages.length} user messages, ${assistantMessages.length} assistant responses.`);
332
+ // Group observations by type
333
+ const grouped = new Map();
334
+ for (const obs of observations) {
335
+ const list = grouped.get(obs.type) ?? [];
336
+ list.push(obs);
337
+ grouped.set(obs.type, list);
338
+ }
339
+ if (grouped.has('decision')) {
340
+ sections.push('Decisions: ' + grouped.get('decision').map(o => o.summary).join('; '));
341
+ }
342
+ if (grouped.has('preference')) {
343
+ sections.push('Preferences: ' + grouped.get('preference').map(o => o.summary).join('; '));
344
+ }
345
+ if (grouped.has('solution')) {
346
+ sections.push('Solutions: ' + grouped.get('solution').map(o => o.summary).join('; '));
347
+ }
348
+ if (grouped.has('fact')) {
349
+ sections.push('Facts: ' + grouped.get('fact').map(o => o.summary).join('; '));
350
+ }
351
+ if (grouped.has('error_pattern')) {
352
+ sections.push('Error patterns: ' + grouped.get('error_pattern').map(o => o.summary).join('; '));
353
+ }
354
+ // Key topics from user messages
355
+ const topics = extractTopics(userMessages.map(m => m.content));
356
+ if (topics.length > 0) {
357
+ sections.push('Topics: ' + topics.join(', '));
358
+ }
359
+ return sections.join('\n');
360
+ }
361
+ // Helpers
362
+ function countByType(observations) {
363
+ const counts = {};
364
+ for (const obs of observations) {
365
+ counts[obs.type] = (counts[obs.type] ?? 0) + 1;
366
+ }
367
+ return counts;
368
+ }
369
+ function extractTopics(texts) {
370
+ const wordFreq = new Map();
371
+ const stopWords = new Set([
372
+ 'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
373
+ 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
374
+ 'should', 'may', 'might', 'must', 'can', 'shall', 'to', 'of', 'in',
375
+ 'on', 'at', 'for', 'with', 'by', 'from', 'up', 'about', 'into',
376
+ 'through', 'how', 'what', 'when', 'where', 'why', 'which', 'this',
377
+ 'that', 'these', 'those', 'and', 'but', 'or', 'not', 'no', 'so',
378
+ 'if', 'then', 'than', 'too', 'very', 'just', 'also', 'its', 'my',
379
+ 'your', 'it', 'i', 'me', 'we', 'you', 'he', 'she', 'they', 'them',
380
+ 'please', 'thanks', 'thank', 'hi', 'hello', 'hey',
381
+ ]);
382
+ for (const text of texts) {
383
+ const words = text.toLowerCase().replace(/[^\w\s]/g, ' ').split(/\s+/);
384
+ for (const word of words) {
385
+ if (word.length < 3 || stopWords.has(word))
386
+ continue;
387
+ wordFreq.set(word, (wordFreq.get(word) ?? 0) + 1);
388
+ }
389
+ }
390
+ return [...wordFreq.entries()]
391
+ .filter(([, count]) => count >= 2)
392
+ .sort((a, b) => b[1] - a[1])
393
+ .slice(0, 8)
394
+ .map(([word]) => word);
395
+ }
396
+ //# sourceMappingURL=observational.js.map
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Content Filter Middleware
3
+ *
4
+ * Optional profanity/content moderation for chat endpoints.
5
+ * Activate with CONTENT_FILTER=true in .env.
6
+ * Skipped in pico mode to preserve memory footprint.
7
+ */
8
+ import { type Context, type Next } from 'hono';
9
+ /**
10
+ * Hono middleware that checks POST body for profanity on chat send endpoints.
11
+ *
12
+ * Conditions for enforcement:
13
+ * - CONTENT_FILTER=true env var is set
14
+ * - Deployment mode is mini or pro (skipped for pico)
15
+ * - Request method is POST
16
+ * - Body has a `message` or `content` string field
17
+ *
18
+ * On flagged content returns 400 { error, flagged: true }.
19
+ * On clean content calls next().
20
+ */
21
+ export declare function contentFilter(): (c: Context, next: Next) => Promise<Response | void>;
22
+ //# sourceMappingURL=content-filter.d.ts.map
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Content Filter Middleware
3
+ *
4
+ * Optional profanity/content moderation for chat endpoints.
5
+ * Activate with CONTENT_FILTER=true in .env.
6
+ * Skipped in pico mode to preserve memory footprint.
7
+ */
8
+ import { logger } from '../utils/logger.js';
9
+ import { getMode } from '../core/deployment.js';
10
+ // Lazy-loaded to avoid paying startup cost when filter is disabled
11
+ let filterInstance = null;
12
+ async function getFilter() {
13
+ if (!filterInstance) {
14
+ const { Filter } = await import('glin-profanity');
15
+ filterInstance = new Filter();
16
+ }
17
+ return filterInstance;
18
+ }
19
+ /**
20
+ * Hono middleware that checks POST body for profanity on chat send endpoints.
21
+ *
22
+ * Conditions for enforcement:
23
+ * - CONTENT_FILTER=true env var is set
24
+ * - Deployment mode is mini or pro (skipped for pico)
25
+ * - Request method is POST
26
+ * - Body has a `message` or `content` string field
27
+ *
28
+ * On flagged content returns 400 { error, flagged: true }.
29
+ * On clean content calls next().
30
+ */
31
+ export function contentFilter() {
32
+ return async (c, next) => {
33
+ const enabled = process.env.CONTENT_FILTER?.toLowerCase() === 'true';
34
+ if (!enabled)
35
+ return next();
36
+ const mode = getMode();
37
+ if (mode === 'pico')
38
+ return next();
39
+ if (c.req.method !== 'POST')
40
+ return next();
41
+ let text;
42
+ try {
43
+ const body = await c.req.json();
44
+ if (typeof body.message === 'string') {
45
+ text = body.message;
46
+ }
47
+ else if (typeof body.content === 'string') {
48
+ text = body.content;
49
+ }
50
+ }
51
+ catch {
52
+ // Unparseable body — let the handler deal with it
53
+ return next();
54
+ }
55
+ if (!text)
56
+ return next();
57
+ const filter = await getFilter();
58
+ const result = filter.checkProfanity(text);
59
+ if (result.containsProfanity) {
60
+ logger.warn('Content filter flagged message', {
61
+ profaneWords: result.profaneWords,
62
+ path: c.req.path,
63
+ });
64
+ return c.json({ error: 'Message flagged by content filter', flagged: true }, 400);
65
+ }
66
+ return next();
67
+ };
68
+ }
69
+ //# sourceMappingURL=content-filter.js.map