@xopcai/xopc 0.0.93 → 0.0.94

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 (356) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  3. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  4. package/dist/extensions/telegram/src/plugin.js +1 -1
  5. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  6. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  7. package/dist/extensions/telegram/xopc.extension.json +1 -1
  8. package/dist/extensions/weixin/src/api/api.js +2 -2
  9. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  10. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  11. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  12. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  13. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  14. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  15. package/dist/extensions/weixin/src/plugin.js +1 -1
  16. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  17. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  18. package/dist/gateway/static/root/assets/agents-OqhbJkMf.js +222 -0
  19. package/dist/gateway/static/root/assets/apps-page-OHXW9XP8.js +1 -0
  20. package/dist/gateway/static/root/assets/channels-settings-4N2R-jof.js +1 -0
  21. package/dist/gateway/static/root/assets/{channels-status-swr-CsGkK9h9.js → channels-status-swr-Bv6f9kDq.js} +1 -1
  22. package/dist/gateway/static/root/assets/{cron-api-CyAm0xJT.js → cron-api-BtaQaHJq.js} +1 -1
  23. package/dist/gateway/static/root/assets/cron-page-Dah32HJK.js +1 -0
  24. package/dist/gateway/static/root/assets/{dist-DHwVV8XK.js → dist-BJfD9Qvs.js} +1 -1
  25. package/dist/gateway/static/root/assets/{extension-debug-page-BK8kcc4F.js → extension-debug-page-DnYuMzmH.js} +1 -1
  26. package/dist/gateway/static/root/assets/{extension-page-Cf8X_QUc.js → extension-page-CJfc-6XV.js} +1 -1
  27. package/dist/gateway/static/root/assets/{extension-settings-page-C5-YLMmy.js → extension-settings-page-BxdfYQMG.js} +1 -1
  28. package/dist/gateway/static/root/assets/{fetch-BAPnkYbC.js → fetch-B0aeeY0q.js} +1 -1
  29. package/dist/gateway/static/root/assets/{field-primitives-8p7ucXa1.js → field-primitives-DOLHwowi.js} +1 -1
  30. package/dist/gateway/static/root/assets/{heartbeat-config-api-CpgW2sGp.js → heartbeat-config-api-Bj2INAf5.js} +1 -1
  31. package/dist/gateway/static/root/assets/index-Bj_l8QDp.css +1 -0
  32. package/dist/gateway/static/root/assets/{index-Do52EfZK.js → index-DuQ1XPoA.js} +99 -98
  33. package/dist/gateway/static/root/assets/logs-page-AsOgLNJE.js +2 -0
  34. package/dist/gateway/static/root/assets/{note-detail-page-WLM6FUIi.js → note-detail-page-24J4mVP-.js} +3 -3
  35. package/dist/gateway/static/root/assets/{note-time-EFyIVhec.js → note-time-JBszYV3s.js} +1 -1
  36. package/dist/gateway/static/root/assets/{notes-page-BYPVYcYn.js → notes-page-BApAirFB.js} +1 -1
  37. package/dist/gateway/static/root/assets/sessions-page-DX9huWsA.js +1 -0
  38. package/dist/gateway/static/root/assets/{settings-advanced-gate-CEs8pGh6.js → settings-advanced-gate-DWvhsTuz.js} +1 -1
  39. package/dist/gateway/static/root/assets/{settings-form-section-C6cGTVwK.js → settings-form-section-CxMjaMiy.js} +1 -1
  40. package/dist/gateway/static/root/assets/settings-page-4VmUTzQs.js +3 -0
  41. package/dist/gateway/static/root/assets/{share-preview-page-tnIfJ4K6.js → share-preview-page-IX0TJvRd.js} +1 -1
  42. package/dist/gateway/static/root/assets/skills-page-CGKGKfwe.js +2 -0
  43. package/dist/gateway/static/root/assets/{theme-store-D6EsNTPr.js → theme-store-Cg_SuBw0.js} +1 -1
  44. package/dist/gateway/static/root/assets/{url-CTjpm0Uz.js → url-BHHmdJYc.js} +2 -2
  45. package/dist/gateway/static/root/assets/{utils-C86AVfY-.js → utils-BmlcxR2j.js} +1 -1
  46. package/dist/gateway/static/root/assets/voice-api-key-field-DaGm2N4J.js +1 -0
  47. package/dist/gateway/static/root/assets/{workflow-page.utils-DsEriMFW.js → workflow-page.utils-D0vsIGHD.js} +1 -1
  48. package/dist/gateway/static/root/assets/workflows-page-BFCrD3nw.js +27 -0
  49. package/dist/gateway/static/root/index.html +5 -5
  50. package/dist/package.js +1 -1
  51. package/dist/src/agent/agent-manager.js +7 -7
  52. package/dist/src/agent/agent-scope.js +1 -1
  53. package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
  54. package/dist/src/agent/context/workspace-seed.js +2 -2
  55. package/dist/src/agent/goals/goal-run-store.js +4 -4
  56. package/dist/src/agent/goals/persistent-goal-service.js +1 -1
  57. package/dist/src/agent/goals/post-turn.js +2 -2
  58. package/dist/src/agent/image/load-image-media.js +2 -2
  59. package/dist/src/agent/inbound/turn-dispatcher.d.ts +1 -0
  60. package/dist/src/agent/inbound/turn-dispatcher.js +3 -0
  61. package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
  62. package/dist/src/agent/ipc/bus.js +1 -1
  63. package/dist/src/agent/ipc/inbox.js +2 -2
  64. package/dist/src/agent/ipc/socket.js +1 -1
  65. package/dist/src/agent/lifecycle/handlers/compaction.js +1 -1
  66. package/dist/src/agent/lifecycle/handlers/compaction.js.map +1 -1
  67. package/dist/src/agent/mcp/bundle-mcp-materialize.js +2 -2
  68. package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
  69. package/dist/src/agent/mcp/bundle-mcp-runtime.js +18 -5
  70. package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
  71. package/dist/src/agent/mcp/mcp-transport-config.js +11 -4
  72. package/dist/src/agent/mcp/mcp-transport-config.js.map +1 -1
  73. package/dist/src/agent/mcp/mcp-transport.js +2 -2
  74. package/dist/src/agent/mcp/mcp-transport.js.map +1 -1
  75. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  76. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  77. package/dist/src/agent/memory/dreaming/events.js +1 -1
  78. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  79. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  80. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  81. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  82. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  83. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  84. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  85. package/dist/src/agent/models/manager.js +1 -1
  86. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  87. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  88. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  89. package/dist/src/agent/sandbox/path-policy.js +2 -2
  90. package/dist/src/agent/service/build-direct-message-content.js +1 -1
  91. package/dist/src/agent/service/process-direct-streaming.d.ts +1 -0
  92. package/dist/src/agent/service/process-direct-streaming.js +15 -12
  93. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  94. package/dist/src/agent/service.d.ts +4 -2
  95. package/dist/src/agent/service.js +24 -8
  96. package/dist/src/agent/service.js.map +1 -1
  97. package/dist/src/agent/service.types.d.ts +3 -1
  98. package/dist/src/agent/session/session-inspector.js +1 -1
  99. package/dist/src/agent/skills/config.js +1 -1
  100. package/dist/src/agent/skills/hub-hash.js +2 -2
  101. package/dist/src/agent/skills/hub-lock.js +1 -1
  102. package/dist/src/agent/skills/hub-pull.js +2 -2
  103. package/dist/src/agent/skills/index.js +1 -1
  104. package/dist/src/agent/skills/managed-store.js +1 -1
  105. package/dist/src/agent/skills/scanner.js +1 -1
  106. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  107. package/dist/src/agent/skills/skill-manager.js +1 -1
  108. package/dist/src/agent/tools/browser/tool/browser-use-tool.js +1 -1
  109. package/dist/src/agent/tools/browser/tool/browser-use-tool.js.map +1 -1
  110. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  111. package/dist/src/agent/tools/factory.js +1 -1
  112. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  113. package/dist/src/agent/tools/search/registry.js +1 -1
  114. package/dist/src/agent/tools/search/registry.js.map +1 -1
  115. package/dist/src/agent/tools/send-media.js +1 -1
  116. package/dist/src/agent/tools/session-search-tool.js +1 -1
  117. package/dist/src/agent/tools/session-search-tool.js.map +1 -1
  118. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  119. package/dist/src/agent/tools/workflow-tool.js +2 -2
  120. package/dist/src/agent/tools/workflow-tool.js.map +1 -1
  121. package/dist/src/agent/tools/write.js +1 -1
  122. package/dist/src/agent/workflow/catalog.js +1 -1
  123. package/dist/src/agent/workflow/progress-broker.js +1 -1
  124. package/dist/src/agent/workflow/progress-broker.js.map +1 -1
  125. package/dist/src/agent/workflow/subagent-runner.js +1 -1
  126. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  127. package/dist/src/auth/credentials.js +3 -3
  128. package/dist/src/auth/profiles/store.js +1 -1
  129. package/dist/src/auth/sync-provider-auth.js +1 -1
  130. package/dist/src/browser/cache-dir-policy.js +1 -1
  131. package/dist/src/browser/cdp-local-launcher.js +2 -2
  132. package/dist/src/browser/providers/browser-ext-install.js +3 -3
  133. package/dist/src/browser/providers/cloakbrowser.js +4 -4
  134. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  135. package/dist/src/browser/stealth.js +1 -1
  136. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  137. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  138. package/dist/src/channels/outbound/persist-store.js +1 -1
  139. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  140. package/dist/src/channels/pairing/pairing-store.js +2 -2
  141. package/dist/src/channels/pipeline.js +3 -2
  142. package/dist/src/channels/pipeline.js.map +1 -1
  143. package/dist/src/chat-commands/agent-edit.js +2 -2
  144. package/dist/src/chat-commands/builtins/config.js +2 -2
  145. package/dist/src/chat-commands/context.js +1 -1
  146. package/dist/src/cli/cli-log-level-preset.d.ts +1 -1
  147. package/dist/src/cli/cli-log-level-preset.js +2 -2
  148. package/dist/src/cli/cli-log-level-preset.js.map +1 -1
  149. package/dist/src/cli/commands/config.js +1 -1
  150. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  151. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  152. package/dist/src/cli/commands/doctor/checks/session-integrity.js +2 -2
  153. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  154. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  155. package/dist/src/cli/commands/extension-dev.js +1 -1
  156. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  157. package/dist/src/cli/commands/extension-pack.js +1 -1
  158. package/dist/src/cli/commands/gateway/logs.js +1 -1
  159. package/dist/src/cli/commands/image.js +1 -1
  160. package/dist/src/cli/commands/init.js +4 -4
  161. package/dist/src/cli/commands/logs.js +3 -3
  162. package/dist/src/cli/commands/logs.js.map +1 -1
  163. package/dist/src/cli/commands/onboard.js +1 -1
  164. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  165. package/dist/src/commands/agents.config.js +1 -1
  166. package/dist/src/config/agent-profile.js +1 -1
  167. package/dist/src/config/gateway-bind.js +1 -1
  168. package/dist/src/config/index.js +5 -5
  169. package/dist/src/config/loader.js +2 -2
  170. package/dist/src/config/models-json.js +2 -2
  171. package/dist/src/config/paths-state.js +1 -1
  172. package/dist/src/config/profile.js +2 -2
  173. package/dist/src/config/workspace-path.js +1 -1
  174. package/dist/src/cron/executor.js +9 -6
  175. package/dist/src/cron/executor.js.map +1 -1
  176. package/dist/src/cron/persistence.js +1 -1
  177. package/dist/src/cron/run-log-store.js +1 -1
  178. package/dist/src/daemon/constants.js +1 -1
  179. package/dist/src/daemon/install-plan.js +2 -2
  180. package/dist/src/daemon/launchd.js +2 -2
  181. package/dist/src/daemon/schtasks.js +2 -2
  182. package/dist/src/daemon/systemd.js +2 -2
  183. package/dist/src/extensions/bundle-mcp.js +1 -1
  184. package/dist/src/extensions/discover-extensions.js +1 -1
  185. package/dist/src/extensions/health.js +1 -1
  186. package/dist/src/extensions/loader.js +1 -1
  187. package/dist/src/extensions/lockfile.js +2 -2
  188. package/dist/src/extensions/update.js +1 -1
  189. package/dist/src/gateway/agents-admin.js +3 -3
  190. package/dist/src/gateway/file-path-classifier.js +2 -2
  191. package/dist/src/gateway/heartbeat/service.js +1 -1
  192. package/dist/src/gateway/hono/app.js +4 -1
  193. package/dist/src/gateway/hono/app.js.map +1 -1
  194. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  195. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  196. package/dist/src/gateway/hono/lib/route-logger.d.ts +6 -0
  197. package/dist/src/gateway/hono/lib/route-logger.js +31 -0
  198. package/dist/src/gateway/hono/lib/route-logger.js.map +1 -0
  199. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  200. package/dist/src/gateway/hono/middleware/auth.js +16 -3
  201. package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
  202. package/dist/src/gateway/hono/middleware/logger.js +1 -1
  203. package/dist/src/gateway/hono/middleware/logger.js.map +1 -1
  204. package/dist/src/gateway/hono/middleware/route-errors.d.ts +5 -0
  205. package/dist/src/gateway/hono/middleware/route-errors.js +27 -0
  206. package/dist/src/gateway/hono/middleware/route-errors.js.map +1 -0
  207. package/dist/src/gateway/hono/oauth.js +1 -1
  208. package/dist/src/gateway/hono/routes/agent-stream.js +6 -0
  209. package/dist/src/gateway/hono/routes/agent-stream.js.map +1 -1
  210. package/dist/src/gateway/hono/routes/agents.js +1 -1
  211. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  212. package/dist/src/gateway/hono/routes/browser-install.js +2 -4
  213. package/dist/src/gateway/hono/routes/browser-install.js.map +1 -1
  214. package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
  215. package/dist/src/gateway/hono/routes/config.js +25 -11
  216. package/dist/src/gateway/hono/routes/config.js.map +1 -1
  217. package/dist/src/gateway/hono/routes/cron.js +5 -0
  218. package/dist/src/gateway/hono/routes/cron.js.map +1 -1
  219. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  220. package/dist/src/gateway/hono/routes/host-fs.js +4 -6
  221. package/dist/src/gateway/hono/routes/host-fs.js.map +1 -1
  222. package/dist/src/gateway/hono/routes/lazy-bundles.js +14 -1
  223. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  224. package/dist/src/gateway/hono/routes/lazy-fallback.js +3 -0
  225. package/dist/src/gateway/hono/routes/lazy-fallback.js.map +1 -1
  226. package/dist/src/gateway/hono/routes/logs.js +39 -7
  227. package/dist/src/gateway/hono/routes/logs.js.map +1 -1
  228. package/dist/src/gateway/hono/routes/mcp.d.ts +3 -0
  229. package/dist/src/gateway/hono/routes/mcp.js +107 -0
  230. package/dist/src/gateway/hono/routes/mcp.js.map +1 -0
  231. package/dist/src/gateway/hono/routes/models.js +1 -1
  232. package/dist/src/gateway/hono/routes/sessions.js +6 -0
  233. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  234. package/dist/src/gateway/hono/routes/shares.js +1 -1
  235. package/dist/src/gateway/hono/routes/update.js +2 -4
  236. package/dist/src/gateway/hono/routes/update.js.map +1 -1
  237. package/dist/src/gateway/hono/routes/voice.js +2 -4
  238. package/dist/src/gateway/hono/routes/voice.js.map +1 -1
  239. package/dist/src/gateway/hono/routes/workspace.js +4 -6
  240. package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
  241. package/dist/src/gateway/hono/sse.js +9 -2
  242. package/dist/src/gateway/hono/sse.js.map +1 -1
  243. package/dist/src/gateway/lock.js +3 -3
  244. package/dist/src/gateway/ports.js +1 -1
  245. package/dist/src/gateway/service/agent-runner.js +3 -3
  246. package/dist/src/gateway/service/agent-runner.js.map +1 -1
  247. package/dist/src/gateway/service/config-coordinator.js +14 -6
  248. package/dist/src/gateway/service/config-coordinator.js.map +1 -1
  249. package/dist/src/gateway/service/marketplace-service.js +3 -3
  250. package/dist/src/gateway/service/marketplace-service.js.map +1 -1
  251. package/dist/src/gateway/service/run-gateway-agent.js +22 -5
  252. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  253. package/dist/src/gateway/service/sse-hub.js +1 -1
  254. package/dist/src/gateway/service/sse-hub.js.map +1 -1
  255. package/dist/src/gateway/service.js +13 -6
  256. package/dist/src/gateway/service.js.map +1 -1
  257. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  258. package/dist/src/heartbeat/index.js +1 -1
  259. package/dist/src/infra/brew.js +1 -1
  260. package/dist/src/infra/package-json.js +1 -1
  261. package/dist/src/infra/package-update-steps.js +1 -1
  262. package/dist/src/infra/path-env.js +2 -2
  263. package/dist/src/infra/restart.js +2 -2
  264. package/dist/src/infra/stable-node-path.js +1 -1
  265. package/dist/src/infra/update-check.js +1 -1
  266. package/dist/src/infra/update-global.js +1 -1
  267. package/dist/src/infra/update-lock.js +3 -3
  268. package/dist/src/infra/update-runner.js +1 -1
  269. package/dist/src/infra/update-startup.js +2 -2
  270. package/dist/src/infra/write-file-atomic.js +2 -2
  271. package/dist/src/mcp/channel-bridge.js +26 -2
  272. package/dist/src/mcp/channel-bridge.js.map +1 -1
  273. package/dist/src/mcp/gateway-http-client.js +24 -2
  274. package/dist/src/mcp/gateway-http-client.js.map +1 -1
  275. package/dist/src/notes/store.js +2 -2
  276. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  277. package/dist/src/providers/index.js +2 -2
  278. package/dist/src/providers/model-registry.js +1 -1
  279. package/dist/src/session/config-store.js +12 -6
  280. package/dist/src/session/config-store.js.map +1 -1
  281. package/dist/src/session/index.d.ts +1 -1
  282. package/dist/src/session/index.js +2 -2
  283. package/dist/src/session/init-session-turn.js +2 -2
  284. package/dist/src/session/manager.js +8 -1
  285. package/dist/src/session/manager.js.map +1 -1
  286. package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
  287. package/dist/src/session/parity/sessions-json-file.js +1 -1
  288. package/dist/src/session/parity/transcript-file-lock.js +2 -2
  289. package/dist/src/session/parity/transcript-paths.js +1 -1
  290. package/dist/src/session/resolve-session.js +4 -4
  291. package/dist/src/session/search-index-cache.js +1 -1
  292. package/dist/src/session/search-index.js +1 -1
  293. package/dist/src/session/session-title.d.ts +19 -3
  294. package/dist/src/session/session-title.js +84 -9
  295. package/dist/src/session/session-title.js.map +1 -1
  296. package/dist/src/session/store.js +6 -6
  297. package/dist/src/share/share-auto.js +2 -2
  298. package/dist/src/share/share-store.js +3 -3
  299. package/dist/src/share/share-thumbnail.js +2 -2
  300. package/dist/src/share/share-zip.js +1 -1
  301. package/dist/src/share/site-share-store.js +3 -3
  302. package/dist/src/share/site-static-serve.js +1 -1
  303. package/dist/src/tui/clipboard-image.js +3 -3
  304. package/dist/src/tui/theme-manager.js +1 -1
  305. package/dist/src/tui/tui-keybindings-file.js +1 -1
  306. package/dist/src/tui/tui-scoped-models.js +2 -2
  307. package/dist/src/tui/tui-settings.js +1 -1
  308. package/dist/src/tui/tui.js +3 -3
  309. package/dist/src/tunnel/frpc-binary.js +3 -3
  310. package/dist/src/tunnel/frpc-config.js +1 -1
  311. package/dist/src/tunnel/frpc-extract.js +1 -1
  312. package/dist/src/tunnel/tunnel-state.js +1 -1
  313. package/dist/src/utils/index.js +4 -4
  314. package/dist/src/utils/logger/audit.js +1 -1
  315. package/dist/src/utils/logger/config.js +2 -6
  316. package/dist/src/utils/logger/config.js.map +1 -1
  317. package/dist/src/utils/logger/context.d.ts +3 -22
  318. package/dist/src/utils/logger/context.js +4 -32
  319. package/dist/src/utils/logger/context.js.map +1 -1
  320. package/dist/src/utils/logger/index.d.ts +4 -7
  321. package/dist/src/utils/logger/index.js +9 -28
  322. package/dist/src/utils/logger/index.js.map +1 -1
  323. package/dist/src/utils/logger/log-store.d.ts +14 -32
  324. package/dist/src/utils/logger/log-store.js +68 -119
  325. package/dist/src/utils/logger/log-store.js.map +1 -1
  326. package/dist/src/utils/logger/log-stream.d.ts +5 -70
  327. package/dist/src/utils/logger/log-stream.js +67 -178
  328. package/dist/src/utils/logger/log-stream.js.map +1 -1
  329. package/dist/src/utils/logger/pino-record.d.ts +8 -0
  330. package/dist/src/utils/logger/pino-record.js +83 -0
  331. package/dist/src/utils/logger/pino-record.js.map +1 -0
  332. package/dist/src/utils/logger/rotation.js +1 -1
  333. package/dist/src/utils/logger/stats.d.ts +1 -1
  334. package/dist/src/utils/logger/stats.js +2 -2
  335. package/dist/src/utils/logger/stats.js.map +1 -1
  336. package/dist/src/utils/logger/streams.js +18 -0
  337. package/dist/src/utils/logger/streams.js.map +1 -1
  338. package/dist/src/utils/logger/types.d.ts +0 -9
  339. package/dist/src/utils/logger/types.js.map +1 -1
  340. package/dist/src/utils/logger.js +4 -4
  341. package/dist/src/voice/tts/audio.js +1 -1
  342. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  343. package/dist/src/workflows/store/event-store.js +1 -1
  344. package/dist/src/workflows/store/run-store.js +1 -1
  345. package/package.json +2 -1
  346. package/dist/gateway/static/root/assets/agents-C7tTJLP9.js +0 -222
  347. package/dist/gateway/static/root/assets/apps-page-BbzdMyrg.js +0 -1
  348. package/dist/gateway/static/root/assets/channels-settings-B49vG2hE.js +0 -1
  349. package/dist/gateway/static/root/assets/cron-page-Bjx7IOdR.js +0 -1
  350. package/dist/gateway/static/root/assets/index-CwDdudZM.css +0 -1
  351. package/dist/gateway/static/root/assets/logs-page-BxukQ-J-.js +0 -1
  352. package/dist/gateway/static/root/assets/sessions-page-BFD2_-Cl.js +0 -1
  353. package/dist/gateway/static/root/assets/settings-page-BiP5iH46.js +0 -2
  354. package/dist/gateway/static/root/assets/skills-page-CNDctFIn.js +0 -2
  355. package/dist/gateway/static/root/assets/voice-api-key-field-CalxUkxm.js +0 -1
  356. package/dist/gateway/static/root/assets/workflows-page-D2fRxXJG.js +0 -27
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","names":[],"sources":["../../../../src/utils/logger/context.ts"],"sourcesContent":["/**\n * Logger Context\n * Context tracking and propagation for structured logging\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\n\nimport type { LogContext, ContextualLogger } from './types.js';\n\nconst contextStore = new Map<string, LogContext>();\n\n/** Correlation fields merged into every log line while the store is active (via pino mixin). */\nconst ASYNC_LOG_CORRELATION_KEYS = ['requestId', 'sessionId', 'userId', 'correlationId'] as const;\n\ntype AsyncLogCorrelationKey = (typeof ASYNC_LOG_CORRELATION_KEYS)[number];\n\nconst logContextStorage = new AsyncLocalStorage<{ ctx: LogContext }>();\n\n/**\n * Run *fn* with merged async log context. Propagates through async/await (Node AsyncLocalStorage).\n * Nested calls merge over the parent context (shallow per key).\n */\nexport function runWithLogContext<T>(context: LogContext, fn: () => T): T {\n const parent = logContextStorage.getStore();\n const merged = parent ? mergeContext(parent.ctx, context) : { ...context };\n return logContextStorage.run({ ctx: { ...merged } }, fn);\n}\n\n/** Current async log context, if any. */\nexport function getAsyncLogContext(): LogContext | undefined {\n return logContextStorage.getStore()?.ctx;\n}\n\n/**\n * Shallow-merge fields into the current async log context (e.g. set sessionId after parsing a body).\n * No-op when not inside {@link runWithLogContext}.\n */\nexport function updateAsyncLogContext(partial: LogContext): void {\n const ref = logContextStorage.getStore();\n if (ref) {\n ref.ctx = mergeContext(ref.ctx, partial);\n }\n}\n\n/** Keys injected from async context into log records (used by logger mixin). */\nexport function getAsyncLogCorrelationKeys(): readonly AsyncLogCorrelationKey[] {\n return ASYNC_LOG_CORRELATION_KEYS;\n}\n\n/**\n * Fields to copy from ALS onto {@link InboundMessage.metadata} when the gateway enqueues\n * a message for the agent bus. Omits `sessionId` so channel routing / sessionKey stays\n * authoritative; the agent sets log sessionId after `routeMessage`.\n */\nconst INBOUND_METADATA_FROM_ASYNC: readonly (keyof LogContext)[] = [\n 'requestId',\n 'correlationId',\n 'userId',\n];\n\nexport function inboundCorrelationMetadataFromAsyncLogContext(): Record<string, unknown> | undefined {\n const ctx = getAsyncLogContext();\n if (!ctx) return undefined;\n const meta: Record<string, unknown> = {};\n for (const key of INBOUND_METADATA_FROM_ASYNC) {\n const v = ctx[key];\n if (v !== undefined && v !== '') {\n meta[key] = v;\n }\n }\n return Object.keys(meta).length > 0 ? meta : undefined;\n}\n\n/**\n * Merge two contexts\n */\nexport function mergeContext(base: LogContext, additional: LogContext): LogContext {\n return { ...base, ...additional };\n}\n\n/**\n * Store context for a request ID\n */\nexport function setRequestContext(requestId: string, context: LogContext): void {\n contextStore.set(requestId, context);\n}\n\n/**\n * Get context for a request ID\n */\nexport function getRequestContext(requestId: string): LogContext | undefined {\n return contextStore.get(requestId);\n}\n\n/**\n * Clear context for a request ID\n */\nexport function clearRequestContext(requestId: string): void {\n contextStore.delete(requestId);\n}\n\n/**\n * Create a child logger with additional context\n * This is a placeholder for the actual implementation\n */\nexport function withContext(logger: ContextualLogger, context: LogContext): ContextualLogger {\n return logger.withContext(context);\n}\n"],"mappings":";;;;;;;;;;;AAsBA,SAAgB,kBAAqB,SAAqB,IAAgB;CACxE,MAAM,SAAS,kBAAkB,UAAU;CAC3C,MAAM,SAAS,SAAS,aAAa,OAAO,KAAK,QAAQ,GAAG,EAAE,GAAG,SAAS;AAC1E,QAAO,kBAAkB,IAAI,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,EAAE,GAAG;;;AAI1D,SAAgB,qBAA6C;AAC3D,QAAO,kBAAkB,UAAU,EAAE;;;;;;AAOvC,SAAgB,sBAAsB,SAA2B;CAC/D,MAAM,MAAM,kBAAkB,UAAU;AACxC,KAAI,IACF,KAAI,MAAM,aAAa,IAAI,KAAK,QAAQ;;;AAK5C,SAAgB,6BAAgE;AAC9E,QAAO;;AAcT,SAAgB,gDAAqF;CACnG,MAAM,MAAM,oBAAoB;AAChC,KAAI,CAAC,IAAK,QAAO,KAAA;CACjB,MAAM,OAAgC,EAAE;AACxC,MAAK,MAAM,OAAO,6BAA6B;EAC7C,MAAM,IAAI,IAAI;AACd,MAAI,MAAM,KAAA,KAAa,MAAM,GAC3B,MAAK,OAAO;;AAGhB,QAAO,OAAO,KAAK,KAAK,CAAC,SAAS,IAAI,OAAO,KAAA;;;;;AAM/C,SAAgB,aAAa,MAAkB,YAAoC;AACjF,QAAO;EAAE,GAAG;EAAM,GAAG;EAAY;;;;;AAMnC,SAAgB,kBAAkB,WAAmB,SAA2B;AAC9E,cAAa,IAAI,WAAW,QAAQ;;;;;AAMtC,SAAgB,kBAAkB,WAA2C;AAC3E,QAAO,aAAa,IAAI,UAAU;;;;;AAMpC,SAAgB,oBAAoB,WAAyB;AAC3D,cAAa,OAAO,UAAU;;;;;;AAOhC,SAAgB,YAAY,QAA0B,SAAuC;AAC3F,QAAO,OAAO,YAAY,QAAQ;;;;AAjG9B,gCAAe,IAAI,KAAyB;AAG5C,8BAA6B;EAAC;EAAa;EAAa;EAAU;EAAgB;AAIlF,qBAAoB,IAAI,mBAAwC;AAsChE,+BAA6D;EACjE;EACA;EACA;EACD"}
1
+ {"version":3,"file":"context.js","names":[],"sources":["../../../../src/utils/logger/context.ts"],"sourcesContent":["/**\n * Logger Context\n * AsyncLocalStorage correlation for structured logging\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\n\nimport type { LogContext } from './types.js';\n\n/** Correlation fields merged into every log line while the store is active (via pino mixin). */\nconst ASYNC_LOG_CORRELATION_KEYS = ['requestId', 'sessionId', 'userId', 'correlationId'] as const;\n\ntype AsyncLogCorrelationKey = (typeof ASYNC_LOG_CORRELATION_KEYS)[number];\n\nconst logContextStorage = new AsyncLocalStorage<{ ctx: LogContext }>();\n\n/**\n * Run *fn* with merged async log context. Propagates through async/await (Node AsyncLocalStorage).\n * Nested calls merge over the parent context (shallow per key).\n */\nexport function runWithLogContext<T>(context: LogContext, fn: () => T): T {\n const parent = logContextStorage.getStore();\n const merged = parent ? mergeContext(parent.ctx, context) : { ...context };\n return logContextStorage.run({ ctx: { ...merged } }, fn);\n}\n\n/** Current async log context, if any. */\nexport function getAsyncLogContext(): LogContext | undefined {\n return logContextStorage.getStore()?.ctx;\n}\n\n/**\n * Shallow-merge fields into the current async log context (e.g. set sessionId after parsing a body).\n * No-op when not inside {@link runWithLogContext}.\n */\nexport function updateAsyncLogContext(partial: LogContext): void {\n const ref = logContextStorage.getStore();\n if (ref) {\n ref.ctx = mergeContext(ref.ctx, partial);\n }\n}\n\n/** Keys injected from async context into log records (used by logger mixin). */\nexport function getAsyncLogCorrelationKeys(): readonly AsyncLogCorrelationKey[] {\n return ASYNC_LOG_CORRELATION_KEYS;\n}\n\n/**\n * Fields to copy from ALS onto {@link InboundMessage.metadata} when the gateway enqueues\n * a message for the agent bus. Omits `sessionId` so channel routing / sessionKey stays\n * authoritative; the agent sets log sessionId after `routeMessage`.\n */\nconst INBOUND_METADATA_FROM_ASYNC: readonly (keyof LogContext)[] = [\n 'requestId',\n 'correlationId',\n 'userId',\n];\n\nexport function inboundCorrelationMetadataFromAsyncLogContext(): Record<string, unknown> | undefined {\n const ctx = getAsyncLogContext();\n if (!ctx) return undefined;\n const meta: Record<string, unknown> = {};\n for (const key of INBOUND_METADATA_FROM_ASYNC) {\n const v = ctx[key];\n if (v !== undefined && v !== '') {\n meta[key] = v;\n }\n }\n return Object.keys(meta).length > 0 ? meta : undefined;\n}\n\n/** Shallow-merge two log context objects. */\nexport function mergeContext(base: LogContext, additional: LogContext): LogContext {\n return { ...base, ...additional };\n}\n"],"mappings":";;;;;;;;;;;AAoBA,SAAgB,kBAAqB,SAAqB,IAAgB;CACxE,MAAM,SAAS,kBAAkB,UAAU;CAC3C,MAAM,SAAS,SAAS,aAAa,OAAO,KAAK,QAAQ,GAAG,EAAE,GAAG,SAAS;AAC1E,QAAO,kBAAkB,IAAI,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,EAAE,GAAG;;;AAI1D,SAAgB,qBAA6C;AAC3D,QAAO,kBAAkB,UAAU,EAAE;;;;;;AAOvC,SAAgB,sBAAsB,SAA2B;CAC/D,MAAM,MAAM,kBAAkB,UAAU;AACxC,KAAI,IACF,KAAI,MAAM,aAAa,IAAI,KAAK,QAAQ;;;AAK5C,SAAgB,6BAAgE;AAC9E,QAAO;;AAcT,SAAgB,gDAAqF;CACnG,MAAM,MAAM,oBAAoB;AAChC,KAAI,CAAC,IAAK,QAAO,KAAA;CACjB,MAAM,OAAgC,EAAE;AACxC,MAAK,MAAM,OAAO,6BAA6B;EAC7C,MAAM,IAAI,IAAI;AACd,MAAI,MAAM,KAAA,KAAa,MAAM,GAC3B,MAAK,OAAO;;AAGhB,QAAO,OAAO,KAAK,KAAK,CAAC,SAAS,IAAI,OAAO,KAAA;;;AAI/C,SAAgB,aAAa,MAAkB,YAAoC;AACjF,QAAO;EAAE,GAAG;EAAM,GAAG;EAAY;;;;AA/D7B,8BAA6B;EAAC;EAAa;EAAa;EAAU;EAAgB;AAIlF,qBAAoB,IAAI,mBAAwC;AAsChE,+BAA6D;EACjE;EACA;EACA;EACD"}
@@ -10,26 +10,23 @@
10
10
  import pino from 'pino';
