@xopcai/xopc 0.0.101 → 0.0.103

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 (323) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  5. package/dist/extensions/feishu/src/transport/webhook/monitor.js +2 -2
  6. package/dist/extensions/feishu/src/transport/webhook/monitor.js.map +1 -1
  7. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  8. package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
  9. package/dist/extensions/telegram/src/inbound-processor.js +1 -1
  10. package/dist/extensions/telegram/src/plugin.js +1 -1
  11. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  12. package/dist/extensions/telegram/src/send-options.js +8 -5
  13. package/dist/extensions/telegram/src/send-options.js.map +1 -1
  14. package/dist/extensions/telegram/src/update-offset-store.js +1 -1
  15. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  16. package/dist/extensions/telegram/xopc.extension.json +1 -1
  17. package/dist/extensions/weixin/src/api/api.js +2 -2
  18. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  19. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  20. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  21. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  22. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  23. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  24. package/dist/extensions/weixin/src/plugin.js +1 -1
  25. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  26. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  27. package/dist/gateway/static/root/assets/{agents-u8cmUfGQ.js → agents-BwXkia_W.js} +1 -1
  28. package/dist/gateway/static/root/assets/{apps-page-DF8m9cUE.js → apps-page-C5RmwmTT.js} +1 -1
  29. package/dist/gateway/static/root/assets/{channels-settings-BM3doRvi.js → channels-settings-tlOTdaXw.js} +1 -1
  30. package/dist/gateway/static/root/assets/{channels-status-swr-ah4zWEIP.js → channels-status-swr-D4XjqwqC.js} +1 -1
  31. package/dist/gateway/static/root/assets/{cron-api-DgMuL_2b.js → cron-api-DcmfGuj0.js} +1 -1
  32. package/dist/gateway/static/root/assets/{cron-page-COfUPKfq.js → cron-page-CijJ4G6F.js} +1 -1
  33. package/dist/gateway/static/root/assets/{dist-Dzy3Q0ZH.js → dist-CWm8hTXZ.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-debug-page-kyxxefKh.js → extension-debug-page-BzYgTkS9.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-page-BVbCBHoI.js → extension-page-BmTZH6gL.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-settings-page-t1lb2A7v.js → extension-settings-page-CyJk_G64.js} +1 -1
  37. package/dist/gateway/static/root/assets/{fetch-drJUxxKP.js → fetch-CMoWY2Si.js} +1 -1
  38. package/dist/gateway/static/root/assets/{field-primitives-6Vo1Yga4.js → field-primitives-C4GpxsDo.js} +1 -1
  39. package/dist/gateway/static/root/assets/{heartbeat-config-api-BF3psu4O.js → heartbeat-config-api-CLD0Gpi3.js} +1 -1
  40. package/dist/gateway/static/root/assets/index-0HmunJW9.js +4845 -0
  41. package/dist/gateway/static/root/assets/index-Bk75Phrd.css +1 -0
  42. package/dist/gateway/static/root/assets/{logs-page-BTVPXcHV.js → logs-page-BjdQjHwk.js} +1 -1
  43. package/dist/gateway/static/root/assets/{note-detail-page-DqSAg_5Z.js → note-detail-page-8Er4197b.js} +2 -2
  44. package/dist/gateway/static/root/assets/{note-time-FSOjchic.js → note-time-CF3vf1jm.js} +1 -1
  45. package/dist/gateway/static/root/assets/{notes-page-DkRX7BE2.js → notes-page-BBnTh0uI.js} +1 -1
  46. package/dist/gateway/static/root/assets/{sessions-page-Khdw35Zk.js → sessions-page-B0riYK7j.js} +1 -1
  47. package/dist/gateway/static/root/assets/{settings-advanced-gate-DspC8oEm.js → settings-advanced-gate-DiP_WHu_.js} +1 -1
  48. package/dist/gateway/static/root/assets/{settings-form-section-DuxvUuur.js → settings-form-section-C7qA7y0J.js} +1 -1
  49. package/dist/gateway/static/root/assets/{settings-page-DN8JBZ8F.js → settings-page-1ZPhcCZ9.js} +2 -2
  50. package/dist/gateway/static/root/assets/share-preview-page-Tvr5Mtq5.js +2 -0
  51. package/dist/gateway/static/root/assets/{skills-page-ByYT0fXZ.js → skills-page-BQ1hllKD.js} +1 -1
  52. package/dist/gateway/static/root/assets/{theme-store-B6KXPHgK.js → theme-store-HTvJlFLL.js} +1 -1
  53. package/dist/gateway/static/root/assets/url-F3_D_6zZ.js +3 -0
  54. package/dist/gateway/static/root/assets/{utils-DK_1H47k.js → utils-CPr3FBh2.js} +1 -1
  55. package/dist/gateway/static/root/assets/{voice-api-key-field-BYN2EIMs.js → voice-api-key-field-BkbDl6dH.js} +1 -1
  56. package/dist/gateway/static/root/assets/{workflow-page.utils-Bi19YNTr.js → workflow-page.utils-CeBkAjP7.js} +1 -1
  57. package/dist/gateway/static/root/assets/{workflows-page-DP57FEKW.js → workflows-page-D059ysoF.js} +1 -1
  58. package/dist/gateway/static/root/index.html +5 -5
  59. package/dist/package.js +1 -1
  60. package/dist/src/agent/agent-manager.js +7 -7
  61. package/dist/src/agent/agent-scope.js +1 -1
  62. package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
  63. package/dist/src/agent/context/workspace-seed.js +2 -2
  64. package/dist/src/agent/context/workspace-state.js +1 -1
  65. package/dist/src/agent/goals/goal-run-store.js +4 -4
  66. package/dist/src/agent/goals/persistent-goal-service.js +1 -1
  67. package/dist/src/agent/goals/post-turn.js +2 -2
  68. package/dist/src/agent/image/load-image-media.js +2 -2
  69. package/dist/src/agent/inbound/attachment-pipeline.js +2 -2
  70. package/dist/src/agent/inbound/attachment-pipeline.js.map +1 -1
  71. package/dist/src/agent/ipc/bus.js +1 -1
  72. package/dist/src/agent/ipc/inbox.js +2 -2
  73. package/dist/src/agent/ipc/socket.js +1 -1
  74. package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
  75. package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
  76. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  77. package/dist/src/agent/mcp/mcp-transport.js +1 -1
  78. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  79. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  80. package/dist/src/agent/memory/dreaming/events.js +1 -1
  81. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  82. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  83. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  84. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  85. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  86. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  87. package/dist/src/agent/memory/memory-flush.js +1 -1
  88. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  89. package/dist/src/agent/models/manager.js +1 -1
  90. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  91. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  92. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  93. package/dist/src/agent/sandbox/path-policy.js +2 -2
  94. package/dist/src/agent/service.js +4 -4
  95. package/dist/src/agent/session/session-inspector.js +1 -1
  96. package/dist/src/agent/skills/config.js +1 -1
  97. package/dist/src/agent/skills/hub-hash.js +2 -2
  98. package/dist/src/agent/skills/hub-lock.js +1 -1
  99. package/dist/src/agent/skills/hub-pull.js +2 -2
  100. package/dist/src/agent/skills/index.js +1 -1
  101. package/dist/src/agent/skills/managed-store.js +1 -1
  102. package/dist/src/agent/skills/scanner.js +1 -1
  103. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  104. package/dist/src/agent/skills/skill-manager.js +1 -1
  105. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  106. package/dist/src/agent/tools/factory.js +1 -1
  107. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  108. package/dist/src/agent/tools/send-media.js +2 -3
  109. package/dist/src/agent/tools/send-media.js.map +1 -1
  110. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  111. package/dist/src/agent/tools/workflow-tool.js +1 -1
  112. package/dist/src/agent/tools/write.js +1 -1
  113. package/dist/src/agent/workflow/catalog.js +1 -1
  114. package/dist/src/auth/credentials.d.ts +7 -0
  115. package/dist/src/auth/credentials.js +37 -4
  116. package/dist/src/auth/credentials.js.map +1 -1
  117. package/dist/src/auth/index.d.ts +1 -1
  118. package/dist/src/auth/index.js.map +1 -1
  119. package/dist/src/auth/oauth/github-copilot.d.ts +1 -1
  120. package/dist/src/auth/oauth/google-antigravity.d.ts +1 -3
  121. package/dist/src/auth/oauth/google-antigravity.js +1 -1
  122. package/dist/src/auth/oauth/google-gemini-cli.d.ts +1 -3
  123. package/dist/src/auth/oauth/google-gemini-cli.js +1 -1
  124. package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-antigravity.js +3 -5
  125. package/dist/src/auth/oauth/google-oauth/google-antigravity.js.map +1 -0
  126. package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-gemini-cli.js +4 -5
  127. package/dist/src/auth/oauth/google-oauth/google-gemini-cli.js.map +1 -0
  128. package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/oauth-page.js +12 -4
  129. package/dist/src/auth/oauth/google-oauth/oauth-page.js.map +1 -0
  130. package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/pkce.d.ts +1 -1
  131. package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/pkce.js +2 -2
  132. package/dist/src/auth/oauth/google-oauth/pkce.js.map +1 -0
  133. package/dist/src/auth/oauth/index.js +2 -2
  134. package/dist/src/auth/oauth/kimi-coding.d.ts +1 -1
  135. package/dist/src/auth/oauth/kimi-coding.js +1 -1
  136. package/dist/src/auth/oauth/kimi-coding.js.map +1 -1
  137. package/dist/src/auth/oauth/minimax-cn.js +1 -1
  138. package/dist/src/auth/oauth/minimax-cn.js.map +1 -1
  139. package/dist/src/auth/oauth/minimax.js +1 -1
  140. package/dist/src/auth/oauth/minimax.js.map +1 -1
  141. package/dist/src/auth/oauth/openai-codex.d.ts +7 -2
  142. package/dist/src/auth/oauth/openai-codex.js +318 -1
  143. package/dist/src/auth/oauth/openai-codex.js.map +1 -0
  144. package/dist/src/auth/profiles/store.js +4 -3
  145. package/dist/src/auth/profiles/store.js.map +1 -1
  146. package/dist/src/auth/sync-provider-auth.js +1 -1
  147. package/dist/src/browser/cache-dir-policy.js +1 -1
  148. package/dist/src/browser/cdp-local-launcher.js +2 -2
  149. package/dist/src/browser/providers/browser-ext-install.js +3 -3
  150. package/dist/src/browser/providers/cloakbrowser.js +4 -4
  151. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  152. package/dist/src/browser/stealth.js +1 -1
  153. package/dist/src/channels/attachments/attachment-classifiers.d.ts +1 -0
  154. package/dist/src/channels/attachments/attachment-classifiers.js +13 -2
  155. package/dist/src/channels/attachments/attachment-classifiers.js.map +1 -1
  156. package/dist/src/channels/outbound/persist-store.js +1 -1
  157. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  158. package/dist/src/channels/pairing/pairing-store.js +2 -2
  159. package/dist/src/chat-commands/agent-edit.js +2 -2
  160. package/dist/src/chat-commands/builtins/config.js +2 -2
  161. package/dist/src/chat-commands/builtins/model.js +2 -2
  162. package/dist/src/chat-commands/builtins/model.js.map +1 -1
  163. package/dist/src/chat-commands/context.js +1 -1
  164. package/dist/src/cli/command-manifest.js +1 -1
  165. package/dist/src/cli/command-manifest.js.map +1 -1
  166. package/dist/src/cli/commands/auth.js +39 -51
  167. package/dist/src/cli/commands/auth.js.map +1 -1
  168. package/dist/src/cli/commands/config.js +1 -1
  169. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  170. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  171. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  172. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  173. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  174. package/dist/src/cli/commands/extension-dev.js +1 -1
  175. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  176. package/dist/src/cli/commands/extension-pack.js +1 -1
  177. package/dist/src/cli/commands/gateway/logs.js +1 -1
  178. package/dist/src/cli/commands/image.js +1 -1
  179. package/dist/src/cli/commands/init.js +3 -3
  180. package/dist/src/cli/commands/models.js +189 -54
  181. package/dist/src/cli/commands/models.js.map +1 -1
  182. package/dist/src/cli/commands/onboard/model.d.ts +1 -4
  183. package/dist/src/cli/commands/onboard/model.js +253 -183
  184. package/dist/src/cli/commands/onboard/model.js.map +1 -1
  185. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  186. package/dist/src/cli/utils/oauth-login.d.ts +17 -0
  187. package/dist/src/cli/utils/oauth-login.js +93 -0
  188. package/dist/src/cli/utils/oauth-login.js.map +1 -0
  189. package/dist/src/cli/utils/oauth-providers.js +2 -2
  190. package/dist/src/commands/agents.config.js +1 -1
  191. package/dist/src/config/agent-profile.js +1 -1
  192. package/dist/src/config/gateway-bind.js +1 -1
  193. package/dist/src/config/index.js +5 -5
  194. package/dist/src/config/loader.js +2 -2
  195. package/dist/src/config/models-json.js +2 -2
  196. package/dist/src/config/paths-state.js +1 -1
  197. package/dist/src/config/profile.js +2 -2
  198. package/dist/src/config/workspace-path.js +1 -1
  199. package/dist/src/cron/executor.js +2 -2
  200. package/dist/src/cron/persistence.js +1 -1
  201. package/dist/src/daemon/constants.js +1 -1
  202. package/dist/src/daemon/install-plan.js +2 -2
  203. package/dist/src/daemon/launchd.js +2 -2
  204. package/dist/src/daemon/schtasks.js +2 -2
  205. package/dist/src/daemon/systemd.js +2 -2
  206. package/dist/src/extensions/bundle-mcp.js +1 -1
  207. package/dist/src/extensions/discover-extensions.js +1 -1
  208. package/dist/src/extensions/health.js +1 -1
  209. package/dist/src/extensions/loader.js +1 -1
  210. package/dist/src/extensions/lockfile.js +2 -2
  211. package/dist/src/extensions/update.js +1 -1
  212. package/dist/src/gateway/agents-admin.js +3 -3
  213. package/dist/src/gateway/file-path-classifier.js +2 -2
  214. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  215. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  216. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  217. package/dist/src/gateway/hono/oauth-async.js +3 -3
  218. package/dist/src/gateway/hono/oauth.js +3 -3
  219. package/dist/src/gateway/hono/routes/agents.js +1 -1
  220. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  221. package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
  222. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  223. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  224. package/dist/src/gateway/hono/routes/models.js +26 -6
  225. package/dist/src/gateway/hono/routes/models.js.map +1 -1
  226. package/dist/src/gateway/hono/routes/notes.js +9 -22
  227. package/dist/src/gateway/hono/routes/notes.js.map +1 -1
  228. package/dist/src/gateway/hono/routes/shares.js +1 -1
  229. package/dist/src/gateway/hono/routes/workspace.js +2 -2
  230. package/dist/src/gateway/lock.js +3 -3
  231. package/dist/src/gateway/ports.js +1 -1
  232. package/dist/src/gateway/service/agent-runner.js +2 -2
  233. package/dist/src/gateway/service/marketplace-service.js +2 -2
  234. package/dist/src/gateway/service.js +1 -1
  235. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  236. package/dist/src/infra/brew.js +1 -1
  237. package/dist/src/infra/package-json.js +1 -1
  238. package/dist/src/infra/package-update-steps.js +1 -1
  239. package/dist/src/infra/path-env.js +2 -2
  240. package/dist/src/infra/restart.js +2 -2
  241. package/dist/src/infra/stable-node-path.js +1 -1
  242. package/dist/src/infra/update-check.js +1 -1
  243. package/dist/src/infra/update-global.js +1 -1
  244. package/dist/src/infra/update-lock.js +3 -3
  245. package/dist/src/infra/update-runner.js +1 -1
  246. package/dist/src/infra/update-startup.js +2 -2
  247. package/dist/src/infra/write-file-atomic.js +2 -2
  248. package/dist/src/media/store.js +4 -1
  249. package/dist/src/media/store.js.map +1 -1
  250. package/dist/src/notes/note-attachment-sync.d.ts +2 -3
  251. package/dist/src/notes/note-attachment-sync.js +2 -27
  252. package/dist/src/notes/note-attachment-sync.js.map +1 -1
  253. package/dist/src/notes/note-index-meta.d.ts +6 -2
  254. package/dist/src/notes/note-index-meta.js +11 -16
  255. package/dist/src/notes/note-index-meta.js.map +1 -1
  256. package/dist/src/notes/note-markdown.d.ts +61 -0
  257. package/dist/src/notes/note-markdown.js +177 -0
  258. package/dist/src/notes/note-markdown.js.map +1 -0
  259. package/dist/src/notes/service.d.ts +9 -7
  260. package/dist/src/notes/service.js +163 -312
  261. package/dist/src/notes/service.js.map +1 -1
  262. package/dist/src/notes/store.js +4 -5
  263. package/dist/src/notes/store.js.map +1 -1
  264. package/dist/src/notes/types.d.ts +29 -58
  265. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  266. package/dist/src/providers/index.d.ts +3 -3
  267. package/dist/src/providers/index.js +25 -17
  268. package/dist/src/providers/index.js.map +1 -1
  269. package/dist/src/providers/model-registry.js +1 -1
  270. package/dist/src/providers/presentation.d.ts +34 -0
  271. package/dist/src/providers/presentation.js +162 -0
  272. package/dist/src/providers/presentation.js.map +1 -0
  273. package/dist/src/session/init-session-turn.js +2 -2
  274. package/dist/src/session/resolve-session.js +3 -3
  275. package/dist/src/session/session-title.js +2 -2
  276. package/dist/src/session/store.js +2 -2
  277. package/dist/src/share/share-auto.js +2 -2
  278. package/dist/src/share/share-store.js +3 -3
  279. package/dist/src/share/share-thumbnail.js +2 -2
  280. package/dist/src/share/share-zip.js +1 -1
  281. package/dist/src/share/site-share-store.js +3 -3
  282. package/dist/src/share/site-static-serve.js +1 -1
  283. package/dist/src/storage/sqlite/connection.js +2 -2
  284. package/dist/src/storage/sqlite/memory-index-repository.js +2 -2
  285. package/dist/src/storage/sqlite/migrations/003_add_note_markdown_meta.sql +4 -0
  286. package/dist/src/storage/sqlite/migrations/discover.js +1 -1
  287. package/dist/src/storage/sqlite/migrations/runner.d.ts +2 -2
  288. package/dist/src/storage/sqlite/migrations/runner.js +5 -5
  289. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  290. package/dist/src/storage/sqlite/migrations/runner.ts +2 -2
  291. package/dist/src/storage/sqlite/notes-repository.js +18 -6
  292. package/dist/src/storage/sqlite/notes-repository.js.map +1 -1
  293. package/dist/src/storage/sqlite/schema.js +4 -4
  294. package/dist/src/storage/sqlite/schema.sql +5 -1
  295. package/dist/src/tui/clipboard-image.js +3 -3
  296. package/dist/src/tui/theme-manager.js +1 -1
  297. package/dist/src/tui/tui-keybindings-file.js +1 -1
  298. package/dist/src/tui/tui-scoped-models.js +2 -2
  299. package/dist/src/tui/tui-settings.js +1 -1
  300. package/dist/src/tui/tui.js +3 -3
  301. package/dist/src/tunnel/frpc-binary.js +3 -3
  302. package/dist/src/tunnel/frpc-config.js +1 -1
  303. package/dist/src/tunnel/frpc-extract.js +1 -1
  304. package/dist/src/tunnel/tunnel-state.js +1 -1
  305. package/dist/src/utils/logger/audit.js +1 -1
  306. package/dist/src/utils/logger/log-store.js +1 -1
  307. package/dist/src/utils/logger/rotation.js +1 -1
  308. package/dist/src/voice/tts/audio.js +1 -1
  309. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  310. package/dist/src/workflows/store/event-store.js +1 -1
  311. package/dist/src/workflows/store/run-store.js +1 -1
  312. package/package.json +1 -1
  313. package/dist/gateway/static/root/assets/index-DjNDHzwG.css +0 -1
  314. package/dist/gateway/static/root/assets/index-WAyKAilR.js +0 -4840
  315. package/dist/gateway/static/root/assets/share-preview-page-UNAcbiMb.js +0 -2
  316. package/dist/gateway/static/root/assets/url-q28QhI7l.js +0 -3
  317. package/dist/src/auth/oauth/vendor-pi-google/google-antigravity.js.map +0 -1
  318. package/dist/src/auth/oauth/vendor-pi-google/google-gemini-cli.js.map +0 -1
  319. package/dist/src/auth/oauth/vendor-pi-google/oauth-page.js.map +0 -1
  320. package/dist/src/auth/oauth/vendor-pi-google/pkce.js.map +0 -1
  321. /package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-antigravity.d.ts +0 -0
  322. /package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-gemini-cli.d.ts +0 -0
  323. /package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/oauth-page.d.ts +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","names":[],"sources":["../../../src/notes/service.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { complete, type UserMessage } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../config/schema.js';\nimport { getDefaultModelSync, resolveModel } from '../providers/index.js';\nimport { createLogger } from '../utils/logger.js';\nimport { buildNoteAttachmentRef, attachmentIdFromTarget } from './attachment-ref.js';\nimport { partitionAttachmentsByReference } from './note-attachment-sync.js';\nimport { NotesStore } from './store.js';\nimport type {\n CaptureSource,\n CreateNoteParams,\n Note,\n NoteAiPatch,\n NoteAttachment,\n NoteBlock,\n NoteCatalysisAction,\n NoteCatalysisMeta,\n NoteCatalysisReport,\n NoteIndexEntry,\n NoteKind,\n NoteSnapshot,\n NoteSnapshotEntry,\n NotesListQuery,\n SnapshotTrigger,\n} from './types.js';\n\nconst log = createLogger('NotesService');\n\nfunction inferKind(\n text?: string,\n hasAttachments?: boolean,\n attachments?: NoteAttachment[],\n): NoteKind {\n if (hasAttachments && attachments?.length && attachments.every((item) => item.type === 'audio')) {\n return 'voice';\n }\n if (hasAttachments) return 'media';\n if (!text) return 'thought';\n const lower = text.toLowerCase();\n if (/^(todo|task|remind|buy|call|email|meet|finish|submit|send)\\b/i.test(lower) ||\n /\\b(明天|今天|记得|别忘|待办|提醒)\\b/.test(text)) {\n return 'todo';\n }\n if (/^https?:\\/\\//.test(text.trim())) return 'bookmark';\n return 'thought';\n}\n\nfunction deriveDefaultTitle(text?: string): string | undefined {\n const normalizedText = text?.trim().replace(/\\s+/g, ' ');\n if (!normalizedText) return undefined;\n return Array.from(normalizedText).slice(0, 10).join('');\n}\n\nfunction createBlockId(): string {\n return `block_${Date.now()}_${randomUUID().slice(0, 8)}`;\n}\n\nconst IMAGE_MARKDOWN = /^!\\[([^\\]]*)\\]\\(([^)]+)\\)$/;\n\nfunction noteTextToBlocks(text?: string, noteId?: string): NoteBlock[] | undefined {\n if (!text?.trim()) return undefined;\n const now = Date.now();\n return text.split(/\\n{2,}/).map((part) => {\n const trimmed = part.trim();\n if (noteId) {\n const imageMatch = trimmed.match(IMAGE_MARKDOWN);\n if (imageMatch) {\n const attachmentId = attachmentIdFromTarget(imageMatch[2], noteId);\n if (attachmentId) {\n return {\n id: createBlockId(),\n type: 'image' as const,\n attachmentId,\n alt: imageMatch[1] || undefined,\n createdAt: now,\n updatedAt: now,\n };\n }\n }\n }\n return {\n id: createBlockId(),\n type: 'paragraph' as const,\n text: trimmed,\n createdAt: now,\n updatedAt: now,\n };\n });\n}\n\nfunction blocksToPlainText(blocks?: NoteBlock[], noteId?: string): string | undefined {\n if (!blocks?.length) return undefined;\n return blocks\n .map((block) => {\n if (block.type === 'divider') return '---';\n if (block.type === 'todo') return `${block.checked ? '[x]' : '[ ]'} ${block.text}`;\n if (block.type === 'image') {\n if (noteId) {\n return `![${block.alt ?? ''}](${buildNoteAttachmentRef(noteId, block.attachmentId)})`;\n }\n return block.alt ?? '';\n }\n return block.text;\n })\n .filter((text) => text.trim().length > 0)\n .join('\\n\\n');\n}\n\nfunction createAiOrganizedBlocks(blocks: NoteBlock[], instruction: string): NoteBlock[] {\n const now = Date.now();\n const plainText = blocksToPlainText(blocks) || '';\n const lines = plainText\n .split(/\\n+/)\n .map((line) => line.trim())\n .filter(Boolean);\n const wantsTodos = /待办|todo|task|行动|提醒/i.test(instruction);\n const wantsSummary = /摘要|总结|summary|压缩/i.test(instruction);\n\n if (wantsTodos) {\n const candidates = lines.filter((line) => /要|需|记得|todo|task|完成|提交|联系|跟进|提醒/i.test(line));\n return (candidates.length ? candidates : lines).slice(0, 12).map((line) => ({\n id: createBlockId(),\n type: 'todo' as const,\n text: line.replace(/^[-*\\d.\\s\\[\\]x]+/i, '').trim(),\n checked: false,\n createdAt: now,\n updatedAt: now,\n }));\n }\n\n if (wantsSummary) {\n const summary = lines.join(' ').slice(0, 220);\n return [{\n id: createBlockId(),\n type: 'paragraph',\n text: summary,\n createdAt: now,\n updatedAt: now,\n }];\n }\n\n const titleText = lines[0]?.slice(0, 40) || '整理后的笔记';\n const bodyLines = lines.slice(1).length ? lines.slice(1) : lines;\n return [\n {\n id: createBlockId(),\n type: 'heading',\n text: titleText,\n level: 2,\n createdAt: now,\n updatedAt: now,\n },\n ...bodyLines.map((line) => ({\n id: createBlockId(),\n type: 'bulletList' as const,\n text: line.replace(/^[-*\\d.\\s]+/, '').trim(),\n indent: 0,\n createdAt: now,\n updatedAt: now,\n })),\n ];\n}\n\nfunction splitMeaningfulLines(text?: string): string[] {\n return (text ?? '')\n .split(/[\\n。!?!?;;]+/)\n .map((line) => line.trim().replace(/^[-*\\d.\\s]+/, ''))\n .filter((line) => line.length > 0);\n}\n\nfunction summarizeIdea(text?: string): string {\n const lines = splitMeaningfulLines(text);\n const joined = lines.join(' ');\n return Array.from(joined || '这个想法').slice(0, 90).join('');\n}\n\nfunction inferCatalysisStage(note: Note): NonNullable<NoteCatalysisMeta['stage']> {\n const text = `${note.title ?? ''}\\n${note.text ?? ''}`;\n if (/发布|上线|分享|推广|launch|ship/i.test(text)) return 'shipped';\n if (/验证|实验|用户|指标|反馈|validate|experiment/i.test(text)) return 'validating';\n if (/实现|开发|MVP|原型|prototype|build/i.test(text)) return 'developing';\n if (text.trim().length > 80) return 'incubating';\n return 'seed';\n}\n\nfunction buildCatalysisReport(note: Note): NoteCatalysisReport {\n const generatedAt = Date.now();\n const summary = summarizeIdea(note.text ?? note.title);\n const title = note.title?.trim() || summary.slice(0, 28) || '未命名想法';\n const hasUserSignal = /用户|客户|读者|创作者|团队|个人|开发者|founder|creator|user/i.test(summary);\n const hasProductSignal = /产品|工具|平台|workflow|agent|AI|自动|系统|应用/i.test(summary);\n const confidence = Math.min(0.86, Math.max(0.42, 0.48 + (hasUserSignal ? 0.16 : 0) + (hasProductSignal ? 0.18 : 0) + Math.min(summary.length, 120) / 600));\n\n return {\n originalNoteId: note.id,\n generatedAt,\n title,\n valueHypothesis: `如果把「${summary}」推进成一个可体验的小成果,它最可能的价值是帮助用户更快完成判断、表达或行动。`,\n targetUsers: hasUserSignal ? ['笔记作者自己', '有类似场景的目标用户'] : ['笔记作者自己', '未来可能被这个想法帮助的人'],\n keyQuestions: [\n '这个想法最想解决的具体痛点是什么?',\n '第一个可验证的用户场景是什么?',\n '什么样的最小成果能证明它值得继续投入?',\n ],\n mvpPath: [\n '把想法改写成一句清晰的问题陈述。',\n '列出 1 个目标用户和 1 个高频使用场景。',\n '产出一个最小原型、提纲或行动清单。',\n ],\n risks: [\n '想法还停留在概念层,缺少明确使用场景。',\n '下一步过大时容易变成长期搁置的项目。',\n ],\n nextActions: [\n { kind: 'chat', text: '和 AI 继续深聊这个想法,收敛成问题陈述。' },\n { kind: 'research', text: '补充 3 个相似产品、案例或用户反馈。' },\n { kind: 'task', text: '写下今天能完成的一个最小推进动作。' },\n ],\n confidence: Number(confidence.toFixed(2)),\n };\n}\n\nfunction stripJsonCodeFence(raw: string): string {\n return raw.trim().replace(/^```(?:json)?\\s*/i, '').replace(/\\s*```$/i, '').trim();\n}\n\nfunction extractJsonObject(raw: string): Record<string, unknown> | null {\n if (!raw.trim()) return null;\n const text = stripJsonCodeFence(raw);\n try {\n const data = JSON.parse(text) as unknown;\n return data && typeof data === 'object' && !Array.isArray(data) ? data as Record<string, unknown> : null;\n } catch {\n const start = text.indexOf('{');\n const end = text.lastIndexOf('}');\n if (start < 0 || end <= start) return null;\n try {\n const data = JSON.parse(text.slice(start, end + 1)) as unknown;\n return data && typeof data === 'object' && !Array.isArray(data) ? data as Record<string, unknown> : null;\n } catch {\n return null;\n }\n }\n}\n\nfunction extractAssistantText(result: { content?: unknown }): string {\n if (!Array.isArray(result.content)) return '';\n return result.content\n .filter((block): block is { type: string; text: string } => {\n return !!block && typeof block === 'object' && (block as { type?: string }).type === 'text';\n })\n .map((block) => block.text)\n .join('')\n .trim();\n}\n\nfunction stringArray(value: unknown, fallback: string[], limit: number): string[] {\n if (!Array.isArray(value)) return fallback;\n const items = value\n .map((item) => typeof item === 'string' ? item.trim() : '')\n .filter(Boolean)\n .slice(0, limit);\n return items.length ? items : fallback;\n}\n\nfunction catalysisActions(value: unknown, fallback: NoteCatalysisAction[]): NoteCatalysisAction[] {\n if (!Array.isArray(value)) return fallback;\n const allowed = new Set<NoteCatalysisAction['kind']>(['task', 'workflow', 'research', 'share', 'chat']);\n const items: NoteCatalysisAction[] = [];\n for (const item of value) {\n if (!item || typeof item !== 'object') continue;\n const row = item as { kind?: unknown; text?: unknown };\n const kind = typeof row.kind === 'string' && allowed.has(row.kind as NoteCatalysisAction['kind'])\n ? row.kind as NoteCatalysisAction['kind']\n : 'task';\n const text = typeof row.text === 'string' ? row.text.trim() : '';\n if (text) items.push({ kind, text });\n }\n return items.length ? items.slice(0, 5) : fallback;\n}\n\nfunction normalizeAiCatalysisReport(note: Note, data: Record<string, unknown>): NoteCatalysisReport {\n const fallback = buildCatalysisReport(note);\n const confidenceRaw = typeof data.confidence === 'number' ? data.confidence : fallback.confidence;\n const confidence = Math.min(1, Math.max(0, confidenceRaw));\n return {\n originalNoteId: note.id,\n generatedAt: Date.now(),\n title: typeof data.title === 'string' && data.title.trim() ? data.title.trim().slice(0, 80) : fallback.title,\n valueHypothesis: typeof data.valueHypothesis === 'string' && data.valueHypothesis.trim()\n ? data.valueHypothesis.trim()\n : fallback.valueHypothesis,\n targetUsers: stringArray(data.targetUsers, fallback.targetUsers, 5),\n keyQuestions: stringArray(data.keyQuestions, fallback.keyQuestions, 6),\n mvpPath: stringArray(data.mvpPath, fallback.mvpPath, 6),\n risks: stringArray(data.risks, fallback.risks, 5),\n nextActions: catalysisActions(data.nextActions, fallback.nextActions),\n confidence: Number(confidence.toFixed(2)),\n };\n}\n\nfunction buildCatalysisPrompt(note: Note): string {\n const title = note.title?.trim() || '未命名笔记';\n const text = (note.text ?? '').trim() || '(无正文)';\n return `你是一个帮助用户把想法推进成成果的个人 AI Agent。请基于这条 Note 做“想法催化”,帮助用户进入:想法 → 创造 → 分享 → 反馈 的循环。\\n\\n要求:\\n- 使用自然、具体的中文。\\n- 不要空泛鼓励,要给出可执行路径。\\n- 输出必须是单个 JSON 对象,不要 Markdown,不要代码块。\\n- 字段必须包含:title, valueHypothesis, targetUsers, keyQuestions, mvpPath, risks, nextActions, confidence。\\n- nextActions 每项格式为 {\"kind\":\"task|workflow|research|share|chat\",\"text\":\"...\"}。\\n- confidence 是 0 到 1 的数字。\\n\\nNote 标题:${title}\\n\\nNote 正文:\\n${text.slice(0, 6000)}`;\n}\n\nasync function buildAiCatalysisReport(note: Note, config?: Config): Promise<NoteCatalysisReport> {\n const model = resolveModel(getDefaultModelSync(config));\n const user: UserMessage = {\n role: 'user',\n content: buildCatalysisPrompt(note),\n timestamp: Date.now(),\n };\n const result = await complete(\n model,\n { messages: [user] },\n { maxTokens: 1800, temperature: 0.2 },\n );\n const text = extractAssistantText(result);\n const data = extractJsonObject(text);\n if (!data) {\n throw new Error('Catalysis model did not return valid JSON');\n }\n return normalizeAiCatalysisReport(note, data);\n}\n\nconst SNAPSHOT_THROTTLE_MS = 60_000;\nconst MAX_SNAPSHOTS_PER_NOTE = 30;\n\nexport class NotesService {\n private store: NotesStore;\n private lastSnapshotAt = new Map<string, number>();\n\n constructor(store: NotesStore) {\n this.store = store;\n }\n\n async initialize(): Promise<void> {\n await this.store.initialize();\n log.debug('NotesService initialized');\n }\n\n async quickCapture(text: string, source: CaptureSource): Promise<Note> {\n const now = Date.now();\n const id = randomUUID();\n const blocks = noteTextToBlocks(text, id);\n const note: Note = {\n id,\n title: deriveDefaultTitle(text),\n kind: inferKind(text),\n status: 'inbox',\n text,\n blocks,\n createdAt: now,\n updatedAt: now,\n capturedVia: source,\n localVersion: 0,\n remoteVersion: 1,\n };\n await this.store.addNote(note);\n log.debug({ id: note.id, kind: note.kind }, 'Quick capture');\n return note;\n }\n\n async createNote(params: CreateNoteParams): Promise<Note> {\n const now = Date.now();\n const id = randomUUID();\n const blocks = params.blocks ?? noteTextToBlocks(params.text, id);\n const text = params.text ?? blocksToPlainText(blocks, id);\n const note: Note = {\n id,\n title: params.title,\n kind: params.kind || inferKind(text),\n status: 'inbox',\n text,\n blocks,\n createdAt: now,\n updatedAt: now,\n capturedVia: params.capturedVia,\n tags: params.tags,\n pinned: params.pinned,\n localVersion: 0,\n remoteVersion: 1,\n };\n await this.store.addNote(note);\n log.debug({ id: note.id, kind: note.kind }, 'Note created');\n return note;\n }\n\n async getNote(id: string): Promise<Note | null> {\n return this.store.getNote(id);\n }\n\n async updateNote(id: string, patch: Partial<Note>, trigger: SnapshotTrigger = 'edit'): Promise<Note | null> {\n const existing = await this.store.getNote(id);\n if (!existing) return null;\n\n const contentTouched = patch.text !== undefined || patch.blocks !== undefined || patch.title !== undefined;\n if (contentTouched) {\n await this.maybeSaveSnapshot(existing, trigger);\n }\n\n const normalizedPatch: Partial<Note> = { ...patch };\n if (patch.blocks) {\n normalizedPatch.text = patch.text ?? blocksToPlainText(patch.blocks, existing.id);\n } else if (typeof patch.text === 'string') {\n normalizedPatch.blocks = patch.blocks ?? noteTextToBlocks(patch.text, existing.id);\n }\n normalizedPatch.remoteVersion = (existing.remoteVersion ?? 0) + 1;\n\n if (contentTouched) {\n const merged: Note = {\n ...existing,\n ...normalizedPatch,\n id: existing.id,\n createdAt: existing.createdAt,\n updatedAt: Date.now(),\n };\n const reconciled = await this.reconcileAttachments(merged);\n normalizedPatch.attachments = reconciled.attachments;\n normalizedPatch.kind = reconciled.kind;\n }\n\n return this.store.updateNote(id, normalizedPatch);\n }\n\n private async reconcileAttachments(note: Note): Promise<Note> {\n const { kept, removed } = partitionAttachmentsByReference(note);\n if (removed.length === 0) return note;\n\n for (const attachment of removed) {\n await this.store.deleteAttachmentFile(note.id, attachment.relativePath);\n }\n\n log.debug(\n { noteId: note.id, removedIds: removed.map((attachment) => attachment.id) },\n 'Pruned orphan note attachments',\n );\n\n const hasAttachments = kept.length > 0;\n return {\n ...note,\n attachments: hasAttachments ? kept : undefined,\n kind: inferKind(note.text, hasAttachments, kept),\n };\n }\n\n async syncNote(\n id: string,\n patch: Partial<Note>,\n baseRemoteVersion?: number,\n ): Promise<{ note: Note | null; conflict: boolean }> {\n const existing = await this.store.getNote(id);\n if (!existing) return { note: null, conflict: false };\n\n const currentRemoteVersion = existing.remoteVersion ?? 0;\n if (baseRemoteVersion !== undefined && baseRemoteVersion < currentRemoteVersion) {\n return { note: existing, conflict: true };\n }\n\n const updated = await this.updateNote(id, patch, 'sync');\n return { note: updated, conflict: false };\n }\n\n async createAiEditPatch(\n id: string,\n instruction: string,\n blocks?: NoteBlock[],\n ): Promise<{ message: string; patch: NoteAiPatch } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n\n const sourceBlocks = blocks?.length ? blocks : note.blocks ?? noteTextToBlocks(note.text, note.id) ?? [];\n const organizedBlocks = createAiOrganizedBlocks(sourceBlocks, instruction);\n const patch: NoteAiPatch = {\n id: randomUUID(),\n summary: `已根据「${instruction.slice(0, 40)}」生成可预览的块级整理建议`,\n operations: [{ type: 'replaceBlocks', blocks: organizedBlocks }],\n };\n\n return {\n message: 'AI edit patch generated',\n patch,\n };\n }\n\n async catalyzeNote(id: string, config?: Config): Promise<{ note: Note; report: NoteCatalysisReport } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n\n let report: NoteCatalysisReport;\n try {\n report = await buildAiCatalysisReport(note, config);\n } catch (err) {\n log.warn({ err, noteId: id }, 'AI note catalysis failed; using local fallback report');\n report = buildCatalysisReport(note);\n }\n\n const existingDeep = note.aiDeep;\n const catalysis: NoteCatalysisMeta = {\n ...existingDeep?.catalysis,\n status: 'catalyzed',\n stage: inferCatalysisStage(note),\n lastCatalyzedAt: report.generatedAt,\n confidence: report.confidence,\n report,\n };\n\n const updated = await this.updateNote(id, {\n ai: {\n ...note.ai,\n intent: note.ai?.intent ?? 'idea',\n summary: note.ai?.summary ?? report.valueHypothesis,\n },\n aiDeep: {\n ...existingDeep,\n processedAt: report.generatedAt,\n insights: report.valueHypothesis,\n catalysis,\n },\n status: note.status === 'inbox' ? 'processed' : note.status,\n }, 'ai_edit');\n\n return updated ? { note: updated, report } : null;\n }\n\n async recordCatalysisFeedback(\n id: string,\n feedback: NonNullable<NoteCatalysisMeta['feedback']>,\n ): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const now = Date.now();\n return this.updateNote(id, {\n aiDeep: {\n ...note.aiDeep,\n processedAt: now,\n catalysis: {\n status: note.aiDeep?.catalysis?.status ?? 'catalyzed',\n ...note.aiDeep?.catalysis,\n feedback,\n },\n },\n }, 'ai_edit');\n }\n\n async linkNoteThread(id: string, sessionKey: string): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const existingKeys = note.aiDeep?.catalysis?.linkedSessionKeys ?? [];\n const linkedSessionKeys = Array.from(new Set([sessionKey, ...existingKeys]));\n return this.updateNote(id, {\n aiDeep: {\n ...note.aiDeep,\n processedAt: Date.now(),\n catalysis: {\n status: note.aiDeep?.catalysis?.status ?? 'none',\n ...note.aiDeep?.catalysis,\n sourceSessionKey: note.aiDeep?.catalysis?.sourceSessionKey ?? sessionKey,\n linkedSessionKeys,\n },\n },\n }, 'sync');\n }\n\n async listNoteThreads(id: string): Promise<string[] | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const keys = [\n note.aiDeep?.catalysis?.sourceSessionKey,\n ...(note.aiDeep?.catalysis?.linkedSessionKeys ?? []),\n ].filter((key): key is string => typeof key === 'string' && key.length > 0);\n return Array.from(new Set(keys));\n }\n\n async appendTextToNote(id: string, content: string, heading = 'AI 讨论沉淀'): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const trimmed = content.trim();\n if (!trimmed) return note;\n const currentText = note.text?.trimEnd() ?? '';\n const nextText = `${currentText}${currentText ? '\\n\\n' : ''}## ${heading}\\n\\n${trimmed}`;\n return this.updateNote(id, { text: nextText }, 'ai_edit');\n }\n\n async deleteNote(id: string): Promise<boolean> {\n const deleted = await this.store.deleteNote(id);\n if (deleted) {\n await this.store.deleteAllSnapshots(id);\n this.lastSnapshotAt.delete(id);\n }\n return deleted;\n }\n\n async listNotes(query: NotesListQuery = {}): Promise<{ items: NoteIndexEntry[]; total: number; limit: number; offset: number; hasMore: boolean }> {\n return this.store.listNotes(query);\n }\n\n async addAttachment(\n noteId: string,\n file: { name: string; buffer: Buffer; mimeType: string; duration?: number },\n ): Promise<NoteAttachment | null> {\n const note = await this.store.getNote(noteId);\n if (!note) return null;\n\n const { relativePath, size } = await this.store.saveAttachment(noteId, file.name, file.buffer);\n\n const attachment: NoteAttachment = {\n id: randomUUID(),\n type: inferAttachmentType(file.mimeType),\n mimeType: file.mimeType,\n fileName: file.name,\n size,\n relativePath,\n duration: file.duration,\n };\n\n const attachments = [...(note.attachments || []), attachment];\n const kind: NoteKind =\n note.kind === 'thought' && attachment.type === 'audio'\n ? 'voice'\n : note.kind === 'thought'\n ? 'media'\n : note.kind;\n await this.store.updateNote(noteId, { attachments, kind });\n\n return attachment;\n }\n\n async getAttachmentPath(\n noteId: string,\n attachmentId: string,\n ): Promise<{ filePath: string; mimeType: string; fileName: string } | null> {\n const note = await this.store.getNote(noteId);\n if (!note) return null;\n\n const attachment = note.attachments?.find((a) => a.id === attachmentId);\n if (!attachment) return null;\n\n const fullPath = this.store.resolveAttachmentPath(noteId, attachment.relativePath);\n return { filePath: fullPath, mimeType: attachment.mimeType, fileName: attachment.fileName };\n }\n\n async listNoteHistory(noteId: string): Promise<NoteSnapshotEntry[]> {\n return this.store.listSnapshots(noteId);\n }\n\n async getNoteSnapshot(noteId: string, timestamp: number): Promise<NoteSnapshot | null> {\n return this.store.getSnapshot(noteId, timestamp);\n }\n\n async restoreNoteSnapshot(noteId: string, timestamp: number): Promise<Note | null> {\n const snapshot = await this.store.getSnapshot(noteId, timestamp);\n if (!snapshot) return null;\n const existing = await this.store.getNote(noteId);\n if (!existing) return null;\n\n await this.store.saveSnapshot(existing, 'restore');\n this.lastSnapshotAt.set(noteId, Date.now());\n await this.store.pruneSnapshots(noteId, MAX_SNAPSHOTS_PER_NOTE);\n\n return this.store.updateNote(noteId, {\n title: snapshot.title,\n text: snapshot.text,\n blocks: snapshot.blocks,\n tags: snapshot.tags,\n });\n }\n\n async flush(): Promise<void> {\n await this.store.flush();\n }\n\n // ── Space grouping ──────────────────────────────────────────────────\n\n async moveToGroup(noteId: string, groupId: string | null): Promise<Note | null> {\n return this.updateNote(noteId, { groupId: groupId ?? undefined });\n }\n\n // ── Task lifecycle ──────────────────────────────────────────────────\n\n async createTask(\n title: string,\n source: CaptureSource,\n options?: { dueAt?: number; priority?: 'high' | 'medium' | 'low'; sourceSessionKey?: string; sourceNoteId?: string; groupId?: string },\n ): Promise<Note> {\n return this.createNote({\n title,\n kind: 'task',\n capturedVia: source,\n groupId: options?.groupId,\n taskMeta: {\n done: false,\n dueAt: options?.dueAt,\n priority: options?.priority,\n sourceSessionKey: options?.sourceSessionKey,\n sourceNoteId: options?.sourceNoteId,\n },\n });\n }\n\n async toggleTaskDone(noteId: string): Promise<Note | null> {\n const note = await this.store.getNote(noteId);\n if (!note || note.kind !== 'task') return null;\n const done = !note.taskMeta?.done;\n return this.updateNote(noteId, {\n taskMeta: { ...note.taskMeta, done },\n status: done ? 'archived' : 'processed',\n });\n }\n\n async updateTaskMeta(noteId: string, patch: Partial<import('./types.js').NoteTaskMeta>): Promise<Note | null> {\n const note = await this.store.getNote(noteId);\n if (!note || note.kind !== 'task') return null;\n return this.updateNote(noteId, {\n taskMeta: { ...note.taskMeta, done: note.taskMeta?.done ?? false, ...patch },\n });\n }\n\n // ── Open tracking ──────────────────────────────────────────────────\n\n async recordOpen(noteId: string): Promise<Note | null> {\n return this.updateNote(noteId, { lastOpenedAt: Date.now() } as Partial<Note>);\n }\n\n private async maybeSaveSnapshot(note: Note, trigger: SnapshotTrigger): Promise<void> {\n if (trigger !== 'edit') {\n await this.store.saveSnapshot(note, trigger);\n this.lastSnapshotAt.set(note.id, Date.now());\n await this.store.pruneSnapshots(note.id, MAX_SNAPSHOTS_PER_NOTE);\n return;\n }\n const last = this.lastSnapshotAt.get(note.id) ?? 0;\n if (Date.now() - last < SNAPSHOT_THROTTLE_MS) return;\n await this.store.saveSnapshot(note, trigger);\n this.lastSnapshotAt.set(note.id, Date.now());\n await this.store.pruneSnapshots(note.id, MAX_SNAPSHOTS_PER_NOTE);\n }\n}\n\nfunction inferAttachmentType(mimeType: string): NoteAttachment['type'] {\n if (mimeType.startsWith('image/')) return 'image';\n if (mimeType.startsWith('video/')) return 'video';\n if (mimeType.startsWith('audio/')) return 'audio';\n return 'file';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"service.js","names":[],"sources":["../../../src/notes/service.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { complete, type UserMessage } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../config/schema.js';\nimport { getDefaultModelSync, resolveModel } from '../providers/index.js';\nimport { createLogger } from '../utils/logger.js';\nimport { buildNoteAttachmentRef } from './attachment-ref.js';\nimport { partitionAttachmentsByReference } from './note-attachment-sync.js';\nimport { parseNoteMarkdown } from './note-markdown.js';\nimport { NotesStore } from './store.js';\nimport type {\n CaptureSource,\n CreateNoteParams,\n Note,\n NoteAiPatch,\n NoteAttachment,\n NoteCatalysisAction,\n NoteCatalysisMeta,\n NoteCatalysisReport,\n NoteIndexEntry,\n NoteKind,\n NoteSnapshot,\n NoteSnapshotEntry,\n NotesListQuery,\n SnapshotTrigger,\n} from './types.js';\n\nconst log = createLogger('NotesService');\nconst MAX_SNAPSHOTS_PER_NOTE = 50;\nconst SNAPSHOT_THROTTLE_MS = 60_000;\n\nfunction inferKind(markdown?: string, hasAttachments?: boolean, attachments?: NoteAttachment[]): NoteKind {\n if (hasAttachments && attachments?.length && attachments.every((item) => item.type === 'audio')) return 'voice';\n if (hasAttachments) return 'media';\n if (!markdown) return 'thought';\n const lower = markdown.toLowerCase();\n if (/^(todo|task|remind|buy|call|email|meet|finish|submit|send)\\b/i.test(lower) || /\\b(明天|今天|记得|别忘|待办|提醒)\\b/.test(markdown)) return 'todo';\n if (/^https?:\\/\\//.test(markdown.trim())) return 'bookmark';\n return 'thought';\n}\n\nfunction deriveDefaultTitle(markdown?: string): string | undefined {\n const normalized = parseNoteMarkdown(markdown ?? '').plainText.trim().replace(/\\s+/g, ' ');\n return normalized ? Array.from(normalized).slice(0, 10).join('') : undefined;\n}\n\nfunction splitMeaningfulLines(markdown?: string): string[] {\n return parseNoteMarkdown(markdown ?? '').plainText.split(/\\n|。|;|;/).map((line) => line.trim()).filter(Boolean);\n}\n\nfunction summarizeIdea(markdown?: string): string {\n const lines = splitMeaningfulLines(markdown);\n return lines.slice(0, 3).join(';').slice(0, 140);\n}\n\nfunction inferCatalysisStage(note: Note): NonNullable<NoteCatalysisMeta['stage']> {\n const text = `${note.title ?? ''}\\n${note.markdown}`;\n if (/上线|发布|launch|ship/i.test(text)) return 'shipped';\n if (/验证|访谈|用户|测试|validate/i.test(text)) return 'validating';\n if (/开发|实现|构建|build|mvp/i.test(text)) return 'developing';\n if (/想法|机会|问题|idea|seed/i.test(text)) return 'seed';\n return 'incubating';\n}\n\nfunction buildCatalysisReport(note: Note): NoteCatalysisReport {\n const summary = summarizeIdea(note.markdown || note.title);\n const title = note.title?.trim() || summary.slice(0, 28) || '未命名想法';\n const actions: NoteCatalysisAction[] = [\n { kind: 'research', text: `验证「${title}」的真实需求和目标用户` },\n { kind: 'task', text: `拆解「${title}」的最小可行下一步` },\n { kind: 'chat', text: `继续和 AI 讨论「${title}」的方案` },\n ];\n return {\n originalNoteId: note.id,\n generatedAt: Date.now(),\n title,\n valueHypothesis: summary || '这条笔记可能包含一个待澄清的想法。',\n targetUsers: ['待确认的核心用户'],\n keyQuestions: ['用户为什么现在需要它?', '最小可验证版本是什么?', '如何判断它值得继续投入?'],\n mvpPath: ['定义目标用户', '写出最小场景', '完成一次验证'],\n risks: ['需求不够明确', '执行路径过大'],\n nextActions: actions,\n confidence: summary ? 0.58 : 0.35,\n };\n}\n\nfunction normalizeAiCatalysisReport(note: Note, data: Record<string, unknown>): NoteCatalysisReport {\n const fallback = buildCatalysisReport(note);\n const stringArray = (value: unknown, fallbackValue: string[]) => Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string').slice(0, 12) : fallbackValue;\n const actions = Array.isArray(data.nextActions)\n ? data.nextActions.map((item): NoteCatalysisAction | null => {\n if (!item || typeof item !== 'object') return null;\n const row = item as { kind?: unknown; text?: unknown };\n const kind = row.kind === 'task' || row.kind === 'workflow' || row.kind === 'research' || row.kind === 'share' || row.kind === 'chat' ? row.kind : 'task';\n return typeof row.text === 'string' && row.text.trim() ? { kind, text: row.text.trim() } : null;\n }).filter((item): item is NoteCatalysisAction => Boolean(item)).slice(0, 12)\n : fallback.nextActions;\n return {\n originalNoteId: note.id,\n generatedAt: Date.now(),\n title: typeof data.title === 'string' && data.title.trim() ? data.title.trim() : fallback.title,\n valueHypothesis: typeof data.valueHypothesis === 'string' && data.valueHypothesis.trim() ? data.valueHypothesis.trim() : fallback.valueHypothesis,\n targetUsers: stringArray(data.targetUsers, fallback.targetUsers),\n keyQuestions: stringArray(data.keyQuestions, fallback.keyQuestions),\n mvpPath: stringArray(data.mvpPath, fallback.mvpPath),\n risks: stringArray(data.risks, fallback.risks),\n nextActions: actions,\n confidence: typeof data.confidence === 'number' ? Math.max(0, Math.min(1, data.confidence)) : fallback.confidence,\n };\n}\n\nfunction buildCatalysisPrompt(note: Note): string {\n const title = note.title?.trim() || '未命名笔记';\n const markdown = note.markdown.trim() || '(无正文)';\n return `请把下面的 Markdown 笔记催化成可执行的想法报告,输出 JSON:\\n{\\n \"title\": string,\\n \"valueHypothesis\": string,\\n \"targetUsers\": string[],\\n \"keyQuestions\": string[],\\n \"mvpPath\": string[],\\n \"risks\": string[],\\n \"nextActions\": [{\"text\": string, \"kind\": \"task\"|\"workflow\"|\"research\"|\"share\"|\"chat\"}],\\n \"confidence\": number\\n}\\n\\n标题:${title}\\n\\nMarkdown:\\n${markdown}`;\n}\n\nasync function buildAiCatalysisReport(note: Note, config?: Config): Promise<NoteCatalysisReport> {\n const modelRef = getDefaultModelSync(config) ?? 'openai/gpt-5.5';\n const resolved = resolveModel(modelRef);\n const messages: UserMessage[] = [{ role: 'user', content: buildCatalysisPrompt(note), timestamp: Date.now() }];\n const response = await complete(resolved, { messages }, { temperature: 0.2 });\n let responseText = '';\n if (Array.isArray(response.content)) {\n for (const part of response.content) {\n if (part && typeof part === 'object' && (part as { type?: string }).type === 'text') {\n responseText += String((part as { text?: string }).text || '');\n }\n }\n }\n const raw = responseText.trim().replace(/^```json\\s*/i, '').replace(/```$/i, '').trim();\n return normalizeAiCatalysisReport(note, JSON.parse(raw) as Record<string, unknown>);\n}\n\nexport class NotesService {\n private lastSnapshotAt = new Map<string, number>();\n\n constructor(private readonly store = new NotesStore()) {}\n\n async initialize(): Promise<void> {\n await this.store.initialize();\n }\n\n async quickCapture(markdown: string, source: CaptureSource): Promise<Note> {\n const id = randomUUID();\n const now = Date.now();\n const note: Note = {\n id,\n title: deriveDefaultTitle(markdown),\n kind: inferKind(markdown),\n status: 'inbox',\n markdown,\n createdAt: now,\n updatedAt: now,\n capturedVia: source,\n remoteVersion: 1,\n localVersion: 1,\n };\n await this.store.addNote(note);\n log.debug({ id: note.id, kind: note.kind }, 'Quick capture');\n return note;\n }\n\n async createNote(params: CreateNoteParams): Promise<Note> {\n const id = randomUUID();\n const now = Date.now();\n const markdown = params.markdown ?? '';\n const note: Note = {\n id,\n title: params.title ?? deriveDefaultTitle(markdown),\n kind: params.kind ?? inferKind(markdown),\n status: 'inbox',\n markdown,\n attachments: [],\n createdAt: now,\n updatedAt: now,\n capturedVia: params.capturedVia,\n tags: params.tags,\n pinned: params.pinned,\n groupId: params.groupId,\n taskMeta: params.taskMeta,\n remoteVersion: 1,\n localVersion: 1,\n };\n await this.store.addNote(note);\n log.debug({ id: note.id, kind: note.kind }, 'Note created');\n return note;\n }\n\n async getNote(id: string): Promise<Note | null> {\n return this.store.getNote(id);\n }\n\n async updateNote(id: string, patch: Partial<Note>, trigger: SnapshotTrigger = 'edit'): Promise<Note | null> {\n const existing = await this.store.getNote(id);\n if (!existing) return null;\n const contentTouched = patch.markdown !== undefined || patch.title !== undefined;\n if (contentTouched) await this.maybeSaveSnapshot(existing, trigger);\n\n const normalizedPatch: Partial<Note> = { ...patch };\n if (patch.markdown !== undefined) {\n normalizedPatch.kind = patch.kind ?? inferKind(patch.markdown, Boolean(existing.attachments?.length), existing.attachments);\n }\n if (contentTouched || patch.attachments) {\n normalizedPatch.remoteVersion = (existing.remoteVersion ?? 1) + 1;\n normalizedPatch.localVersion = patch.localVersion ?? (existing.localVersion ?? 1) + 1;\n }\n\n const updatedRaw = await this.store.updateNote(id, normalizedPatch);\n return updatedRaw ? this.reconcileAttachments(updatedRaw) : null;\n }\n\n private async reconcileAttachments(note: Note): Promise<Note> {\n const { kept, removed } = partitionAttachmentsByReference(note);\n if (removed.length === 0) return note;\n for (const attachment of removed) await this.store.deleteAttachmentFile(note.id, attachment.relativePath);\n log.debug({ noteId: note.id, removedIds: removed.map((attachment) => attachment.id) }, 'Pruned orphan note attachments');\n const hasAttachments = kept.length > 0;\n const updated = await this.store.updateNote(note.id, { attachments: kept, kind: inferKind(note.markdown, hasAttachments, kept) });\n return updated ?? { ...note, attachments: kept };\n }\n\n async syncNote(id: string, patch: Partial<Note>, baseRemoteVersion?: number): Promise<{ note: Note | null; conflict: boolean }> {\n const existing = await this.store.getNote(id);\n if (!existing) return { note: null, conflict: false };\n if (baseRemoteVersion !== undefined && existing.remoteVersion !== undefined && baseRemoteVersion < existing.remoteVersion) {\n return { note: existing, conflict: true };\n }\n const updated = await this.updateNote(id, patch, 'sync');\n return { note: updated, conflict: false };\n }\n\n async createAiEditPatch(id: string, instruction: string, markdownOverride?: string): Promise<{ message: string; patch: NoteAiPatch } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const source = markdownOverride ?? note.markdown;\n const parsed = parseNoteMarkdown(source, id);\n const wantsTodos = /待办|todo|task|行动|提醒/i.test(instruction);\n const wantsSummary = /摘要|总结|summary|压缩/i.test(instruction);\n let generated = '';\n if (wantsTodos) {\n const lines = source.split(/\\n|。|;|;/).map((line) => line.trim()).filter(Boolean);\n generated = (lines.length ? lines : [parsed.plainText]).slice(0, 12).map((line) => `- [ ] ${line.replace(/^[-*\\d.\\s\\[\\]x]+/i, '').trim()}`).join('\\n');\n } else if (wantsSummary) {\n generated = `> [!SUMMARY]\\n> ${parsed.plainText.slice(0, 220)}`;\n } else {\n generated = `${source.trimEnd()}\\n\\n## AI 整理\\n\\n${instruction.trim()}`;\n }\n return {\n message: 'AI edit patch generated',\n patch: {\n id: randomUUID(),\n summary: instruction,\n operations: [{ type: 'replaceRange', from: 0, to: source.length, markdown: generated || source }],\n },\n };\n }\n\n async catalyzeNote(id: string, config?: Config): Promise<{ note: Note; report: NoteCatalysisReport } | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n let report: NoteCatalysisReport;\n try {\n report = await buildAiCatalysisReport(note, config);\n } catch (err) {\n log.warn({ err, noteId: id }, 'AI note catalysis failed; using local fallback report');\n report = buildCatalysisReport(note);\n }\n const updated = await this.updateNote(id, {\n aiDeep: {\n ...note.aiDeep,\n processedAt: Date.now(),\n catalysis: {\n status: 'catalyzed',\n stage: inferCatalysisStage(note),\n lastCatalyzedAt: Date.now(),\n confidence: report.confidence,\n report,\n ...note.aiDeep?.catalysis,\n },\n },\n ai: { ...note.ai, intent: note.ai?.intent ?? 'idea', summary: note.ai?.summary ?? report.valueHypothesis },\n status: note.status === 'inbox' ? 'processed' : note.status,\n }, 'ai_edit');\n return updated ? { note: updated, report } : null;\n }\n\n async recordCatalysisFeedback(id: string, feedback: 'helpful' | 'not_helpful' | 'neutral'): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n return this.updateNote(id, { aiDeep: { ...note.aiDeep, processedAt: Date.now(), catalysis: { status: note.aiDeep?.catalysis?.status ?? 'catalyzed', ...note.aiDeep?.catalysis, feedback } } });\n }\n\n async linkNoteThread(id: string, sessionKey: string): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const existingKeys = note.aiDeep?.catalysis?.linkedSessionKeys ?? [];\n return this.updateNote(id, {\n aiDeep: {\n ...note.aiDeep,\n processedAt: Date.now(),\n catalysis: {\n status: note.aiDeep?.catalysis?.status ?? 'none',\n ...note.aiDeep?.catalysis,\n sourceSessionKey: note.aiDeep?.catalysis?.sourceSessionKey ?? sessionKey,\n linkedSessionKeys: Array.from(new Set([...existingKeys, sessionKey])),\n },\n },\n }, 'sync');\n }\n\n async listNoteThreads(id: string): Promise<string[] | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n return Array.from(new Set([note.aiDeep?.catalysis?.sourceSessionKey, ...(note.aiDeep?.catalysis?.linkedSessionKeys ?? [])].filter((key): key is string => Boolean(key))));\n }\n\n async appendTextToNote(id: string, content: string, heading = 'AI 讨论沉淀'): Promise<Note | null> {\n const note = await this.store.getNote(id);\n if (!note) return null;\n const trimmed = content.trim();\n if (!trimmed) return note;\n const current = note.markdown.trimEnd();\n const nextMarkdown = `${current}${current ? '\\n\\n' : ''}## ${heading}\\n\\n${trimmed}\\n`;\n return this.updateNote(id, { markdown: nextMarkdown }, 'ai_edit');\n }\n\n async deleteNote(id: string): Promise<boolean> {\n const removed = await this.store.deleteNote(id);\n if (removed) await this.store.deleteAllSnapshots(id);\n return removed;\n }\n\n async listNotes(query: NotesListQuery = {}): Promise<{ items: NoteIndexEntry[]; total: number; limit: number; offset: number; hasMore: boolean }> {\n return this.store.listNotes(query);\n }\n\n async addAttachment(noteId: string, file: { name: string; buffer: Buffer; mimeType: string; duration?: number }): Promise<NoteAttachment | null> {\n const note = await this.store.getNote(noteId);\n if (!note) return null;\n const { relativePath, size } = await this.store.saveAttachment(noteId, file.name, file.buffer);\n const attachment: NoteAttachment = {\n id: randomUUID(),\n type: file.mimeType.startsWith('image/') ? 'image' : file.mimeType.startsWith('audio/') ? 'audio' : file.mimeType.startsWith('video/') ? 'video' : 'file',\n mimeType: file.mimeType,\n fileName: file.name,\n size,\n relativePath,\n duration: file.duration,\n };\n const attachments = [...(note.attachments || []), attachment];\n const kind = note.kind === 'thought' && attachment.type === 'audio' ? 'voice' : note.kind === 'thought' ? 'media' : note.kind;\n await this.store.updateNote(noteId, { attachments, kind });\n return attachment;\n }\n\n async getAttachmentPath(noteId: string, attachmentId: string): Promise<{ filePath: string; mimeType: string; fileName: string } | null> {\n const note = await this.store.getNote(noteId);\n if (!note) return null;\n const attachment = note.attachments?.find((a) => a.id === attachmentId);\n if (!attachment) return null;\n return { filePath: this.store.resolveAttachmentPath(noteId, attachment.relativePath), mimeType: attachment.mimeType, fileName: attachment.fileName };\n }\n\n async listNoteHistory(noteId: string): Promise<NoteSnapshotEntry[]> { return this.store.listSnapshots(noteId); }\n async getNoteSnapshot(noteId: string, timestamp: number): Promise<NoteSnapshot | null> { return this.store.getSnapshot(noteId, timestamp); }\n\n async restoreNoteSnapshot(noteId: string, timestamp: number): Promise<Note | null> {\n const snapshot = await this.store.getSnapshot(noteId, timestamp);\n const existing = await this.store.getNote(noteId);\n if (!snapshot || !existing) return null;\n await this.maybeSaveSnapshot(existing, 'restore');\n this.lastSnapshotAt.set(noteId, Date.now());\n await this.store.pruneSnapshots(noteId, MAX_SNAPSHOTS_PER_NOTE);\n return this.store.updateNote(noteId, { title: snapshot.title, markdown: snapshot.markdown, tags: snapshot.tags, kind: snapshot.kind, status: snapshot.status });\n }\n\n async flush(): Promise<void> { await this.store.flush(); }\n async moveToGroup(noteId: string, groupId: string | null): Promise<Note | null> { return this.updateNote(noteId, { groupId: groupId ?? undefined }); }\n\n async createTask(title: string, source: CaptureSource, opts: { dueAt?: number; priority?: 'high' | 'medium' | 'low'; sourceSessionKey?: string; sourceNoteId?: string; groupId?: string } = {}): Promise<Note> {\n return this.createNote({\n title,\n markdown: `- [ ] ${title}`,\n kind: 'task',\n capturedVia: source,\n groupId: opts.groupId,\n taskMeta: { done: false, dueAt: opts.dueAt, priority: opts.priority, sourceSessionKey: opts.sourceSessionKey, sourceNoteId: opts.sourceNoteId },\n });\n }\n\n async toggleTaskDone(noteId: string): Promise<Note | null> {\n const note = await this.store.getNote(noteId);\n if (!note || note.kind !== 'task') return null;\n const done = !note.taskMeta?.done;\n const markdown = note.markdown.replace(/^- \\[[ xX]\\]/m, `- [${done ? 'x' : ' '}]`);\n return this.updateNote(noteId, { markdown, taskMeta: { ...note.taskMeta, done } });\n }\n\n async updateTaskMeta(noteId: string, patch: Partial<import('./types.js').NoteTaskMeta>): Promise<Note | null> {\n const note = await this.store.getNote(noteId);\n if (!note || note.kind !== 'task') return null;\n return this.updateNote(noteId, { taskMeta: { ...note.taskMeta, done: note.taskMeta?.done ?? false, ...patch } });\n }\n\n async recordOpen(noteId: string): Promise<Note | null> {\n return this.updateNote(noteId, { lastOpenedAt: Date.now() } as Partial<Note>);\n }\n\n private async maybeSaveSnapshot(note: Note, trigger: SnapshotTrigger): Promise<void> {\n if (trigger !== 'edit') {\n await this.store.saveSnapshot(note, trigger);\n this.lastSnapshotAt.set(note.id, Date.now());\n await this.store.pruneSnapshots(note.id, MAX_SNAPSHOTS_PER_NOTE);\n return;\n }\n const last = this.lastSnapshotAt.get(note.id) ?? 0;\n if (Date.now() - last < SNAPSHOT_THROTTLE_MS) return;\n await this.store.saveSnapshot(note, trigger);\n this.lastSnapshotAt.set(note.id, Date.now());\n await this.store.pruneSnapshots(note.id, MAX_SNAPSHOTS_PER_NOTE);\n }\n}\n\nexport { buildNoteAttachmentRef };\n"],"mappings":"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"}
@@ -1,14 +1,14 @@
1
+ import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
1
2
  import { createLogger } from "../utils/logger/index.js";
2
3
  import { init_logger } from "../utils/logger.js";
3
- import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
4
4
  import { requireXopcDatabase } from "../storage/sqlite/connection.js";
5
5
  import { buildNoteIndexMeta } from "./note-index-meta.js";
6
6
  import { deleteNoteRecord, getNoteRecord, listNoteRecords, upsertNoteRecord } from "../storage/sqlite/notes-repository.js";
7
7
  import "../storage/sqlite/index.js";
8
8
  import { resolveNoteHistoryDir, resolveNoteMediaDir } from "./paths.js";
9
- import { join } from "node:path";
10
9
  import { randomUUID } from "node:crypto";
11
10
  import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
11
+ import { join } from "node:path";
12
12
  //#region src/notes/store.ts
13
13
  init_write_file_atomic();
14
14
  init_logger();
@@ -86,8 +86,7 @@ var NotesStore = class {
86
86
  timestamp: Date.now(),
87
87
  trigger,
88
88
  title: note.title,
89
- text: note.text,
90
- blocks: note.blocks,
89
+ markdown: note.markdown,
91
90
  tags: note.tags,
92
91
  kind: note.kind,
93
92
  status: note.status
@@ -115,7 +114,7 @@ var NotesStore = class {
115
114
  try {
116
115
  const content = await readFile(join(historyDir, file), "utf-8");
117
116
  const snapshot = JSON.parse(content);
118
- const rawText = snapshot.text ?? "";
117
+ const rawText = snapshot.markdown ?? "";
119
118
  entries.push({
120
119
  timestamp: snapshot.timestamp,
121
120
  trigger: snapshot.trigger,
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","names":[],"sources":["../../../src/notes/store.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { readFile, mkdir, writeFile, rm, readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { writeTextAtomic } from '../infra/write-file-atomic.js';\nimport { createLogger } from '../utils/logger.js';\nimport {\n deleteNoteRecord,\n getNoteRecord,\n listNoteRecords,\n requireXopcDatabase,\n upsertNoteRecord,\n} from '../storage/sqlite/index.js';\nimport { buildNoteIndexMeta } from './note-index-meta.js';\nimport { resolveNoteMediaDir, resolveNoteHistoryDir } from './paths.js';\nimport type {\n Note,\n NoteIndexEntry,\n NoteSnapshot,\n NoteSnapshotEntry,\n NotesListQuery,\n SnapshotTrigger,\n} from './types.js';\n\nconst log = createLogger('NotesStore');\n\nexport class NotesStore {\n private initialized = false;\n\n async initialize(): Promise<void> {\n if (this.initialized) return;\n requireXopcDatabase();\n this.initialized = true;\n log.debug('NotesStore initialized');\n }\n\n async addNote(note: Note): Promise<void> {\n requireXopcDatabase();\n upsertNoteRecord(note);\n }\n\n async getNote(id: string): Promise<Note | null> {\n requireXopcDatabase();\n return getNoteRecord(id);\n }\n\n async updateNote(id: string, patch: Partial<Note>): Promise<Note | null> {\n const existing = await this.getNote(id);\n if (!existing) return null;\n\n const updated: Note = {\n ...existing,\n ...patch,\n id: existing.id,\n createdAt: existing.createdAt,\n updatedAt: Date.now(),\n };\n\n requireXopcDatabase();\n upsertNoteRecord(updated);\n return updated;\n }\n\n async deleteNote(id: string): Promise<boolean> {\n requireXopcDatabase();\n const deleted = deleteNoteRecord(id);\n if (!deleted) {\n return false;\n }\n\n const mediaDir = resolveNoteMediaDir(id);\n await rm(mediaDir, { recursive: true, force: true }).catch(() => undefined);\n return true;\n }\n\n async listNotes(query: NotesListQuery = {}): Promise<{\n items: NoteIndexEntry[];\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n }> {\n requireXopcDatabase();\n return listNoteRecords(query);\n }\n\n async saveAttachment(\n noteId: string,\n fileName: string,\n buffer: Buffer,\n ): Promise<{ relativePath: string; size: number }> {\n const mediaDir = resolveNoteMediaDir(noteId);\n await mkdir(mediaDir, { recursive: true });\n const safeName = `${randomUUID().slice(0, 8)}_${fileName.replace(/[^a-zA-Z0-9._-]/g, '_')}`;\n const filePath = join(mediaDir, safeName);\n await writeFile(filePath, buffer);\n return { relativePath: safeName, size: buffer.length };\n }\n\n resolveAttachmentPath(noteId: string, relativePath: string): string {\n return join(resolveNoteMediaDir(noteId), relativePath);\n }\n\n async deleteAttachmentFile(noteId: string, relativePath: string): Promise<void> {\n const filePath = this.resolveAttachmentPath(noteId, relativePath);\n await rm(filePath, { force: true }).catch((err) => {\n log.warn({ err, noteId, relativePath }, 'Failed to remove note attachment file');\n });\n }\n\n async saveSnapshot(note: Note, trigger: SnapshotTrigger): Promise<void> {\n const historyDir = resolveNoteHistoryDir(note.id);\n await mkdir(historyDir, { recursive: true });\n const snapshot: NoteSnapshot = {\n noteId: note.id,\n timestamp: Date.now(),\n trigger,\n title: note.title,\n text: note.text,\n blocks: note.blocks,\n tags: note.tags,\n kind: note.kind,\n status: note.status,\n };\n const filePath = join(historyDir, `${snapshot.timestamp}.json`);\n await writeTextAtomic(filePath, JSON.stringify(snapshot, null, 2));\n log.debug({ noteId: note.id, trigger, timestamp: snapshot.timestamp }, 'Snapshot saved');\n }\n\n async listSnapshots(noteId: string): Promise<NoteSnapshotEntry[]> {\n const historyDir = resolveNoteHistoryDir(noteId);\n let files: string[];\n try {\n files = await readdir(historyDir);\n } catch {\n return [];\n }\n const entries: NoteSnapshotEntry[] = [];\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n const timestamp = parseInt(file.slice(0, -'.json'.length), 10);\n if (!Number.isFinite(timestamp)) continue;\n try {\n const content = await readFile(join(historyDir, file), 'utf-8');\n const snapshot = JSON.parse(content) as NoteSnapshot;\n const rawText = snapshot.text ?? '';\n entries.push({\n timestamp: snapshot.timestamp,\n trigger: snapshot.trigger,\n snippet: rawText.slice(0, 80) || undefined,\n });\n } catch {\n log.debug({ noteId, file }, 'Skipped unreadable snapshot');\n }\n }\n entries.sort((a, b) => b.timestamp - a.timestamp);\n return entries;\n }\n\n async getSnapshot(noteId: string, timestamp: number): Promise<NoteSnapshot | null> {\n const filePath = join(resolveNoteHistoryDir(noteId), `${timestamp}.json`);\n try {\n const content = await readFile(filePath, 'utf-8');\n return JSON.parse(content) as NoteSnapshot;\n } catch {\n return null;\n }\n }\n\n async pruneSnapshots(noteId: string, maxCount: number): Promise<void> {\n const historyDir = resolveNoteHistoryDir(noteId);\n let files: string[];\n try {\n files = await readdir(historyDir);\n } catch {\n return;\n }\n const jsonFiles = files.filter((f) => f.endsWith('.json')).sort();\n if (jsonFiles.length <= maxCount) return;\n const toDelete = jsonFiles.slice(0, jsonFiles.length - maxCount);\n for (const file of toDelete) {\n await rm(join(historyDir, file), { force: true }).catch(() => undefined);\n }\n log.debug({ noteId, deleted: toDelete.length }, 'Pruned old snapshots');\n }\n\n async deleteAllSnapshots(noteId: string): Promise<void> {\n const historyDir = resolveNoteHistoryDir(noteId);\n await rm(historyDir, { recursive: true, force: true }).catch(() => undefined);\n }\n\n /** No-op: SQLite writes are synchronous. Kept for API compatibility with tests. */\n async flush(): Promise<void> {}\n}\n\nexport { buildNoteIndexMeta };\n"],"mappings":"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"}
1
+ {"version":3,"file":"store.js","names":[],"sources":["../../../src/notes/store.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { readFile, mkdir, writeFile, rm, readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { writeTextAtomic } from '../infra/write-file-atomic.js';\nimport { createLogger } from '../utils/logger.js';\nimport {\n deleteNoteRecord,\n getNoteRecord,\n listNoteRecords,\n requireXopcDatabase,\n upsertNoteRecord,\n} from '../storage/sqlite/index.js';\nimport { buildNoteIndexMeta } from './note-index-meta.js';\nimport { resolveNoteMediaDir, resolveNoteHistoryDir } from './paths.js';\nimport type {\n Note,\n NoteIndexEntry,\n NoteSnapshot,\n NoteSnapshotEntry,\n NotesListQuery,\n SnapshotTrigger,\n} from './types.js';\n\nconst log = createLogger('NotesStore');\n\nexport class NotesStore {\n private initialized = false;\n\n async initialize(): Promise<void> {\n if (this.initialized) return;\n requireXopcDatabase();\n this.initialized = true;\n log.debug('NotesStore initialized');\n }\n\n async addNote(note: Note): Promise<void> {\n requireXopcDatabase();\n upsertNoteRecord(note);\n }\n\n async getNote(id: string): Promise<Note | null> {\n requireXopcDatabase();\n return getNoteRecord(id);\n }\n\n async updateNote(id: string, patch: Partial<Note>): Promise<Note | null> {\n const existing = await this.getNote(id);\n if (!existing) return null;\n\n const updated: Note = {\n ...existing,\n ...patch,\n id: existing.id,\n createdAt: existing.createdAt,\n updatedAt: Date.now(),\n };\n\n requireXopcDatabase();\n upsertNoteRecord(updated);\n return updated;\n }\n\n async deleteNote(id: string): Promise<boolean> {\n requireXopcDatabase();\n const deleted = deleteNoteRecord(id);\n if (!deleted) {\n return false;\n }\n\n const mediaDir = resolveNoteMediaDir(id);\n await rm(mediaDir, { recursive: true, force: true }).catch(() => undefined);\n return true;\n }\n\n async listNotes(query: NotesListQuery = {}): Promise<{\n items: NoteIndexEntry[];\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n }> {\n requireXopcDatabase();\n return listNoteRecords(query);\n }\n\n async saveAttachment(\n noteId: string,\n fileName: string,\n buffer: Buffer,\n ): Promise<{ relativePath: string; size: number }> {\n const mediaDir = resolveNoteMediaDir(noteId);\n await mkdir(mediaDir, { recursive: true });\n const safeName = `${randomUUID().slice(0, 8)}_${fileName.replace(/[^a-zA-Z0-9._-]/g, '_')}`;\n const filePath = join(mediaDir, safeName);\n await writeFile(filePath, buffer);\n return { relativePath: safeName, size: buffer.length };\n }\n\n resolveAttachmentPath(noteId: string, relativePath: string): string {\n return join(resolveNoteMediaDir(noteId), relativePath);\n }\n\n async deleteAttachmentFile(noteId: string, relativePath: string): Promise<void> {\n const filePath = this.resolveAttachmentPath(noteId, relativePath);\n await rm(filePath, { force: true }).catch((err) => {\n log.warn({ err, noteId, relativePath }, 'Failed to remove note attachment file');\n });\n }\n\n async saveSnapshot(note: Note, trigger: SnapshotTrigger): Promise<void> {\n const historyDir = resolveNoteHistoryDir(note.id);\n await mkdir(historyDir, { recursive: true });\n const snapshot: NoteSnapshot = {\n noteId: note.id,\n timestamp: Date.now(),\n trigger,\n title: note.title,\n markdown: note.markdown,\n tags: note.tags,\n kind: note.kind,\n status: note.status,\n };\n const filePath = join(historyDir, `${snapshot.timestamp}.json`);\n await writeTextAtomic(filePath, JSON.stringify(snapshot, null, 2));\n log.debug({ noteId: note.id, trigger, timestamp: snapshot.timestamp }, 'Snapshot saved');\n }\n\n async listSnapshots(noteId: string): Promise<NoteSnapshotEntry[]> {\n const historyDir = resolveNoteHistoryDir(noteId);\n let files: string[];\n try {\n files = await readdir(historyDir);\n } catch {\n return [];\n }\n const entries: NoteSnapshotEntry[] = [];\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n const timestamp = parseInt(file.slice(0, -'.json'.length), 10);\n if (!Number.isFinite(timestamp)) continue;\n try {\n const content = await readFile(join(historyDir, file), 'utf-8');\n const snapshot = JSON.parse(content) as NoteSnapshot;\n const rawText = snapshot.markdown ?? '';\n entries.push({\n timestamp: snapshot.timestamp,\n trigger: snapshot.trigger,\n snippet: rawText.slice(0, 80) || undefined,\n });\n } catch {\n log.debug({ noteId, file }, 'Skipped unreadable snapshot');\n }\n }\n entries.sort((a, b) => b.timestamp - a.timestamp);\n return entries;\n }\n\n async getSnapshot(noteId: string, timestamp: number): Promise<NoteSnapshot | null> {\n const filePath = join(resolveNoteHistoryDir(noteId), `${timestamp}.json`);\n try {\n const content = await readFile(filePath, 'utf-8');\n return JSON.parse(content) as NoteSnapshot;\n } catch {\n return null;\n }\n }\n\n async pruneSnapshots(noteId: string, maxCount: number): Promise<void> {\n const historyDir = resolveNoteHistoryDir(noteId);\n let files: string[];\n try {\n files = await readdir(historyDir);\n } catch {\n return;\n }\n const jsonFiles = files.filter((f) => f.endsWith('.json')).sort();\n if (jsonFiles.length <= maxCount) return;\n const toDelete = jsonFiles.slice(0, jsonFiles.length - maxCount);\n for (const file of toDelete) {\n await rm(join(historyDir, file), { force: true }).catch(() => undefined);\n }\n log.debug({ noteId, deleted: toDelete.length }, 'Pruned old snapshots');\n }\n\n async deleteAllSnapshots(noteId: string): Promise<void> {\n const historyDir = resolveNoteHistoryDir(noteId);\n await rm(historyDir, { recursive: true, force: true }).catch(() => undefined);\n }\n\n /** No-op: SQLite writes are synchronous. Kept for API compatibility with tests. */\n async flush(): Promise<void> {}\n}\n\nexport { buildNoteIndexMeta };\n"],"mappings":"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"}
@@ -1,45 +1,30 @@
1
1
  export type NoteKind = 'thought' | 'todo' | 'voice' | 'media' | 'bookmark' | 'mixed' | 'task';
2
2
  export type NoteStatus = 'inbox' | 'processed' | 'archived' | 'trashed';
3
3
  export type CaptureChannel = 'app' | 'web' | 'electron' | 'tui' | 'telegram' | 'wechat' | 'feishu';
4
- export type NoteBlockType = 'paragraph' | 'heading' | 'todo' | 'bulletList' | 'numberedList' | 'quote' | 'code' | 'divider' | 'image' | 'aiSuggestion';
5
- export interface BaseNoteBlock {
6
- id: string;
7
- type: NoteBlockType;
8
- createdAt: number;
9
- updatedAt: number;
10
- }
11
- export interface TextNoteBlock extends BaseNoteBlock {
12
- type: 'paragraph' | 'heading' | 'bulletList' | 'numberedList' | 'quote' | 'code' | 'aiSuggestion';
13
- text: string;
14
- level?: 1 | 2 | 3;
15
- indent?: number;
16
- }
17
- export interface TodoNoteBlock extends BaseNoteBlock {
18
- type: 'todo';
19
- text: string;
20
- checked: boolean;
21
- }
22
- export interface DividerNoteBlock extends BaseNoteBlock {
23
- type: 'divider';
24
- }
25
- export interface ImageNoteBlock extends BaseNoteBlock {
26
- type: 'image';
27
- attachmentId: string;
28
- alt?: string;
29
- width?: number;
30
- }
31
- export type NoteBlock = TextNoteBlock | TodoNoteBlock | DividerNoteBlock | ImageNoteBlock;
32
4
  export type NotePatchOperation = {
33
- type: 'replaceBlocks';
34
- blocks: NoteBlock[];
5
+ type: 'replaceRange';
6
+ from: number;
7
+ to: number;
8
+ markdown: string;
9
+ } | {
10
+ type: 'insertAt';
11
+ offset: number;
12
+ markdown: string;
13
+ } | {
14
+ type: 'replaceSection';
15
+ sectionId: string;
16
+ markdown: string;
17
+ } | {
18
+ type: 'appendSection';
19
+ heading: string;
20
+ markdown: string;
35
21
  } | {
36
- type: 'insertBlocksAfter';
37
- afterBlockId: string;
38
- blocks: NoteBlock[];
22
+ type: 'prependSection';
23
+ heading: string;
24
+ markdown: string;
39
25
  } | {
40
- type: 'updateBlock';
41
- blockId: string;
42
- patch: Partial<NoteBlock>;
26
+ type: 'updateFrontmatter';
27
+ patch: Record<string, unknown>;
43
28
  } | {
44
29
  type: 'updateMetadata';
45
30
  title?: string;
@@ -117,9 +102,7 @@ export interface NoteTaskMeta {
117
102
  done: boolean;
118
103
  dueAt?: number;
119
104
  priority?: 'high' | 'medium' | 'low';
120
- /** Session key of the thread that created this task. */
121
105
  sourceSessionKey?: string;
122
- /** Note id of the page this task was extracted from. */
123
106
  sourceNoteId?: string;
124
107
  }
125
108
  export interface Note {
@@ -127,8 +110,8 @@ export interface Note {
127
110
  title?: string;
128
111
  kind: NoteKind;
129
112
  status: NoteStatus;
130
- text?: string;
131
- blocks?: NoteBlock[];
113
+ /** Canonical note body. Markdown is the only content truth. */
114
+ markdown: string;
132
115
  attachments?: NoteAttachment[];
133
116
  createdAt: number;
134
117
  updatedAt: number;
@@ -139,11 +122,8 @@ export interface Note {
139
122
  pinned?: boolean;
140
123
  localVersion?: number;
141
124
  remoteVersion?: number;
142
- /** Space grouping — null means ungrouped (appears in root). */
143
125
  groupId?: string;
144
- /** Last time the user explicitly opened this note. */
145
126
  lastOpenedAt?: number;
146
- /** Task lifecycle metadata (only when kind === 'task'). */
147
127
  taskMeta?: NoteTaskMeta;
148
128
  }
149
129
  export interface NoteIndexEntry {
@@ -156,22 +136,18 @@ export interface NoteIndexEntry {
156
136
  pinned?: boolean;
157
137
  tags?: string[];
158
138
  snippet?: string;
159
- /** First image attachment id for list thumbnails. */
160
139
  coverAttachmentId?: string;
161
- /** First audio attachment id for inline voice playback. */
162
140
  voiceAttachmentId?: string;
163
- /** Duration in seconds of the voice attachment (when available). */
164
141
  voiceDurationSec?: number;
165
- /** Lowercased attachment file names for list search. */
166
142
  attachmentNames?: string[];
167
- /** Space group id. */
168
143
  groupId?: string;
169
- /** Last opened timestamp for "continue" rail. */
170
144
  lastOpenedAt?: number;
171
- /** Task done flag (only when kind === 'task'). */
172
145
  taskDone?: boolean;
173
- /** Task due timestamp (only when kind === 'task'). */
174
146
  taskDueAt?: number;
147
+ headingCount?: number;
148
+ taskCount?: number;
149
+ uncheckedTaskCount?: number;
150
+ linkCount?: number;
175
151
  }
176
152
  export interface NotesIndexFile {
177
153
  version: number;
@@ -183,8 +159,7 @@ export interface NoteSnapshot {
183
159
  timestamp: number;
184
160
  trigger: SnapshotTrigger;
185
161
  title?: string;
186
- text?: string;
187
- blocks?: NoteBlock[];
162
+ markdown: string;
188
163
  tags?: string[];
189
164
  kind: NoteKind;
190
165
  status: NoteStatus;
@@ -204,15 +179,12 @@ export interface NotesListQuery {
204
179
  offset?: number;
205
180
  sortBy?: 'createdAt' | 'updatedAt' | 'lastOpenedAt';
206
181
  sortOrder?: 'asc' | 'desc';
207
- /** Filter by space group id. Use `'ungrouped'` for root-level notes. */
208
182
  groupId?: string;
209
- /** Filter to only task notes with done === false. */
210
183
  pendingTasksOnly?: boolean;
211
184
  }
212
185
  export interface CreateNoteParams {
213
186
  title?: string;
214
- text?: string;
215
- blocks?: NoteBlock[];
187
+ markdown?: string;
216
188
  kind?: NoteKind;
217
189
  tags?: string[];
218
190
  capturedVia: CaptureSource;
@@ -220,7 +192,6 @@ export interface CreateNoteParams {
220
192
  groupId?: string;
221
193
  taskMeta?: NoteTaskMeta;
222
194
  }
223
- /** A lightweight space group (persisted as a note with kind='mixed', used for grouping). */
224
195
  export interface NoteGroup {
225
196
  id: string;
226
197
  name: string;
@@ -1,7 +1,7 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
- import { dirname, join } from "node:path";
4
3
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
4
+ import { dirname, join } from "node:path";
5
5
  //#region src/providers/auth-runtime/auth-profile-store.ts
6
6
  /**
7
7
  * {@link AuthProfileStore} implementations.
@@ -61,7 +61,7 @@ export declare function providerSupportsApiKey(provider: string): boolean;
61
61
  * Get a default model reference.
62
62
  * Priority:
63
63
  * 1. Explicitly configured model in agents.defaults.model (if set and available)
64
- * 2. Default fallback: deepseek/deepseek-v4-flash
64
+ * 2. Default fallback: openai/gpt-5.5
65
65
  */
66
66
  export declare function getDefaultModel(config?: Config | null | undefined): Promise<string>;
67
67
  /**
@@ -69,8 +69,8 @@ export declare function getDefaultModel(config?: Config | null | undefined): Pro
69
69
  * Uses catalog/registry only (no async credential checks).
70
70
  *
71
71
  * When no model is explicitly configured, returns the preferred default
72
- * (`deepseek/deepseek-v4-flash`) rather than picking an arbitrary first
73
- * model from the full catalog.
72
+ * (`openai/gpt-5.5`) rather than picking an arbitrary first model from the
73
+ * full catalog.
74
74
  */
75
75
  export declare function getDefaultModelSync(config?: Config | null | undefined): string;
76
76
  export { ModelRegistry, getModelRegistry, resetModelRegistry, prewarmModelRegistry } from './model-registry.js';
@@ -1,8 +1,8 @@
1
1
  import { __esmMin, __exportAll } from "../../_virtual/_rolldown/runtime.js";
2
- import { hasProviderAuthOnDiskSync, init_sync_provider_auth } from "../auth/sync-provider-auth.js";
3
2
  import { PROVIDER_ENV_MAP, getApiKeyFromEnv, init_env_keys } from "./env-keys.js";
4
- import { ModelRegistry, getModelRegistry, init_model_registry, prewarmModelRegistry, resetModelRegistry } from "./model-registry.js";
5
3
  import { CredentialResolver, hasCredentials, init_credentials, resolveApiKey } from "../auth/credentials.js";
4
+ import { hasProviderAuthOnDiskSync, init_sync_provider_auth } from "../auth/sync-provider-auth.js";
5
+ import { ModelRegistry, getModelRegistry, init_model_registry, prewarmModelRegistry, resetModelRegistry } from "./model-registry.js";
6
6
  import { getProviderRegistry, init_plugin_registry } from "./plugin-registry.js";
7
7
  import { getModel, getModels, getProviders } from "@earendil-works/pi-ai";
8
8
  //#region src/providers/index.ts
@@ -38,6 +38,13 @@ var providers_exports = /* @__PURE__ */ __exportAll({
38
38
  resetModelRegistry: () => resetModelRegistry,
39
39
  resolveModel: () => resolveModel
40
40
  });
41
+ function normalizeProviderModel(model) {
42
+ if (model.provider === "openai-codex" && model.api === "openai-codex-responses") return {
43
+ ...model,
44
+ baseUrl: OPENAI_CODEX_CANONICAL_BASE_URL
45
+ };
46
+ return model;
47
+ }
41
48
  /** Map a plugin registry model to the pi-ai {@link Model} shape. */
42
49
  function pluginModelToModel(providerId, definition) {
43
50
  return {
@@ -80,7 +87,7 @@ function resolveModel(ref) {
80
87
  if (ref.includes("/")) {
81
88
  const [provider, modelId] = ref.split("/");
82
89
  const piAiModel = getModel(provider, modelId);
83
- if (piAiModel) return piAiModel;
90
+ if (piAiModel) return normalizeProviderModel(piAiModel);
84
91
  const plugin = getProviderRegistry().get(provider);
85
92
  if (plugin) {
86
93
  const pluginModel = plugin.models.find((m) => m.id === modelId);
@@ -90,7 +97,7 @@ function resolveModel(ref) {
90
97
  }
91
98
  for (const provider of getProviders()) try {
92
99
  const found = getModels(provider).find((m) => m.id === ref);
93
- if (found) return found;
100
+ if (found) return normalizeProviderModel(found);
94
101
  } catch {
95
102
  continue;
96
103
  }
@@ -102,7 +109,7 @@ function resolveModel(ref) {
102
109
  throw new Error(`Model not found: ${ref}. Use format: provider/model-id`);
103
110
  }
104
111
  function getModelsByProvider(provider) {
105
- const fromRegistry = getModelRegistry().getAll().filter((m) => m.provider === provider);
112
+ const fromRegistry = getModelRegistry().getAll().filter((m) => m.provider === provider).map(normalizeProviderModel);
106
113
  const plugin = getProviderRegistry().get(provider);
107
114
  if (!plugin) return fromRegistry;
108
115
  const pluginModels = plugin.models.map((m) => pluginModelToModel(provider, m));
@@ -191,7 +198,7 @@ async function getConfiguredProviders() {
191
198
  return configured;
192
199
  }
193
200
  function getAllModels() {
194
- const registryModels = getModelRegistry().getAll();
201
+ const registryModels = getModelRegistry().getAll().map(normalizeProviderModel);
195
202
  const pluginProviders = getProviderRegistry().listAll();
196
203
  if (pluginProviders.length === 0) return registryModels;
197
204
  const existingIds = new Set(registryModels.map((m) => `${m.provider}/${m.id}`));
@@ -245,7 +252,7 @@ function providerSupportsApiKey(provider) {
245
252
  * Get a default model reference.
246
253
  * Priority:
247
254
  * 1. Explicitly configured model in agents.defaults.model (if set and available)
248
- * 2. Default fallback: deepseek/deepseek-v4-flash
255
+ * 2. Default fallback: openai/gpt-5.5
249
256
  */
250
257
  async function getDefaultModel(config) {
251
258
  const defaultModel = config?.agents?.defaults?.model;
@@ -264,8 +271,8 @@ async function getDefaultModel(config) {
264
271
  * Uses catalog/registry only (no async credential checks).
265
272
  *
266
273
  * When no model is explicitly configured, returns the preferred default
267
- * (`deepseek/deepseek-v4-flash`) rather than picking an arbitrary first
268
- * model from the full catalog.
274
+ * (`openai/gpt-5.5`) rather than picking an arbitrary first model from the
275
+ * full catalog.
269
276
  */
270
277
  function getDefaultModelSync(config) {
271
278
  const defaultModel = config?.agents?.defaults?.model;
@@ -275,7 +282,7 @@ function getDefaultModelSync(config) {
275
282
  }
276
283
  return DEFAULT_FALLBACK_MODEL;
277
284
  }
278
- var EXTENSION_PROVIDER_BASE_URL, PROVIDER_META, DEFAULT_FALLBACK_MODEL;
285
+ var EXTENSION_PROVIDER_BASE_URL, OPENAI_CODEX_CANONICAL_BASE_URL, PROVIDER_META, DEFAULT_FALLBACK_MODEL;
279
286
  var init_providers = __esmMin((() => {
280
287
  init_model_registry();
281
288
  init_credentials();
@@ -283,14 +290,15 @@ var init_providers = __esmMin((() => {
283
290
  init_env_keys();
284
291
  init_plugin_registry();
285
292
  EXTENSION_PROVIDER_BASE_URL = "extension://provider-plugin";
293
+ OPENAI_CODEX_CANONICAL_BASE_URL = "https://chatgpt.com/backend-api/codex";
286
294
  PROVIDER_META = {
287
295
  "openai": {
288
- name: "OpenAI (GPT-4, o1, o3)",
296
+ name: "OpenAI",
289
297
  category: "common",
290
298
  supportsApiKey: true
291
299
  },
292
300
  "anthropic": {
293
- name: "Anthropic Claude",
301
+ name: "Anthropic",
294
302
  category: "common",
295
303
  supportsApiKey: true,
296
304
  supportsOAuth: true
@@ -301,12 +309,12 @@ var init_providers = __esmMin((() => {
301
309
  supportsApiKey: true
302
310
  },
303
311
  "google": {
304
- name: "Google Gemini",
312
+ name: "Google AI",
305
313
  category: "common",
306
314
  supportsApiKey: true
307
315
  },
308
316
  "groq": {
309
- name: "Groq (Fast Inference)",
317
+ name: "Groq",
310
318
  category: "common",
311
319
  supportsApiKey: true
312
320
  },
@@ -329,7 +337,7 @@ var init_providers = __esmMin((() => {
329
337
  supportsOAuth: true
330
338
  },
331
339
  "xai": {
332
- name: "xAI (Grok)",
340
+ name: "xAI",
333
341
  category: "specialty",
334
342
  supportsApiKey: true
335
343
  },
@@ -344,7 +352,7 @@ var init_providers = __esmMin((() => {
344
352
  supportsApiKey: true
345
353
  },
346
354
  "openrouter": {
347
- name: "OpenRouter (Multi-provider)",
355
+ name: "OpenRouter",
348
356
  category: "specialty",
349
357
  supportsApiKey: true
350
358
  },
@@ -470,7 +478,7 @@ var init_providers = __esmMin((() => {
470
478
  supportsApiKey: false
471
479
  }
472
480
  };
473
- DEFAULT_FALLBACK_MODEL = "deepseek/deepseek-v4-flash";
481
+ DEFAULT_FALLBACK_MODEL = "openai/gpt-5.5";
474
482
  }));
475
483
  //#endregion
476
484
  init_providers();