@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.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/feishu/src/transport/webhook/monitor.js +2 -2
- package/dist/extensions/feishu/src/transport/webhook/monitor.js.map +1 -1
- package/dist/extensions/feishu/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
- package/dist/extensions/telegram/src/inbound-processor.js +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/src/send-options.js +8 -5
- package/dist/extensions/telegram/src/send-options.js.map +1 -1
- package/dist/extensions/telegram/src/update-offset-store.js +1 -1
- package/dist/extensions/telegram/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +2 -2
- package/dist/extensions/weixin/src/auth/accounts.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/gateway/static/root/assets/{agents-u8cmUfGQ.js → agents-BwXkia_W.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-DF8m9cUE.js → apps-page-C5RmwmTT.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-BM3doRvi.js → channels-settings-tlOTdaXw.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-status-swr-ah4zWEIP.js → channels-status-swr-D4XjqwqC.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-api-DgMuL_2b.js → cron-api-DcmfGuj0.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-COfUPKfq.js → cron-page-CijJ4G6F.js} +1 -1
- package/dist/gateway/static/root/assets/{dist-Dzy3Q0ZH.js → dist-CWm8hTXZ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-kyxxefKh.js → extension-debug-page-BzYgTkS9.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BVbCBHoI.js → extension-page-BmTZH6gL.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-t1lb2A7v.js → extension-settings-page-CyJk_G64.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-drJUxxKP.js → fetch-CMoWY2Si.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-6Vo1Yga4.js → field-primitives-C4GpxsDo.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-BF3psu4O.js → heartbeat-config-api-CLD0Gpi3.js} +1 -1
- package/dist/gateway/static/root/assets/index-0HmunJW9.js +4845 -0
- package/dist/gateway/static/root/assets/index-Bk75Phrd.css +1 -0
- package/dist/gateway/static/root/assets/{logs-page-BTVPXcHV.js → logs-page-BjdQjHwk.js} +1 -1
- package/dist/gateway/static/root/assets/{note-detail-page-DqSAg_5Z.js → note-detail-page-8Er4197b.js} +2 -2
- package/dist/gateway/static/root/assets/{note-time-FSOjchic.js → note-time-CF3vf1jm.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-DkRX7BE2.js → notes-page-BBnTh0uI.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-Khdw35Zk.js → sessions-page-B0riYK7j.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-advanced-gate-DspC8oEm.js → settings-advanced-gate-DiP_WHu_.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-DuxvUuur.js → settings-form-section-C7qA7y0J.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-DN8JBZ8F.js → settings-page-1ZPhcCZ9.js} +2 -2
- package/dist/gateway/static/root/assets/share-preview-page-Tvr5Mtq5.js +2 -0
- package/dist/gateway/static/root/assets/{skills-page-ByYT0fXZ.js → skills-page-BQ1hllKD.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-B6KXPHgK.js → theme-store-HTvJlFLL.js} +1 -1
- package/dist/gateway/static/root/assets/url-F3_D_6zZ.js +3 -0
- package/dist/gateway/static/root/assets/{utils-DK_1H47k.js → utils-CPr3FBh2.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-BYN2EIMs.js → voice-api-key-field-BkbDl6dH.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-page.utils-Bi19YNTr.js → workflow-page.utils-CeBkAjP7.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-DP57FEKW.js → workflows-page-D059ysoF.js} +1 -1
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +7 -7
- package/dist/src/agent/agent-scope.js +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
- package/dist/src/agent/context/workspace-seed.js +2 -2
- package/dist/src/agent/context/workspace-state.js +1 -1
- package/dist/src/agent/goals/goal-run-store.js +4 -4
- package/dist/src/agent/goals/persistent-goal-service.js +1 -1
- package/dist/src/agent/goals/post-turn.js +2 -2
- package/dist/src/agent/image/load-image-media.js +2 -2
- package/dist/src/agent/inbound/attachment-pipeline.js +2 -2
- package/dist/src/agent/inbound/attachment-pipeline.js.map +1 -1
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +2 -2
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
- package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/memory-flush.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +2 -2
- package/dist/src/agent/service.js +4 -4
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/config.js +1 -1
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +2 -2
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/send-media.js +2 -3
- package/dist/src/agent/tools/send-media.js.map +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/workflow-tool.js +1 -1
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/agent/workflow/catalog.js +1 -1
- package/dist/src/auth/credentials.d.ts +7 -0
- package/dist/src/auth/credentials.js +37 -4
- package/dist/src/auth/credentials.js.map +1 -1
- package/dist/src/auth/index.d.ts +1 -1
- package/dist/src/auth/index.js.map +1 -1
- package/dist/src/auth/oauth/github-copilot.d.ts +1 -1
- package/dist/src/auth/oauth/google-antigravity.d.ts +1 -3
- package/dist/src/auth/oauth/google-antigravity.js +1 -1
- package/dist/src/auth/oauth/google-gemini-cli.d.ts +1 -3
- package/dist/src/auth/oauth/google-gemini-cli.js +1 -1
- package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-antigravity.js +3 -5
- package/dist/src/auth/oauth/google-oauth/google-antigravity.js.map +1 -0
- package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-gemini-cli.js +4 -5
- package/dist/src/auth/oauth/google-oauth/google-gemini-cli.js.map +1 -0
- package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/oauth-page.js +12 -4
- package/dist/src/auth/oauth/google-oauth/oauth-page.js.map +1 -0
- package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/pkce.d.ts +1 -1
- package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/pkce.js +2 -2
- package/dist/src/auth/oauth/google-oauth/pkce.js.map +1 -0
- package/dist/src/auth/oauth/index.js +2 -2
- package/dist/src/auth/oauth/kimi-coding.d.ts +1 -1
- package/dist/src/auth/oauth/kimi-coding.js +1 -1
- package/dist/src/auth/oauth/kimi-coding.js.map +1 -1
- package/dist/src/auth/oauth/minimax-cn.js +1 -1
- package/dist/src/auth/oauth/minimax-cn.js.map +1 -1
- package/dist/src/auth/oauth/minimax.js +1 -1
- package/dist/src/auth/oauth/minimax.js.map +1 -1
- package/dist/src/auth/oauth/openai-codex.d.ts +7 -2
- package/dist/src/auth/oauth/openai-codex.js +318 -1
- package/dist/src/auth/oauth/openai-codex.js.map +1 -0
- package/dist/src/auth/profiles/store.js +4 -3
- package/dist/src/auth/profiles/store.js.map +1 -1
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/cache-dir-policy.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +2 -2
- package/dist/src/browser/providers/browser-ext-install.js +3 -3
- package/dist/src/browser/providers/cloakbrowser.js +4 -4
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/channels/attachments/attachment-classifiers.d.ts +1 -0
- package/dist/src/channels/attachments/attachment-classifiers.js +13 -2
- package/dist/src/channels/attachments/attachment-classifiers.js.map +1 -1
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +1 -1
- package/dist/src/channels/pairing/pairing-store.js +2 -2
- package/dist/src/chat-commands/agent-edit.js +2 -2
- package/dist/src/chat-commands/builtins/config.js +2 -2
- package/dist/src/chat-commands/builtins/model.js +2 -2
- package/dist/src/chat-commands/builtins/model.js.map +1 -1
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/cli/command-manifest.js +1 -1
- package/dist/src/cli/command-manifest.js.map +1 -1
- package/dist/src/cli/commands/auth.js +39 -51
- package/dist/src/cli/commands/auth.js.map +1 -1
- package/dist/src/cli/commands/config.js +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/extension-pack.js +1 -1
- package/dist/src/cli/commands/gateway/logs.js +1 -1
- package/dist/src/cli/commands/image.js +1 -1
- package/dist/src/cli/commands/init.js +3 -3
- package/dist/src/cli/commands/models.js +189 -54
- package/dist/src/cli/commands/models.js.map +1 -1
- package/dist/src/cli/commands/onboard/model.d.ts +1 -4
- package/dist/src/cli/commands/onboard/model.js +253 -183
- package/dist/src/cli/commands/onboard/model.js.map +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -2
- package/dist/src/cli/utils/oauth-login.d.ts +17 -0
- package/dist/src/cli/utils/oauth-login.js +93 -0
- package/dist/src/cli/utils/oauth-login.js.map +1 -0
- package/dist/src/cli/utils/oauth-providers.js +2 -2
- package/dist/src/commands/agents.config.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +5 -5
- package/dist/src/config/loader.js +2 -2
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/paths-state.js +1 -1
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/daemon/constants.js +1 -1
- package/dist/src/daemon/install-plan.js +2 -2
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/schtasks.js +2 -2
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +1 -1
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/loader.js +1 -1
- package/dist/src/extensions/lockfile.js +2 -2
- package/dist/src/extensions/update.js +1 -1
- package/dist/src/gateway/agents-admin.js +3 -3
- package/dist/src/gateway/file-path-classifier.js +2 -2
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +2 -2
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/oauth-async.js +3 -3
- package/dist/src/gateway/hono/oauth.js +3 -3
- package/dist/src/gateway/hono/routes/agents.js +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +1 -1
- package/dist/src/gateway/hono/routes/host-fs.js +2 -2
- package/dist/src/gateway/hono/routes/models.js +26 -6
- package/dist/src/gateway/hono/routes/models.js.map +1 -1
- package/dist/src/gateway/hono/routes/notes.js +9 -22
- package/dist/src/gateway/hono/routes/notes.js.map +1 -1
- package/dist/src/gateway/hono/routes/shares.js +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +2 -2
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/ports.js +1 -1
- package/dist/src/gateway/service/agent-runner.js +2 -2
- package/dist/src/gateway/service/marketplace-service.js +2 -2
- package/dist/src/gateway/service.js +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/infra/brew.js +1 -1
- package/dist/src/infra/package-json.js +1 -1
- package/dist/src/infra/package-update-steps.js +1 -1
- package/dist/src/infra/path-env.js +2 -2
- package/dist/src/infra/restart.js +2 -2
- package/dist/src/infra/stable-node-path.js +1 -1
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-global.js +1 -1
- package/dist/src/infra/update-lock.js +3 -3
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +2 -2
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/media/store.js +4 -1
- package/dist/src/media/store.js.map +1 -1
- package/dist/src/notes/note-attachment-sync.d.ts +2 -3
- package/dist/src/notes/note-attachment-sync.js +2 -27
- package/dist/src/notes/note-attachment-sync.js.map +1 -1
- package/dist/src/notes/note-index-meta.d.ts +6 -2
- package/dist/src/notes/note-index-meta.js +11 -16
- package/dist/src/notes/note-index-meta.js.map +1 -1
- package/dist/src/notes/note-markdown.d.ts +61 -0
- package/dist/src/notes/note-markdown.js +177 -0
- package/dist/src/notes/note-markdown.js.map +1 -0
- package/dist/src/notes/service.d.ts +9 -7
- package/dist/src/notes/service.js +163 -312
- package/dist/src/notes/service.js.map +1 -1
- package/dist/src/notes/store.js +4 -5
- package/dist/src/notes/store.js.map +1 -1
- package/dist/src/notes/types.d.ts +29 -58
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.d.ts +3 -3
- package/dist/src/providers/index.js +25 -17
- package/dist/src/providers/index.js.map +1 -1
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/providers/presentation.d.ts +34 -0
- package/dist/src/providers/presentation.js +162 -0
- package/dist/src/providers/presentation.js.map +1 -0
- package/dist/src/session/init-session-turn.js +2 -2
- package/dist/src/session/resolve-session.js +3 -3
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/store.js +2 -2
- package/dist/src/share/share-auto.js +2 -2
- package/dist/src/share/share-store.js +3 -3
- package/dist/src/share/share-thumbnail.js +2 -2
- package/dist/src/share/share-zip.js +1 -1
- package/dist/src/share/site-share-store.js +3 -3
- package/dist/src/share/site-static-serve.js +1 -1
- package/dist/src/storage/sqlite/connection.js +2 -2
- package/dist/src/storage/sqlite/memory-index-repository.js +2 -2
- package/dist/src/storage/sqlite/migrations/003_add_note_markdown_meta.sql +4 -0
- package/dist/src/storage/sqlite/migrations/discover.js +1 -1
- package/dist/src/storage/sqlite/migrations/runner.d.ts +2 -2
- package/dist/src/storage/sqlite/migrations/runner.js +5 -5
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +2 -2
- package/dist/src/storage/sqlite/notes-repository.js +18 -6
- package/dist/src/storage/sqlite/notes-repository.js.map +1 -1
- package/dist/src/storage/sqlite/schema.js +4 -4
- package/dist/src/storage/sqlite/schema.sql +5 -1
- package/dist/src/tui/clipboard-image.js +3 -3
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-keybindings-file.js +1 -1
- package/dist/src/tui/tui-scoped-models.js +2 -2
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui.js +3 -3
- package/dist/src/tunnel/frpc-binary.js +3 -3
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +2 -2
- package/dist/src/workflows/store/event-store.js +1 -1
- package/dist/src/workflows/store/run-store.js +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/index-DjNDHzwG.css +0 -1
- package/dist/gateway/static/root/assets/index-WAyKAilR.js +0 -4840
- package/dist/gateway/static/root/assets/share-preview-page-UNAcbiMb.js +0 -2
- package/dist/gateway/static/root/assets/url-q28QhI7l.js +0 -3
- package/dist/src/auth/oauth/vendor-pi-google/google-antigravity.js.map +0 -1
- package/dist/src/auth/oauth/vendor-pi-google/google-gemini-cli.js.map +0 -1
- package/dist/src/auth/oauth/vendor-pi-google/oauth-page.js.map +0 -1
- package/dist/src/auth/oauth/vendor-pi-google/pkce.js.map +0 -1
- /package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-antigravity.d.ts +0 -0
- /package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/google-gemini-cli.d.ts +0 -0
- /package/dist/src/auth/oauth/{vendor-pi-google → google-oauth}/oauth-page.d.ts +0 -0
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { resolveModelsJsonPath } from "../../../config/paths.js";
|
|
2
|
+
import { CredentialResolver, init_credentials } from "../../../auth/credentials.js";
|
|
2
3
|
import { init_resolve_config_value, testApiKeyResolution } from "../../../config/resolve-config-value.js";
|
|
3
4
|
import { init_models_json, loadModelsJson, saveModelsJson, validateModelsConfig } from "../../../config/models-json.js";
|
|
4
5
|
import { getModelRegistry } from "../../../providers/model-registry.js";
|
|
5
|
-
import { CredentialResolver, init_credentials } from "../../../auth/credentials.js";
|
|
6
6
|
import { getProviderRegistry, init_plugin_registry } from "../../../providers/plugin-registry.js";
|
|
7
7
|
import { PROVIDER_META, getAllModels, getAllProviders, getAvailableModels, getProviderAuthState, init_providers, isProviderConfigured } from "../../../providers/index.js";
|
|
8
8
|
import { getImageGenerationProvider } from "../../../agent/image/generation/provider-registry.js";
|
|
9
9
|
import { listImageGenerationProvidersSummary } from "../../../agent/image/generation/runtime.js";
|
|
10
10
|
import { respondStartupUnavailable } from "../lib/startup-unavailable.js";
|
|
11
|
+
import { getProviderHint, getRecommendedModelsForProvider, isRecommendedModel, sortModelsForPicker, sortProvidersForPicker } from "../../../providers/presentation.js";
|
|
11
12
|
//#region src/gateway/hono/routes/models.ts
|
|
12
13
|
init_models_json();
|
|
13
14
|
init_resolve_config_value();
|
|
@@ -53,6 +54,7 @@ function mapPluginModel(providerId, model, available) {
|
|
|
53
54
|
output: model.pricing?.output ?? 0
|
|
54
55
|
},
|
|
55
56
|
available,
|
|
57
|
+
recommended: isRecommendedModel(providerId, model.id),
|
|
56
58
|
source: "extension"
|
|
57
59
|
};
|
|
58
60
|
}
|
|
@@ -126,7 +128,7 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
126
128
|
authenticated.get("/api/models", async (c) => {
|
|
127
129
|
if (!service.isGatewayReady()) return respondStartupUnavailable(c, "models.list");
|
|
128
130
|
const pluginRegistry = getProviderRegistry();
|
|
129
|
-
const models = (await getAvailableModels()).map((m) => ({
|
|
131
|
+
const models = sortModelsForPicker(await getAvailableModels()).map((m) => ({
|
|
130
132
|
id: `${m.provider}/${m.id}`,
|
|
131
133
|
name: m.name,
|
|
132
134
|
provider: m.provider,
|
|
@@ -134,6 +136,7 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
134
136
|
maxTokens: m.maxTokens ?? 4096,
|
|
135
137
|
reasoning: m.reasoning ?? false,
|
|
136
138
|
vision: m.input?.includes("image") ?? false,
|
|
139
|
+
recommended: isRecommendedModel(m.provider, m.id),
|
|
137
140
|
cost: {
|
|
138
141
|
input: m.cost?.input ?? 0,
|
|
139
142
|
output: m.cost?.output ?? 0
|
|
@@ -149,8 +152,9 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
149
152
|
}
|
|
150
153
|
}
|
|
151
154
|
models.sort((a, b) => {
|
|
155
|
+
if (a.recommended !== b.recommended) return a.recommended ? -1 : 1;
|
|
152
156
|
if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);
|
|
153
|
-
return a.name.localeCompare(b.name);
|
|
157
|
+
return a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
|
|
154
158
|
});
|
|
155
159
|
return c.json({
|
|
156
160
|
ok: true,
|
|
@@ -230,7 +234,7 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
230
234
|
const allModels = getAllModels();
|
|
231
235
|
const availableModels = await getAvailableModels();
|
|
232
236
|
const configured = new Set(availableModels.map((m) => `${m.provider}/${m.id}`));
|
|
233
|
-
const models = allModels.map((m) => ({
|
|
237
|
+
const models = sortModelsForPicker(allModels).map((m) => ({
|
|
234
238
|
id: `${m.provider}/${m.id}`,
|
|
235
239
|
name: m.name,
|
|
236
240
|
provider: m.provider,
|
|
@@ -238,6 +242,7 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
238
242
|
maxTokens: m.maxTokens ?? 4096,
|
|
239
243
|
reasoning: m.reasoning ?? false,
|
|
240
244
|
vision: m.input?.includes("image") ?? false,
|
|
245
|
+
recommended: isRecommendedModel(m.provider, m.id),
|
|
241
246
|
cost: {
|
|
242
247
|
input: m.cost?.input ?? 0,
|
|
243
248
|
output: m.cost?.output ?? 0
|
|
@@ -254,8 +259,9 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
254
259
|
}
|
|
255
260
|
}
|
|
256
261
|
models.sort((a, b) => {
|
|
262
|
+
if (a.recommended !== b.recommended) return a.recommended ? -1 : 1;
|
|
257
263
|
if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);
|
|
258
|
-
return a.name.localeCompare(b.name);
|
|
264
|
+
return a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
|
|
259
265
|
});
|
|
260
266
|
return c.json({
|
|
261
267
|
ok: true,
|
|
@@ -263,7 +269,7 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
263
269
|
});
|
|
264
270
|
});
|
|
265
271
|
authenticated.get("/api/providers/meta", async (c) => {
|
|
266
|
-
const providers = getAllProviders();
|
|
272
|
+
const providers = sortProvidersForPicker(getAllProviders());
|
|
267
273
|
const pluginRegistry = getProviderRegistry();
|
|
268
274
|
const meta = await Promise.all(providers.map(async (provider) => {
|
|
269
275
|
const plugin = pluginRegistry.get(provider);
|
|
@@ -277,6 +283,17 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
277
283
|
supportsOAuth: plugin ? false : PROVIDER_META[provider]?.supportsOAuth ?? false,
|
|
278
284
|
supportsApiKey: plugin ? false : PROVIDER_META[provider]?.supportsApiKey ?? true,
|
|
279
285
|
configured,
|
|
286
|
+
onboardingFeatured: [
|
|
287
|
+
"openai",
|
|
288
|
+
"anthropic",
|
|
289
|
+
"xai",
|
|
290
|
+
"google",
|
|
291
|
+
"openrouter",
|
|
292
|
+
"deepseek"
|
|
293
|
+
].includes(provider),
|
|
294
|
+
recommendedModels: getRecommendedModelsForProvider(provider),
|
|
295
|
+
modelCount: getAllModels().filter((m) => m.provider === provider).length,
|
|
296
|
+
...getProviderHint(provider) ? { hint: getProviderHint(provider) } : {},
|
|
280
297
|
activeKeySource: authState.authMode,
|
|
281
298
|
authMode: authState.authMode,
|
|
282
299
|
authStatus: authState.authStatus,
|
|
@@ -295,6 +312,9 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
295
312
|
supportsOAuth: false,
|
|
296
313
|
supportsApiKey: false,
|
|
297
314
|
configured: true,
|
|
315
|
+
onboardingFeatured: false,
|
|
316
|
+
recommendedModels: getRecommendedModelsForProvider(plugin.id),
|
|
317
|
+
modelCount: plugin.models.length,
|
|
298
318
|
activeKeySource: "extension",
|
|
299
319
|
authMode: "extension",
|
|
300
320
|
authStatus: "connected",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.js","names":["getModelsJsonPath"],"sources":["../../../../../src/gateway/hono/routes/models.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport {\n getModelsJsonPath,\n loadModelsJson,\n saveModelsJson,\n validateModelsConfig,\n} from '../../../config/models-json.js';\nimport type { Config } from '../../../config/schema.js';\nimport { testApiKeyResolution } from '../../../config/resolve-config-value.js';\nimport {\n getImageGenerationProvider,\n listImageGenerationProvidersSummary,\n} from '../../../agent/image/generation/runtime.js';\nimport {\n EXTENSION_PROVIDER_BASE_URL,\n getAllModels,\n getAvailableModels,\n getModelRegistry,\n getAllProviders,\n getProviderAuthState,\n isProviderConfigured,\n PROVIDER_META,\n} from '../../../providers/index.js';\nimport { CredentialResolver } from '../../../auth/credentials.js';\nimport { getProviderRegistry } from '../../../providers/plugin-registry.js';\nimport type { ProviderModelDefinition } from '../../../extensions/types/providers.js';\nimport type { GatewayService } from '../../service.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\nimport { respondStartupUnavailable } from '../lib/startup-unavailable.js';\n\nfunction readModelsJsonProviderApiKey(providerId: string): string | undefined {\n const { config } = loadModelsJson(getModelsJsonPath());\n const entry = config.providers?.[providerId.trim()];\n const key = entry?.apiKey;\n return typeof key === 'string' && key.trim() ? key.trim() : undefined;\n}\n\n/** Plaintext key only when persisted under `cfg.providers.<id>.apiKey` (not env / credential store). */\nfunction readProviderApiKeyFromConfigFileOnly(cfg: Config, providerId: string): string | undefined {\n const id = providerId.trim().toLowerCase();\n const bucket = cfg.providers?.[id];\n if (!bucket || typeof bucket !== 'object' || Array.isArray(bucket)) return undefined;\n const k = (bucket as { apiKey?: unknown }).apiKey;\n return typeof k === 'string' && k.trim() ? k.trim() : undefined;\n}\n\n/** Extension id from manifest `providers[]` (e.g. provider `demo` → extension `demo-provider`). */\nfunction resolveExtensionIdForProvider(service: GatewayService, providerId: string): string | undefined {\n const loader = service.getExtensionLoader();\n if (!loader) return undefined;\n return loader.buildManifestRegistry().findByProvider(providerId)?.id;\n}\n\n/** Effective LLM REST base URL for a provider (models.json overrides included). */\nfunction resolveProviderApiBaseUrl(providerId: string): string | undefined {\n const model = getModelRegistry().getAll().find((m) => m.provider === providerId);\n if (!model?.baseUrl || model.baseUrl === EXTENSION_PROVIDER_BASE_URL) return undefined;\n return model.baseUrl;\n}\n\nfunction mapPluginModel(providerId: string, model: ProviderModelDefinition, available: boolean) {\n return {\n id: `${providerId}/${model.id}`,\n name: model.name,\n provider: providerId,\n contextWindow: model.contextWindow ?? 128000,\n maxTokens: model.maxOutputTokens ?? 4096,\n reasoning: false,\n vision: model.supportsImages ?? false,\n cost: { input: model.pricing?.input ?? 0, output: model.pricing?.output ?? 0 },\n available,\n source: 'extension' as const,\n };\n}\n\nexport function registerModelsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware } = deps;\n\n // GET /api/models-json - Get models.json configuration\n authenticated.get('/api/models-json', async (c) => {\n const path = getModelsJsonPath();\n const { config, error } = loadModelsJson(path);\n const registry = getModelRegistry();\n \n return c.json({\n ok: true,\n payload: {\n config,\n path,\n exists: error === undefined,\n loadError: error || registry.getError(),\n },\n });\n });\n\n // POST /api/models-json/validate - Validate models.json configuration\n authenticated.post('/api/models-json/validate', async (c) => {\n const body = await c.req.json();\n const { config } = body;\n \n const result = validateModelsConfig(config);\n \n return c.json({\n ok: true,\n payload: result,\n });\n });\n\n // PATCH /api/models-json - Save models.json configuration\n authenticated.patch('/api/models-json', async (c) => {\n const body = await c.req.json();\n const { config } = body;\n \n const path = getModelsJsonPath();\n const result = saveModelsJson(path, config);\n \n if (!result.success) {\n return c.json({ ok: false, error: result.error }, 400);\n }\n \n // Refresh registry\n const registry = getModelRegistry();\n registry.refresh();\n \n // Emit event\n service.emit('models-json.updated', { \n modelCount: registry.getAll().length,\n });\n \n return c.json({ \n ok: true, \n payload: { \n saved: true,\n modelCount: registry.getAll().length,\n },\n });\n });\n\n // POST /api/models-json/reload - Hot reload models.json\n authenticated.post('/api/models-json/reload', async (c) => {\n const registry = getModelRegistry();\n registry.refresh();\n \n const error = registry.getError();\n const models = registry.getAll();\n \n service.emit('models-json.reloaded', { \n modelCount: models.length,\n error: error || undefined,\n });\n \n return c.json({\n ok: true,\n payload: {\n modelCount: models.length,\n error,\n },\n });\n });\n\n // POST /api/models-json/test-api-key - Test API key resolution\n authenticated.post('/api/models-json/test-api-key', async (c) => {\n const body = await c.req.json();\n const { value } = body;\n \n const result = testApiKeyResolution(value);\n \n return c.json({\n ok: true,\n payload: result,\n });\n });\n\n // GET /api/models - Get available models (only configured providers)\n authenticated.get('/api/models', async (c) => {\n if (!service.isGatewayReady()) {\n return respondStartupUnavailable(c, 'models.list');\n }\n const pluginRegistry = getProviderRegistry();\n const models = (await getAvailableModels()).map(m => ({\n id: `${m.provider}/${m.id}`,\n name: m.name,\n provider: m.provider,\n contextWindow: m.contextWindow ?? 128000,\n maxTokens: m.maxTokens ?? 4096,\n reasoning: m.reasoning ?? false,\n vision: m.input?.includes('image') ?? false,\n cost: {\n input: m.cost?.input ?? 0,\n output: m.cost?.output ?? 0,\n },\n ...(pluginRegistry.has(m.provider) ? { source: 'extension' as const } : {}),\n }));\n\n const existingIds = new Set(models.map(m => m.id));\n for (const plugin of pluginRegistry.listAll()) {\n for (const model of plugin.models) {\n const compositeId = `${plugin.id}/${model.id}`;\n if (!existingIds.has(compositeId)) {\n models.push(mapPluginModel(plugin.id, model, true));\n existingIds.add(compositeId);\n }\n }\n }\n\n // Sort by provider then name\n models.sort((a, b) => {\n if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);\n return a.name.localeCompare(b.name);\n });\n\n return c.json({ ok: true, payload: { models } });\n });\n\n // GET /api/image/providers — registered image generation providers and models (not in LLM model registry)\n authenticated.get('/api/image/providers', (c) => {\n const cfg = deps.service.currentConfig;\n const summaries = listImageGenerationProvidersSummary(cfg);\n const providers = summaries.map((p) => {\n const provider = getImageGenerationProvider(p.id, cfg);\n let configured = false;\n try {\n configured = provider?.isConfigured?.({ cfg }) === true;\n } catch {\n configured = false;\n }\n return { ...p, configured };\n });\n return c.json({ ok: true, payload: { providers } });\n });\n\n // POST /api/image/providers/:id/test — lightweight credential probe; does NOT\n // hit the vendor (no quota burn). Returns `{ ok, configured, reason }`.\n authenticated.post('/api/image/providers/:id/test', (c) => {\n const id = c.req.param('id');\n const cfg = deps.service.currentConfig;\n const provider = getImageGenerationProvider(id, cfg);\n if (!provider) {\n return c.json(\n { ok: false, error: { message: `Image generation provider not found: ${id}` } },\n 404,\n );\n }\n let configured = false;\n let reason: string | undefined;\n try {\n configured = provider.isConfigured?.({ cfg }) === true;\n if (!configured) reason = 'Missing API key (set via config or environment).';\n } catch (err) {\n reason = err instanceof Error ? err.message : String(err);\n }\n return c.json({\n ok: true,\n payload: {\n id: provider.id,\n configured,\n ...(reason ? { reason } : {}),\n defaultModel: provider.defaultModel ?? null,\n },\n });\n });\n\n /**\n * POST /api/image/providers/:id/reveal-api-key — return `cfg.providers.<id>.apiKey` plaintext for the\n * gateway console (same auth as PATCH /api/config). Does not resolve env vars or credential files.\n */\n authenticated.post(\n '/api/image/providers/:id/reveal-api-key',\n strictRateLimitMiddleware,\n async (c) => {\n const rawId = c.req.param('id');\n const cfg = deps.service.currentConfig;\n const provider = getImageGenerationProvider(rawId, cfg);\n if (!provider) {\n return c.json(\n { ok: false, error: { message: `Image generation provider not found: ${rawId}` } },\n 404,\n );\n }\n const apiKey = readProviderApiKeyFromConfigFileOnly(cfg, provider.id);\n return c.json({\n ok: true,\n payload: {\n id: provider.id,\n apiKey: apiKey ?? null,\n source: apiKey ? ('config' as const) : ('none' as const),\n },\n });\n },\n );\n\n // GET /api/providers - Get ALL available providers and models\n authenticated.get('/api/providers', async (c) => {\n const pluginRegistry = getProviderRegistry();\n const allModels = getAllModels();\n const availableModels = await getAvailableModels();\n const configured = new Set(availableModels.map(m => `${m.provider}/${m.id}`));\n\n const models = allModels.map(m => ({\n id: `${m.provider}/${m.id}`,\n name: m.name,\n provider: m.provider,\n contextWindow: m.contextWindow ?? 128000,\n maxTokens: m.maxTokens ?? 4096,\n reasoning: m.reasoning ?? false,\n vision: m.input?.includes('image') ?? false,\n cost: {\n input: m.cost?.input ?? 0,\n output: m.cost?.output ?? 0,\n },\n available: configured.has(`${m.provider}/${m.id}`),\n ...(pluginRegistry.has(m.provider) ? { source: 'extension' as const } : {}),\n }));\n\n const existingIds = new Set(models.map(m => m.id));\n for (const plugin of pluginRegistry.listAll()) {\n for (const model of plugin.models) {\n const compositeId = `${plugin.id}/${model.id}`;\n if (!existingIds.has(compositeId)) {\n models.push(mapPluginModel(plugin.id, model, configured.has(compositeId)));\n existingIds.add(compositeId);\n }\n }\n }\n\n // Sort by provider then name\n models.sort((a, b) => {\n if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);\n return a.name.localeCompare(b.name);\n });\n\n return c.json({ ok: true, payload: { models } });\n });\n\n // GET /api/providers/meta - Get provider metadata (categories, display names)\n authenticated.get('/api/providers/meta', async (c) => {\n const providers = getAllProviders();\n const pluginRegistry = getProviderRegistry();\n\n const meta = await Promise.all(\n providers.map(async (provider) => {\n const plugin = pluginRegistry.get(provider);\n const extensionId = plugin\n ? resolveExtensionIdForProvider(service, provider)\n : undefined;\n const authState = await getProviderAuthState(provider);\n const configured = authState.authMode !== 'none' || (await isProviderConfigured(provider));\n return {\n id: provider,\n name: plugin?.name ?? PROVIDER_META[provider]?.name ?? provider,\n category: plugin ? ('extension' as const) : PROVIDER_META[provider]?.category || 'specialty',\n supportsOAuth: plugin ? false : (PROVIDER_META[provider]?.supportsOAuth ?? false),\n supportsApiKey: plugin ? false : (PROVIDER_META[provider]?.supportsApiKey ?? true),\n configured,\n activeKeySource: authState.authMode,\n authMode: authState.authMode,\n authStatus: authState.authStatus,\n ...(authState.expiresAt ? { expiresAt: authState.expiresAt } : {}),\n baseUrl: resolveProviderApiBaseUrl(provider),\n ...(extensionId ? { extensionId } : {}),\n };\n }),\n );\n\n const knownProviderIds = new Set(providers);\n for (const plugin of pluginRegistry.listAll()) {\n if (!knownProviderIds.has(plugin.id)) {\n const extensionId = resolveExtensionIdForProvider(service, plugin.id);\n meta.push({\n id: plugin.id,\n name: plugin.name,\n category: 'extension',\n supportsOAuth: false,\n supportsApiKey: false,\n configured: true,\n activeKeySource: 'extension',\n authMode: 'extension',\n authStatus: 'connected',\n baseUrl: resolveProviderApiBaseUrl(plugin.id),\n ...(extensionId ? { extensionId } : {}),\n });\n }\n }\n\n return c.json({ ok: true, payload: { providers: meta } });\n });\n\n /**\n * POST /api/providers/:providerId/reveal-api-key — plaintext key when stored in the\n * gateway credential store or models.json (not env vars or OAuth tokens).\n */\n authenticated.post(\n '/api/providers/:providerId/reveal-api-key',\n strictRateLimitMiddleware,\n async (c) => {\n const rawId = c.req.param('providerId')?.trim();\n if (!rawId) {\n return c.json({ ok: false, error: { message: 'Missing providerId' } }, 400);\n }\n const providerId = rawId.toLowerCase();\n const resolver = new CredentialResolver();\n const stored = await resolver.revealGatewayStoredApiKey(providerId);\n if (stored) {\n return c.json({\n ok: true,\n payload: { id: providerId, apiKey: stored, source: 'credential' as const },\n });\n }\n const fromModelsJson = readModelsJsonProviderApiKey(providerId);\n if (fromModelsJson) {\n return c.json({\n ok: true,\n payload: { id: providerId, apiKey: fromModelsJson, source: 'models_json' as const },\n });\n }\n return c.json({\n ok: true,\n payload: { id: providerId, apiKey: null, source: 'none' as const },\n });\n },\n );\n\n // DELETE /api/providers/:providerId/key - Remove a provider's stored API key\n authenticated.delete('/api/providers/:providerId/key', strictRateLimitMiddleware, async (c) => {\n const providerId = c.req.param('providerId');\n if (!providerId) {\n return c.json({ ok: false, error: { message: 'Missing providerId' } }, 400);\n }\n\n const normalizedProvider = providerId.toLowerCase();\n const resolver = new CredentialResolver();\n\n try {\n await resolver.deleteProviderCredential(normalizedProvider);\n return c.json({ ok: true, payload: { deleted: normalizedProvider } });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return c.json({ ok: false, error: { message: `Failed to delete key: ${errorMessage}` } }, 500);\n }\n });\n}\n"],"mappings":";;;;;;;;;;;kBAOwC;2BAEuC;gBAc1C;kBAC6B;sBACU;AAM5E,SAAS,6BAA6B,YAAwC;CAC5E,MAAM,EAAE,WAAW,eAAeA,uBAAmB,CAAC;CAEtD,MAAM,OADQ,OAAO,YAAY,WAAW,MAAM,IAC/B;AACnB,QAAO,OAAO,QAAQ,YAAY,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,KAAA;;;AAI9D,SAAS,qCAAqC,KAAa,YAAwC;CACjG,MAAM,KAAK,WAAW,MAAM,CAAC,aAAa;CAC1C,MAAM,SAAS,IAAI,YAAY;AAC/B,KAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,OAAO,CAAE,QAAO,KAAA;CAC3E,MAAM,IAAK,OAAgC;AAC3C,QAAO,OAAO,MAAM,YAAY,EAAE,MAAM,GAAG,EAAE,MAAM,GAAG,KAAA;;;AAIxD,SAAS,8BAA8B,SAAyB,YAAwC;CACtG,MAAM,SAAS,QAAQ,oBAAoB;AAC3C,KAAI,CAAC,OAAQ,QAAO,KAAA;AACpB,QAAO,OAAO,uBAAuB,CAAC,eAAe,WAAW,EAAE;;;AAIpE,SAAS,0BAA0B,YAAwC;CACzE,MAAM,QAAQ,kBAAkB,CAAC,QAAQ,CAAC,MAAM,MAAM,EAAE,aAAa,WAAW;AAChF,KAAI,CAAC,OAAO,WAAW,MAAM,YAAA,8BAAyC,QAAO,KAAA;AAC7E,QAAO,MAAM;;AAGf,SAAS,eAAe,YAAoB,OAAgC,WAAoB;AAC9F,QAAO;EACL,IAAI,GAAG,WAAW,GAAG,MAAM;EAC3B,MAAM,MAAM;EACZ,UAAU;EACV,eAAe,MAAM,iBAAiB;EACtC,WAAW,MAAM,mBAAmB;EACpC,WAAW;EACX,QAAQ,MAAM,kBAAkB;EAChC,MAAM;GAAE,OAAO,MAAM,SAAS,SAAS;GAAG,QAAQ,MAAM,SAAS,UAAU;GAAG;EAC9E;EACA,QAAQ;EACT;;AAGH,SAAgB,qBAAqB,eAAqB,MAAoC;CAC5F,MAAM,EAAE,SAAS,8BAA8B;AAG/C,eAAc,IAAI,oBAAoB,OAAO,MAAM;EACjD,MAAM,OAAOA,uBAAmB;EAChC,MAAM,EAAE,QAAQ,UAAU,eAAe,KAAK;EAC9C,MAAM,WAAW,kBAAkB;AAEnC,SAAO,EAAE,KAAK;GACZ,IAAI;GACJ,SAAS;IACP;IACA;IACA,QAAQ,UAAU,KAAA;IAClB,WAAW,SAAS,SAAS,UAAU;IACxC;GACF,CAAC;GACF;AAGF,eAAc,KAAK,6BAA6B,OAAO,MAAM;EAE3D,MAAM,EAAE,WAAW,MADA,EAAE,IAAI,MAAM;EAG/B,MAAM,SAAS,qBAAqB,OAAO;AAE3C,SAAO,EAAE,KAAK;GACZ,IAAI;GACJ,SAAS;GACV,CAAC;GACF;AAGF,eAAc,MAAM,oBAAoB,OAAO,MAAM;EAEnD,MAAM,EAAE,WAAW,MADA,EAAE,IAAI,MAAM;EAI/B,MAAM,SAAS,eADFA,uBACqB,EAAE,OAAO;AAE3C,MAAI,CAAC,OAAO,QACV,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,OAAO;GAAO,EAAE,IAAI;EAIxD,MAAM,WAAW,kBAAkB;AACnC,WAAS,SAAS;AAGlB,UAAQ,KAAK,uBAAuB,EAClC,YAAY,SAAS,QAAQ,CAAC,QAC/B,CAAC;AAEF,SAAO,EAAE,KAAK;GACZ,IAAI;GACJ,SAAS;IACP,OAAO;IACP,YAAY,SAAS,QAAQ,CAAC;IAC/B;GACF,CAAC;GACF;AAGF,eAAc,KAAK,2BAA2B,OAAO,MAAM;EACzD,MAAM,WAAW,kBAAkB;AACnC,WAAS,SAAS;EAElB,MAAM,QAAQ,SAAS,UAAU;EACjC,MAAM,SAAS,SAAS,QAAQ;AAEhC,UAAQ,KAAK,wBAAwB;GACnC,YAAY,OAAO;GACnB,OAAO,SAAS,KAAA;GACjB,CAAC;AAEF,SAAO,EAAE,KAAK;GACZ,IAAI;GACJ,SAAS;IACP,YAAY,OAAO;IACnB;IACD;GACF,CAAC;GACF;AAGF,eAAc,KAAK,iCAAiC,OAAO,MAAM;EAE/D,MAAM,EAAE,UAAU,MADC,EAAE,IAAI,MAAM;EAG/B,MAAM,SAAS,qBAAqB,MAAM;AAE1C,SAAO,EAAE,KAAK;GACZ,IAAI;GACJ,SAAS;GACV,CAAC;GACF;AAGF,eAAc,IAAI,eAAe,OAAO,MAAM;AAC5C,MAAI,CAAC,QAAQ,gBAAgB,CAC3B,QAAO,0BAA0B,GAAG,cAAc;EAEpD,MAAM,iBAAiB,qBAAqB;EAC5C,MAAM,UAAU,MAAM,oBAAoB,EAAE,KAAI,OAAM;GACpD,IAAI,GAAG,EAAE,SAAS,GAAG,EAAE;GACvB,MAAM,EAAE;GACR,UAAU,EAAE;GACZ,eAAe,EAAE,iBAAiB;GAClC,WAAW,EAAE,aAAa;GAC1B,WAAW,EAAE,aAAa;GAC1B,QAAQ,EAAE,OAAO,SAAS,QAAQ,IAAI;GACtC,MAAM;IACJ,OAAO,EAAE,MAAM,SAAS;IACxB,QAAQ,EAAE,MAAM,UAAU;IAC3B;GACD,GAAI,eAAe,IAAI,EAAE,SAAS,GAAG,EAAE,QAAQ,aAAsB,GAAG,EAAE;GAC3E,EAAE;EAEH,MAAM,cAAc,IAAI,IAAI,OAAO,KAAI,MAAK,EAAE,GAAG,CAAC;AAClD,OAAK,MAAM,UAAU,eAAe,SAAS,CAC3C,MAAK,MAAM,SAAS,OAAO,QAAQ;GACjC,MAAM,cAAc,GAAG,OAAO,GAAG,GAAG,MAAM;AAC1C,OAAI,CAAC,YAAY,IAAI,YAAY,EAAE;AACjC,WAAO,KAAK,eAAe,OAAO,IAAI,OAAO,KAAK,CAAC;AACnD,gBAAY,IAAI,YAAY;;;AAMlC,SAAO,MAAM,GAAG,MAAM;AACpB,OAAI,EAAE,aAAa,EAAE,SAAU,QAAO,EAAE,SAAS,cAAc,EAAE,SAAS;AAC1E,UAAO,EAAE,KAAK,cAAc,EAAE,KAAK;IACnC;AAEF,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,SAAS,EAAE,QAAQ;GAAE,CAAC;GAChD;AAGF,eAAc,IAAI,yBAAyB,MAAM;EAC/C,MAAM,MAAM,KAAK,QAAQ;EAEzB,MAAM,YADY,oCAAoC,IAC3B,CAAC,KAAK,MAAM;GACrC,MAAM,WAAW,2BAA2B,EAAE,IAAI,IAAI;GACtD,IAAI,aAAa;AACjB,OAAI;AACF,iBAAa,UAAU,eAAe,EAAE,KAAK,CAAC,KAAK;WAC7C;AACN,iBAAa;;AAEf,UAAO;IAAE,GAAG;IAAG;IAAY;IAC3B;AACF,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,SAAS,EAAE,WAAW;GAAE,CAAC;GACnD;AAIF,eAAc,KAAK,kCAAkC,MAAM;EACzD,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK;EAC5B,MAAM,MAAM,KAAK,QAAQ;EACzB,MAAM,WAAW,2BAA2B,IAAI,IAAI;AACpD,MAAI,CAAC,SACH,QAAO,EAAE,KACP;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,wCAAwC,MAAM;GAAE,EAC/E,IACD;EAEH,IAAI,aAAa;EACjB,IAAI;AACJ,MAAI;AACF,gBAAa,SAAS,eAAe,EAAE,KAAK,CAAC,KAAK;AAClD,OAAI,CAAC,WAAY,UAAS;WACnB,KAAK;AACZ,YAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;;AAE3D,SAAO,EAAE,KAAK;GACZ,IAAI;GACJ,SAAS;IACP,IAAI,SAAS;IACb;IACA,GAAI,SAAS,EAAE,QAAQ,GAAG,EAAE;IAC5B,cAAc,SAAS,gBAAgB;IACxC;GACF,CAAC;GACF;;;;;AAMF,eAAc,KACZ,2CACA,2BACA,OAAO,MAAM;EACX,MAAM,QAAQ,EAAE,IAAI,MAAM,KAAK;EAC/B,MAAM,MAAM,KAAK,QAAQ;EACzB,MAAM,WAAW,2BAA2B,OAAO,IAAI;AACvD,MAAI,CAAC,SACH,QAAO,EAAE,KACP;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,wCAAwC,SAAS;GAAE,EAClF,IACD;EAEH,MAAM,SAAS,qCAAqC,KAAK,SAAS,GAAG;AACrE,SAAO,EAAE,KAAK;GACZ,IAAI;GACJ,SAAS;IACP,IAAI,SAAS;IACb,QAAQ,UAAU;IAClB,QAAQ,SAAU,WAAsB;IACzC;GACF,CAAC;GAEL;AAGD,eAAc,IAAI,kBAAkB,OAAO,MAAM;EAC/C,MAAM,iBAAiB,qBAAqB;EAC5C,MAAM,YAAY,cAAc;EAChC,MAAM,kBAAkB,MAAM,oBAAoB;EAClD,MAAM,aAAa,IAAI,IAAI,gBAAgB,KAAI,MAAK,GAAG,EAAE,SAAS,GAAG,EAAE,KAAK,CAAC;EAE7E,MAAM,SAAS,UAAU,KAAI,OAAM;GACjC,IAAI,GAAG,EAAE,SAAS,GAAG,EAAE;GACvB,MAAM,EAAE;GACR,UAAU,EAAE;GACZ,eAAe,EAAE,iBAAiB;GAClC,WAAW,EAAE,aAAa;GAC1B,WAAW,EAAE,aAAa;GAC1B,QAAQ,EAAE,OAAO,SAAS,QAAQ,IAAI;GACtC,MAAM;IACJ,OAAO,EAAE,MAAM,SAAS;IACxB,QAAQ,EAAE,MAAM,UAAU;IAC3B;GACD,WAAW,WAAW,IAAI,GAAG,EAAE,SAAS,GAAG,EAAE,KAAK;GAClD,GAAI,eAAe,IAAI,EAAE,SAAS,GAAG,EAAE,QAAQ,aAAsB,GAAG,EAAE;GAC3E,EAAE;EAEH,MAAM,cAAc,IAAI,IAAI,OAAO,KAAI,MAAK,EAAE,GAAG,CAAC;AAClD,OAAK,MAAM,UAAU,eAAe,SAAS,CAC3C,MAAK,MAAM,SAAS,OAAO,QAAQ;GACjC,MAAM,cAAc,GAAG,OAAO,GAAG,GAAG,MAAM;AAC1C,OAAI,CAAC,YAAY,IAAI,YAAY,EAAE;AACjC,WAAO,KAAK,eAAe,OAAO,IAAI,OAAO,WAAW,IAAI,YAAY,CAAC,CAAC;AAC1E,gBAAY,IAAI,YAAY;;;AAMlC,SAAO,MAAM,GAAG,MAAM;AACpB,OAAI,EAAE,aAAa,EAAE,SAAU,QAAO,EAAE,SAAS,cAAc,EAAE,SAAS;AAC1E,UAAO,EAAE,KAAK,cAAc,EAAE,KAAK;IACnC;AAEF,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,SAAS,EAAE,QAAQ;GAAE,CAAC;GAChD;AAGF,eAAc,IAAI,uBAAuB,OAAO,MAAM;EACpD,MAAM,YAAY,iBAAiB;EACnC,MAAM,iBAAiB,qBAAqB;EAE5C,MAAM,OAAO,MAAM,QAAQ,IACzB,UAAU,IAAI,OAAO,aAAa;GAChC,MAAM,SAAS,eAAe,IAAI,SAAS;GAC3C,MAAM,cAAc,SAChB,8BAA8B,SAAS,SAAS,GAChD,KAAA;GACJ,MAAM,YAAY,MAAM,qBAAqB,SAAS;GACtD,MAAM,aAAa,UAAU,aAAa,UAAW,MAAM,qBAAqB,SAAS;AACzF,UAAO;IACL,IAAI;IACJ,MAAM,QAAQ,QAAQ,cAAc,WAAW,QAAQ;IACvD,UAAU,SAAU,cAAwB,cAAc,WAAW,YAAY;IACjF,eAAe,SAAS,QAAS,cAAc,WAAW,iBAAiB;IAC3E,gBAAgB,SAAS,QAAS,cAAc,WAAW,kBAAkB;IAC7E;IACA,iBAAiB,UAAU;IAC3B,UAAU,UAAU;IACpB,YAAY,UAAU;IACtB,GAAI,UAAU,YAAY,EAAE,WAAW,UAAU,WAAW,GAAG,EAAE;IACjE,SAAS,0BAA0B,SAAS;IAC5C,GAAI,cAAc,EAAE,aAAa,GAAG,EAAE;IACvC;IACD,CACH;EAED,MAAM,mBAAmB,IAAI,IAAI,UAAU;AAC3C,OAAK,MAAM,UAAU,eAAe,SAAS,CAC3C,KAAI,CAAC,iBAAiB,IAAI,OAAO,GAAG,EAAE;GACpC,MAAM,cAAc,8BAA8B,SAAS,OAAO,GAAG;AACrE,QAAK,KAAK;IACR,IAAI,OAAO;IACX,MAAM,OAAO;IACb,UAAU;IACV,eAAe;IACf,gBAAgB;IAChB,YAAY;IACZ,iBAAiB;IACjB,UAAU;IACV,YAAY;IACZ,SAAS,0BAA0B,OAAO,GAAG;IAC7C,GAAI,cAAc,EAAE,aAAa,GAAG,EAAE;IACvC,CAAC;;AAIN,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,SAAS,EAAE,WAAW,MAAM;GAAE,CAAC;GACzD;;;;;AAMF,eAAc,KACZ,6CACA,2BACA,OAAO,MAAM;EACX,MAAM,QAAQ,EAAE,IAAI,MAAM,aAAa,EAAE,MAAM;AAC/C,MAAI,CAAC,MACH,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,sBAAsB;GAAE,EAAE,IAAI;EAE7E,MAAM,aAAa,MAAM,aAAa;EAEtC,MAAM,SAAS,MAAM,IADA,oBACQ,CAAC,0BAA0B,WAAW;AACnE,MAAI,OACF,QAAO,EAAE,KAAK;GACZ,IAAI;GACJ,SAAS;IAAE,IAAI;IAAY,QAAQ;IAAQ,QAAQ;IAAuB;GAC3E,CAAC;EAEJ,MAAM,iBAAiB,6BAA6B,WAAW;AAC/D,MAAI,eACF,QAAO,EAAE,KAAK;GACZ,IAAI;GACJ,SAAS;IAAE,IAAI;IAAY,QAAQ;IAAgB,QAAQ;IAAwB;GACpF,CAAC;AAEJ,SAAO,EAAE,KAAK;GACZ,IAAI;GACJ,SAAS;IAAE,IAAI;IAAY,QAAQ;IAAM,QAAQ;IAAiB;GACnE,CAAC;GAEL;AAGD,eAAc,OAAO,kCAAkC,2BAA2B,OAAO,MAAM;EAC7F,MAAM,aAAa,EAAE,IAAI,MAAM,aAAa;AAC5C,MAAI,CAAC,WACH,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,sBAAsB;GAAE,EAAE,IAAI;EAG7E,MAAM,qBAAqB,WAAW,aAAa;EACnD,MAAM,WAAW,IAAI,oBAAoB;AAEzC,MAAI;AACF,SAAM,SAAS,yBAAyB,mBAAmB;AAC3D,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM,SAAS,EAAE,SAAS,oBAAoB;IAAE,CAAC;WAC9D,OAAO;GACd,MAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AAC3E,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,EAAE,SAAS,yBAAyB,gBAAgB;IAAE,EAAE,IAAI;;GAEhG"}
|
|
1
|
+
{"version":3,"file":"models.js","names":["getModelsJsonPath"],"sources":["../../../../../src/gateway/hono/routes/models.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport {\n getModelsJsonPath,\n loadModelsJson,\n saveModelsJson,\n validateModelsConfig,\n} from '../../../config/models-json.js';\nimport type { Config } from '../../../config/schema.js';\nimport { testApiKeyResolution } from '../../../config/resolve-config-value.js';\nimport {\n getImageGenerationProvider,\n listImageGenerationProvidersSummary,\n} from '../../../agent/image/generation/runtime.js';\nimport {\n EXTENSION_PROVIDER_BASE_URL,\n getAllModels,\n getAvailableModels,\n getModelRegistry,\n getAllProviders,\n getProviderAuthState,\n isProviderConfigured,\n PROVIDER_META,\n} from '../../../providers/index.js';\nimport {\n getProviderHint,\n getRecommendedModelsForProvider,\n isRecommendedModel,\n sortModelsForPicker,\n sortProvidersForPicker,\n} from '../../../providers/presentation.js';\nimport { CredentialResolver } from '../../../auth/credentials.js';\nimport { getProviderRegistry } from '../../../providers/plugin-registry.js';\nimport type { ProviderModelDefinition } from '../../../extensions/types/providers.js';\nimport type { GatewayService } from '../../service.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\nimport { respondStartupUnavailable } from '../lib/startup-unavailable.js';\n\nfunction readModelsJsonProviderApiKey(providerId: string): string | undefined {\n const { config } = loadModelsJson(getModelsJsonPath());\n const entry = config.providers?.[providerId.trim()];\n const key = entry?.apiKey;\n return typeof key === 'string' && key.trim() ? key.trim() : undefined;\n}\n\n/** Plaintext key only when persisted under `cfg.providers.<id>.apiKey` (not env / credential store). */\nfunction readProviderApiKeyFromConfigFileOnly(cfg: Config, providerId: string): string | undefined {\n const id = providerId.trim().toLowerCase();\n const bucket = cfg.providers?.[id];\n if (!bucket || typeof bucket !== 'object' || Array.isArray(bucket)) return undefined;\n const k = (bucket as { apiKey?: unknown }).apiKey;\n return typeof k === 'string' && k.trim() ? k.trim() : undefined;\n}\n\n/** Extension id from manifest `providers[]` (e.g. provider `demo` → extension `demo-provider`). */\nfunction resolveExtensionIdForProvider(service: GatewayService, providerId: string): string | undefined {\n const loader = service.getExtensionLoader();\n if (!loader) return undefined;\n return loader.buildManifestRegistry().findByProvider(providerId)?.id;\n}\n\n/** Effective LLM REST base URL for a provider (models.json overrides included). */\nfunction resolveProviderApiBaseUrl(providerId: string): string | undefined {\n const model = getModelRegistry().getAll().find((m) => m.provider === providerId);\n if (!model?.baseUrl || model.baseUrl === EXTENSION_PROVIDER_BASE_URL) return undefined;\n return model.baseUrl;\n}\n\nfunction mapPluginModel(providerId: string, model: ProviderModelDefinition, available: boolean) {\n return {\n id: `${providerId}/${model.id}`,\n name: model.name,\n provider: providerId,\n contextWindow: model.contextWindow ?? 128000,\n maxTokens: model.maxOutputTokens ?? 4096,\n reasoning: false,\n vision: model.supportsImages ?? false,\n cost: { input: model.pricing?.input ?? 0, output: model.pricing?.output ?? 0 },\n available,\n recommended: isRecommendedModel(providerId, model.id),\n source: 'extension' as const,\n };\n}\n\nexport function registerModelsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware } = deps;\n\n // GET /api/models-json - Get models.json configuration\n authenticated.get('/api/models-json', async (c) => {\n const path = getModelsJsonPath();\n const { config, error } = loadModelsJson(path);\n const registry = getModelRegistry();\n \n return c.json({\n ok: true,\n payload: {\n config,\n path,\n exists: error === undefined,\n loadError: error || registry.getError(),\n },\n });\n });\n\n // POST /api/models-json/validate - Validate models.json configuration\n authenticated.post('/api/models-json/validate', async (c) => {\n const body = await c.req.json();\n const { config } = body;\n \n const result = validateModelsConfig(config);\n \n return c.json({\n ok: true,\n payload: result,\n });\n });\n\n // PATCH /api/models-json - Save models.json configuration\n authenticated.patch('/api/models-json', async (c) => {\n const body = await c.req.json();\n const { config } = body;\n \n const path = getModelsJsonPath();\n const result = saveModelsJson(path, config);\n \n if (!result.success) {\n return c.json({ ok: false, error: result.error }, 400);\n }\n \n // Refresh registry\n const registry = getModelRegistry();\n registry.refresh();\n \n // Emit event\n service.emit('models-json.updated', { \n modelCount: registry.getAll().length,\n });\n \n return c.json({ \n ok: true, \n payload: { \n saved: true,\n modelCount: registry.getAll().length,\n },\n });\n });\n\n // POST /api/models-json/reload - Hot reload models.json\n authenticated.post('/api/models-json/reload', async (c) => {\n const registry = getModelRegistry();\n registry.refresh();\n \n const error = registry.getError();\n const models = registry.getAll();\n \n service.emit('models-json.reloaded', { \n modelCount: models.length,\n error: error || undefined,\n });\n \n return c.json({\n ok: true,\n payload: {\n modelCount: models.length,\n error,\n },\n });\n });\n\n // POST /api/models-json/test-api-key - Test API key resolution\n authenticated.post('/api/models-json/test-api-key', async (c) => {\n const body = await c.req.json();\n const { value } = body;\n \n const result = testApiKeyResolution(value);\n \n return c.json({\n ok: true,\n payload: result,\n });\n });\n\n // GET /api/models - Get available models (only configured providers)\n authenticated.get('/api/models', async (c) => {\n if (!service.isGatewayReady()) {\n return respondStartupUnavailable(c, 'models.list');\n }\n const pluginRegistry = getProviderRegistry();\n const models = sortModelsForPicker(await getAvailableModels()).map(m => ({\n id: `${m.provider}/${m.id}`,\n name: m.name,\n provider: m.provider,\n contextWindow: m.contextWindow ?? 128000,\n maxTokens: m.maxTokens ?? 4096,\n reasoning: m.reasoning ?? false,\n vision: m.input?.includes('image') ?? false,\n recommended: isRecommendedModel(m.provider, m.id),\n cost: {\n input: m.cost?.input ?? 0,\n output: m.cost?.output ?? 0,\n },\n ...(pluginRegistry.has(m.provider) ? { source: 'extension' as const } : {}),\n }));\n\n const existingIds = new Set(models.map(m => m.id));\n for (const plugin of pluginRegistry.listAll()) {\n for (const model of plugin.models) {\n const compositeId = `${plugin.id}/${model.id}`;\n if (!existingIds.has(compositeId)) {\n models.push(mapPluginModel(plugin.id, model, true));\n existingIds.add(compositeId);\n }\n }\n }\n\n models.sort((a, b) => {\n if (a.recommended !== b.recommended) return a.recommended ? -1 : 1;\n if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);\n return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' });\n });\n\n return c.json({ ok: true, payload: { models } });\n });\n\n // GET /api/image/providers — registered image generation providers and models (not in LLM model registry)\n authenticated.get('/api/image/providers', (c) => {\n const cfg = deps.service.currentConfig;\n const summaries = listImageGenerationProvidersSummary(cfg);\n const providers = summaries.map((p) => {\n const provider = getImageGenerationProvider(p.id, cfg);\n let configured = false;\n try {\n configured = provider?.isConfigured?.({ cfg }) === true;\n } catch {\n configured = false;\n }\n return { ...p, configured };\n });\n return c.json({ ok: true, payload: { providers } });\n });\n\n // POST /api/image/providers/:id/test — lightweight credential probe; does NOT\n // hit the vendor (no quota burn). Returns `{ ok, configured, reason }`.\n authenticated.post('/api/image/providers/:id/test', (c) => {\n const id = c.req.param('id');\n const cfg = deps.service.currentConfig;\n const provider = getImageGenerationProvider(id, cfg);\n if (!provider) {\n return c.json(\n { ok: false, error: { message: `Image generation provider not found: ${id}` } },\n 404,\n );\n }\n let configured = false;\n let reason: string | undefined;\n try {\n configured = provider.isConfigured?.({ cfg }) === true;\n if (!configured) reason = 'Missing API key (set via config or environment).';\n } catch (err) {\n reason = err instanceof Error ? err.message : String(err);\n }\n return c.json({\n ok: true,\n payload: {\n id: provider.id,\n configured,\n ...(reason ? { reason } : {}),\n defaultModel: provider.defaultModel ?? null,\n },\n });\n });\n\n /**\n * POST /api/image/providers/:id/reveal-api-key — return `cfg.providers.<id>.apiKey` plaintext for the\n * gateway console (same auth as PATCH /api/config). Does not resolve env vars or credential files.\n */\n authenticated.post(\n '/api/image/providers/:id/reveal-api-key',\n strictRateLimitMiddleware,\n async (c) => {\n const rawId = c.req.param('id');\n const cfg = deps.service.currentConfig;\n const provider = getImageGenerationProvider(rawId, cfg);\n if (!provider) {\n return c.json(\n { ok: false, error: { message: `Image generation provider not found: ${rawId}` } },\n 404,\n );\n }\n const apiKey = readProviderApiKeyFromConfigFileOnly(cfg, provider.id);\n return c.json({\n ok: true,\n payload: {\n id: provider.id,\n apiKey: apiKey ?? null,\n source: apiKey ? ('config' as const) : ('none' as const),\n },\n });\n },\n );\n\n // GET /api/providers - Get ALL available providers and models\n authenticated.get('/api/providers', async (c) => {\n const pluginRegistry = getProviderRegistry();\n const allModels = getAllModels();\n const availableModels = await getAvailableModels();\n const configured = new Set(availableModels.map(m => `${m.provider}/${m.id}`));\n\n const models = sortModelsForPicker(allModels).map(m => ({\n id: `${m.provider}/${m.id}`,\n name: m.name,\n provider: m.provider,\n contextWindow: m.contextWindow ?? 128000,\n maxTokens: m.maxTokens ?? 4096,\n reasoning: m.reasoning ?? false,\n vision: m.input?.includes('image') ?? false,\n recommended: isRecommendedModel(m.provider, m.id),\n cost: {\n input: m.cost?.input ?? 0,\n output: m.cost?.output ?? 0,\n },\n available: configured.has(`${m.provider}/${m.id}`),\n ...(pluginRegistry.has(m.provider) ? { source: 'extension' as const } : {}),\n }));\n\n const existingIds = new Set(models.map(m => m.id));\n for (const plugin of pluginRegistry.listAll()) {\n for (const model of plugin.models) {\n const compositeId = `${plugin.id}/${model.id}`;\n if (!existingIds.has(compositeId)) {\n models.push(mapPluginModel(plugin.id, model, configured.has(compositeId)));\n existingIds.add(compositeId);\n }\n }\n }\n\n models.sort((a, b) => {\n if (a.recommended !== b.recommended) return a.recommended ? -1 : 1;\n if (a.provider !== b.provider) return a.provider.localeCompare(b.provider);\n return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' });\n });\n\n return c.json({ ok: true, payload: { models } });\n });\n\n // GET /api/providers/meta - Get provider metadata (categories, display names)\n authenticated.get('/api/providers/meta', async (c) => {\n const providers = sortProvidersForPicker(getAllProviders());\n const pluginRegistry = getProviderRegistry();\n\n const meta = await Promise.all(\n providers.map(async (provider) => {\n const plugin = pluginRegistry.get(provider);\n const extensionId = plugin\n ? resolveExtensionIdForProvider(service, provider)\n : undefined;\n const authState = await getProviderAuthState(provider);\n const configured = authState.authMode !== 'none' || (await isProviderConfigured(provider));\n return {\n id: provider,\n name: plugin?.name ?? PROVIDER_META[provider]?.name ?? provider,\n category: plugin ? ('extension' as const) : PROVIDER_META[provider]?.category || 'specialty',\n supportsOAuth: plugin ? false : (PROVIDER_META[provider]?.supportsOAuth ?? false),\n supportsApiKey: plugin ? false : (PROVIDER_META[provider]?.supportsApiKey ?? true),\n configured,\n onboardingFeatured: ['openai', 'anthropic', 'xai', 'google', 'openrouter', 'deepseek'].includes(provider),\n recommendedModels: getRecommendedModelsForProvider(provider),\n modelCount: getAllModels().filter((m) => m.provider === provider).length,\n ...(getProviderHint(provider) ? { hint: getProviderHint(provider) } : {}),\n activeKeySource: authState.authMode,\n authMode: authState.authMode,\n authStatus: authState.authStatus,\n ...(authState.expiresAt ? { expiresAt: authState.expiresAt } : {}),\n baseUrl: resolveProviderApiBaseUrl(provider),\n ...(extensionId ? { extensionId } : {}),\n };\n }),\n );\n\n const knownProviderIds = new Set(providers);\n for (const plugin of pluginRegistry.listAll()) {\n if (!knownProviderIds.has(plugin.id)) {\n const extensionId = resolveExtensionIdForProvider(service, plugin.id);\n meta.push({\n id: plugin.id,\n name: plugin.name,\n category: 'extension',\n supportsOAuth: false,\n supportsApiKey: false,\n configured: true,\n onboardingFeatured: false,\n recommendedModels: getRecommendedModelsForProvider(plugin.id),\n modelCount: plugin.models.length,\n activeKeySource: 'extension',\n authMode: 'extension',\n authStatus: 'connected',\n baseUrl: resolveProviderApiBaseUrl(plugin.id),\n ...(extensionId ? { extensionId } : {}),\n });\n }\n }\n\n return c.json({ ok: true, payload: { providers: meta } });\n });\n\n /**\n * POST /api/providers/:providerId/reveal-api-key — plaintext key when stored in the\n * gateway credential store or models.json (not env vars or OAuth tokens).\n */\n authenticated.post(\n '/api/providers/:providerId/reveal-api-key',\n strictRateLimitMiddleware,\n async (c) => {\n const rawId = c.req.param('providerId')?.trim();\n if (!rawId) {\n return c.json({ ok: false, error: { message: 'Missing providerId' } }, 400);\n }\n const providerId = rawId.toLowerCase();\n const resolver = new CredentialResolver();\n const stored = await resolver.revealGatewayStoredApiKey(providerId);\n if (stored) {\n return c.json({\n ok: true,\n payload: { id: providerId, apiKey: stored, source: 'credential' as const },\n });\n }\n const fromModelsJson = readModelsJsonProviderApiKey(providerId);\n if (fromModelsJson) {\n return c.json({\n ok: true,\n payload: { id: providerId, apiKey: fromModelsJson, source: 'models_json' as const },\n });\n }\n return c.json({\n ok: true,\n payload: { id: providerId, apiKey: null, source: 'none' as const },\n });\n },\n );\n\n // DELETE /api/providers/:providerId/key - Remove a provider's stored API key\n authenticated.delete('/api/providers/:providerId/key', strictRateLimitMiddleware, async (c) => {\n const providerId = c.req.param('providerId');\n if (!providerId) {\n return c.json({ ok: false, error: { message: 'Missing providerId' } }, 400);\n }\n\n const normalizedProvider = providerId.toLowerCase();\n const resolver = new CredentialResolver();\n\n try {\n await resolver.deleteProviderCredential(normalizedProvider);\n return c.json({ ok: true, payload: { deleted: normalizedProvider } });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return c.json({ ok: false, error: { message: `Failed to delete key: ${errorMessage}` } }, 500);\n }\n });\n}\n"],"mappings":"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"}
|
|
@@ -37,21 +37,10 @@ function parseCaptureSource(body) {
|
|
|
37
37
|
platform: body.platform === "ios" || body.platform === "android" ? body.platform : void 0
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
-
function parseBlocks(value) {
|
|
41
|
-
if (!Array.isArray(value)) return void 0;
|
|
42
|
-
return value.filter((block) => {
|
|
43
|
-
if (!block || typeof block !== "object") return false;
|
|
44
|
-
const candidate = block;
|
|
45
|
-
if (typeof candidate.id !== "string" || typeof candidate.type !== "string") return false;
|
|
46
|
-
if (candidate.type === "image") return typeof candidate.attachmentId === "string";
|
|
47
|
-
return true;
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
40
|
function buildNotePatch(body) {
|
|
51
41
|
const patch = {};
|
|
52
42
|
if (typeof body.title === "string") patch.title = body.title;
|
|
53
|
-
if (typeof body.
|
|
54
|
-
if (Array.isArray(body.blocks)) patch.blocks = parseBlocks(body.blocks);
|
|
43
|
+
if (typeof body.markdown === "string") patch.markdown = body.markdown;
|
|
55
44
|
if (typeof body.kind === "string" && VALID_KINDS.has(body.kind)) patch.kind = body.kind;
|
|
56
45
|
if (typeof body.status === "string" && VALID_STATUSES.has(body.status)) patch.status = body.status;
|
|
57
46
|
if (Array.isArray(body.tags)) patch.tags = body.tags.filter((tag) => typeof tag === "string");
|
|
@@ -63,7 +52,7 @@ function buildNotePatch(body) {
|
|
|
63
52
|
}
|
|
64
53
|
function buildNoteThreadContext(note) {
|
|
65
54
|
const title = note.title?.trim() || "未命名笔记";
|
|
66
|
-
const body = note.
|
|
55
|
+
const body = note.markdown.trim() || "这条笔记暂无正文。";
|
|
67
56
|
return [
|
|
68
57
|
`来源 Note:${title}`,
|
|
69
58
|
"",
|
|
@@ -71,7 +60,7 @@ function buildNoteThreadContext(note) {
|
|
|
71
60
|
].join("\n");
|
|
72
61
|
}
|
|
73
62
|
function noteThreadName(note) {
|
|
74
|
-
return `讨论:${note.title?.trim() || note.
|
|
63
|
+
return `讨论:${note.title?.trim() || note.markdown.trim().slice(0, 28) || "未命名笔记"}`;
|
|
75
64
|
}
|
|
76
65
|
function registerNotesRoutes(authenticated, deps) {
|
|
77
66
|
const { service } = deps;
|
|
@@ -114,12 +103,12 @@ function registerNotesRoutes(authenticated, deps) {
|
|
|
114
103
|
} catch {
|
|
115
104
|
return c.json({ error: "Invalid multipart body" }, 400);
|
|
116
105
|
}
|
|
117
|
-
const
|
|
106
|
+
const markdown = typeof body.markdown === "string" ? body.markdown.trim() : void 0;
|
|
118
107
|
const kindRaw = typeof body.kind === "string" ? body.kind : void 0;
|
|
119
108
|
const tagsRaw = typeof body.tags === "string" ? body.tags : void 0;
|
|
120
109
|
const source = parseCaptureSource(body);
|
|
121
110
|
const note = await service.notesServiceInstance.createNote({
|
|
122
|
-
|
|
111
|
+
markdown,
|
|
123
112
|
kind: kindRaw && VALID_KINDS.has(kindRaw) ? kindRaw : void 0,
|
|
124
113
|
tags: tagsRaw ? tagsRaw.split(",").map((t) => t.trim()).filter(Boolean) : void 0,
|
|
125
114
|
capturedVia: source
|
|
@@ -149,14 +138,12 @@ function registerNotesRoutes(authenticated, deps) {
|
|
|
149
138
|
return c.json({ note: full }, 201);
|
|
150
139
|
}
|
|
151
140
|
const body = await c.req.json().catch(() => ({}));
|
|
152
|
-
const
|
|
153
|
-
const blocks = parseBlocks(body.blocks);
|
|
141
|
+
const markdown = typeof body.markdown === "string" ? body.markdown.trim() : void 0;
|
|
154
142
|
const kindRaw = typeof body.kind === "string" ? body.kind : void 0;
|
|
155
143
|
const tagsRaw = Array.isArray(body.tags) ? body.tags.filter((t) => typeof t === "string") : void 0;
|
|
156
144
|
const source = parseCaptureSource(body);
|
|
157
145
|
const note = await service.notesServiceInstance.createNote({
|
|
158
|
-
|
|
159
|
-
blocks,
|
|
146
|
+
markdown,
|
|
160
147
|
kind: kindRaw && VALID_KINDS.has(kindRaw) ? kindRaw : void 0,
|
|
161
148
|
tags: tagsRaw,
|
|
162
149
|
capturedVia: source,
|
|
@@ -315,8 +302,8 @@ function registerNotesRoutes(authenticated, deps) {
|
|
|
315
302
|
const body = await c.req.json().catch(() => ({}));
|
|
316
303
|
const instruction = typeof body.instruction === "string" ? body.instruction.trim() : "";
|
|
317
304
|
if (!instruction) return c.json({ error: "Missing required field: instruction" }, 400);
|
|
318
|
-
const
|
|
319
|
-
const result = await service.notesServiceInstance.createAiEditPatch(id, instruction,
|
|
305
|
+
const markdown = typeof body.markdown === "string" ? body.markdown : void 0;
|
|
306
|
+
const result = await service.notesServiceInstance.createAiEditPatch(id, instruction, markdown);
|
|
320
307
|
if (!result) return c.json({ error: "Note not found" }, 404);
|
|
321
308
|
return c.json(result);
|
|
322
309
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notes.js","names":[],"sources":["../../../../../src/gateway/hono/routes/notes.ts"],"sourcesContent":["import { createReadStream } from 'node:fs';\nimport { access, stat } from 'node:fs/promises';\nimport { Readable } from 'node:stream';\n\nimport type { Hono } from 'hono';\nimport { stream } from 'hono/streaming';\n\nimport { buildSessionKey } from '../../../routing/session-key.js';\nimport { agentExists, getDefaultAgentId } from '../../../routing/resolve-route.js';\nimport type { CaptureChannel, CaptureSource, Note, NoteBlock, NoteKind, NoteStatus, SnapshotTrigger } from '../../../notes/types.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nconst VALID_KINDS = new Set<NoteKind>(['thought', 'todo', 'voice', 'media', 'bookmark', 'mixed', 'task']);\nconst VALID_STATUSES = new Set<NoteStatus>(['inbox', 'processed', 'archived', 'trashed']);\nconst VALID_CHANNELS = new Set<CaptureChannel>(['app', 'web', 'electron', 'tui', 'telegram', 'wechat', 'feishu']);\n\nfunction parseCaptureSource(body: Record<string, unknown>): CaptureSource {\n const channel = typeof body.channel === 'string' && VALID_CHANNELS.has(body.channel as CaptureChannel)\n ? (body.channel as CaptureChannel)\n : 'web';\n const platform = body.platform === 'ios' || body.platform === 'android' ? body.platform : undefined;\n return { channel, platform };\n}\n\nfunction parseBlocks(value: unknown): NoteBlock[] | undefined {\n if (!Array.isArray(value)) return undefined;\n return value.filter((block): block is NoteBlock => {\n if (!block || typeof block !== 'object') return false;\n const candidate = block as Record<string, unknown>;\n if (typeof candidate.id !== 'string' || typeof candidate.type !== 'string') return false;\n if (candidate.type === 'image') {\n return typeof candidate.attachmentId === 'string';\n }\n return true;\n });\n}\n\nfunction buildNotePatch(body: Record<string, unknown>): Partial<Note> {\n const patch: Partial<Note> = {};\n if (typeof body.title === 'string') patch.title = body.title;\n if (typeof body.text === 'string') patch.text = body.text;\n if (Array.isArray(body.blocks)) patch.blocks = parseBlocks(body.blocks);\n if (typeof body.kind === 'string' && VALID_KINDS.has(body.kind as NoteKind)) patch.kind = body.kind as NoteKind;\n if (typeof body.status === 'string' && VALID_STATUSES.has(body.status as NoteStatus)) patch.status = body.status as NoteStatus;\n if (Array.isArray(body.tags)) patch.tags = body.tags.filter((tag): tag is string => typeof tag === 'string');\n if (typeof body.pinned === 'boolean') patch.pinned = body.pinned;\n if (typeof body.localVersion === 'number') patch.localVersion = body.localVersion;\n if (body.ai && typeof body.ai === 'object') patch.ai = body.ai as Note['ai'];\n if (body.aiDeep && typeof body.aiDeep === 'object') patch.aiDeep = body.aiDeep as Note['aiDeep'];\n return patch;\n}\n\nfunction buildNoteThreadContext(note: Note): string {\n const title = note.title?.trim() || '未命名笔记';\n const body = note.text?.trim() || '这条笔记暂无正文。';\n return [`来源 Note:${title}`, '', body].join('\\n');\n}\n\nfunction noteThreadName(note: Note): string {\n const title = note.title?.trim() || note.text?.trim()?.slice(0, 28) || '未命名笔记';\n return `讨论:${title}`;\n}\n\nexport function registerNotesRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n // POST /api/notes/quick-capture — minimal text capture\n authenticated.post('/api/notes/quick-capture', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const text = typeof body.text === 'string' ? body.text.trim() : '';\n if (!text) {\n return c.json({ error: 'Missing required field: text' }, 400);\n }\n const source = parseCaptureSource(body);\n const note = await service.notesServiceInstance.quickCapture(text, source);\n return c.json({ note }, 201);\n });\n\n // GET /api/notes — list with filters\n authenticated.get('/api/notes', async (c) => {\n const status = c.req.query('status') as NoteStatus | undefined;\n const kind = c.req.query('kind') as NoteKind | undefined;\n const tag = c.req.query('tag');\n const search = c.req.query('search');\n const pinnedRaw = c.req.query('pinned');\n const limitRaw = c.req.query('limit');\n const offsetRaw = c.req.query('offset');\n const sortBy = c.req.query('sortBy') as 'createdAt' | 'updatedAt' | undefined;\n const sortOrder = c.req.query('sortOrder') as 'asc' | 'desc' | undefined;\n\n const result = await service.notesServiceInstance.listNotes({\n status: status && VALID_STATUSES.has(status) ? status : undefined,\n kind: kind && VALID_KINDS.has(kind) ? kind : undefined,\n tag: tag || undefined,\n search: search || undefined,\n pinned: pinnedRaw === 'true' ? true : pinnedRaw === 'false' ? false : undefined,\n limit: limitRaw ? parseInt(limitRaw, 10) : undefined,\n offset: offsetRaw ? parseInt(offsetRaw, 10) : undefined,\n sortBy: sortBy === 'createdAt' || sortBy === 'updatedAt' ? sortBy : undefined,\n sortOrder: sortOrder === 'asc' || sortOrder === 'desc' ? sortOrder : undefined,\n });\n return c.json(result);\n });\n\n // POST /api/notes — full create (JSON or multipart)\n authenticated.post('/api/notes', async (c) => {\n const contentType = c.req.header('content-type') || '';\n\n if (contentType.includes('multipart/form-data')) {\n let body: Record<string, unknown>;\n try {\n body = await c.req.parseBody({ all: true });\n } catch {\n return c.json({ error: 'Invalid multipart body' }, 400);\n }\n\n const text = typeof body.text === 'string' ? body.text.trim() : undefined;\n const kindRaw = typeof body.kind === 'string' ? body.kind : undefined;\n const tagsRaw = typeof body.tags === 'string' ? body.tags : undefined;\n const source = parseCaptureSource(body as Record<string, unknown>);\n\n const note = await service.notesServiceInstance.createNote({\n text,\n kind: kindRaw && VALID_KINDS.has(kindRaw as NoteKind) ? (kindRaw as NoteKind) : undefined,\n tags: tagsRaw ? tagsRaw.split(',').map((t) => t.trim()).filter(Boolean) : undefined,\n capturedVia: source,\n });\n\n const file = body.file;\n if (file && typeof file === 'object') {\n let buf: Buffer | null = null;\n let fileName = 'upload';\n let mimeType = 'application/octet-stream';\n\n if (file instanceof File) {\n buf = Buffer.from(await file.arrayBuffer());\n fileName = file.name || fileName;\n mimeType = file.type || mimeType;\n } else if (typeof (file as Blob).arrayBuffer === 'function') {\n buf = Buffer.from(await (file as Blob).arrayBuffer());\n }\n\n if (buf) {\n const durationRaw = body.duration;\n const duration =\n typeof durationRaw === 'string'\n ? parseInt(durationRaw, 10)\n : typeof durationRaw === 'number'\n ? durationRaw\n : undefined;\n await service.notesServiceInstance.addAttachment(note.id, {\n name: fileName,\n buffer: buf,\n mimeType,\n duration: Number.isFinite(duration) ? duration : undefined,\n });\n }\n }\n\n const full = await service.notesServiceInstance.getNote(note.id);\n return c.json({ note: full }, 201);\n }\n\n // JSON body\n const body = await c.req.json().catch(() => ({}));\n const text = typeof body.text === 'string' ? body.text.trim() : undefined;\n const blocks = parseBlocks(body.blocks);\n const kindRaw = typeof body.kind === 'string' ? body.kind : undefined;\n const tagsRaw = Array.isArray(body.tags) ? body.tags.filter((t: unknown) => typeof t === 'string') : undefined;\n const source = parseCaptureSource(body);\n\n const note = await service.notesServiceInstance.createNote({\n text,\n blocks,\n kind: kindRaw && VALID_KINDS.has(kindRaw as NoteKind) ? (kindRaw as NoteKind) : undefined,\n tags: tagsRaw,\n capturedVia: source,\n pinned: body.pinned === true,\n });\n return c.json({ note }, 201);\n });\n\n // POST /api/notes/sync — local-first block sync with optimistic conflict check\n authenticated.post('/api/notes/sync', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const noteId = typeof body.noteId === 'string' ? body.noteId : '';\n if (!noteId) {\n return c.json({ error: 'Missing required field: noteId' }, 400);\n }\n\n const baseRemoteVersion = typeof body.baseRemoteVersion === 'number' ? body.baseRemoteVersion : undefined;\n const patch = buildNotePatch(body);\n const result = await service.notesServiceInstance.syncNote(noteId, patch, baseRemoteVersion);\n if (!result.note) {\n return c.json({ error: 'Note not found' }, 404);\n }\n if (result.conflict) {\n return c.json({ conflict: true, note: result.note }, 409);\n }\n return c.json({ conflict: false, note: result.note });\n });\n\n // POST /api/notes/:id/catalyze — generate an AI catalysis report and write it back\n authenticated.post('/api/notes/:id/catalyze', async (c) => {\n const result = await service.notesServiceInstance.catalyzeNote(c.req.param('id'), service.currentConfig);\n if (!result) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json(result);\n });\n\n // POST /api/notes/:id/catalysis-feedback — record whether the catalysis was useful\n authenticated.post('/api/notes/:id/catalysis-feedback', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const feedback = body.feedback;\n if (feedback !== 'helpful' && feedback !== 'not_helpful' && feedback !== 'neutral') {\n return c.json({ error: 'Invalid feedback' }, 400);\n }\n const note = await service.notesServiceInstance.recordCatalysisFeedback(c.req.param('id'), feedback);\n if (!note) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json({ note });\n });\n\n // POST /api/notes/:id/chat — create or reuse a note-bound web chat thread\n authenticated.post('/api/notes/:id/chat', async (c) => {\n const noteId = c.req.param('id');\n const note = await service.notesServiceInstance.getNote(noteId);\n if (!note) {\n return c.json({ error: 'Note not found' }, 404);\n }\n\n const body = await c.req.json().catch(() => ({}));\n const routingCfg = service.currentConfig;\n let agentId =\n typeof body.agentId === 'string' && body.agentId.trim()\n ? body.agentId.trim().toLowerCase()\n : getDefaultAgentId(routingCfg);\n if (!agentExists(agentId, routingCfg)) {\n agentId = getDefaultAgentId(routingCfg);\n }\n\n const existingKey = note.aiDeep?.catalysis?.sourceSessionKey;\n if (existingKey) {\n const existingSession = await service.sessions.getSession(existingKey);\n if (existingSession) {\n return c.json({ session: existingSession, sessionKey: existingKey, reused: true });\n }\n }\n\n const sessionKey = buildSessionKey({\n agentId,\n source: 'webchat',\n accountId: 'default',\n peerKind: 'direct',\n peerId: `note_${noteId}_${Date.now()}`,\n });\n\n await service.sessionIndexInstance.saveMessages(sessionKey, []);\n await service.sessionIndexInstance.appendTranscriptContextEntry(sessionKey, {\n id: `source-note:${noteId}`,\n text: buildNoteThreadContext(note),\n data: {\n kind: 'source_note',\n noteId,\n title: note.title ?? '',\n },\n });\n\n const meta = await service.sessionIndexInstance.getSessionMetadata(sessionKey);\n await service.sessionIndexInstance.updateSessionMetadata(sessionKey, {\n name: noteThreadName(note),\n tags: Array.from(new Set([...(meta?.tags ?? []), 'note'])),\n customData: {\n ...(meta?.customData ?? {}),\n sourceNoteId: noteId,\n sourceNoteTitle: note.title ?? '',\n },\n });\n\n await service.notesServiceInstance.linkNoteThread(noteId, sessionKey);\n const session = await service.sessions.getSession(sessionKey);\n return c.json({ session, sessionKey, reused: false }, 201);\n });\n\n // GET /api/notes/:id/threads — list chat threads linked to a note\n authenticated.get('/api/notes/:id/threads', async (c) => {\n const noteId = c.req.param('id');\n const keys = await service.notesServiceInstance.listNoteThreads(noteId);\n if (!keys) {\n return c.json({ error: 'Note not found' }, 404);\n }\n const sessions = [];\n for (const key of keys) {\n const session = await service.sessions.getSession(key);\n if (session) sessions.push(session);\n }\n return c.json({ items: sessions, total: sessions.length });\n });\n\n // POST /api/notes/:id/append — append assistant output or selected text back to the note\n authenticated.post('/api/notes/:id/append', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const content = typeof body.content === 'string' ? body.content.trim() : '';\n const heading = typeof body.heading === 'string' && body.heading.trim() ? body.heading.trim() : undefined;\n if (!content) {\n return c.json({ error: 'Missing required field: content' }, 400);\n }\n const note = await service.notesServiceInstance.appendTextToNote(c.req.param('id'), content, heading);\n if (!note) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json({ note });\n });\n\n // GET /api/notes/:id — single note\n authenticated.get('/api/notes/:id', async (c) => {\n const id = c.req.param('id');\n const note = await service.notesServiceInstance.getNote(id);\n if (!note) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json({ note });\n });\n\n // PATCH /api/notes/:id — update\n authenticated.patch('/api/notes/:id', async (c) => {\n const id = c.req.param('id');\n const body = await c.req.json().catch(() => ({}));\n\n const patch = buildNotePatch(body);\n const trigger: SnapshotTrigger =\n body.trigger === 'ai_edit' || body.trigger === 'sync' || body.trigger === 'restore'\n ? body.trigger\n : 'edit';\n\n const updated = await service.notesServiceInstance.updateNote(id, patch, trigger);\n if (!updated) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json({ note: updated });\n });\n\n // DELETE /api/notes/:id — delete note\n authenticated.delete('/api/notes/:id', async (c) => {\n const id = c.req.param('id');\n const removed = await service.notesServiceInstance.deleteNote(id);\n if (!removed) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json({ deleted: true });\n });\n\n // GET /api/notes/:id/history — list version snapshots\n authenticated.get('/api/notes/:id/history', async (c) => {\n const id = c.req.param('id');\n const entries = await service.notesServiceInstance.listNoteHistory(id);\n return c.json({ entries });\n });\n\n // GET /api/notes/:id/history/:timestamp — get full snapshot\n authenticated.get('/api/notes/:id/history/:timestamp', async (c) => {\n const id = c.req.param('id');\n const timestamp = parseInt(c.req.param('timestamp'), 10);\n if (!Number.isFinite(timestamp)) {\n return c.json({ error: 'Invalid timestamp' }, 400);\n }\n const snapshot = await service.notesServiceInstance.getNoteSnapshot(id, timestamp);\n if (!snapshot) {\n return c.json({ error: 'Snapshot not found' }, 404);\n }\n return c.json({ snapshot });\n });\n\n // POST /api/notes/:id/history/restore — restore a snapshot\n authenticated.post('/api/notes/:id/history/restore', async (c) => {\n const id = c.req.param('id');\n const body = await c.req.json().catch(() => ({}));\n const timestamp = typeof body.timestamp === 'number' ? body.timestamp : 0;\n if (!timestamp) {\n return c.json({ error: 'Missing required field: timestamp' }, 400);\n }\n const note = await service.notesServiceInstance.restoreNoteSnapshot(id, timestamp);\n if (!note) {\n return c.json({ error: 'Snapshot or note not found' }, 404);\n }\n return c.json({ note });\n });\n\n // POST /api/notes/:id/ai/edit — generate previewable block-level AI patch\n authenticated.post('/api/notes/:id/ai/edit', async (c) => {\n const id = c.req.param('id');\n const body = await c.req.json().catch(() => ({}));\n const instruction = typeof body.instruction === 'string' ? body.instruction.trim() : '';\n if (!instruction) {\n return c.json({ error: 'Missing required field: instruction' }, 400);\n }\n\n const blocks = parseBlocks(body.blocks);\n const result = await service.notesServiceInstance.createAiEditPatch(id, instruction, blocks);\n if (!result) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json(result);\n });\n\n // POST /api/notes/:id/media — upload attachment to existing note\n authenticated.post('/api/notes/:id/media', async (c) => {\n const noteId = c.req.param('id');\n let body: Record<string, unknown>;\n try {\n body = await c.req.parseBody({ all: true });\n } catch {\n return c.json({ error: 'Invalid multipart body' }, 400);\n }\n\n const file = body.file;\n if (!file || typeof file !== 'object') {\n return c.json({ error: 'Missing file field' }, 400);\n }\n\n let buf: Buffer;\n let fileName = 'upload';\n let mimeType = 'application/octet-stream';\n\n if (file instanceof File) {\n buf = Buffer.from(await file.arrayBuffer());\n fileName = file.name || fileName;\n mimeType = file.type || mimeType;\n } else if (typeof (file as Blob).arrayBuffer === 'function') {\n buf = Buffer.from(await (file as Blob).arrayBuffer());\n } else {\n return c.json({ error: 'Invalid file upload' }, 400);\n }\n\n const durationRaw = body.duration;\n const duration = typeof durationRaw === 'string' ? parseInt(durationRaw, 10) : undefined;\n\n const attachment = await service.notesServiceInstance.addAttachment(noteId, {\n name: fileName,\n buffer: buf,\n mimeType,\n duration: Number.isFinite(duration) ? duration : undefined,\n });\n\n if (!attachment) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json({ attachment }, 201);\n });\n\n // GET /api/notes/:id/media/:attachmentId — serve attachment file\n authenticated.get('/api/notes/:id/media/:attachmentId', async (c) => {\n const noteId = c.req.param('id');\n const attachmentId = c.req.param('attachmentId');\n\n const result = await service.notesServiceInstance.getAttachmentPath(noteId, attachmentId);\n if (!result) {\n return c.json({ error: 'Attachment not found' }, 404);\n }\n\n const { filePath, mimeType, fileName } = result;\n\n try {\n await access(filePath);\n } catch {\n return c.json({ error: 'Attachment file missing' }, 404);\n }\n\n const fileStat = await stat(filePath);\n\n c.header('Content-Type', mimeType);\n c.header('Content-Length', String(fileStat.size));\n c.header('Content-Disposition', `inline; filename=\"${encodeURIComponent(fileName)}\"`);\n c.header('Cache-Control', 'private, max-age=31536000, immutable');\n\n return stream(c, async (s) => {\n const readable = Readable.toWeb(createReadStream(filePath)) as ReadableStream<Uint8Array>;\n await s.pipe(readable);\n });\n });\n\n // ── Task / Space / Open tracking ────────────────────────────────────\n\n authenticated.post('/api/notes/task', async (c) => {\n const body = await c.req.json().catch(() => ({})) as Record<string, unknown>;\n const title = typeof body.title === 'string' ? body.title.trim() : '';\n if (!title) return c.json({ error: 'Missing required field: title' }, 400);\n\n const source = parseCaptureSource(body);\n const note = await service.notesServiceInstance.createTask(title, source, {\n dueAt: typeof body.dueAt === 'number' ? body.dueAt : undefined,\n priority: body.priority === 'high' || body.priority === 'medium' || body.priority === 'low' ? body.priority : undefined,\n sourceSessionKey: typeof body.sourceSessionKey === 'string' ? body.sourceSessionKey : undefined,\n sourceNoteId: typeof body.sourceNoteId === 'string' ? body.sourceNoteId : undefined,\n groupId: typeof body.groupId === 'string' ? body.groupId : undefined,\n });\n return c.json({ note }, 201);\n });\n\n authenticated.post('/api/notes/:id/toggle-done', async (c) => {\n const note = await service.notesServiceInstance.toggleTaskDone(c.req.param('id'));\n if (!note) return c.json({ error: 'Not found or not a task' }, 404);\n return c.json({ note });\n });\n\n authenticated.post('/api/notes/:id/open', async (c) => {\n const note = await service.notesServiceInstance.recordOpen(c.req.param('id'));\n if (!note) return c.json({ error: 'Not found' }, 404);\n return c.json({ note });\n });\n\n authenticated.post('/api/notes/:id/move', async (c) => {\n const body = await c.req.json().catch(() => ({})) as Record<string, unknown>;\n const groupId = typeof body.groupId === 'string' ? body.groupId : null;\n const note = await service.notesServiceInstance.moveToGroup(c.req.param('id'), groupId);\n if (!note) return c.json({ error: 'Not found' }, 404);\n return c.json({ note });\n });\n}\n"],"mappings":";;;;;;;kBAOkE;oBACiB;AAInF,MAAM,cAAc,IAAI,IAAc;CAAC;CAAW;CAAQ;CAAS;CAAS;CAAY;CAAS;CAAO,CAAC;AACzG,MAAM,iBAAiB,IAAI,IAAgB;CAAC;CAAS;CAAa;CAAY;CAAU,CAAC;AACzF,MAAM,iBAAiB,IAAI,IAAoB;CAAC;CAAO;CAAO;CAAY;CAAO;CAAY;CAAU;CAAS,CAAC;AAEjH,SAAS,mBAAmB,MAA8C;AAKxE,QAAO;EAAE,SAJO,OAAO,KAAK,YAAY,YAAY,eAAe,IAAI,KAAK,QAA0B,GACjG,KAAK,UACN;EAEc,UADD,KAAK,aAAa,SAAS,KAAK,aAAa,YAAY,KAAK,WAAW,KAAA;EAC9D;;AAG9B,SAAS,YAAY,OAAyC;AAC5D,KAAI,CAAC,MAAM,QAAQ,MAAM,CAAE,QAAO,KAAA;AAClC,QAAO,MAAM,QAAQ,UAA8B;AACjD,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;EAChD,MAAM,YAAY;AAClB,MAAI,OAAO,UAAU,OAAO,YAAY,OAAO,UAAU,SAAS,SAAU,QAAO;AACnF,MAAI,UAAU,SAAS,QACrB,QAAO,OAAO,UAAU,iBAAiB;AAE3C,SAAO;GACP;;AAGJ,SAAS,eAAe,MAA8C;CACpE,MAAM,QAAuB,EAAE;AAC/B,KAAI,OAAO,KAAK,UAAU,SAAU,OAAM,QAAQ,KAAK;AACvD,KAAI,OAAO,KAAK,SAAS,SAAU,OAAM,OAAO,KAAK;AACrD,KAAI,MAAM,QAAQ,KAAK,OAAO,CAAE,OAAM,SAAS,YAAY,KAAK,OAAO;AACvE,KAAI,OAAO,KAAK,SAAS,YAAY,YAAY,IAAI,KAAK,KAAiB,CAAE,OAAM,OAAO,KAAK;AAC/F,KAAI,OAAO,KAAK,WAAW,YAAY,eAAe,IAAI,KAAK,OAAqB,CAAE,OAAM,SAAS,KAAK;AAC1G,KAAI,MAAM,QAAQ,KAAK,KAAK,CAAE,OAAM,OAAO,KAAK,KAAK,QAAQ,QAAuB,OAAO,QAAQ,SAAS;AAC5G,KAAI,OAAO,KAAK,WAAW,UAAW,OAAM,SAAS,KAAK;AAC1D,KAAI,OAAO,KAAK,iBAAiB,SAAU,OAAM,eAAe,KAAK;AACrE,KAAI,KAAK,MAAM,OAAO,KAAK,OAAO,SAAU,OAAM,KAAK,KAAK;AAC5D,KAAI,KAAK,UAAU,OAAO,KAAK,WAAW,SAAU,OAAM,SAAS,KAAK;AACxE,QAAO;;AAGT,SAAS,uBAAuB,MAAoB;CAClD,MAAM,QAAQ,KAAK,OAAO,MAAM,IAAI;CACpC,MAAM,OAAO,KAAK,MAAM,MAAM,IAAI;AAClC,QAAO;EAAC,WAAW;EAAS;EAAI;EAAK,CAAC,KAAK,KAAK;;AAGlD,SAAS,eAAe,MAAoB;AAE1C,QAAO,MADO,KAAK,OAAO,MAAM,IAAI,KAAK,MAAM,MAAM,EAAE,MAAM,GAAG,GAAG,IAAI;;AAIzE,SAAgB,oBAAoB,eAAqB,MAAoC;CAC3F,MAAM,EAAE,YAAY;AAGpB,eAAc,KAAK,4BAA4B,OAAO,MAAM;EAC1D,MAAM,OAAO,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EACjD,MAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,KAAK,MAAM,GAAG;AAChE,MAAI,CAAC,KACH,QAAO,EAAE,KAAK,EAAE,OAAO,gCAAgC,EAAE,IAAI;EAE/D,MAAM,SAAS,mBAAmB,KAAK;EACvC,MAAM,OAAO,MAAM,QAAQ,qBAAqB,aAAa,MAAM,OAAO;AAC1E,SAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI;GAC5B;AAGF,eAAc,IAAI,cAAc,OAAO,MAAM;EAC3C,MAAM,SAAS,EAAE,IAAI,MAAM,SAAS;EACpC,MAAM,OAAO,EAAE,IAAI,MAAM,OAAO;EAChC,MAAM,MAAM,EAAE,IAAI,MAAM,MAAM;EAC9B,MAAM,SAAS,EAAE,IAAI,MAAM,SAAS;EACpC,MAAM,YAAY,EAAE,IAAI,MAAM,SAAS;EACvC,MAAM,WAAW,EAAE,IAAI,MAAM,QAAQ;EACrC,MAAM,YAAY,EAAE,IAAI,MAAM,SAAS;EACvC,MAAM,SAAS,EAAE,IAAI,MAAM,SAAS;EACpC,MAAM,YAAY,EAAE,IAAI,MAAM,YAAY;EAE1C,MAAM,SAAS,MAAM,QAAQ,qBAAqB,UAAU;GAC1D,QAAQ,UAAU,eAAe,IAAI,OAAO,GAAG,SAAS,KAAA;GACxD,MAAM,QAAQ,YAAY,IAAI,KAAK,GAAG,OAAO,KAAA;GAC7C,KAAK,OAAO,KAAA;GACZ,QAAQ,UAAU,KAAA;GAClB,QAAQ,cAAc,SAAS,OAAO,cAAc,UAAU,QAAQ,KAAA;GACtE,OAAO,WAAW,SAAS,UAAU,GAAG,GAAG,KAAA;GAC3C,QAAQ,YAAY,SAAS,WAAW,GAAG,GAAG,KAAA;GAC9C,QAAQ,WAAW,eAAe,WAAW,cAAc,SAAS,KAAA;GACpE,WAAW,cAAc,SAAS,cAAc,SAAS,YAAY,KAAA;GACtE,CAAC;AACF,SAAO,EAAE,KAAK,OAAO;GACrB;AAGF,eAAc,KAAK,cAAc,OAAO,MAAM;AAG5C,OAFoB,EAAE,IAAI,OAAO,eAAe,IAAI,IAEpC,SAAS,sBAAsB,EAAE;GAC/C,IAAI;AACJ,OAAI;AACF,WAAO,MAAM,EAAE,IAAI,UAAU,EAAE,KAAK,MAAM,CAAC;WACrC;AACN,WAAO,EAAE,KAAK,EAAE,OAAO,0BAA0B,EAAE,IAAI;;GAGzD,MAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,KAAK,MAAM,GAAG,KAAA;GAChE,MAAM,UAAU,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO,KAAA;GAC5D,MAAM,UAAU,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO,KAAA;GAC5D,MAAM,SAAS,mBAAmB,KAAgC;GAElE,MAAM,OAAO,MAAM,QAAQ,qBAAqB,WAAW;IACzD;IACA,MAAM,WAAW,YAAY,IAAI,QAAoB,GAAI,UAAuB,KAAA;IAChF,MAAM,UAAU,QAAQ,MAAM,IAAI,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC,CAAC,OAAO,QAAQ,GAAG,KAAA;IAC1E,aAAa;IACd,CAAC;GAEF,MAAM,OAAO,KAAK;AAClB,OAAI,QAAQ,OAAO,SAAS,UAAU;IACpC,IAAI,MAAqB;IACzB,IAAI,WAAW;IACf,IAAI,WAAW;AAEf,QAAI,gBAAgB,MAAM;AACxB,WAAM,OAAO,KAAK,MAAM,KAAK,aAAa,CAAC;AAC3C,gBAAW,KAAK,QAAQ;AACxB,gBAAW,KAAK,QAAQ;eACf,OAAQ,KAAc,gBAAgB,WAC/C,OAAM,OAAO,KAAK,MAAO,KAAc,aAAa,CAAC;AAGvD,QAAI,KAAK;KACP,MAAM,cAAc,KAAK;KACzB,MAAM,WACJ,OAAO,gBAAgB,WACnB,SAAS,aAAa,GAAG,GACzB,OAAO,gBAAgB,WACrB,cACA,KAAA;AACR,WAAM,QAAQ,qBAAqB,cAAc,KAAK,IAAI;MACxD,MAAM;MACN,QAAQ;MACR;MACA,UAAU,OAAO,SAAS,SAAS,GAAG,WAAW,KAAA;MAClD,CAAC;;;GAIN,MAAM,OAAO,MAAM,QAAQ,qBAAqB,QAAQ,KAAK,GAAG;AAChE,UAAO,EAAE,KAAK,EAAE,MAAM,MAAM,EAAE,IAAI;;EAIpC,MAAM,OAAO,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EACjD,MAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,KAAK,MAAM,GAAG,KAAA;EAChE,MAAM,SAAS,YAAY,KAAK,OAAO;EACvC,MAAM,UAAU,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO,KAAA;EAC5D,MAAM,UAAU,MAAM,QAAQ,KAAK,KAAK,GAAG,KAAK,KAAK,QAAQ,MAAe,OAAO,MAAM,SAAS,GAAG,KAAA;EACrG,MAAM,SAAS,mBAAmB,KAAK;EAEvC,MAAM,OAAO,MAAM,QAAQ,qBAAqB,WAAW;GACzD;GACA;GACA,MAAM,WAAW,YAAY,IAAI,QAAoB,GAAI,UAAuB,KAAA;GAChF,MAAM;GACN,aAAa;GACb,QAAQ,KAAK,WAAW;GACzB,CAAC;AACF,SAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI;GAC5B;AAGF,eAAc,KAAK,mBAAmB,OAAO,MAAM;EACjD,MAAM,OAAO,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EACjD,MAAM,SAAS,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;AAC/D,MAAI,CAAC,OACH,QAAO,EAAE,KAAK,EAAE,OAAO,kCAAkC,EAAE,IAAI;EAGjE,MAAM,oBAAoB,OAAO,KAAK,sBAAsB,WAAW,KAAK,oBAAoB,KAAA;EAChG,MAAM,QAAQ,eAAe,KAAK;EAClC,MAAM,SAAS,MAAM,QAAQ,qBAAqB,SAAS,QAAQ,OAAO,kBAAkB;AAC5F,MAAI,CAAC,OAAO,KACV,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;AAEjD,MAAI,OAAO,SACT,QAAO,EAAE,KAAK;GAAE,UAAU;GAAM,MAAM,OAAO;GAAM,EAAE,IAAI;AAE3D,SAAO,EAAE,KAAK;GAAE,UAAU;GAAO,MAAM,OAAO;GAAM,CAAC;GACrD;AAGF,eAAc,KAAK,2BAA2B,OAAO,MAAM;EACzD,MAAM,SAAS,MAAM,QAAQ,qBAAqB,aAAa,EAAE,IAAI,MAAM,KAAK,EAAE,QAAQ,cAAc;AACxG,MAAI,CAAC,OACH,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;AAEjD,SAAO,EAAE,KAAK,OAAO;GACrB;AAGF,eAAc,KAAK,qCAAqC,OAAO,MAAM;EAEnE,MAAM,YAAW,MADE,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE,EAC3B;AACtB,MAAI,aAAa,aAAa,aAAa,iBAAiB,aAAa,UACvE,QAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,EAAE,IAAI;EAEnD,MAAM,OAAO,MAAM,QAAQ,qBAAqB,wBAAwB,EAAE,IAAI,MAAM,KAAK,EAAE,SAAS;AACpG,MAAI,CAAC,KACH,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;AAEjD,SAAO,EAAE,KAAK,EAAE,MAAM,CAAC;GACvB;AAGF,eAAc,KAAK,uBAAuB,OAAO,MAAM;EACrD,MAAM,SAAS,EAAE,IAAI,MAAM,KAAK;EAChC,MAAM,OAAO,MAAM,QAAQ,qBAAqB,QAAQ,OAAO;AAC/D,MAAI,CAAC,KACH,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;EAGjD,MAAM,OAAO,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EACjD,MAAM,aAAa,QAAQ;EAC3B,IAAI,UACF,OAAO,KAAK,YAAY,YAAY,KAAK,QAAQ,MAAM,GACnD,KAAK,QAAQ,MAAM,CAAC,aAAa,GACjC,kBAAkB,WAAW;AACnC,MAAI,CAAC,YAAY,SAAS,WAAW,CACnC,WAAU,kBAAkB,WAAW;EAGzC,MAAM,cAAc,KAAK,QAAQ,WAAW;AAC5C,MAAI,aAAa;GACf,MAAM,kBAAkB,MAAM,QAAQ,SAAS,WAAW,YAAY;AACtE,OAAI,gBACF,QAAO,EAAE,KAAK;IAAE,SAAS;IAAiB,YAAY;IAAa,QAAQ;IAAM,CAAC;;EAItF,MAAM,aAAa,gBAAgB;GACjC;GACA,QAAQ;GACR,WAAW;GACX,UAAU;GACV,QAAQ,QAAQ,OAAO,GAAG,KAAK,KAAK;GACrC,CAAC;AAEF,QAAM,QAAQ,qBAAqB,aAAa,YAAY,EAAE,CAAC;AAC/D,QAAM,QAAQ,qBAAqB,6BAA6B,YAAY;GAC1E,IAAI,eAAe;GACnB,MAAM,uBAAuB,KAAK;GAClC,MAAM;IACJ,MAAM;IACN;IACA,OAAO,KAAK,SAAS;IACtB;GACF,CAAC;EAEF,MAAM,OAAO,MAAM,QAAQ,qBAAqB,mBAAmB,WAAW;AAC9E,QAAM,QAAQ,qBAAqB,sBAAsB,YAAY;GACnE,MAAM,eAAe,KAAK;GAC1B,MAAM,MAAM,KAAK,IAAI,IAAI,CAAC,GAAI,MAAM,QAAQ,EAAE,EAAG,OAAO,CAAC,CAAC;GAC1D,YAAY;IACV,GAAI,MAAM,cAAc,EAAE;IAC1B,cAAc;IACd,iBAAiB,KAAK,SAAS;IAChC;GACF,CAAC;AAEF,QAAM,QAAQ,qBAAqB,eAAe,QAAQ,WAAW;EACrE,MAAM,UAAU,MAAM,QAAQ,SAAS,WAAW,WAAW;AAC7D,SAAO,EAAE,KAAK;GAAE;GAAS;GAAY,QAAQ;GAAO,EAAE,IAAI;GAC1D;AAGF,eAAc,IAAI,0BAA0B,OAAO,MAAM;EACvD,MAAM,SAAS,EAAE,IAAI,MAAM,KAAK;EAChC,MAAM,OAAO,MAAM,QAAQ,qBAAqB,gBAAgB,OAAO;AACvE,MAAI,CAAC,KACH,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;EAEjD,MAAM,WAAW,EAAE;AACnB,OAAK,MAAM,OAAO,MAAM;GACtB,MAAM,UAAU,MAAM,QAAQ,SAAS,WAAW,IAAI;AACtD,OAAI,QAAS,UAAS,KAAK,QAAQ;;AAErC,SAAO,EAAE,KAAK;GAAE,OAAO;GAAU,OAAO,SAAS;GAAQ,CAAC;GAC1D;AAGF,eAAc,KAAK,yBAAyB,OAAO,MAAM;EACvD,MAAM,OAAO,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EACjD,MAAM,UAAU,OAAO,KAAK,YAAY,WAAW,KAAK,QAAQ,MAAM,GAAG;EACzE,MAAM,UAAU,OAAO,KAAK,YAAY,YAAY,KAAK,QAAQ,MAAM,GAAG,KAAK,QAAQ,MAAM,GAAG,KAAA;AAChG,MAAI,CAAC,QACH,QAAO,EAAE,KAAK,EAAE,OAAO,mCAAmC,EAAE,IAAI;EAElE,MAAM,OAAO,MAAM,QAAQ,qBAAqB,iBAAiB,EAAE,IAAI,MAAM,KAAK,EAAE,SAAS,QAAQ;AACrG,MAAI,CAAC,KACH,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;AAEjD,SAAO,EAAE,KAAK,EAAE,MAAM,CAAC;GACvB;AAGF,eAAc,IAAI,kBAAkB,OAAO,MAAM;EAC/C,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK;EAC5B,MAAM,OAAO,MAAM,QAAQ,qBAAqB,QAAQ,GAAG;AAC3D,MAAI,CAAC,KACH,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;AAEjD,SAAO,EAAE,KAAK,EAAE,MAAM,CAAC;GACvB;AAGF,eAAc,MAAM,kBAAkB,OAAO,MAAM;EACjD,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK;EAC5B,MAAM,OAAO,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EAEjD,MAAM,QAAQ,eAAe,KAAK;EAClC,MAAM,UACJ,KAAK,YAAY,aAAa,KAAK,YAAY,UAAU,KAAK,YAAY,YACtE,KAAK,UACL;EAEN,MAAM,UAAU,MAAM,QAAQ,qBAAqB,WAAW,IAAI,OAAO,QAAQ;AACjF,MAAI,CAAC,QACH,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;AAEjD,SAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;GAChC;AAGF,eAAc,OAAO,kBAAkB,OAAO,MAAM;EAClD,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK;AAE5B,MAAI,CAAC,MADiB,QAAQ,qBAAqB,WAAW,GAAG,CAE/D,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;AAEjD,SAAO,EAAE,KAAK,EAAE,SAAS,MAAM,CAAC;GAChC;AAGF,eAAc,IAAI,0BAA0B,OAAO,MAAM;EACvD,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK;EAC5B,MAAM,UAAU,MAAM,QAAQ,qBAAqB,gBAAgB,GAAG;AACtE,SAAO,EAAE,KAAK,EAAE,SAAS,CAAC;GAC1B;AAGF,eAAc,IAAI,qCAAqC,OAAO,MAAM;EAClE,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK;EAC5B,MAAM,YAAY,SAAS,EAAE,IAAI,MAAM,YAAY,EAAE,GAAG;AACxD,MAAI,CAAC,OAAO,SAAS,UAAU,CAC7B,QAAO,EAAE,KAAK,EAAE,OAAO,qBAAqB,EAAE,IAAI;EAEpD,MAAM,WAAW,MAAM,QAAQ,qBAAqB,gBAAgB,IAAI,UAAU;AAClF,MAAI,CAAC,SACH,QAAO,EAAE,KAAK,EAAE,OAAO,sBAAsB,EAAE,IAAI;AAErD,SAAO,EAAE,KAAK,EAAE,UAAU,CAAC;GAC3B;AAGF,eAAc,KAAK,kCAAkC,OAAO,MAAM;EAChE,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK;EAC5B,MAAM,OAAO,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EACjD,MAAM,YAAY,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AACxE,MAAI,CAAC,UACH,QAAO,EAAE,KAAK,EAAE,OAAO,qCAAqC,EAAE,IAAI;EAEpE,MAAM,OAAO,MAAM,QAAQ,qBAAqB,oBAAoB,IAAI,UAAU;AAClF,MAAI,CAAC,KACH,QAAO,EAAE,KAAK,EAAE,OAAO,8BAA8B,EAAE,IAAI;AAE7D,SAAO,EAAE,KAAK,EAAE,MAAM,CAAC;GACvB;AAGF,eAAc,KAAK,0BAA0B,OAAO,MAAM;EACxD,MAAM,KAAK,EAAE,IAAI,MAAM,KAAK;EAC5B,MAAM,OAAO,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EACjD,MAAM,cAAc,OAAO,KAAK,gBAAgB,WAAW,KAAK,YAAY,MAAM,GAAG;AACrF,MAAI,CAAC,YACH,QAAO,EAAE,KAAK,EAAE,OAAO,uCAAuC,EAAE,IAAI;EAGtE,MAAM,SAAS,YAAY,KAAK,OAAO;EACvC,MAAM,SAAS,MAAM,QAAQ,qBAAqB,kBAAkB,IAAI,aAAa,OAAO;AAC5F,MAAI,CAAC,OACH,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;AAEjD,SAAO,EAAE,KAAK,OAAO;GACrB;AAGF,eAAc,KAAK,wBAAwB,OAAO,MAAM;EACtD,MAAM,SAAS,EAAE,IAAI,MAAM,KAAK;EAChC,IAAI;AACJ,MAAI;AACF,UAAO,MAAM,EAAE,IAAI,UAAU,EAAE,KAAK,MAAM,CAAC;UACrC;AACN,UAAO,EAAE,KAAK,EAAE,OAAO,0BAA0B,EAAE,IAAI;;EAGzD,MAAM,OAAO,KAAK;AAClB,MAAI,CAAC,QAAQ,OAAO,SAAS,SAC3B,QAAO,EAAE,KAAK,EAAE,OAAO,sBAAsB,EAAE,IAAI;EAGrD,IAAI;EACJ,IAAI,WAAW;EACf,IAAI,WAAW;AAEf,MAAI,gBAAgB,MAAM;AACxB,SAAM,OAAO,KAAK,MAAM,KAAK,aAAa,CAAC;AAC3C,cAAW,KAAK,QAAQ;AACxB,cAAW,KAAK,QAAQ;aACf,OAAQ,KAAc,gBAAgB,WAC/C,OAAM,OAAO,KAAK,MAAO,KAAc,aAAa,CAAC;MAErD,QAAO,EAAE,KAAK,EAAE,OAAO,uBAAuB,EAAE,IAAI;EAGtD,MAAM,cAAc,KAAK;EACzB,MAAM,WAAW,OAAO,gBAAgB,WAAW,SAAS,aAAa,GAAG,GAAG,KAAA;EAE/E,MAAM,aAAa,MAAM,QAAQ,qBAAqB,cAAc,QAAQ;GAC1E,MAAM;GACN,QAAQ;GACR;GACA,UAAU,OAAO,SAAS,SAAS,GAAG,WAAW,KAAA;GAClD,CAAC;AAEF,MAAI,CAAC,WACH,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;AAEjD,SAAO,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI;GAClC;AAGF,eAAc,IAAI,sCAAsC,OAAO,MAAM;EACnE,MAAM,SAAS,EAAE,IAAI,MAAM,KAAK;EAChC,MAAM,eAAe,EAAE,IAAI,MAAM,eAAe;EAEhD,MAAM,SAAS,MAAM,QAAQ,qBAAqB,kBAAkB,QAAQ,aAAa;AACzF,MAAI,CAAC,OACH,QAAO,EAAE,KAAK,EAAE,OAAO,wBAAwB,EAAE,IAAI;EAGvD,MAAM,EAAE,UAAU,UAAU,aAAa;AAEzC,MAAI;AACF,SAAM,OAAO,SAAS;UAChB;AACN,UAAO,EAAE,KAAK,EAAE,OAAO,2BAA2B,EAAE,IAAI;;EAG1D,MAAM,WAAW,MAAM,KAAK,SAAS;AAErC,IAAE,OAAO,gBAAgB,SAAS;AAClC,IAAE,OAAO,kBAAkB,OAAO,SAAS,KAAK,CAAC;AACjD,IAAE,OAAO,uBAAuB,qBAAqB,mBAAmB,SAAS,CAAC,GAAG;AACrF,IAAE,OAAO,iBAAiB,uCAAuC;AAEjE,SAAO,OAAO,GAAG,OAAO,MAAM;GAC5B,MAAM,WAAW,SAAS,MAAM,iBAAiB,SAAS,CAAC;AAC3D,SAAM,EAAE,KAAK,SAAS;IACtB;GACF;AAIF,eAAc,KAAK,mBAAmB,OAAO,MAAM;EACjD,MAAM,OAAO,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EACjD,MAAM,QAAQ,OAAO,KAAK,UAAU,WAAW,KAAK,MAAM,MAAM,GAAG;AACnE,MAAI,CAAC,MAAO,QAAO,EAAE,KAAK,EAAE,OAAO,iCAAiC,EAAE,IAAI;EAE1E,MAAM,SAAS,mBAAmB,KAAK;EACvC,MAAM,OAAO,MAAM,QAAQ,qBAAqB,WAAW,OAAO,QAAQ;GACxE,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,KAAA;GACrD,UAAU,KAAK,aAAa,UAAU,KAAK,aAAa,YAAY,KAAK,aAAa,QAAQ,KAAK,WAAW,KAAA;GAC9G,kBAAkB,OAAO,KAAK,qBAAqB,WAAW,KAAK,mBAAmB,KAAA;GACtF,cAAc,OAAO,KAAK,iBAAiB,WAAW,KAAK,eAAe,KAAA;GAC1E,SAAS,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU,KAAA;GAC5D,CAAC;AACF,SAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI;GAC5B;AAEF,eAAc,KAAK,8BAA8B,OAAO,MAAM;EAC5D,MAAM,OAAO,MAAM,QAAQ,qBAAqB,eAAe,EAAE,IAAI,MAAM,KAAK,CAAC;AACjF,MAAI,CAAC,KAAM,QAAO,EAAE,KAAK,EAAE,OAAO,2BAA2B,EAAE,IAAI;AACnE,SAAO,EAAE,KAAK,EAAE,MAAM,CAAC;GACvB;AAEF,eAAc,KAAK,uBAAuB,OAAO,MAAM;EACrD,MAAM,OAAO,MAAM,QAAQ,qBAAqB,WAAW,EAAE,IAAI,MAAM,KAAK,CAAC;AAC7E,MAAI,CAAC,KAAM,QAAO,EAAE,KAAK,EAAE,OAAO,aAAa,EAAE,IAAI;AACrD,SAAO,EAAE,KAAK,EAAE,MAAM,CAAC;GACvB;AAEF,eAAc,KAAK,uBAAuB,OAAO,MAAM;EACrD,MAAM,OAAO,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EACjD,MAAM,UAAU,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU;EAClE,MAAM,OAAO,MAAM,QAAQ,qBAAqB,YAAY,EAAE,IAAI,MAAM,KAAK,EAAE,QAAQ;AACvF,MAAI,CAAC,KAAM,QAAO,EAAE,KAAK,EAAE,OAAO,aAAa,EAAE,IAAI;AACrD,SAAO,EAAE,KAAK,EAAE,MAAM,CAAC;GACvB"}
|
|
1
|
+
{"version":3,"file":"notes.js","names":[],"sources":["../../../../../src/gateway/hono/routes/notes.ts"],"sourcesContent":["import { createReadStream } from 'node:fs';\nimport { access, stat } from 'node:fs/promises';\nimport { Readable } from 'node:stream';\n\nimport type { Hono } from 'hono';\nimport { stream } from 'hono/streaming';\n\nimport { buildSessionKey } from '../../../routing/session-key.js';\nimport { agentExists, getDefaultAgentId } from '../../../routing/resolve-route.js';\nimport type { CaptureChannel, CaptureSource, Note, NoteKind, NoteStatus, SnapshotTrigger } from '../../../notes/types.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nconst VALID_KINDS = new Set<NoteKind>(['thought', 'todo', 'voice', 'media', 'bookmark', 'mixed', 'task']);\nconst VALID_STATUSES = new Set<NoteStatus>(['inbox', 'processed', 'archived', 'trashed']);\nconst VALID_CHANNELS = new Set<CaptureChannel>(['app', 'web', 'electron', 'tui', 'telegram', 'wechat', 'feishu']);\n\nfunction parseCaptureSource(body: Record<string, unknown>): CaptureSource {\n const channel = typeof body.channel === 'string' && VALID_CHANNELS.has(body.channel as CaptureChannel)\n ? (body.channel as CaptureChannel)\n : 'web';\n const platform = body.platform === 'ios' || body.platform === 'android' ? body.platform : undefined;\n return { channel, platform };\n}\n\nfunction buildNotePatch(body: Record<string, unknown>): Partial<Note> {\n const patch: Partial<Note> = {};\n if (typeof body.title === 'string') patch.title = body.title;\n if (typeof body.markdown === 'string') patch.markdown = body.markdown;\n if (typeof body.kind === 'string' && VALID_KINDS.has(body.kind as NoteKind)) patch.kind = body.kind as NoteKind;\n if (typeof body.status === 'string' && VALID_STATUSES.has(body.status as NoteStatus)) patch.status = body.status as NoteStatus;\n if (Array.isArray(body.tags)) patch.tags = body.tags.filter((tag): tag is string => typeof tag === 'string');\n if (typeof body.pinned === 'boolean') patch.pinned = body.pinned;\n if (typeof body.localVersion === 'number') patch.localVersion = body.localVersion;\n if (body.ai && typeof body.ai === 'object') patch.ai = body.ai as Note['ai'];\n if (body.aiDeep && typeof body.aiDeep === 'object') patch.aiDeep = body.aiDeep as Note['aiDeep'];\n return patch;\n}\n\nfunction buildNoteThreadContext(note: Note): string {\n const title = note.title?.trim() || '未命名笔记';\n const body = note.markdown.trim() || '这条笔记暂无正文。';\n return [`来源 Note:${title}`, '', body].join('\\n');\n}\n\nfunction noteThreadName(note: Note): string {\n const title = note.title?.trim() || note.markdown.trim().slice(0, 28) || '未命名笔记';\n return `讨论:${title}`;\n}\n\nexport function registerNotesRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n // POST /api/notes/quick-capture — minimal text capture\n authenticated.post('/api/notes/quick-capture', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const text = typeof body.text === 'string' ? body.text.trim() : '';\n if (!text) {\n return c.json({ error: 'Missing required field: text' }, 400);\n }\n const source = parseCaptureSource(body);\n const note = await service.notesServiceInstance.quickCapture(text, source);\n return c.json({ note }, 201);\n });\n\n // GET /api/notes — list with filters\n authenticated.get('/api/notes', async (c) => {\n const status = c.req.query('status') as NoteStatus | undefined;\n const kind = c.req.query('kind') as NoteKind | undefined;\n const tag = c.req.query('tag');\n const search = c.req.query('search');\n const pinnedRaw = c.req.query('pinned');\n const limitRaw = c.req.query('limit');\n const offsetRaw = c.req.query('offset');\n const sortBy = c.req.query('sortBy') as 'createdAt' | 'updatedAt' | undefined;\n const sortOrder = c.req.query('sortOrder') as 'asc' | 'desc' | undefined;\n\n const result = await service.notesServiceInstance.listNotes({\n status: status && VALID_STATUSES.has(status) ? status : undefined,\n kind: kind && VALID_KINDS.has(kind) ? kind : undefined,\n tag: tag || undefined,\n search: search || undefined,\n pinned: pinnedRaw === 'true' ? true : pinnedRaw === 'false' ? false : undefined,\n limit: limitRaw ? parseInt(limitRaw, 10) : undefined,\n offset: offsetRaw ? parseInt(offsetRaw, 10) : undefined,\n sortBy: sortBy === 'createdAt' || sortBy === 'updatedAt' ? sortBy : undefined,\n sortOrder: sortOrder === 'asc' || sortOrder === 'desc' ? sortOrder : undefined,\n });\n return c.json(result);\n });\n\n // POST /api/notes — full create (JSON or multipart)\n authenticated.post('/api/notes', async (c) => {\n const contentType = c.req.header('content-type') || '';\n\n if (contentType.includes('multipart/form-data')) {\n let body: Record<string, unknown>;\n try {\n body = await c.req.parseBody({ all: true });\n } catch {\n return c.json({ error: 'Invalid multipart body' }, 400);\n }\n\n const markdown = typeof body.markdown === 'string' ? body.markdown.trim() : undefined;\n const kindRaw = typeof body.kind === 'string' ? body.kind : undefined;\n const tagsRaw = typeof body.tags === 'string' ? body.tags : undefined;\n const source = parseCaptureSource(body as Record<string, unknown>);\n\n const note = await service.notesServiceInstance.createNote({\n markdown,\n kind: kindRaw && VALID_KINDS.has(kindRaw as NoteKind) ? (kindRaw as NoteKind) : undefined,\n tags: tagsRaw ? tagsRaw.split(',').map((t) => t.trim()).filter(Boolean) : undefined,\n capturedVia: source,\n });\n\n const file = body.file;\n if (file && typeof file === 'object') {\n let buf: Buffer | null = null;\n let fileName = 'upload';\n let mimeType = 'application/octet-stream';\n\n if (file instanceof File) {\n buf = Buffer.from(await file.arrayBuffer());\n fileName = file.name || fileName;\n mimeType = file.type || mimeType;\n } else if (typeof (file as Blob).arrayBuffer === 'function') {\n buf = Buffer.from(await (file as Blob).arrayBuffer());\n }\n\n if (buf) {\n const durationRaw = body.duration;\n const duration =\n typeof durationRaw === 'string'\n ? parseInt(durationRaw, 10)\n : typeof durationRaw === 'number'\n ? durationRaw\n : undefined;\n await service.notesServiceInstance.addAttachment(note.id, {\n name: fileName,\n buffer: buf,\n mimeType,\n duration: Number.isFinite(duration) ? duration : undefined,\n });\n }\n }\n\n const full = await service.notesServiceInstance.getNote(note.id);\n return c.json({ note: full }, 201);\n }\n\n // JSON body\n const body = await c.req.json().catch(() => ({}));\n const markdown = typeof body.markdown === 'string' ? body.markdown.trim() : undefined;\n const kindRaw = typeof body.kind === 'string' ? body.kind : undefined;\n const tagsRaw = Array.isArray(body.tags) ? body.tags.filter((t: unknown) => typeof t === 'string') : undefined;\n const source = parseCaptureSource(body);\n\n const note = await service.notesServiceInstance.createNote({\n markdown,\n kind: kindRaw && VALID_KINDS.has(kindRaw as NoteKind) ? (kindRaw as NoteKind) : undefined,\n tags: tagsRaw,\n capturedVia: source,\n pinned: body.pinned === true,\n });\n return c.json({ note }, 201);\n });\n\n // POST /api/notes/sync — local-first markdown sync with optimistic conflict check\n authenticated.post('/api/notes/sync', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const noteId = typeof body.noteId === 'string' ? body.noteId : '';\n if (!noteId) {\n return c.json({ error: 'Missing required field: noteId' }, 400);\n }\n\n const baseRemoteVersion = typeof body.baseRemoteVersion === 'number' ? body.baseRemoteVersion : undefined;\n const patch = buildNotePatch(body);\n const result = await service.notesServiceInstance.syncNote(noteId, patch, baseRemoteVersion);\n if (!result.note) {\n return c.json({ error: 'Note not found' }, 404);\n }\n if (result.conflict) {\n return c.json({ conflict: true, note: result.note }, 409);\n }\n return c.json({ conflict: false, note: result.note });\n });\n\n // POST /api/notes/:id/catalyze — generate an AI catalysis report and write it back\n authenticated.post('/api/notes/:id/catalyze', async (c) => {\n const result = await service.notesServiceInstance.catalyzeNote(c.req.param('id'), service.currentConfig);\n if (!result) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json(result);\n });\n\n // POST /api/notes/:id/catalysis-feedback — record whether the catalysis was useful\n authenticated.post('/api/notes/:id/catalysis-feedback', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const feedback = body.feedback;\n if (feedback !== 'helpful' && feedback !== 'not_helpful' && feedback !== 'neutral') {\n return c.json({ error: 'Invalid feedback' }, 400);\n }\n const note = await service.notesServiceInstance.recordCatalysisFeedback(c.req.param('id'), feedback);\n if (!note) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json({ note });\n });\n\n // POST /api/notes/:id/chat — create or reuse a note-bound web chat thread\n authenticated.post('/api/notes/:id/chat', async (c) => {\n const noteId = c.req.param('id');\n const note = await service.notesServiceInstance.getNote(noteId);\n if (!note) {\n return c.json({ error: 'Note not found' }, 404);\n }\n\n const body = await c.req.json().catch(() => ({}));\n const routingCfg = service.currentConfig;\n let agentId =\n typeof body.agentId === 'string' && body.agentId.trim()\n ? body.agentId.trim().toLowerCase()\n : getDefaultAgentId(routingCfg);\n if (!agentExists(agentId, routingCfg)) {\n agentId = getDefaultAgentId(routingCfg);\n }\n\n const existingKey = note.aiDeep?.catalysis?.sourceSessionKey;\n if (existingKey) {\n const existingSession = await service.sessions.getSession(existingKey);\n if (existingSession) {\n return c.json({ session: existingSession, sessionKey: existingKey, reused: true });\n }\n }\n\n const sessionKey = buildSessionKey({\n agentId,\n source: 'webchat',\n accountId: 'default',\n peerKind: 'direct',\n peerId: `note_${noteId}_${Date.now()}`,\n });\n\n await service.sessionIndexInstance.saveMessages(sessionKey, []);\n await service.sessionIndexInstance.appendTranscriptContextEntry(sessionKey, {\n id: `source-note:${noteId}`,\n text: buildNoteThreadContext(note),\n data: {\n kind: 'source_note',\n noteId,\n title: note.title ?? '',\n },\n });\n\n const meta = await service.sessionIndexInstance.getSessionMetadata(sessionKey);\n await service.sessionIndexInstance.updateSessionMetadata(sessionKey, {\n name: noteThreadName(note),\n tags: Array.from(new Set([...(meta?.tags ?? []), 'note'])),\n customData: {\n ...(meta?.customData ?? {}),\n sourceNoteId: noteId,\n sourceNoteTitle: note.title ?? '',\n },\n });\n\n await service.notesServiceInstance.linkNoteThread(noteId, sessionKey);\n const session = await service.sessions.getSession(sessionKey);\n return c.json({ session, sessionKey, reused: false }, 201);\n });\n\n // GET /api/notes/:id/threads — list chat threads linked to a note\n authenticated.get('/api/notes/:id/threads', async (c) => {\n const noteId = c.req.param('id');\n const keys = await service.notesServiceInstance.listNoteThreads(noteId);\n if (!keys) {\n return c.json({ error: 'Note not found' }, 404);\n }\n const sessions = [];\n for (const key of keys) {\n const session = await service.sessions.getSession(key);\n if (session) sessions.push(session);\n }\n return c.json({ items: sessions, total: sessions.length });\n });\n\n // POST /api/notes/:id/append — append assistant output or selected text back to the note\n authenticated.post('/api/notes/:id/append', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const content = typeof body.content === 'string' ? body.content.trim() : '';\n const heading = typeof body.heading === 'string' && body.heading.trim() ? body.heading.trim() : undefined;\n if (!content) {\n return c.json({ error: 'Missing required field: content' }, 400);\n }\n const note = await service.notesServiceInstance.appendTextToNote(c.req.param('id'), content, heading);\n if (!note) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json({ note });\n });\n\n // GET /api/notes/:id — single note\n authenticated.get('/api/notes/:id', async (c) => {\n const id = c.req.param('id');\n const note = await service.notesServiceInstance.getNote(id);\n if (!note) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json({ note });\n });\n\n // PATCH /api/notes/:id — update\n authenticated.patch('/api/notes/:id', async (c) => {\n const id = c.req.param('id');\n const body = await c.req.json().catch(() => ({}));\n\n const patch = buildNotePatch(body);\n const trigger: SnapshotTrigger =\n body.trigger === 'ai_edit' || body.trigger === 'sync' || body.trigger === 'restore'\n ? body.trigger\n : 'edit';\n\n const updated = await service.notesServiceInstance.updateNote(id, patch, trigger);\n if (!updated) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json({ note: updated });\n });\n\n // DELETE /api/notes/:id — delete note\n authenticated.delete('/api/notes/:id', async (c) => {\n const id = c.req.param('id');\n const removed = await service.notesServiceInstance.deleteNote(id);\n if (!removed) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json({ deleted: true });\n });\n\n // GET /api/notes/:id/history — list version snapshots\n authenticated.get('/api/notes/:id/history', async (c) => {\n const id = c.req.param('id');\n const entries = await service.notesServiceInstance.listNoteHistory(id);\n return c.json({ entries });\n });\n\n // GET /api/notes/:id/history/:timestamp — get full snapshot\n authenticated.get('/api/notes/:id/history/:timestamp', async (c) => {\n const id = c.req.param('id');\n const timestamp = parseInt(c.req.param('timestamp'), 10);\n if (!Number.isFinite(timestamp)) {\n return c.json({ error: 'Invalid timestamp' }, 400);\n }\n const snapshot = await service.notesServiceInstance.getNoteSnapshot(id, timestamp);\n if (!snapshot) {\n return c.json({ error: 'Snapshot not found' }, 404);\n }\n return c.json({ snapshot });\n });\n\n // POST /api/notes/:id/history/restore — restore a snapshot\n authenticated.post('/api/notes/:id/history/restore', async (c) => {\n const id = c.req.param('id');\n const body = await c.req.json().catch(() => ({}));\n const timestamp = typeof body.timestamp === 'number' ? body.timestamp : 0;\n if (!timestamp) {\n return c.json({ error: 'Missing required field: timestamp' }, 400);\n }\n const note = await service.notesServiceInstance.restoreNoteSnapshot(id, timestamp);\n if (!note) {\n return c.json({ error: 'Snapshot or note not found' }, 404);\n }\n return c.json({ note });\n });\n\n // POST /api/notes/:id/ai/edit — generate previewable markdown AI patch\n authenticated.post('/api/notes/:id/ai/edit', async (c) => {\n const id = c.req.param('id');\n const body = await c.req.json().catch(() => ({}));\n const instruction = typeof body.instruction === 'string' ? body.instruction.trim() : '';\n if (!instruction) {\n return c.json({ error: 'Missing required field: instruction' }, 400);\n }\n\n const markdown = typeof body.markdown === 'string' ? body.markdown : undefined;\n const result = await service.notesServiceInstance.createAiEditPatch(id, instruction, markdown);\n if (!result) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json(result);\n });\n\n // POST /api/notes/:id/media — upload attachment to existing note\n authenticated.post('/api/notes/:id/media', async (c) => {\n const noteId = c.req.param('id');\n let body: Record<string, unknown>;\n try {\n body = await c.req.parseBody({ all: true });\n } catch {\n return c.json({ error: 'Invalid multipart body' }, 400);\n }\n\n const file = body.file;\n if (!file || typeof file !== 'object') {\n return c.json({ error: 'Missing file field' }, 400);\n }\n\n let buf: Buffer;\n let fileName = 'upload';\n let mimeType = 'application/octet-stream';\n\n if (file instanceof File) {\n buf = Buffer.from(await file.arrayBuffer());\n fileName = file.name || fileName;\n mimeType = file.type || mimeType;\n } else if (typeof (file as Blob).arrayBuffer === 'function') {\n buf = Buffer.from(await (file as Blob).arrayBuffer());\n } else {\n return c.json({ error: 'Invalid file upload' }, 400);\n }\n\n const durationRaw = body.duration;\n const duration = typeof durationRaw === 'string' ? parseInt(durationRaw, 10) : undefined;\n\n const attachment = await service.notesServiceInstance.addAttachment(noteId, {\n name: fileName,\n buffer: buf,\n mimeType,\n duration: Number.isFinite(duration) ? duration : undefined,\n });\n\n if (!attachment) {\n return c.json({ error: 'Note not found' }, 404);\n }\n return c.json({ attachment }, 201);\n });\n\n // GET /api/notes/:id/media/:attachmentId — serve attachment file\n authenticated.get('/api/notes/:id/media/:attachmentId', async (c) => {\n const noteId = c.req.param('id');\n const attachmentId = c.req.param('attachmentId');\n\n const result = await service.notesServiceInstance.getAttachmentPath(noteId, attachmentId);\n if (!result) {\n return c.json({ error: 'Attachment not found' }, 404);\n }\n\n const { filePath, mimeType, fileName } = result;\n\n try {\n await access(filePath);\n } catch {\n return c.json({ error: 'Attachment file missing' }, 404);\n }\n\n const fileStat = await stat(filePath);\n\n c.header('Content-Type', mimeType);\n c.header('Content-Length', String(fileStat.size));\n c.header('Content-Disposition', `inline; filename=\"${encodeURIComponent(fileName)}\"`);\n c.header('Cache-Control', 'private, max-age=31536000, immutable');\n\n return stream(c, async (s) => {\n const readable = Readable.toWeb(createReadStream(filePath)) as ReadableStream<Uint8Array>;\n await s.pipe(readable);\n });\n });\n\n // ── Task / Space / Open tracking ────────────────────────────────────\n\n authenticated.post('/api/notes/task', async (c) => {\n const body = await c.req.json().catch(() => ({})) as Record<string, unknown>;\n const title = typeof body.title === 'string' ? body.title.trim() : '';\n if (!title) return c.json({ error: 'Missing required field: title' }, 400);\n\n const source = parseCaptureSource(body);\n const note = await service.notesServiceInstance.createTask(title, source, {\n dueAt: typeof body.dueAt === 'number' ? body.dueAt : undefined,\n priority: body.priority === 'high' || body.priority === 'medium' || body.priority === 'low' ? body.priority : undefined,\n sourceSessionKey: typeof body.sourceSessionKey === 'string' ? body.sourceSessionKey : undefined,\n sourceNoteId: typeof body.sourceNoteId === 'string' ? body.sourceNoteId : undefined,\n groupId: typeof body.groupId === 'string' ? body.groupId : undefined,\n });\n return c.json({ note }, 201);\n });\n\n authenticated.post('/api/notes/:id/toggle-done', async (c) => {\n const note = await service.notesServiceInstance.toggleTaskDone(c.req.param('id'));\n if (!note) return c.json({ error: 'Not found or not a task' }, 404);\n return c.json({ note });\n });\n\n authenticated.post('/api/notes/:id/open', async (c) => {\n const note = await service.notesServiceInstance.recordOpen(c.req.param('id'));\n if (!note) return c.json({ error: 'Not found' }, 404);\n return c.json({ note });\n });\n\n authenticated.post('/api/notes/:id/move', async (c) => {\n const body = await c.req.json().catch(() => ({})) as Record<string, unknown>;\n const groupId = typeof body.groupId === 'string' ? body.groupId : null;\n const note = await service.notesServiceInstance.moveToGroup(c.req.param('id'), groupId);\n if (!note) return c.json({ error: 'Not found' }, 404);\n return c.json({ note });\n });\n}\n"],"mappings":"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"}
|
|
@@ -13,8 +13,8 @@ import { getClientIpFromHeaders } from "../../security/loopback.js";
|
|
|
13
13
|
import { renderFolderLandingPage, renderShareExpiredPage, renderShareLandingPage } from "../../../share/share-landing.js";
|
|
14
14
|
import { consumeSharePublicLimit } from "../../../share/share-rate-limit.js";
|
|
15
15
|
import { createZipStream, planDirectoryFiles } from "../../../share/share-zip.js";
|
|
16
|
-
import { createReadStream } from "node:fs";
|
|
17
16
|
import { createHash } from "node:crypto";
|
|
17
|
+
import { createReadStream } from "node:fs";
|
|
18
18
|
import { stat } from "node:fs/promises";
|
|
19
19
|
import { Readable } from "node:stream";
|
|
20
20
|
//#region src/gateway/hono/routes/shares.ts
|
|
@@ -8,10 +8,10 @@ import { resolveHeartbeatMdPath } from "../../workspace-heartbeat-path.js";
|
|
|
8
8
|
import { createGatewayRouteLogger } from "../lib/route-logger.js";
|
|
9
9
|
import { listWorkspaceRelativeFilesFsFallback } from "../../workspace-fs-file-list.js";
|
|
10
10
|
import { runRipgrepInDirectory, runRipgrepListFiles } from "../../workspace-ripgrep.js";
|
|
11
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
12
|
-
import { constants } from "node:fs";
|
|
13
11
|
import { randomUUID } from "node:crypto";
|
|
12
|
+
import { constants } from "node:fs";
|
|
14
13
|
import { copyFile, link, mkdir, readFile, readdir, rename, stat, unlink, writeFile } from "node:fs/promises";
|
|
14
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
15
15
|
//#region src/gateway/hono/routes/workspace.ts
|
|
16
16
|
init_agent_scope();
|
|
17
17
|
const log = createGatewayRouteLogger("Workspace");
|
package/dist/src/gateway/lock.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import net from "node:net";
|
|
3
|
-
import fs from "node:fs";
|
|
4
1
|
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
5
3
|
import fs$1 from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import net from "node:net";
|
|
6
6
|
import { homedir } from "os";
|
|
7
7
|
//#region src/gateway/lock.ts
|
|
8
8
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
|
-
import net from "node:net";
|
|
4
3
|
import fs from "node:fs";
|
|
4
|
+
import net from "node:net";
|
|
5
5
|
import { execFileSync } from "node:child_process";
|
|
6
6
|
//#region src/gateway/ports.ts
|
|
7
7
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { buildSessionKey, init_session_key, parseSessionKey } from "../../routing/session-key.js";
|
|
2
|
-
import { getDefaultAgentId, init_resolve_route } from "../../routing/resolve-route.js";
|
|
3
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
4
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
+
import { buildSessionKey, init_session_key, parseSessionKey } from "../../routing/session-key.js";
|
|
4
|
+
import { getDefaultAgentId, init_resolve_route } from "../../routing/resolve-route.js";
|
|
5
5
|
import { AgentRunRelay } from "../agent-run-relay.js";
|
|
6
6
|
import { ClarifyBridge } from "../clarify-bridge.js";
|
|
7
7
|
import { runGatewayAgent } from "./run-gateway-agent.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { resolveStateDir } from "../../config/paths-state.js";
|
|
2
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
3
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
+
import { resolveStateDir } from "../../config/paths-state.js";
|
|
4
4
|
import { init_paths, resolveExtensionsDir } from "../../config/paths.js";
|
|
5
5
|
import { createSkillConfigManager } from "../../agent/skills/config.js";
|
|
6
6
|
import { removeSkillsLockEntry } from "../../agent/skills/hub-lock.js";
|
|
@@ -11,8 +11,8 @@ import { installExtensionFromStoreZip, peekExtensionIdFromStoreZip } from "../..
|
|
|
11
11
|
import { downloadExtensionStoreZipBuffer, fetchMarketplacePackageDetail, resolveExtensionZipDownloadUrl, resolveExtensionsStoreBaseUrl } from "../../agent/skills/marketplace/adapters/store/store-api-client.js";
|
|
12
12
|
import { getMarketplaceProviderDisplayName, resolveSkillsMarketplaceProvider } from "../../agent/skills/marketplace/resolve-adapter.js";
|
|
13
13
|
import { downloadFromMarketplace, getMarketplacePackageDetail, listMarketplaceCategories, listMarketplacePackages } from "../../agent/skills/skills-marketplace.js";
|
|
14
|
-
import { join } from "node:path";
|
|
15
14
|
import { existsSync, mkdirSync, rmSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
16
|
//#region src/gateway/service/marketplace-service.ts
|
|
17
17
|
/**
|
|
18
18
|
* GatewayMarketplaceService — install / browse / remove for the two marketplaces
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { __toCommonJS } from "../../_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { PACKAGE_VERSION, init_package_version } from "../package-version.js";
|
|
3
|
-
import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
|
|
4
3
|
import { getLogDir } from "../utils/logger/config.js";
|
|
5
4
|
import { getRuntimeLogStats } from "../utils/logger/stats.js";
|
|
6
5
|
import { createLogger } from "../utils/logger/index.js";
|
|
7
6
|
import { init_logger } from "../utils/logger.js";
|
|
8
7
|
import { init_paths, resolveAgentDir, resolveConfigPath, resolveCronJobsPath, resolveExtensionsDir } from "../config/paths.js";
|
|
9
8
|
import { loadConfig, saveConfig } from "../config/loader.js";
|
|
9
|
+
import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
|
|
10
10
|
import { prewarmModelRegistry } from "../providers/model-registry.js";
|
|
11
11
|
import { init_providers, providers_exports } from "../providers/index.js";
|
|
12
12
|
import { closeXopcDatabase, openXopcDatabase } from "../storage/sqlite/connection.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
|
-
import { join, relative } from "node:path";
|
|
4
3
|
import { readdir } from "node:fs/promises";
|
|
4
|
+
import { join, relative } from "node:path";
|
|
5
5
|
//#region src/gateway/workspace-fs-file-list.ts
|
|
6
6
|
init_logger();
|
|
7
7
|
const log = createLogger("WorkspaceFsFileList");
|
package/dist/src/infra/brew.js
CHANGED