11
11
  import type { LogLevel, LogContext, ContextualLogger } from './types.js';
12
12
  import { getLogDir, getLoggerConfig } from './config.js';
13
- import { getLogStats } from './stats.js';
13
+ import { getRuntimeLogStats } from './stats.js';
14
14
  import { isLoggerShuttingDown, flushAndClose, setShuttingDown } from './shutdown.js';
15
15
  import { rotateLogs, cleanOldLogs } from './rotation.js';
16
16
  export declare const logger: ContextualLogger;
17
- export declare function createLogger(prefix: string, context?: LogContext): ContextualLogger;
17
+ export declare function createLogger(module: string, context?: LogContext): ContextualLogger;
18
18
  export declare function createModuleLogger(moduleName: string, _modulePath?: string): ContextualLogger;
19
19
  export declare function createExtensionLogger(extensionName: string): ContextualLogger;
20
20
  export declare function createServiceLogger(serviceId: string): ContextualLogger;
21
- export declare function createRequestLogger(requestId: string, initialContext?: LogContext): ContextualLogger;
22
21
  export declare function setLogLevel(level: LogLevel): void;
23
22
  export declare function getLogLevel(): LogLevel;
24
23
  export declare function withLogLevel<T>(level: LogLevel, fn: () => T): T;
25
24
  export declare function isLevelEnabled(level: LogLevel): boolean;
26
25
  export type { LogLevel, LogContext, LogEntry, LoggerConfig, LogFileMeta, LogQuery, LogStats, RotationResult, ContextualLogger, } from './types.js';
27
- export { getLogDir, getLoggerConfig, getLogStats, isLoggerShuttingDown, flushAndClose, setShuttingDown, rotateLogs, cleanOldLogs, };
26
+ export { getLogDir, getLoggerConfig, getRuntimeLogStats, isLoggerShuttingDown, flushAndClose, setShuttingDown, rotateLogs, cleanOldLogs, };
28
27
  export { type LogExporter, type ExporterConfig, type LokiConfig, type ElkConfig, type DatadogConfig, type WebhookConfig, initializeExporters, exportLog, flushExporters, getExporters, } from './exporters.js';
29
28
  export { redactSensitiveInfo, redactObject, redactPemBlock, redactSecret, isLogRedactionEnabled, } from './redact.js';
30
29
  export { type AuditEvent, type AuditEventType, type AuditLogConfig, logAuditEvent, logAuthEvent, logConfigChange, logPermissionChange, logDataAccess, configureAuditLog, getAuditConfig, } from './audit.js';
31
- export { logger as default };
32
30
  export { logger as baseLogger };
33
31
  export { pino as Pino };
34
- export declare function registerShutdownHandler(): void;
35
- export { runWithLogContext, getAsyncLogContext, updateAsyncLogContext, inboundCorrelationMetadataFromAsyncLogContext, setRequestContext as setRequestLogger, clearRequestContext as clearRequestLogger, } from './context.js';
32
+ export { runWithLogContext, getAsyncLogContext, updateAsyncLogContext, inboundCorrelationMetadataFromAsyncLogContext, } from './context.js';
@@ -2,10 +2,10 @@ import { __esmMin } from "../../../_virtual/_rolldown/runtime.js";
2
2
  import { PACKAGE_VERSION, init_package_version } from "../../package-version.js";
3
3
  import { config, getLogDir, getLoggerConfig, init_config } from "./config.js";
4
4
  import { init_streams, initializeStreams } from "./streams.js";
5
- import { getLogStats, incrementStats, init_stats } from "./stats.js";
5
+ import { getRuntimeLogStats, incrementStats, init_stats } from "./stats.js";
6
6
  import { flushAndClose, init_shutdown, isLoggerShuttingDown, setShuttingDown } from "./shutdown.js";
7
7
  import { cleanOldLogs, init_rotation, rotateLogs } from "./rotation.js";
8
- import { clearRequestContext, getAsyncLogContext, getAsyncLogCorrelationKeys, inboundCorrelationMetadataFromAsyncLogContext, init_context, mergeContext, runWithLogContext, setRequestContext, updateAsyncLogContext } from "./context.js";
8
+ import { getAsyncLogContext, getAsyncLogCorrelationKeys, inboundCorrelationMetadataFromAsyncLogContext, init_context, mergeContext, runWithLogContext, updateAsyncLogContext } from "./context.js";
9
9
  import { init_redact, isLogRedactionEnabled, redactLogRecord, redactObject, redactPemBlock, redactSecret, redactSensitiveInfo } from "./redact.js";
10
10
  import { exportLog, flushExporters, getExporters, init_exporters, initializeExporters } from "./exporters.js";
11
11
  import { configureAuditLog, getAuditConfig, init_audit, logAuditEvent, logAuthEvent, logConfigChange, logDataAccess, logPermissionChange } from "./audit.js";
@@ -25,7 +25,8 @@ function wrapLogMethod(method, defaultContext, level) {
25
25
  if (isLoggerShuttingDown()) {
26
26
  if (level !== "error" && level !== "fatal") return;
27
27
  }
28
- incrementStats(level, defaultContext.module || defaultContext.prefix);
28
+ const module = defaultContext.module;
29
+ incrementStats(level, module);
29
30
  return msg !== void 0 ? method.call(this, data, msg) : method.call(this, data);
30
31
  };
31
32
  }
@@ -35,9 +36,6 @@ function createProxyLogger(logger, defaultContext = {}) {
35
36
  if (prop === "withContext") return (context) => {
36
37
  return createProxyLogger(target.child({ ...context }), mergeContext(defaultContext, context));
37
38
  };
38
- if (prop === "childContext") return (context) => {
39
- return createProxyLogger(target.child({ ...context }), mergeContext(defaultContext, context));
40
- };
41
39
  const value = target[propKey];
42
40
  if (typeof value === "function") {
43
41
  if ([
@@ -52,9 +50,9 @@ function createProxyLogger(logger, defaultContext = {}) {
52
50
  return value;
53
51
  } });
54
52
  }
55
- function createLogger(prefix, context) {
56
- return createProxyLogger(baseLogger.child({ prefix }), {
57
- module: prefix,
53
+ function createLogger(module, context) {
54
+ return createProxyLogger(baseLogger.child({ module }), {
55
+ module,
58
56
  ...context
59
57
  });
60
58
  }
@@ -73,13 +71,6 @@ function createServiceLogger(serviceId) {
73
71
  scope: serviceId
74
72
  });
75
73
  }
76
- function createRequestLogger(requestId, initialContext) {
77
- const context = {
78
- requestId,
79
- ...initialContext
80
- };
81
- return createProxyLogger(baseLogger.child({ requestId }), context);
82
- }
83
74
  function setLogLevel(level) {
84
75
  baseLogger.level = level;
85
76
  }
@@ -105,18 +96,8 @@ function isLevelEnabled(level) {
105
96
  fatal: 60,
106
97
  silent: Number.MAX_VALUE
107
98
  };
108
- const currentLevelValues = {
109
- trace: 10,
110
- debug: 20,
111
- info: 30,
112
- warn: 40,
113
- error: 50,
114
- fatal: 60,
115
- silent: Number.MAX_VALUE
116
- };
117
- return levelValues[level] >= currentLevelValues[getLogLevel()];
99
+ return levelValues[level] >= levelValues[getLogLevel()];
118
100
  }
119
- function registerShutdownHandler() {}
120
101
  var pinoOptions, streams, baseLogger, logger;
121
102
  var init_logger = __esmMin((() => {
122
103
  init_config();
@@ -199,6 +180,6 @@ var init_logger = __esmMin((() => {
199
180
  }));
200
181
  //#endregion
201
182
  init_logger();
202
- export { pino as Pino, logger as baseLogger, logger as default, logger, cleanOldLogs, clearRequestContext as clearRequestLogger, configureAuditLog, createExtensionLogger, createLogger, createModuleLogger, createRequestLogger, createServiceLogger, exportLog, flushAndClose, flushExporters, getAsyncLogContext, getAuditConfig, getExporters, getLogDir, getLogLevel, getLogStats, getLoggerConfig, inboundCorrelationMetadataFromAsyncLogContext, init_logger, initializeExporters, isLevelEnabled, isLogRedactionEnabled, isLoggerShuttingDown, logAuditEvent, logAuthEvent, logConfigChange, logDataAccess, logPermissionChange, redactObject, redactPemBlock, redactSecret, redactSensitiveInfo, registerShutdownHandler, rotateLogs, runWithLogContext, setLogLevel, setRequestContext as setRequestLogger, setShuttingDown, updateAsyncLogContext, withLogLevel };
183
+ export { pino as Pino, logger as baseLogger, logger, cleanOldLogs, configureAuditLog, createExtensionLogger, createLogger, createModuleLogger, createServiceLogger, exportLog, flushAndClose, flushExporters, getAsyncLogContext, getAuditConfig, getExporters, getLogDir, getLogLevel, getLoggerConfig, getRuntimeLogStats, inboundCorrelationMetadataFromAsyncLogContext, init_logger, initializeExporters, isLevelEnabled, isLogRedactionEnabled, isLoggerShuttingDown, logAuditEvent, logAuthEvent, logConfigChange, logDataAccess, logPermissionChange, redactObject, redactPemBlock, redactSecret, redactSensitiveInfo, rotateLogs, runWithLogContext, setLogLevel, setShuttingDown, updateAsyncLogContext, withLogLevel };
203
184
 
204
185
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../../src/utils/logger/index.ts"],"sourcesContent":["/**\n * Modular Logger System\n * \n * Production-grade logging with:\n * - Modular architecture\n * - Context tracking\n * - Statistics\n * - Graceful shutdown\n */\n\nimport pino from 'pino';\nimport type { Logger as PinoLogger } from 'pino';\nimport type { LogLevel, LogContext, ContextualLogger } from './types.js';\n\n// Internal modules\nimport { config, getLogDir, getLoggerConfig } from './config.js';\nimport { initializeStreams } from './streams.js';\nimport { incrementStats, getLogStats } from './stats.js';\nimport { isLoggerShuttingDown, flushAndClose, setShuttingDown } from './shutdown.js';\nimport { rotateLogs, cleanOldLogs } from './rotation.js';\nimport { getAsyncLogContext, getAsyncLogCorrelationKeys, mergeContext } from './context.js';\nimport { redactLogRecord } from './redact.js';\nimport { PACKAGE_VERSION } from '../../package-version.js';\n\n// ============================================\n// Base Logger Creation\n// ============================================\n\nconst customLevels = {\n trace: 10,\n debug: 20,\n info: 30,\n warn: 40,\n error: 50,\n fatal: 60,\n};\n\nconst pinoOptions: pino.LoggerOptions = {\n level: config.level,\n base: {\n service: 'xopc',\n version: process.env.npm_package_version || PACKAGE_VERSION,\n },\n timestamp: pino.stdTimeFunctions.isoTime,\n mixin(mergeObject, _level, logger) {\n const ctx = getAsyncLogContext();\n if (!ctx) return {};\n const bindings =\n logger && typeof logger.bindings === 'function'\n ? (logger.bindings() as Record<string, unknown>)\n : {};\n const mo = mergeObject as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of getAsyncLogCorrelationKeys()) {\n const v = ctx[key];\n if (v === undefined || v === '') continue;\n if (mo[key] !== undefined) continue;\n if (bindings[key] !== undefined) continue;\n out[key] = v;\n }\n return out;\n },\n formatters: {\n level: (label) => ({ level: label }),\n bindings: (bindings) => ({\n pid: bindings.pid,\n host: bindings.host,\n }),\n log: (object) => {\n // Serialize errors with full stack trace\n if (object.err && object.err instanceof Error) {\n object.err = {\n name: object.err.name,\n message: object.err.message,\n stack: object.err.stack,\n cause: object.err.cause instanceof Error \n ? { name: object.err.cause.name, message: object.err.cause.message, stack: object.err.cause.stack }\n : object.err.cause,\n };\n }\n for (const key of Object.keys(object)) {\n if (object[key] instanceof Error) {\n object[key] = {\n name: object[key].name,\n message: object[key].message,\n stack: object[key].stack,\n };\n }\n }\n return redactLogRecord(object as Record<string, unknown>);\n },\n },\n customLevels,\n};\n\n// Add pretty print for development\nif (config.prettyPrint) {\n pinoOptions.transport = {\n target: 'pino-pretty',\n options: {\n colorize: true,\n translateTime: 'SYS:standard',\n ignore: 'pid,host',\n },\n };\n}\n\nconst streams = initializeStreams();\nconst baseLogger = pino(pinoOptions, pino.multistream(streams));\n\n// ============================================\n// Contextual Logger\n// ============================================\n\nfunction wrapLogMethod(method: Function, defaultContext: LogContext, level: LogLevel) {\n return function (data: unknown, msg?: string) {\n // During shutdown, only allow error and fatal logs\n if (isLoggerShuttingDown()) {\n if (level !== 'error' && level !== 'fatal') {\n return;\n }\n }\n \n const module = (defaultContext.module || defaultContext.prefix) as string | undefined;\n incrementStats(level, module);\n \n return msg !== undefined ? method.call(this, data, msg) : method.call(this, data);\n };\n}\n\nfunction createProxyLogger(logger: PinoLogger, defaultContext: LogContext = {}): ContextualLogger {\n const proxy = new Proxy(logger, {\n get(target, prop) {\n const propKey = prop as string;\n \n if (prop === 'withContext') {\n return (context: LogContext) => {\n return createProxyLogger(target.child({ ...context }), mergeContext(defaultContext, context));\n };\n }\n if (prop === 'childContext') {\n return (context: LogContext) => {\n return createProxyLogger(target.child({ ...context }), mergeContext(defaultContext, context));\n };\n }\n \n const value = (target as unknown as Record<string, unknown>)[propKey];\n if (typeof value === 'function') {\n if (['trace', 'debug', 'info', 'warn', 'error', 'fatal'].includes(propKey)) {\n return wrapLogMethod(value, defaultContext, propKey as LogLevel);\n }\n }\n \n return value;\n },\n });\n\n return proxy as ContextualLogger;\n}\n\n// ============================================\n// Public API\n// ============================================\n\nexport const logger = createProxyLogger(baseLogger);\n\nexport function createLogger(prefix: string, context?: LogContext): ContextualLogger {\n const child = baseLogger.child({ prefix });\n return createProxyLogger(child, { module: prefix, ...context });\n}\n\nexport function createModuleLogger(moduleName: string, _modulePath?: string): ContextualLogger {\n const child = baseLogger.child({ module: moduleName });\n return createProxyLogger(child, { module: moduleName });\n}\n\nexport function createExtensionLogger(extensionName: string): ContextualLogger {\n const child = baseLogger.child({ extension: extensionName });\n return createProxyLogger(child, { extension: extensionName });\n}\n\nexport function createServiceLogger(serviceId: string): ContextualLogger {\n const child = baseLogger.child({ service: 'cron', scope: serviceId });\n return createProxyLogger(child, { service: 'cron', scope: serviceId });\n}\n\nexport function createRequestLogger(requestId: string, initialContext?: LogContext): ContextualLogger {\n const context: LogContext = { requestId, ...initialContext };\n const child = baseLogger.child({ requestId });\n return createProxyLogger(child, context);\n}\n\n// ============================================\n// Log Level Management\n// ============================================\n\nexport function setLogLevel(level: LogLevel): void {\n baseLogger.level = level;\n}\n\nexport function getLogLevel(): LogLevel {\n return baseLogger.level as LogLevel;\n}\n\nexport function withLogLevel<T>(level: LogLevel, fn: () => T): T {\n const previous = baseLogger.level;\n baseLogger.level = level;\n try {\n return fn();\n } finally {\n baseLogger.level = previous;\n }\n}\n\nexport function isLevelEnabled(level: LogLevel): boolean {\n const levelValues: Record<LogLevel, number> = {\n trace: 10, debug: 20, info: 30, warn: 40, error: 50, fatal: 60, silent: Number.MAX_VALUE,\n };\n const currentLevelValues: Record<LogLevel, number> = {\n trace: 10, debug: 20, info: 30, warn: 40, error: 50, fatal: 60, silent: Number.MAX_VALUE,\n };\n return levelValues[level] >= currentLevelValues[getLogLevel()];\n}\n\n// ============================================\n// Re-exports\n// ============================================\n\nexport type {\n LogLevel,\n LogContext,\n LogEntry,\n LoggerConfig,\n LogFileMeta,\n LogQuery,\n LogStats,\n RotationResult,\n ContextualLogger,\n} from './types.js';\n\nexport {\n // Config\n getLogDir,\n getLoggerConfig,\n \n // Stats\n getLogStats,\n \n // Shutdown\n isLoggerShuttingDown,\n flushAndClose,\n setShuttingDown,\n \n // Rotation\n rotateLogs,\n cleanOldLogs,\n};\n\n// Exporters\nexport {\n type LogExporter,\n type ExporterConfig,\n type LokiConfig,\n type ElkConfig,\n type DatadogConfig,\n type WebhookConfig,\n initializeExporters,\n exportLog,\n flushExporters,\n getExporters,\n} from './exporters.js';\n\nexport {\n redactSensitiveInfo,\n redactObject,\n redactPemBlock,\n redactSecret,\n isLogRedactionEnabled,\n} from './redact.js';\n\n// Audit Log\nexport {\n type AuditEvent,\n type AuditEventType,\n type AuditLogConfig,\n logAuditEvent,\n logAuthEvent,\n logConfigChange,\n logPermissionChange,\n logDataAccess,\n configureAuditLog,\n getAuditConfig,\n} from './audit.js';\n\nexport { logger as default };\nexport { logger as baseLogger };\nexport { pino as Pino };\n\nexport function registerShutdownHandler(): void {}\n\nexport {\n runWithLogContext,\n getAsyncLogContext,\n updateAsyncLogContext,\n inboundCorrelationMetadataFromAsyncLogContext,\n setRequestContext as setRequestLogger,\n clearRequestContext as clearRequestLogger,\n} from './context.js';\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/utils/logger/index.ts"],"sourcesContent":["/**\n * Modular Logger System\n * \n * Production-grade logging with:\n * - Modular architecture\n * - Context tracking\n * - Statistics\n * - Graceful shutdown\n */\n\nimport pino from 'pino';\nimport type { Logger as PinoLogger } from 'pino';\nimport type { LogLevel, LogContext, ContextualLogger } from './types.js';\n\n// Internal modules\nimport { config, getLogDir, getLoggerConfig } from './config.js';\nimport { initializeStreams } from './streams.js';\nimport { incrementStats, getRuntimeLogStats } from './stats.js';\nimport { isLoggerShuttingDown, flushAndClose, setShuttingDown } from './shutdown.js';\nimport { rotateLogs, cleanOldLogs } from './rotation.js';\nimport { getAsyncLogContext, getAsyncLogCorrelationKeys, mergeContext } from './context.js';\nimport { redactLogRecord } from './redact.js';\nimport { PACKAGE_VERSION } from '../../package-version.js';\n\n// ============================================\n// Base Logger Creation\n// ============================================\n\nconst customLevels = {\n trace: 10,\n debug: 20,\n info: 30,\n warn: 40,\n error: 50,\n fatal: 60,\n};\n\nconst pinoOptions: pino.LoggerOptions = {\n level: config.level,\n base: {\n service: 'xopc',\n version: process.env.npm_package_version || PACKAGE_VERSION,\n },\n timestamp: pino.stdTimeFunctions.isoTime,\n mixin(mergeObject, _level, logger) {\n const ctx = getAsyncLogContext();\n if (!ctx) return {};\n const bindings =\n logger && typeof logger.bindings === 'function'\n ? (logger.bindings() as Record<string, unknown>)\n : {};\n const mo = mergeObject as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of getAsyncLogCorrelationKeys()) {\n const v = ctx[key];\n if (v === undefined || v === '') continue;\n if (mo[key] !== undefined) continue;\n if (bindings[key] !== undefined) continue;\n out[key] = v;\n }\n return out;\n },\n formatters: {\n level: (label) => ({ level: label }),\n bindings: (bindings) => ({\n pid: bindings.pid,\n host: bindings.host,\n }),\n log: (object) => {\n // Serialize errors with full stack trace\n if (object.err && object.err instanceof Error) {\n object.err = {\n name: object.err.name,\n message: object.err.message,\n stack: object.err.stack,\n cause: object.err.cause instanceof Error \n ? { name: object.err.cause.name, message: object.err.cause.message, stack: object.err.cause.stack }\n : object.err.cause,\n };\n }\n for (const key of Object.keys(object)) {\n if (object[key] instanceof Error) {\n object[key] = {\n name: object[key].name,\n message: object[key].message,\n stack: object[key].stack,\n };\n }\n }\n return redactLogRecord(object as Record<string, unknown>);\n },\n },\n customLevels,\n};\n\n// Add pretty print for development\nif (config.prettyPrint) {\n pinoOptions.transport = {\n target: 'pino-pretty',\n options: {\n colorize: true,\n translateTime: 'SYS:standard',\n ignore: 'pid,host',\n },\n };\n}\n\nconst streams = initializeStreams();\nconst baseLogger = pino(pinoOptions, pino.multistream(streams));\n\n// ============================================\n// Contextual Logger\n// ============================================\n\nfunction wrapLogMethod(method: Function, defaultContext: LogContext, level: LogLevel) {\n return function (data: unknown, msg?: string) {\n // During shutdown, only allow error and fatal logs\n if (isLoggerShuttingDown()) {\n if (level !== 'error' && level !== 'fatal') {\n return;\n }\n }\n \n const module = defaultContext.module as string | undefined;\n incrementStats(level, module);\n \n return msg !== undefined ? method.call(this, data, msg) : method.call(this, data);\n };\n}\n\nfunction createProxyLogger(logger: PinoLogger, defaultContext: LogContext = {}): ContextualLogger {\n const proxy = new Proxy(logger, {\n get(target, prop) {\n const propKey = prop as string;\n \n if (prop === 'withContext') {\n return (context: LogContext) => {\n return createProxyLogger(target.child({ ...context }), mergeContext(defaultContext, context));\n };\n }\n \n const value = (target as unknown as Record<string, unknown>)[propKey];\n if (typeof value === 'function') {\n if (['trace', 'debug', 'info', 'warn', 'error', 'fatal'].includes(propKey)) {\n return wrapLogMethod(value, defaultContext, propKey as LogLevel);\n }\n }\n \n return value;\n },\n });\n\n return proxy as ContextualLogger;\n}\n\n// ============================================\n// Public API\n// ============================================\n\nexport const logger = createProxyLogger(baseLogger);\n\nexport function createLogger(module: string, context?: LogContext): ContextualLogger {\n const child = baseLogger.child({ module });\n return createProxyLogger(child, { module, ...context });\n}\n\nexport function createModuleLogger(moduleName: string, _modulePath?: string): ContextualLogger {\n const child = baseLogger.child({ module: moduleName });\n return createProxyLogger(child, { module: moduleName });\n}\n\nexport function createExtensionLogger(extensionName: string): ContextualLogger {\n const child = baseLogger.child({ extension: extensionName });\n return createProxyLogger(child, { extension: extensionName });\n}\n\nexport function createServiceLogger(serviceId: string): ContextualLogger {\n const child = baseLogger.child({ service: 'cron', scope: serviceId });\n return createProxyLogger(child, { service: 'cron', scope: serviceId });\n}\n\n// ============================================\n// Log Level Management\n// ============================================\n\nexport function setLogLevel(level: LogLevel): void {\n baseLogger.level = level;\n}\n\nexport function getLogLevel(): LogLevel {\n return baseLogger.level as LogLevel;\n}\n\nexport function withLogLevel<T>(level: LogLevel, fn: () => T): T {\n const previous = baseLogger.level;\n baseLogger.level = level;\n try {\n return fn();\n } finally {\n baseLogger.level = previous;\n }\n}\n\nexport function isLevelEnabled(level: LogLevel): boolean {\n const levelValues: Record<LogLevel, number> = {\n trace: 10, debug: 20, info: 30, warn: 40, error: 50, fatal: 60, silent: Number.MAX_VALUE,\n };\n return levelValues[level] >= levelValues[getLogLevel()];\n}\n\n// ============================================\n// Re-exports\n// ============================================\n\nexport type {\n LogLevel,\n LogContext,\n LogEntry,\n LoggerConfig,\n LogFileMeta,\n LogQuery,\n LogStats,\n RotationResult,\n ContextualLogger,\n} from './types.js';\n\nexport {\n // Config\n getLogDir,\n getLoggerConfig,\n \n // Stats\n getRuntimeLogStats,\n \n // Shutdown\n isLoggerShuttingDown,\n flushAndClose,\n setShuttingDown,\n \n // Rotation\n rotateLogs,\n cleanOldLogs,\n};\n\n// Exporters\nexport {\n type LogExporter,\n type ExporterConfig,\n type LokiConfig,\n type ElkConfig,\n type DatadogConfig,\n type WebhookConfig,\n initializeExporters,\n exportLog,\n flushExporters,\n getExporters,\n} from './exporters.js';\n\nexport {\n redactSensitiveInfo,\n redactObject,\n redactPemBlock,\n redactSecret,\n isLogRedactionEnabled,\n} from './redact.js';\n\n// Audit Log\nexport {\n type AuditEvent,\n type AuditEventType,\n type AuditLogConfig,\n logAuditEvent,\n logAuthEvent,\n logConfigChange,\n logPermissionChange,\n logDataAccess,\n configureAuditLog,\n getAuditConfig,\n} from './audit.js';\n\nexport { logger as baseLogger };\nexport { pino as Pino };\n\nexport {\n runWithLogContext,\n getAsyncLogContext,\n updateAsyncLogContext,\n inboundCorrelationMetadataFromAsyncLogContext,\n} from './context.js';\n"],"mappings":"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"}
@@ -22,46 +22,28 @@ export declare function getLogPath(date?: Date, type?: 'app' | 'error' | 'audit'
22
22
  * Query logs across multiple files
23
23
  */
24
24
  export declare function queryLogs(query?: LogQuery): Promise<LogEntry[]>;
25
+ export declare function getLogModules(): Promise<string[]>;
25
26
  /**
26
- * Get recent logs (convenience method)
27
+ * Get log statistics by level (sampled from recent files)
27
28
  */
28
- export declare function getRecentLogs(options?: {
29
- level?: LogLevel;
30
- limit?: number;
29
+ export declare function getFileLogStats(): Promise<LogStats>;
30
+ export interface LogErrorSummaryItem {
31
+ key: string;
32
+ errName: string;
33
+ phase?: string;
31
34
  module?: string;
32
- }): Promise<LogEntry[]>;
35
+ count: number;
36
+ lastSeen: string;
37
+ sampleMessage: string;
38
+ }
33
39
  /**
34
- * Search logs by keyword
40
+ * Aggregate recent error/fatal logs by err name + phase + module.
35
41
  */
36
- export declare function searchLogs(keyword: string, options?: {
42
+ export declare function getLogErrorSummary(options?: {
37
43
  from?: string;
38
44
  to?: string;
39
45
  limit?: number;
40
- }): Promise<LogEntry[]>;
41
- /**
42
- * Get logs for a specific request/session
43
- */
44
- export declare function getLogsByContext(contextType: 'requestId' | 'sessionId', contextValue: string, limit?: number): Promise<LogEntry[]>;
45
- /**
46
- * Get available log levels from actual log data
47
- */
48
- export declare function getLogLevelsFromData(): Promise<LogLevel[]>;
49
- /**
50
- * Get available modules from log data
51
- */
52
- export declare function getLogModules(): Promise<string[]>;
53
- /**
54
- * Get log statistics by level (sampled from recent files)
55
- */
56
- export declare function getLogStats(): Promise<LogStats>;
57
- /**
58
- * Clean old logs (actually deletes files)
59
- */
60
- export declare function cleanOldLogs(keepDays?: number): {
61
- deleted: number;
62
- freedBytes: number;
63
- errors: string[];
64
- };
46
+ }): Promise<LogErrorSummaryItem[]>;
65
47
  /**
66
48
  * Get available log levels
67
49
  */
@@ -1,10 +1,11 @@
1
- import { readFile } from "fs/promises";
1
+ import { init_pino_record, logEntrySearchText, pinoRecordToLogEntry } from "./pino-record.js";
2
2
  import { basename, join } from "path";
3
- import { createReadStream, existsSync, mkdirSync, readdirSync, statSync, unlinkSync } from "fs";
3
+ import { createReadStream, existsSync, mkdirSync, readdirSync, statSync } from "fs";
4
+ import { Readable } from "stream";
5
+ import { readFile } from "fs/promises";
4
6
  import { gunzip } from "zlib";
5
7
  import { promisify } from "util";
6
8
  import { createInterface } from "readline";
7
- import { Readable } from "stream";
8
9
  //#region src/utils/logger/log-store.ts
9
10
  /**
10
11
  * Log Store - Enhanced File-based Log Storage
@@ -16,6 +17,7 @@ import { Readable } from "stream";
16
17
  * - Statistics and analytics
17
18
  * - Safe log cleanup with actual deletion
18
19
  */
20
+ init_pino_record();
19
21
  const gunzipAsync = promisify(gunzip);
20
22
  const LOG_DIR = process.env.XOPC_LOG_DIR || join(process.env.HOME || ".", ".xopc", "logs");
21
23
  function ensureLogDir() {
@@ -69,45 +71,12 @@ function parseLogLine(line, source, lineNumber) {
69
71
  const trimmed = line.trim();
70
72
  if (!trimmed) return null;
71
73
  try {
72
- const parsed = JSON.parse(trimmed);
73
- const levelNum = typeof parsed.level === "number" ? parsed.level : 30;
74
- return {
75
- timestamp: parsed.time || parsed.timestamp || "",
76
- level: {
77
- 10: "trace",
78
- 20: "debug",
79
- 30: "info",
80
- 40: "warn",
81
- 50: "error",
82
- 60: "fatal"
83
- }[levelNum] || (parsed.level?.toString() || "info").toLowerCase(),
84
- message: parsed.msg || parsed.message || "",
85
- module: parsed.module,
86
- prefix: parsed.prefix,
87
- service: parsed.service,
88
- extension: parsed.extension,
89
- requestId: parsed.requestId,
90
- sessionId: parsed.sessionId,
91
- _source: source,
92
- _lineNumber: lineNumber,
93
- ...parsed
94
- };
74
+ const entry = pinoRecordToLogEntry(JSON.parse(trimmed));
75
+ entry._source = source;
76
+ entry._lineNumber = lineNumber;
77
+ return entry;
95
78
  } catch {
96
- const match = trimmed.match(/^\[([^\]]+)\]\s+(\w+):\s+(.+)$/);
97
- if (match) return {
98
- timestamp: match[1],
99
- level: match[2].toLowerCase(),
100
- message: match[3],
101
- _source: source,
102
- _lineNumber: lineNumber
103
- };
104
- return {
105
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
106
- level: "info",
107
- message: trimmed,
108
- _source: source,
109
- _lineNumber: lineNumber
110
- };
79
+ return null;
111
80
  }
112
81
  }
113
82
  /**
@@ -164,15 +133,7 @@ function matchesQuery(entry, query) {
164
133
  }
165
134
  if (query.q) {
166
135
  const keyword = query.q.toLowerCase();
167
- if (![
168
- entry.message,
169
- entry.module,
170
- entry.prefix,
171
- entry.service,
172
- entry.extension,
173
- entry.requestId,
174
- entry.sessionId
175
- ].filter(Boolean).map(String).join(" ").toLowerCase().includes(keyword)) return false;
136
+ if (!logEntrySearchText(entry).includes(keyword)) return false;
176
137
  }
177
138
  if (query.module && entry.module !== query.module) return false;
178
139
  if (query.extension && entry.extension !== query.extension) return false;
@@ -207,62 +168,16 @@ async function queryLogs(query = {}) {
207
168
  const limit = query.limit || 100;
208
169
  return results.slice(offset, offset + limit).map(({ _source, _lineNumber, ...rest }) => rest);
209
170
  }
210
- /**
211
- * Get recent logs (convenience method)
212
- */
213
- async function getRecentLogs(options) {
214
- return queryLogs({
215
- levels: options?.level ? [options.level] : void 0,
216
- limit: options?.limit || 50,
217
- module: options?.module,
218
- order: "desc"
219
- });
220
- }
221
- /**
222
- * Search logs by keyword
223
- */
224
- async function searchLogs(keyword, options) {
225
- return queryLogs({
226
- q: keyword,
227
- ...options,
228
- limit: options?.limit || 100
229
- });
230
- }
231
- /**
232
- * Get logs for a specific request/session
233
- */
234
- async function getLogsByContext(contextType, contextValue, limit = 100) {
235
- return queryLogs({
236
- [contextType]: contextValue,
237
- limit,
238
- order: "asc"
239
- });
240
- }
241
- /**
242
- * Get available log levels from actual log data
243
- */
244
- async function getLogLevelsFromData() {
245
- const levels = /* @__PURE__ */ new Set();
246
- const files = getLogFiles().slice(0, 3);
247
- for (const file of files) for await (const entry of streamLogFile(file.path, { limit: 500 })) levels.add(entry.level);
248
- return Array.from(levels).sort();
249
- }
250
- /**
251
- * Get available modules from log data
252
- */
253
171
  async function getLogModules() {
254
172
  const modules = /* @__PURE__ */ new Set();
255
173
  const files = getLogFiles().slice(0, 7);
256
- for (const file of files) for await (const entry of streamLogFile(file.path, { limit: 1e3 })) {
257
- if (entry.module) modules.add(entry.module);
258
- if (entry.prefix) modules.add(entry.prefix);
259
- }
174
+ for (const file of files) for await (const entry of streamLogFile(file.path, { limit: 1e3 })) if (entry.module) modules.add(entry.module);
260
175
  return Array.from(modules).filter(Boolean).sort();
261
176
  }
262
177
  /**
263
178
  * Get log statistics by level (sampled from recent files)
264
179
  */
265
- async function getLogStats() {
180
+ async function getFileLogStats() {
266
181
  const files = getLogFiles();
267
182
  const byLevel = {
268
183
  trace: 0,
@@ -276,29 +191,63 @@ async function getLogStats() {
276
191
  for (const file of files.slice(0, 7)) for await (const entry of streamLogFile(file.path, { limit: 1e3 })) if (entry.level in byLevel) byLevel[entry.level]++;
277
192
  return { byLevel };
278
193
  }
194
+ function entryMeta(entry) {
195
+ if (!entry.meta || typeof entry.meta !== "object") return void 0;
196
+ return entry.meta;
197
+ }
198
+ function extractErrName(entry) {
199
+ const meta = entryMeta(entry);
200
+ const raw = entry.err ?? meta?.err;
201
+ if (raw && typeof raw === "object" && raw !== null) {
202
+ const name = raw.name;
203
+ if (typeof name === "string" && name.trim()) return name;
204
+ const message = raw.message;
205
+ if (typeof message === "string" && message.trim()) return message.slice(0, 120);
206
+ }
207
+ if (typeof entry.errorMessage === "string" && entry.errorMessage.trim()) return entry.errorMessage.slice(0, 120);
208
+ return entry.message?.slice(0, 120) || "Error";
209
+ }
210
+ function summaryKey(entry) {
211
+ const errName = extractErrName(entry);
212
+ const meta = entryMeta(entry);
213
+ return `${errName}::${typeof entry.phase === "string" ? entry.phase : typeof meta?.phase === "string" ? meta.phase : ""}::${entry.module || ""}`;
214
+ }
279
215
  /**
280
- * Clean old logs (actually deletes files)
216
+ * Aggregate recent error/fatal logs by err name + phase + module.
281
217
  */
282
- function cleanOldLogs(keepDays = 7) {
283
- const cutoff = /* @__PURE__ */ new Date();
284
- cutoff.setDate(cutoff.getDate() - keepDays);
285
- let deleted = 0;
286
- let freedBytes = 0;
287
- const errors = [];
288
- const files = getLogFiles();
289
- for (const file of files) if (new Date(file.modified) < cutoff) try {
290
- const size = file.size;
291
- unlinkSync(file.path);
292
- deleted++;
293
- freedBytes += size;
294
- } catch (err) {
295
- errors.push(`Failed to delete ${file.name}: ${err}`);
218
+ async function getLogErrorSummary(options) {
219
+ const limit = options?.limit ?? 20;
220
+ const groups = /* @__PURE__ */ new Map();
221
+ const entries = await queryLogs({
222
+ levels: ["error", "fatal"],
223
+ from: options?.from,
224
+ to: options?.to,
225
+ limit: 5e3,
226
+ order: "desc"
227
+ });
228
+ for (const entry of entries) {
229
+ const key = summaryKey(entry);
230
+ const parsed = entry;
231
+ const existing = groups.get(key);
232
+ if (existing) {
233
+ existing.count += 1;
234
+ if (entry.timestamp > existing.lastSeen) {
235
+ existing.lastSeen = entry.timestamp;
236
+ existing.sampleMessage = entry.message;
237
+ }
238
+ continue;
239
+ }
240
+ groups.set(key, {
241
+ key,
242
+ errName: extractErrName(parsed),
243
+ phase: typeof parsed.phase === "string" ? parsed.phase : typeof entryMeta(parsed)?.phase === "string" ? String(entryMeta(parsed)?.phase) : void 0,
244
+ module: parsed.module,
245
+ count: 1,
246
+ lastSeen: entry.timestamp,
247
+ sampleMessage: entry.message
248
+ });
296
249
  }
297
- return {
298
- deleted,
299
- freedBytes,
300
- errors
301
- };
250
+ return Array.from(groups.values()).sort((a, b) => b.count - a.count || b.lastSeen.localeCompare(a.lastSeen)).slice(0, limit);
302
251
  }
303
252
  const LOG_LEVELS = [
304
253
  "trace",
@@ -315,6 +264,6 @@ function getLogLevels() {
315
264
  return [...LOG_LEVELS];
316
265
  }
317
266
  //#endregion
318
- export { LOG_DIR, cleanOldLogs, getLogFiles, getLogLevels, getLogLevelsFromData, getLogModules, getLogPath, getLogStats, getLogsByContext, getRecentLogs, queryLogs, searchLogs };
267
+ export { LOG_DIR, getFileLogStats, getLogErrorSummary, getLogFiles, getLogLevels, getLogModules, getLogPath, queryLogs };
319
268
 
320
269
  //# sourceMappingURL=log-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"log-store.js","names":[],"sources":["../../../../src/utils/logger/log-store.ts"],"sourcesContent":["/**\n * Log Store - Enhanced File-based Log Storage\n * \n * Features:\n * - Query logs across multiple files with filtering\n * - Support for compressed (.gz) log files\n * - Pagination and sorting\n * - Statistics and analytics\n * - Safe log cleanup with actual deletion\n */\n\nimport { \n existsSync, \n mkdirSync, \n readdirSync, \n statSync, \n createReadStream,\n unlinkSync,\n} from 'fs';\nimport { readFile } from 'fs/promises';\nimport { join, basename } from 'path';\nimport { createInterface } from 'readline';\nimport { gunzip } from 'zlib';\nimport { promisify } from 'util';\nimport { Readable } from 'stream';\nimport type { LogLevel, LogFileMeta, LogQuery, LogStats, LogEntry } from './types.js';\n\nconst gunzipAsync = promisify(gunzip);\n\n// ============================================\n// Types\n// ============================================\n\ninterface ParsedLogEntry extends LogEntry {\n _source?: string;\n _lineNumber?: number;\n}\n\n// ============================================\n// Configuration\n// ============================================\n\nconst LOG_DIR = process.env.XOPC_LOG_DIR || join(process.env.HOME || '.', '.xopc', 'logs');\n\nfunction ensureLogDir(): void {\n if (!existsSync(LOG_DIR)) {\n mkdirSync(LOG_DIR, { recursive: true });\n }\n}\n\n// ============================================\n// File Management\n// ============================================\n\n/**\n * Get all log files (including compressed)\n */\nexport function getLogFiles(): LogFileMeta[] {\n ensureLogDir();\n\n const files = readdirSync(LOG_DIR)\n .filter(f => f.endsWith('.log') || f.endsWith('.log.gz'))\n .map(f => {\n const filePath = join(LOG_DIR, f);\n const stats = statSync(filePath);\n \n let type: LogFileMeta['type'] = 'app';\n if (f.includes('error')) type = 'error';\n else if (f.includes('audit')) type = 'audit';\n else if (f.includes('access')) type = 'access';\n\n return {\n name: f,\n path: filePath,\n size: stats.size,\n created: stats.birthtime.toISOString(),\n modified: stats.mtime.toISOString(),\n type,\n };\n })\n .sort((a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime());\n\n return files;\n}\n\n/**\n * Get log file path for a specific date and type\n */\nexport function getLogPath(\n date: Date = new Date(), \n type: 'app' | 'error' | 'audit' | 'access' = 'app'\n): string {\n ensureLogDir();\n const dateStr = date.toISOString().split('T')[0];\n return join(LOG_DIR, `${type}-${dateStr}.log`);\n}\n\n/**\n * Get available log files for a date range\n */\nfunction getLogFilesForRange(from: Date, to: Date): LogFileMeta[] {\n const allFiles = getLogFiles();\n \n return allFiles.filter(f => {\n // Extract date from filename (e.g., app-2024-01-01.log)\n const match = f.name.match(/(\\d{4}-\\d{2}-\\d{2})/);\n if (!match) return false;\n \n const fileDate = new Date(match[1]);\n return fileDate >= from && fileDate <= to;\n });\n}\n\n// ============================================\n// Log Parsing\n// ============================================\n\n/**\n * Parse a single log line (JSON format from pino)\n */\nfunction parseLogLine(line: string, source?: string, lineNumber?: number): ParsedLogEntry | null {\n const trimmed = line.trim();\n if (!trimmed) return null;\n\n try {\n // Try JSON format (pino default)\n const parsed = JSON.parse(trimmed);\n \n // Convert pino numeric level to string (10=trace, 20=debug, 30=info, 40=warn, 50=error, 60=fatal)\n const levelNum = typeof parsed.level === 'number' ? parsed.level : 30;\n const levelMap: Record<number, string> = {\n 10: 'trace',\n 20: 'debug',\n 30: 'info',\n 40: 'warn',\n 50: 'error',\n 60: 'fatal',\n };\n\n return {\n timestamp: parsed.time || parsed.timestamp || '',\n level: levelMap[levelNum] || (parsed.level?.toString() || 'info').toLowerCase(),\n message: parsed.msg || parsed.message || '',\n module: parsed.module,\n prefix: parsed.prefix,\n service: parsed.service,\n extension: parsed.extension,\n requestId: parsed.requestId,\n sessionId: parsed.sessionId,\n _source: source,\n _lineNumber: lineNumber,\n ...parsed,\n };\n } catch {\n // Fallback: try to parse pino's text format\n const match = trimmed.match(/^\\[([^\\]]+)\\]\\s+(\\w+):\\s+(.+)$/);\n if (match) {\n return {\n timestamp: match[1],\n level: match[2].toLowerCase() as LogLevel,\n message: match[3],\n _source: source,\n _lineNumber: lineNumber,\n };\n }\n \n // Plain text fallback\n return {\n timestamp: new Date().toISOString(),\n level: 'info',\n message: trimmed,\n _source: source,\n _lineNumber: lineNumber,\n };\n }\n}\n\n// ============================================\n// Streaming\n// ============================================\n\n/**\n * Create a readable stream for a log file (handles .gz files)\n */\nasync function createLogFileStream(filePath: string): Promise<Readable> {\n if (filePath.endsWith('.gz')) {\n const compressed = await readFile(filePath);\n const decompressed = await gunzipAsync(compressed);\n return Readable.from(decompressed.toString('utf-8').split('\\n'));\n }\n \n return createReadStream(filePath, { encoding: 'utf-8' });\n}\n\n/**\n * Stream and filter log entries from a file\n */\nasync function* streamLogFile(\n filePath: string,\n query: LogQuery = {}\n): AsyncGenerator<ParsedLogEntry> {\n if (!existsSync(filePath)) return;\n\n const fileName = basename(filePath);\n let stream: Readable;\n \n try {\n stream = await createLogFileStream(filePath);\n } catch {\n return;\n }\n\n const rl = createInterface({ \n input: stream,\n crlfDelay: Infinity \n });\n\n let lineNumber = 0;\n\n try {\n for await (const line of rl) {\n lineNumber++;\n const entry = parseLogLine(line, fileName, lineNumber);\n if (!entry) continue;\n\n // Apply filters\n if (!matchesQuery(entry, query)) continue;\n\n yield entry;\n }\n } finally {\n rl.close();\n }\n}\n\n/**\n * Check if a log entry matches the query filters\n */\nfunction matchesQuery(entry: ParsedLogEntry, query: LogQuery): boolean {\n // Filter by levels\n if (query.levels?.length && !query.levels.includes(entry.level as LogLevel)) {\n return false;\n }\n\n // Filter by time range\n if (query.from) {\n const fromDate = new Date(query.from);\n const entryDate = new Date(entry.timestamp);\n if (entryDate < fromDate) return false;\n }\n if (query.to) {\n const toDate = new Date(query.to);\n const entryDate = new Date(entry.timestamp);\n if (entryDate > toDate) return false;\n }\n\n // Filter by keyword (search in message and context fields)\n if (query.q) {\n const keyword = query.q.toLowerCase();\n const searchable = [\n entry.message,\n entry.module,\n entry.prefix,\n entry.service,\n entry.extension,\n entry.requestId,\n entry.sessionId,\n ]\n .filter(Boolean)\n .map(String)\n .join(' ')\n .toLowerCase();\n \n if (!searchable.includes(keyword)) return false;\n }\n\n // Filter by specific fields\n if (query.module && entry.module !== query.module) return false;\n if (query.extension && entry.extension !== query.extension) return false;\n if (query.service && entry.service !== query.service) return false;\n if (query.requestId && entry.requestId !== query.requestId) return false;\n if (query.sessionId && entry.sessionId !== query.sessionId) return false;\n\n return true;\n}\n\n// ============================================\n// Query API\n// ============================================\n\n/** Cap matched rows before sort/slice so query stays bounded on huge log dirs. */\nconst QUERY_LOGS_MAX_MATCHED = 25_000;\n\n/**\n * Query logs across multiple files\n */\nexport async function queryLogs(query: LogQuery = {}): Promise<LogEntry[]> {\n ensureLogDir();\n\n const results: ParsedLogEntry[] = [];\n const files = getLogFiles();\n\n // Filter files by date range if specified\n let relevantFiles = files;\n if (query.from || query.to) {\n const fromDate = query.from ? new Date(query.from) : new Date(0);\n const toDate = query.to ? new Date(query.to) : new Date();\n relevantFiles = getLogFilesForRange(fromDate, toDate);\n }\n\n // Collect all matches (files are newest-first; lines in each file are time-asc).\n // Do not stop at `limit` while streaming — that only captured the oldest tail of\n // early files and made \"newest first\" wrong after sort.\n for (const file of relevantFiles) {\n if (results.length >= QUERY_LOGS_MAX_MATCHED) break;\n for await (const entry of streamLogFile(file.path, query)) {\n results.push(entry);\n if (results.length >= QUERY_LOGS_MAX_MATCHED) break;\n }\n }\n\n // Sort by timestamp\n const order = query.order || 'desc';\n results.sort((a, b) => {\n const diff = new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime();\n return order === 'desc' ? diff : -diff;\n });\n\n // Apply offset/limit\n const offset = query.offset || 0;\n const limit = query.limit || 100;\n return results.slice(offset, offset + limit).map(({ _source, _lineNumber, ...rest }) => rest);\n}\n\n/**\n * Get recent logs (convenience method)\n */\nexport async function getRecentLogs(options?: {\n level?: LogLevel;\n limit?: number;\n module?: string;\n}): Promise<LogEntry[]> {\n return queryLogs({\n levels: options?.level ? [options.level] : undefined,\n limit: options?.limit || 50,\n module: options?.module,\n order: 'desc',\n });\n}\n\n/**\n * Search logs by keyword\n */\nexport async function searchLogs(\n keyword: string,\n options?: {\n from?: string;\n to?: string;\n limit?: number;\n }\n): Promise<LogEntry[]> {\n return queryLogs({\n q: keyword,\n ...options,\n limit: options?.limit || 100,\n });\n}\n\n/**\n * Get logs for a specific request/session\n */\nexport async function getLogsByContext(\n contextType: 'requestId' | 'sessionId',\n contextValue: string,\n limit: number = 100\n): Promise<LogEntry[]> {\n return queryLogs({\n [contextType]: contextValue,\n limit,\n order: 'asc',\n });\n}\n\n// ============================================\n// Statistics\n// ============================================\n\n/**\n * Get available log levels from actual log data\n */\nexport async function getLogLevelsFromData(): Promise<LogLevel[]> {\n const levels = new Set<LogLevel>();\n const files = getLogFiles().slice(0, 3); // Check last 3 files\n\n for (const file of files) {\n for await (const entry of streamLogFile(file.path, { limit: 500 })) {\n levels.add(entry.level as LogLevel);\n }\n }\n\n return Array.from(levels).sort();\n}\n\n/**\n * Get available modules from log data\n */\nexport async function getLogModules(): Promise<string[]> {\n const modules = new Set<string>();\n const files = getLogFiles().slice(0, 7);\n\n for (const file of files) {\n for await (const entry of streamLogFile(file.path, { limit: 1000 })) {\n if (entry.module) modules.add(entry.module);\n if (entry.prefix) modules.add(entry.prefix);\n }\n }\n\n return Array.from(modules).filter(Boolean).sort();\n}\n\n/**\n * Get log statistics by level (sampled from recent files)\n */\nexport async function getLogStats(): Promise<LogStats> {\n const files = getLogFiles();\n\n // Count by level (sample from recent files)\n const byLevel: Record<LogLevel, number> = {\n trace: 0,\n debug: 0,\n info: 0,\n warn: 0,\n error: 0,\n fatal: 0,\n silent: 0,\n };\n\n for (const file of files.slice(0, 7)) {\n for await (const entry of streamLogFile(file.path, { limit: 1000 })) {\n if (entry.level in byLevel) {\n byLevel[entry.level as LogLevel]++;\n }\n }\n }\n\n return { byLevel };\n}\n\n// ============================================\n// Cleanup\n// ============================================\n\n/**\n * Clean old logs (actually deletes files)\n */\nexport function cleanOldLogs(keepDays: number = 7): {\n deleted: number;\n freedBytes: number;\n errors: string[];\n} {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - keepDays);\n\n let deleted = 0;\n let freedBytes = 0;\n const errors: string[] = [];\n\n const files = getLogFiles();\n for (const file of files) {\n const fileDate = new Date(file.modified);\n if (fileDate < cutoff) {\n try {\n const size = file.size;\n unlinkSync(file.path);\n deleted++;\n freedBytes += size;\n } catch (err) {\n errors.push(`Failed to delete ${file.name}: ${err}`);\n }\n }\n }\n\n return { deleted, freedBytes, errors };\n}\n\n/**\n * Clean logs by size (keep total under limit)\n */\nfunction _cleanBySize(maxTotalMB: number = 500): {\n deleted: number;\n freedBytes: number;\n errors: string[];\n} {\n const maxBytes = maxTotalMB * 1024 * 1024;\n const files = getLogFiles();\n \n let totalSize = files.reduce((sum, f) => sum + f.size, 0);\n let deleted = 0;\n let freedBytes = 0;\n const errors: string[] = [];\n\n // Delete oldest files until under limit\n for (const file of files.slice().reverse()) {\n if (totalSize <= maxBytes) break;\n\n try {\n unlinkSync(file.path);\n freedBytes += file.size;\n totalSize -= file.size;\n deleted++;\n } catch (err) {\n errors.push(`Failed to delete ${file.name}: ${err}`);\n }\n }\n\n return { deleted, freedBytes, errors };\n}\n\n// ============================================\n// Log Levels\n// ============================================\n\nconst LOG_LEVELS: LogLevel[] = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];\n\n/**\n * Get available log levels\n */\nexport function getLogLevels(): LogLevel[] {\n return [...LOG_LEVELS];\n}\n\n// ============================================\n// Exports\n// ============================================\n\nexport { LOG_DIR };\nexport type { LogEntry, LogQuery, LogFileMeta, LogStats } from './types.js';\n"],"mappings":"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"}
1
+ {"version":3,"file":"log-store.js","names":[],"sources":["../../../../src/utils/logger/log-store.ts"],"sourcesContent":["/**\n * Log Store - Enhanced File-based Log Storage\n * \n * Features:\n * - Query logs across multiple files with filtering\n * - Support for compressed (.gz) log files\n * - Pagination and sorting\n * - Statistics and analytics\n * - Safe log cleanup with actual deletion\n */\n\nimport { \n existsSync, \n mkdirSync, \n readdirSync, \n statSync, \n createReadStream,\n} from 'fs';\nimport { readFile } from 'fs/promises';\nimport { join, basename } from 'path';\nimport { createInterface } from 'readline';\nimport { gunzip } from 'zlib';\nimport { promisify } from 'util';\nimport { Readable } from 'stream';\nimport type { LogLevel, LogFileMeta, LogQuery, LogStats, LogEntry } from './types.js';\nimport { logEntrySearchText, pinoRecordToLogEntry } from './pino-record.js';\n\nconst gunzipAsync = promisify(gunzip);\n\n// ============================================\n// Types\n// ============================================\n\ninterface ParsedLogEntry extends LogEntry {\n _source?: string;\n _lineNumber?: number;\n}\n\n// ============================================\n// Configuration\n// ============================================\n\nconst LOG_DIR = process.env.XOPC_LOG_DIR || join(process.env.HOME || '.', '.xopc', 'logs');\n\nfunction ensureLogDir(): void {\n if (!existsSync(LOG_DIR)) {\n mkdirSync(LOG_DIR, { recursive: true });\n }\n}\n\n// ============================================\n// File Management\n// ============================================\n\n/**\n * Get all log files (including compressed)\n */\nexport function getLogFiles(): LogFileMeta[] {\n ensureLogDir();\n\n const files = readdirSync(LOG_DIR)\n .filter(f => f.endsWith('.log') || f.endsWith('.log.gz'))\n .map(f => {\n const filePath = join(LOG_DIR, f);\n const stats = statSync(filePath);\n \n let type: LogFileMeta['type'] = 'app';\n if (f.includes('error')) type = 'error';\n else if (f.includes('audit')) type = 'audit';\n else if (f.includes('access')) type = 'access';\n\n return {\n name: f,\n path: filePath,\n size: stats.size,\n created: stats.birthtime.toISOString(),\n modified: stats.mtime.toISOString(),\n type,\n };\n })\n .sort((a, b) => new Date(b.modified).getTime() - new Date(a.modified).getTime());\n\n return files;\n}\n\n/**\n * Get log file path for a specific date and type\n */\nexport function getLogPath(\n date: Date = new Date(), \n type: 'app' | 'error' | 'audit' | 'access' = 'app'\n): string {\n ensureLogDir();\n const dateStr = date.toISOString().split('T')[0];\n return join(LOG_DIR, `${type}-${dateStr}.log`);\n}\n\n/**\n * Get available log files for a date range\n */\nfunction getLogFilesForRange(from: Date, to: Date): LogFileMeta[] {\n const allFiles = getLogFiles();\n \n return allFiles.filter(f => {\n // Extract date from filename (e.g., app-2024-01-01.log)\n const match = f.name.match(/(\\d{4}-\\d{2}-\\d{2})/);\n if (!match) return false;\n \n const fileDate = new Date(match[1]);\n return fileDate >= from && fileDate <= to;\n });\n}\n\n// ============================================\n// Log Parsing\n// ============================================\n\n/**\n * Parse a single log line (JSON format from pino)\n */\nfunction parseLogLine(line: string, source?: string, lineNumber?: number): ParsedLogEntry | null {\n const trimmed = line.trim();\n if (!trimmed) return null;\n\n try {\n const parsed = JSON.parse(trimmed) as Record<string, unknown>;\n const entry = pinoRecordToLogEntry(parsed) as ParsedLogEntry;\n entry._source = source;\n entry._lineNumber = lineNumber;\n return entry;\n } catch {\n return null;\n }\n}\n\n// ============================================\n// Streaming\n// ============================================\n\n/**\n * Create a readable stream for a log file (handles .gz files)\n */\nasync function createLogFileStream(filePath: string): Promise<Readable> {\n if (filePath.endsWith('.gz')) {\n const compressed = await readFile(filePath);\n const decompressed = await gunzipAsync(compressed);\n return Readable.from(decompressed.toString('utf-8').split('\\n'));\n }\n \n return createReadStream(filePath, { encoding: 'utf-8' });\n}\n\n/**\n * Stream and filter log entries from a file\n */\nasync function* streamLogFile(\n filePath: string,\n query: LogQuery = {}\n): AsyncGenerator<ParsedLogEntry> {\n if (!existsSync(filePath)) return;\n\n const fileName = basename(filePath);\n let stream: Readable;\n \n try {\n stream = await createLogFileStream(filePath);\n } catch {\n return;\n }\n\n const rl = createInterface({ \n input: stream,\n crlfDelay: Infinity \n });\n\n let lineNumber = 0;\n\n try {\n for await (const line of rl) {\n lineNumber++;\n const entry = parseLogLine(line, fileName, lineNumber);\n if (!entry) continue;\n\n // Apply filters\n if (!matchesQuery(entry, query)) continue;\n\n yield entry;\n }\n } finally {\n rl.close();\n }\n}\n\n/**\n * Check if a log entry matches the query filters\n */\nfunction matchesQuery(entry: ParsedLogEntry, query: LogQuery): boolean {\n // Filter by levels\n if (query.levels?.length && !query.levels.includes(entry.level as LogLevel)) {\n return false;\n }\n\n // Filter by time range\n if (query.from) {\n const fromDate = new Date(query.from);\n const entryDate = new Date(entry.timestamp);\n if (entryDate < fromDate) return false;\n }\n if (query.to) {\n const toDate = new Date(query.to);\n const entryDate = new Date(entry.timestamp);\n if (entryDate > toDate) return false;\n }\n\n // Filter by keyword (search message, module, phase, err, structured fields)\n if (query.q) {\n const keyword = query.q.toLowerCase();\n if (!logEntrySearchText(entry).includes(keyword)) return false;\n }\n\n if (query.module && entry.module !== query.module) return false;\n if (query.extension && entry.extension !== query.extension) return false;\n if (query.service && entry.service !== query.service) return false;\n if (query.requestId && entry.requestId !== query.requestId) return false;\n if (query.sessionId && entry.sessionId !== query.sessionId) return false;\n\n return true;\n}\n\n// ============================================\n// Query API\n// ============================================\n\n/** Cap matched rows before sort/slice so query stays bounded on huge log dirs. */\nconst QUERY_LOGS_MAX_MATCHED = 25_000;\n\n/**\n * Query logs across multiple files\n */\nexport async function queryLogs(query: LogQuery = {}): Promise<LogEntry[]> {\n ensureLogDir();\n\n const results: ParsedLogEntry[] = [];\n const files = getLogFiles();\n\n // Filter files by date range if specified\n let relevantFiles = files;\n if (query.from || query.to) {\n const fromDate = query.from ? new Date(query.from) : new Date(0);\n const toDate = query.to ? new Date(query.to) : new Date();\n relevantFiles = getLogFilesForRange(fromDate, toDate);\n }\n\n // Collect all matches (files are newest-first; lines in each file are time-asc).\n // Do not stop at `limit` while streaming — that only captured the oldest tail of\n // early files and made \"newest first\" wrong after sort.\n for (const file of relevantFiles) {\n if (results.length >= QUERY_LOGS_MAX_MATCHED) break;\n for await (const entry of streamLogFile(file.path, query)) {\n results.push(entry);\n if (results.length >= QUERY_LOGS_MAX_MATCHED) break;\n }\n }\n\n // Sort by timestamp\n const order = query.order || 'desc';\n results.sort((a, b) => {\n const diff = new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime();\n return order === 'desc' ? diff : -diff;\n });\n\n // Apply offset/limit\n const offset = query.offset || 0;\n const limit = query.limit || 100;\n return results.slice(offset, offset + limit).map(({ _source, _lineNumber, ...rest }) => rest);\n}\n\n// ============================================\n// Statistics\n// ============================================\nexport async function getLogModules(): Promise<string[]> {\n const modules = new Set<string>();\n const files = getLogFiles().slice(0, 7);\n\n for (const file of files) {\n for await (const entry of streamLogFile(file.path, { limit: 1000 })) {\n if (entry.module) modules.add(entry.module);\n }\n }\n\n return Array.from(modules).filter(Boolean).sort();\n}\n\n/**\n * Get log statistics by level (sampled from recent files)\n */\nexport async function getFileLogStats(): Promise<LogStats> {\n const files = getLogFiles();\n\n // Count by level (sample from recent files)\n const byLevel: Record<LogLevel, number> = {\n trace: 0,\n debug: 0,\n info: 0,\n warn: 0,\n error: 0,\n fatal: 0,\n silent: 0,\n };\n\n for (const file of files.slice(0, 7)) {\n for await (const entry of streamLogFile(file.path, { limit: 1000 })) {\n if (entry.level in byLevel) {\n byLevel[entry.level as LogLevel]++;\n }\n }\n }\n\n return { byLevel };\n}\n\n// ============================================\n// Error aggregation\n// ============================================\n\nexport interface LogErrorSummaryItem {\n key: string;\n errName: string;\n phase?: string;\n module?: string;\n count: number;\n lastSeen: string;\n sampleMessage: string;\n}\n\nfunction entryMeta(entry: ParsedLogEntry): Record<string, unknown> | undefined {\n if (!entry.meta || typeof entry.meta !== 'object') return undefined;\n return entry.meta as Record<string, unknown>;\n}\n\nfunction extractErrName(entry: ParsedLogEntry): string {\n const meta = entryMeta(entry);\n const raw = entry.err ?? meta?.err;\n if (raw && typeof raw === 'object' && raw !== null) {\n const name = (raw as Record<string, unknown>).name;\n if (typeof name === 'string' && name.trim()) return name;\n const message = (raw as Record<string, unknown>).message;\n if (typeof message === 'string' && message.trim()) return message.slice(0, 120);\n }\n if (typeof entry.errorMessage === 'string' && entry.errorMessage.trim()) {\n return entry.errorMessage.slice(0, 120);\n }\n return entry.message?.slice(0, 120) || 'Error';\n}\n\nfunction summaryKey(entry: ParsedLogEntry): string {\n const errName = extractErrName(entry);\n const meta = entryMeta(entry);\n const phase =\n typeof entry.phase === 'string'\n ? entry.phase\n : typeof meta?.phase === 'string'\n ? meta.phase\n : '';\n const module = entry.module || '';\n return `${errName}::${phase}::${module}`;\n}\n\n/**\n * Aggregate recent error/fatal logs by err name + phase + module.\n */\nexport async function getLogErrorSummary(options?: {\n from?: string;\n to?: string;\n limit?: number;\n}): Promise<LogErrorSummaryItem[]> {\n const limit = options?.limit ?? 20;\n const groups = new Map<string, LogErrorSummaryItem>();\n\n const entries = await queryLogs({\n levels: ['error', 'fatal'],\n from: options?.from,\n to: options?.to,\n limit: 5000,\n order: 'desc',\n });\n\n for (const entry of entries) {\n const key = summaryKey(entry as ParsedLogEntry);\n const parsed = entry as ParsedLogEntry;\n const existing = groups.get(key);\n if (existing) {\n existing.count += 1;\n if (entry.timestamp > existing.lastSeen) {\n existing.lastSeen = entry.timestamp;\n existing.sampleMessage = entry.message;\n }\n continue;\n }\n groups.set(key, {\n key,\n errName: extractErrName(parsed),\n phase:\n typeof parsed.phase === 'string'\n ? parsed.phase\n : typeof entryMeta(parsed)?.phase === 'string'\n ? String(entryMeta(parsed)?.phase)\n : undefined,\n module: parsed.module,\n count: 1,\n lastSeen: entry.timestamp,\n sampleMessage: entry.message,\n });\n }\n\n return Array.from(groups.values())\n .sort((a, b) => b.count - a.count || b.lastSeen.localeCompare(a.lastSeen))\n .slice(0, limit);\n}\n\n// ============================================\n// Log Levels\n// ============================================\n\nconst LOG_LEVELS: LogLevel[] = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];\n\n/**\n * Get available log levels\n */\nexport function getLogLevels(): LogLevel[] {\n return [...LOG_LEVELS];\n}\n\n// ============================================\n// Exports\n// ============================================\n\nexport { LOG_DIR };\nexport type { LogEntry, LogQuery, LogFileMeta, LogStats } from './types.js';\n"],"mappings":"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"}