@xopcai/xopc 0.0.90 → 0.0.91
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 +36 -12
- package/README.zh-CN.md +36 -12
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/feishu/src/workflow-progress.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/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/Combination-HAlzriaz.js +41 -0
- package/dist/gateway/static/root/assets/agents-bVWUlrlD.js +222 -0
- package/dist/gateway/static/root/assets/apps-page-CIC8bmvZ.js +1 -0
- package/dist/gateway/static/root/assets/{attachment-preview-renderer-CpyoFbs4.js → attachment-preview-renderer-DBAxQXb-.js} +2 -2
- package/dist/gateway/static/root/assets/{attachment-process-heavy-CqVriadb.js → attachment-process-heavy-Csq3TrrP.js} +4 -4
- package/dist/gateway/static/root/assets/channels-settings-C8G8RAAP.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-BrtH2VzC.js → channels-status-swr-CYWL5DLD.js} +1 -1
- package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +1 -0
- package/dist/gateway/static/root/assets/{cron-api-CyqbgfHM.js → cron-api-TVqLlGAC.js} +1 -1
- package/dist/gateway/static/root/assets/cron-page-BtcFYlvv.js +1 -0
- package/dist/gateway/static/root/assets/dist-CUV1uY5f.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-D6Ak0STa.js → extension-debug-page-mTLHRDp1.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-Q0P3d6DW.js → extension-page-iI8BI7WK.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-CL55LwU_.js → extension-settings-page-ByXcdubM.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-Dqa9iTWl.js → fetch-BWtQq_Ys.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-HUR6JElP.js → field-primitives-BsZ-4VT5.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-DusckjUX.js → heartbeat-config-api-WjTsRLCU.js} +1 -1
- package/dist/gateway/static/root/assets/{index-BYcGfwcE.js → index-CKkR-v9U.js} +85 -81
- package/dist/gateway/static/root/assets/index-VlELBY99.css +1 -0
- package/dist/gateway/static/root/assets/logs-page-ClnIpxfd.js +1 -0
- package/dist/gateway/static/root/assets/note-detail-page-B91pLkEI.css +1 -0
- package/dist/gateway/static/root/assets/note-detail-page-DJ2Mb4x7.js +179 -0
- package/dist/gateway/static/root/assets/note-time-JLBPSLzK.js +1 -0
- package/dist/gateway/static/root/assets/notes-page-BE-75qz9.js +1 -0
- package/dist/gateway/static/root/assets/{pdf-BnEvgIXZ.js → pdf-epILhEOn.js} +1 -1
- package/dist/gateway/static/root/assets/preload-helper-zJ_50EbN.js +1 -0
- package/dist/gateway/static/root/assets/sessions-page-bJJkWtTl.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-a0qGVOlr.js → settings-form-section-DSYCknxM.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-WcMXLq2U.js +3 -0
- package/dist/gateway/static/root/assets/share-preview-page-awRqs4hV.js +2 -0
- package/dist/gateway/static/root/assets/skills-page-Lu-i1JG7.js +2 -0
- package/dist/gateway/static/root/assets/{theme-store-C0Ehmdo5.js → theme-store-BC-42BoZ.js} +1 -1
- package/dist/gateway/static/root/assets/toast-z0toXu32.js +1 -0
- package/dist/gateway/static/root/assets/url-CY1RQKTU.js +3 -0
- package/dist/gateway/static/root/assets/{utils-DRQryzdn.js → utils-DX3TQuap.js} +1 -1
- package/dist/gateway/static/root/assets/vendor-codemirror-DYoKfS8f.js +45 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-D0viACE2.js → voice-api-key-field-B5uKlDqA.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-page.utils-DnG8JBhV.js → workflow-page.utils-ClC37yEp.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-C7VhIXtR.js +27 -0
- package/dist/gateway/static/root/index.html +10 -8
- 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/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/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/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/build-direct-message-content.js +1 -1
- 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 +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.js +3 -3
- package/dist/src/auth/profiles/store.js +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/inbound-persist.js +1 -1
- package/dist/src/channels/attachments/outbound-tts-persist.js +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/context.js +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/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +2 -2
- 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 +4 -4
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/cli/utils/init-workspace-core.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/cron/run-log-store.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.d.ts +1 -0
- package/dist/src/gateway/hono/lib/config-payload.js +2 -1
- package/dist/src/gateway/hono/lib/config-payload.js.map +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/middleware/auth.js +1 -2
- package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
- package/dist/src/gateway/hono/oauth.js +1 -1
- 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/gateway.d.ts +2 -2
- package/dist/src/gateway/hono/routes/config-patch/gateway.js +12 -0
- package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +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/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/notes.d.ts +3 -0
- package/dist/src/gateway/hono/routes/notes.js +274 -0
- package/dist/src/gateway/hono/routes/notes.js.map +1 -0
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/shares.js +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +4 -4
- 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.d.ts +3 -0
- package/dist/src/gateway/service.js +11 -1
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/gateway/workspace-ripgrep.d.ts +6 -0
- package/dist/src/gateway/workspace-ripgrep.js +62 -11
- package/dist/src/gateway/workspace-ripgrep.js.map +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/notes/attachment-ref.d.ts +9 -0
- package/dist/src/notes/attachment-ref.js +27 -0
- package/dist/src/notes/attachment-ref.js.map +1 -0
- package/dist/src/notes/index.d.ts +4 -0
- package/dist/src/notes/index.js +4 -0
- package/dist/src/notes/note-attachment-sync.d.ts +7 -0
- package/dist/src/notes/note-attachment-sync.js +46 -0
- package/dist/src/notes/note-attachment-sync.js.map +1 -0
- package/dist/src/notes/note-index-meta.d.ts +14 -0
- package/dist/src/notes/note-index-meta.js +87 -0
- package/dist/src/notes/note-index-meta.js.map +1 -0
- package/dist/src/notes/paths.d.ts +5 -0
- package/dist/src/notes/paths.js +23 -0
- package/dist/src/notes/paths.js.map +1 -0
- package/dist/src/notes/service.d.ts +42 -0
- package/dist/src/notes/service.js +331 -0
- package/dist/src/notes/service.js.map +1 -0
- package/dist/src/notes/store.d.ts +33 -0
- package/dist/src/notes/store.js +317 -0
- package/dist/src/notes/store.js.map +1 -0
- package/dist/src/notes/types.d.ts +162 -0
- package/dist/src/notes/types.js +1 -0
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/session/config-store.js +2 -2
- package/dist/src/session/init-session-turn.js +2 -2
- package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
- package/dist/src/session/parity/sessions-json-file.js +1 -1
- package/dist/src/session/parity/transcript-file-lock.js +2 -2
- package/dist/src/session/parity/transcript-paths.js +1 -1
- package/dist/src/session/resolve-session.js +4 -4
- package/dist/src/session/search-index-cache.js +1 -1
- package/dist/src/session/search-index.js +1 -1
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/store.js +6 -6
- 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/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/agents-cPvvYLXo.js +0 -222
- package/dist/gateway/static/root/assets/apps-page-Bk1_P5FJ.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-CZoeQwHz.js +0 -1
- package/dist/gateway/static/root/assets/cron-page-BpLdiQN8.js +0 -1
- package/dist/gateway/static/root/assets/dist-BTWC-BTN.js +0 -45
- package/dist/gateway/static/root/assets/dist-BpAiK86n.js +0 -1
- package/dist/gateway/static/root/assets/eye-DAfL1U7M.js +0 -1
- package/dist/gateway/static/root/assets/index-V7MQ7834.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-_HcZ2fgK.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-iezSMjho.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-C9_nYQwM.js +0 -3
- package/dist/gateway/static/root/assets/share-preview-page-DExl7CJy.js +0 -2
- package/dist/gateway/static/root/assets/skills-page-BlgGD93t.js +0 -2
- package/dist/gateway/static/root/assets/url-fxyYANfA.js +0 -3
- package/dist/gateway/static/root/assets/vendor-codemirror-D0yxdRpg.js +0 -58
- package/dist/gateway/static/root/assets/workflows-page-BvMobnJP.js +0 -27
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../utils/logger.js";
|
|
3
|
+
import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
|
|
4
|
+
import { buildNoteIndexMeta } from "./note-index-meta.js";
|
|
5
|
+
import { resolveNoteHistoryDir, resolveNoteItemPath, resolveNoteMediaDir, resolveNotesDir, resolveNotesIndexPath } from "./paths.js";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { randomUUID } from "node:crypto";
|
|
8
|
+
import { access, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
9
|
+
//#region src/notes/store.ts
|
|
10
|
+
init_write_file_atomic();
|
|
11
|
+
init_logger();
|
|
12
|
+
const log = createLogger("NotesStore");
|
|
13
|
+
const DEFAULT_INDEX = {
|
|
14
|
+
version: 3,
|
|
15
|
+
notes: []
|
|
16
|
+
};
|
|
17
|
+
const INDEX_VERSION = 3;
|
|
18
|
+
const DEBOUNCE_MS = 500;
|
|
19
|
+
function noteToIndexEntry(note) {
|
|
20
|
+
const { snippet, coverAttachmentId, voiceAttachmentId, voiceDurationSec, attachmentNames } = buildNoteIndexMeta(note);
|
|
21
|
+
return {
|
|
22
|
+
id: note.id,
|
|
23
|
+
title: note.title || void 0,
|
|
24
|
+
kind: note.kind,
|
|
25
|
+
status: note.status,
|
|
26
|
+
createdAt: note.createdAt,
|
|
27
|
+
updatedAt: note.updatedAt,
|
|
28
|
+
pinned: note.pinned || void 0,
|
|
29
|
+
tags: note.tags?.length ? note.tags : void 0,
|
|
30
|
+
snippet,
|
|
31
|
+
coverAttachmentId,
|
|
32
|
+
voiceAttachmentId,
|
|
33
|
+
voiceDurationSec,
|
|
34
|
+
attachmentNames
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
var NotesStore = class {
|
|
38
|
+
indexCache = null;
|
|
39
|
+
dirty = false;
|
|
40
|
+
saveTimeout = null;
|
|
41
|
+
initialized = false;
|
|
42
|
+
async initialize() {
|
|
43
|
+
if (this.initialized) return;
|
|
44
|
+
const indexPath = resolveNotesIndexPath();
|
|
45
|
+
try {
|
|
46
|
+
await access(indexPath);
|
|
47
|
+
await this.loadIndex();
|
|
48
|
+
if ((this.indexCache?.version ?? 0) < INDEX_VERSION) await this.rebuildIndexFromItems();
|
|
49
|
+
} catch {
|
|
50
|
+
await this.writeIndex(DEFAULT_INDEX);
|
|
51
|
+
this.indexCache = DEFAULT_INDEX;
|
|
52
|
+
}
|
|
53
|
+
this.initialized = true;
|
|
54
|
+
log.debug("NotesStore initialized");
|
|
55
|
+
}
|
|
56
|
+
async addNote(note) {
|
|
57
|
+
const index = await this.loadIndex();
|
|
58
|
+
await this.writeNoteItem(note);
|
|
59
|
+
index.notes.push(noteToIndexEntry(note));
|
|
60
|
+
index.version++;
|
|
61
|
+
this.scheduleIndexSave(index);
|
|
62
|
+
}
|
|
63
|
+
async getNote(id) {
|
|
64
|
+
const itemPath = resolveNoteItemPath(id);
|
|
65
|
+
try {
|
|
66
|
+
const content = await readFile(itemPath, "utf-8");
|
|
67
|
+
return JSON.parse(content);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
if ((err && typeof err === "object" && "code" in err ? err.code : "") !== "ENOENT") log.debug({
|
|
70
|
+
err,
|
|
71
|
+
id
|
|
72
|
+
}, "Failed to read note item");
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async updateNote(id, patch) {
|
|
77
|
+
const existing = await this.getNote(id);
|
|
78
|
+
if (!existing) return null;
|
|
79
|
+
const updated = {
|
|
80
|
+
...existing,
|
|
81
|
+
...patch,
|
|
82
|
+
id: existing.id,
|
|
83
|
+
createdAt: existing.createdAt,
|
|
84
|
+
updatedAt: Date.now()
|
|
85
|
+
};
|
|
86
|
+
await this.writeNoteItem(updated);
|
|
87
|
+
const index = await this.loadIndex();
|
|
88
|
+
const idx = index.notes.findIndex((n) => n.id === id);
|
|
89
|
+
if (idx !== -1) index.notes[idx] = noteToIndexEntry(updated);
|
|
90
|
+
index.version++;
|
|
91
|
+
this.scheduleIndexSave(index);
|
|
92
|
+
return updated;
|
|
93
|
+
}
|
|
94
|
+
async deleteNote(id) {
|
|
95
|
+
if (!await this.getNote(id)) return false;
|
|
96
|
+
await rm(resolveNoteItemPath(id), { force: true }).catch((err) => {
|
|
97
|
+
log.warn({
|
|
98
|
+
err,
|
|
99
|
+
id
|
|
100
|
+
}, "Failed to remove note item file");
|
|
101
|
+
});
|
|
102
|
+
await rm(resolveNoteMediaDir(id), {
|
|
103
|
+
recursive: true,
|
|
104
|
+
force: true
|
|
105
|
+
}).catch(() => void 0);
|
|
106
|
+
const index = await this.loadIndex();
|
|
107
|
+
const before = index.notes.length;
|
|
108
|
+
index.notes = index.notes.filter((n) => n.id !== id);
|
|
109
|
+
if (index.notes.length === before) log.debug({ id }, "Deleted note file but index entry was missing");
|
|
110
|
+
index.version++;
|
|
111
|
+
this.scheduleIndexSave(index);
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
async listNotes(query = {}) {
|
|
115
|
+
let results = (await this.loadIndex()).notes;
|
|
116
|
+
if (query.status) results = results.filter((n) => n.status === query.status);
|
|
117
|
+
else results = results.filter((n) => n.status !== "trashed");
|
|
118
|
+
if (query.kind) results = results.filter((n) => n.kind === query.kind);
|
|
119
|
+
if (query.tag) results = results.filter((n) => n.tags?.includes(query.tag));
|
|
120
|
+
if (query.pinned !== void 0) results = results.filter((n) => Boolean(n.pinned) === query.pinned);
|
|
121
|
+
if (query.search) {
|
|
122
|
+
const term = query.search.toLowerCase();
|
|
123
|
+
results = results.filter((n) => n.title?.toLowerCase().includes(term) || n.snippet?.toLowerCase().includes(term) || n.tags?.some((t) => t.toLowerCase().includes(term)) || n.attachmentNames?.some((name) => name.includes(term)));
|
|
124
|
+
}
|
|
125
|
+
const sortField = query.sortBy || "createdAt";
|
|
126
|
+
const sortDir = query.sortOrder === "asc" ? 1 : -1;
|
|
127
|
+
results = [...results].sort((a, b) => (a[sortField] - b[sortField]) * sortDir);
|
|
128
|
+
const total = results.length;
|
|
129
|
+
const offset = query.offset || 0;
|
|
130
|
+
const limit = Math.min(query.limit || 50, 200);
|
|
131
|
+
return {
|
|
132
|
+
items: results.slice(offset, offset + limit),
|
|
133
|
+
total
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async saveAttachment(noteId, fileName, buffer) {
|
|
137
|
+
const mediaDir = resolveNoteMediaDir(noteId);
|
|
138
|
+
await mkdir(mediaDir, { recursive: true });
|
|
139
|
+
const safeName = `${randomUUID().slice(0, 8)}_${fileName.replace(/[^a-zA-Z0-9._-]/g, "_")}`;
|
|
140
|
+
await writeFile(join(mediaDir, safeName), buffer);
|
|
141
|
+
return {
|
|
142
|
+
relativePath: safeName,
|
|
143
|
+
size: buffer.length
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
resolveAttachmentPath(noteId, relativePath) {
|
|
147
|
+
return join(resolveNoteMediaDir(noteId), relativePath);
|
|
148
|
+
}
|
|
149
|
+
async deleteAttachmentFile(noteId, relativePath) {
|
|
150
|
+
await rm(this.resolveAttachmentPath(noteId, relativePath), { force: true }).catch((err) => {
|
|
151
|
+
log.warn({
|
|
152
|
+
err,
|
|
153
|
+
noteId,
|
|
154
|
+
relativePath
|
|
155
|
+
}, "Failed to remove note attachment file");
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
async saveSnapshot(note, trigger) {
|
|
159
|
+
const historyDir = resolveNoteHistoryDir(note.id);
|
|
160
|
+
await mkdir(historyDir, { recursive: true });
|
|
161
|
+
const snapshot = {
|
|
162
|
+
noteId: note.id,
|
|
163
|
+
timestamp: Date.now(),
|
|
164
|
+
trigger,
|
|
165
|
+
title: note.title,
|
|
166
|
+
text: note.text,
|
|
167
|
+
blocks: note.blocks,
|
|
168
|
+
tags: note.tags,
|
|
169
|
+
kind: note.kind,
|
|
170
|
+
status: note.status
|
|
171
|
+
};
|
|
172
|
+
await writeTextAtomic(join(historyDir, `${snapshot.timestamp}.json`), JSON.stringify(snapshot, null, 2));
|
|
173
|
+
log.debug({
|
|
174
|
+
noteId: note.id,
|
|
175
|
+
trigger,
|
|
176
|
+
timestamp: snapshot.timestamp
|
|
177
|
+
}, "Snapshot saved");
|
|
178
|
+
}
|
|
179
|
+
async listSnapshots(noteId) {
|
|
180
|
+
const historyDir = resolveNoteHistoryDir(noteId);
|
|
181
|
+
let files;
|
|
182
|
+
try {
|
|
183
|
+
files = await readdir(historyDir);
|
|
184
|
+
} catch {
|
|
185
|
+
return [];
|
|
186
|
+
}
|
|
187
|
+
const entries = [];
|
|
188
|
+
for (const file of files) {
|
|
189
|
+
if (!file.endsWith(".json")) continue;
|
|
190
|
+
const timestamp = parseInt(file.slice(0, -5), 10);
|
|
191
|
+
if (!Number.isFinite(timestamp)) continue;
|
|
192
|
+
try {
|
|
193
|
+
const content = await readFile(join(historyDir, file), "utf-8");
|
|
194
|
+
const snapshot = JSON.parse(content);
|
|
195
|
+
const rawText = snapshot.text ?? "";
|
|
196
|
+
entries.push({
|
|
197
|
+
timestamp: snapshot.timestamp,
|
|
198
|
+
trigger: snapshot.trigger,
|
|
199
|
+
snippet: rawText.slice(0, 80) || void 0
|
|
200
|
+
});
|
|
201
|
+
} catch {
|
|
202
|
+
log.debug({
|
|
203
|
+
noteId,
|
|
204
|
+
file
|
|
205
|
+
}, "Skipped unreadable snapshot");
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
entries.sort((a, b) => b.timestamp - a.timestamp);
|
|
209
|
+
return entries;
|
|
210
|
+
}
|
|
211
|
+
async getSnapshot(noteId, timestamp) {
|
|
212
|
+
const filePath = join(resolveNoteHistoryDir(noteId), `${timestamp}.json`);
|
|
213
|
+
try {
|
|
214
|
+
const content = await readFile(filePath, "utf-8");
|
|
215
|
+
return JSON.parse(content);
|
|
216
|
+
} catch {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async pruneSnapshots(noteId, maxCount) {
|
|
221
|
+
const historyDir = resolveNoteHistoryDir(noteId);
|
|
222
|
+
let files;
|
|
223
|
+
try {
|
|
224
|
+
files = await readdir(historyDir);
|
|
225
|
+
} catch {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const jsonFiles = files.filter((f) => f.endsWith(".json")).sort();
|
|
229
|
+
if (jsonFiles.length <= maxCount) return;
|
|
230
|
+
const toDelete = jsonFiles.slice(0, jsonFiles.length - maxCount);
|
|
231
|
+
for (const file of toDelete) await rm(join(historyDir, file), { force: true }).catch(() => void 0);
|
|
232
|
+
log.debug({
|
|
233
|
+
noteId,
|
|
234
|
+
deleted: toDelete.length
|
|
235
|
+
}, "Pruned old snapshots");
|
|
236
|
+
}
|
|
237
|
+
async deleteAllSnapshots(noteId) {
|
|
238
|
+
await rm(resolveNoteHistoryDir(noteId), {
|
|
239
|
+
recursive: true,
|
|
240
|
+
force: true
|
|
241
|
+
}).catch(() => void 0);
|
|
242
|
+
}
|
|
243
|
+
async flush() {
|
|
244
|
+
if (!this.dirty || !this.indexCache) return;
|
|
245
|
+
if (this.saveTimeout) {
|
|
246
|
+
clearTimeout(this.saveTimeout);
|
|
247
|
+
this.saveTimeout = null;
|
|
248
|
+
}
|
|
249
|
+
await this.writeIndex(this.indexCache);
|
|
250
|
+
this.dirty = false;
|
|
251
|
+
}
|
|
252
|
+
async loadIndex() {
|
|
253
|
+
if (this.indexCache) return this.indexCache;
|
|
254
|
+
const indexPath = resolveNotesIndexPath();
|
|
255
|
+
try {
|
|
256
|
+
const content = await readFile(indexPath, "utf-8");
|
|
257
|
+
const data = JSON.parse(content);
|
|
258
|
+
if (!data.notes || !Array.isArray(data.notes)) {
|
|
259
|
+
log.warn("Notes index invalid, resetting");
|
|
260
|
+
this.indexCache = DEFAULT_INDEX;
|
|
261
|
+
return this.indexCache;
|
|
262
|
+
}
|
|
263
|
+
this.indexCache = data;
|
|
264
|
+
return data;
|
|
265
|
+
} catch {
|
|
266
|
+
this.indexCache = DEFAULT_INDEX;
|
|
267
|
+
return this.indexCache;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
async writeIndex(data) {
|
|
271
|
+
await writeTextAtomic(resolveNotesIndexPath(), JSON.stringify(data, null, 2));
|
|
272
|
+
log.debug({ count: data.notes.length }, "Notes index saved");
|
|
273
|
+
}
|
|
274
|
+
async writeNoteItem(note) {
|
|
275
|
+
await writeTextAtomic(resolveNoteItemPath(note.id), JSON.stringify(note, null, 2));
|
|
276
|
+
}
|
|
277
|
+
scheduleIndexSave(data) {
|
|
278
|
+
this.indexCache = data;
|
|
279
|
+
this.dirty = true;
|
|
280
|
+
if (this.saveTimeout) clearTimeout(this.saveTimeout);
|
|
281
|
+
this.saveTimeout = setTimeout(() => {
|
|
282
|
+
this.flush().catch((err) => {
|
|
283
|
+
log.error({ err }, "Failed to flush notes index");
|
|
284
|
+
});
|
|
285
|
+
}, DEBOUNCE_MS);
|
|
286
|
+
}
|
|
287
|
+
async rebuildIndexFromItems() {
|
|
288
|
+
const itemsDir = join(resolveNotesDir(), "items");
|
|
289
|
+
let files;
|
|
290
|
+
try {
|
|
291
|
+
files = await readdir(itemsDir);
|
|
292
|
+
} catch {
|
|
293
|
+
this.indexCache = DEFAULT_INDEX;
|
|
294
|
+
await this.writeIndex(DEFAULT_INDEX);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const entries = [];
|
|
298
|
+
for (const file of files) {
|
|
299
|
+
if (!file.endsWith(".json")) continue;
|
|
300
|
+
const noteId = file.slice(0, -5);
|
|
301
|
+
const note = await this.getNote(noteId);
|
|
302
|
+
if (note) entries.push(noteToIndexEntry(note));
|
|
303
|
+
}
|
|
304
|
+
entries.sort((a, b) => b.createdAt - a.createdAt);
|
|
305
|
+
const index = {
|
|
306
|
+
version: INDEX_VERSION,
|
|
307
|
+
notes: entries
|
|
308
|
+
};
|
|
309
|
+
this.indexCache = index;
|
|
310
|
+
await this.writeIndex(index);
|
|
311
|
+
log.debug({ count: entries.length }, "Notes index rebuilt");
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
//#endregion
|
|
315
|
+
export { NotesStore };
|
|
316
|
+
|
|
317
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","names":[],"sources":["../../../src/notes/store.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { readFile, access, mkdir, writeFile, rm, readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { writeTextAtomic } from '../infra/write-file-atomic.js';\nimport { createLogger } from '../utils/logger.js';\nimport { buildNoteIndexMeta } from './note-index-meta.js';\nimport { resolveNotesDir, resolveNotesIndexPath, resolveNoteItemPath, resolveNoteMediaDir, resolveNoteHistoryDir } from './paths.js';\nimport type {\n Note,\n NoteIndexEntry,\n NoteSnapshot,\n NoteSnapshotEntry,\n NotesIndexFile,\n NotesListQuery,\n SnapshotTrigger,\n} from './types.js';\n\nconst log = createLogger('NotesStore');\n\nconst DEFAULT_INDEX: NotesIndexFile = { version: 3, notes: [] };\nconst INDEX_VERSION = 3;\nconst DEBOUNCE_MS = 500;\n\nfunction noteToIndexEntry(note: Note): NoteIndexEntry {\n const { snippet, coverAttachmentId, voiceAttachmentId, voiceDurationSec, attachmentNames } = buildNoteIndexMeta(note);\n return {\n id: note.id,\n title: note.title || undefined,\n kind: note.kind,\n status: note.status,\n createdAt: note.createdAt,\n updatedAt: note.updatedAt,\n pinned: note.pinned || undefined,\n tags: note.tags?.length ? note.tags : undefined,\n snippet,\n coverAttachmentId,\n voiceAttachmentId,\n voiceDurationSec,\n attachmentNames,\n };\n}\n\nexport class NotesStore {\n private indexCache: NotesIndexFile | null = null;\n private dirty = false;\n private saveTimeout: ReturnType<typeof setTimeout> | null = null;\n private initialized = false;\n\n async initialize(): Promise<void> {\n if (this.initialized) return;\n const indexPath = resolveNotesIndexPath();\n try {\n await access(indexPath);\n await this.loadIndex();\n if ((this.indexCache?.version ?? 0) < INDEX_VERSION) {\n await this.rebuildIndexFromItems();\n }\n } catch {\n await this.writeIndex(DEFAULT_INDEX);\n this.indexCache = DEFAULT_INDEX;\n }\n this.initialized = true;\n log.debug('NotesStore initialized');\n }\n\n async addNote(note: Note): Promise<void> {\n const index = await this.loadIndex();\n await this.writeNoteItem(note);\n index.notes.push(noteToIndexEntry(note));\n index.version++;\n this.scheduleIndexSave(index);\n }\n\n async getNote(id: string): Promise<Note | null> {\n const itemPath = resolveNoteItemPath(id);\n try {\n const content = await readFile(itemPath, 'utf-8');\n return JSON.parse(content) as Note;\n } catch (err) {\n const code = err && typeof err === 'object' && 'code' in err\n ? (err as NodeJS.ErrnoException).code : '';\n if (code !== 'ENOENT') {\n log.debug({ err, id }, 'Failed to read note item');\n }\n return null;\n }\n }\n\n async updateNote(id: string, patch: Partial<Note>): Promise<Note | null> {\n const existing = await this.getNote(id);\n if (!existing) return null;\n\n const updated: Note = {\n ...existing,\n ...patch,\n id: existing.id,\n createdAt: existing.createdAt,\n updatedAt: Date.now(),\n };\n\n await this.writeNoteItem(updated);\n\n const index = await this.loadIndex();\n const idx = index.notes.findIndex((n) => n.id === id);\n if (idx !== -1) {\n index.notes[idx] = noteToIndexEntry(updated);\n }\n index.version++;\n this.scheduleIndexSave(index);\n\n return updated;\n }\n\n async deleteNote(id: string): Promise<boolean> {\n const existing = await this.getNote(id);\n if (!existing) return false;\n\n const itemPath = resolveNoteItemPath(id);\n await rm(itemPath, { force: true }).catch((err) => {\n log.warn({ err, id }, 'Failed to remove note item file');\n });\n\n const mediaDir = resolveNoteMediaDir(id);\n await rm(mediaDir, { recursive: true, force: true }).catch(() => undefined);\n\n const index = await this.loadIndex();\n const before = index.notes.length;\n index.notes = index.notes.filter((n) => n.id !== id);\n if (index.notes.length === before) {\n log.debug({ id }, 'Deleted note file but index entry was missing');\n }\n index.version++;\n this.scheduleIndexSave(index);\n\n return true;\n }\n\n async listNotes(query: NotesListQuery = {}): Promise<{ items: NoteIndexEntry[]; total: number }> {\n const index = await this.loadIndex();\n let results = index.notes;\n\n if (query.status) {\n results = results.filter((n) => n.status === query.status);\n } else {\n results = results.filter((n) => n.status !== 'trashed');\n }\n if (query.kind) {\n results = results.filter((n) => n.kind === query.kind);\n }\n if (query.tag) {\n results = results.filter((n) => n.tags?.includes(query.tag!));\n }\n if (query.pinned !== undefined) {\n results = results.filter((n) => Boolean(n.pinned) === query.pinned);\n }\n if (query.search) {\n const term = query.search.toLowerCase();\n results = results.filter((n) =>\n n.title?.toLowerCase().includes(term) ||\n n.snippet?.toLowerCase().includes(term) ||\n n.tags?.some((t) => t.toLowerCase().includes(term)) ||\n n.attachmentNames?.some((name) => name.includes(term)),\n );\n }\n\n const sortField = query.sortBy || 'createdAt';\n const sortDir = query.sortOrder === 'asc' ? 1 : -1;\n results = [...results].sort((a, b) => (a[sortField] - b[sortField]) * sortDir);\n\n const total = results.length;\n const offset = query.offset || 0;\n const limit = Math.min(query.limit || 50, 200);\n const items = results.slice(offset, offset + limit);\n\n return { items, total };\n }\n\n async saveAttachment(\n noteId: string,\n fileName: string,\n buffer: Buffer,\n ): Promise<{ relativePath: string; size: number }> {\n const mediaDir = resolveNoteMediaDir(noteId);\n await mkdir(mediaDir, { recursive: true });\n const safeName = `${randomUUID().slice(0, 8)}_${fileName.replace(/[^a-zA-Z0-9._-]/g, '_')}`;\n const filePath = join(mediaDir, safeName);\n await writeFile(filePath, buffer);\n return { relativePath: safeName, size: buffer.length };\n }\n\n resolveAttachmentPath(noteId: string, relativePath: string): string {\n return join(resolveNoteMediaDir(noteId), relativePath);\n }\n\n async deleteAttachmentFile(noteId: string, relativePath: string): Promise<void> {\n const filePath = this.resolveAttachmentPath(noteId, relativePath);\n await rm(filePath, { force: true }).catch((err) => {\n log.warn({ err, noteId, relativePath }, 'Failed to remove note attachment file');\n });\n }\n\n async saveSnapshot(note: Note, trigger: SnapshotTrigger): Promise<void> {\n const historyDir = resolveNoteHistoryDir(note.id);\n await mkdir(historyDir, { recursive: true });\n const snapshot: NoteSnapshot = {\n noteId: note.id,\n timestamp: Date.now(),\n trigger,\n title: note.title,\n text: note.text,\n blocks: note.blocks,\n tags: note.tags,\n kind: note.kind,\n status: note.status,\n };\n const filePath = join(historyDir, `${snapshot.timestamp}.json`);\n await writeTextAtomic(filePath, JSON.stringify(snapshot, null, 2));\n log.debug({ noteId: note.id, trigger, timestamp: snapshot.timestamp }, 'Snapshot saved');\n }\n\n async listSnapshots(noteId: string): Promise<NoteSnapshotEntry[]> {\n const historyDir = resolveNoteHistoryDir(noteId);\n let files: string[];\n try {\n files = await readdir(historyDir);\n } catch {\n return [];\n }\n const entries: NoteSnapshotEntry[] = [];\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n const timestamp = parseInt(file.slice(0, -'.json'.length), 10);\n if (!Number.isFinite(timestamp)) continue;\n try {\n const content = await readFile(join(historyDir, file), 'utf-8');\n const snapshot = JSON.parse(content) as NoteSnapshot;\n const rawText = snapshot.text ?? '';\n entries.push({\n timestamp: snapshot.timestamp,\n trigger: snapshot.trigger,\n snippet: rawText.slice(0, 80) || undefined,\n });\n } catch {\n log.debug({ noteId, file }, 'Skipped unreadable snapshot');\n }\n }\n entries.sort((a, b) => b.timestamp - a.timestamp);\n return entries;\n }\n\n async getSnapshot(noteId: string, timestamp: number): Promise<NoteSnapshot | null> {\n const filePath = join(resolveNoteHistoryDir(noteId), `${timestamp}.json`);\n try {\n const content = await readFile(filePath, 'utf-8');\n return JSON.parse(content) as NoteSnapshot;\n } catch {\n return null;\n }\n }\n\n async pruneSnapshots(noteId: string, maxCount: number): Promise<void> {\n const historyDir = resolveNoteHistoryDir(noteId);\n let files: string[];\n try {\n files = await readdir(historyDir);\n } catch {\n return;\n }\n const jsonFiles = files\n .filter((f) => f.endsWith('.json'))\n .sort();\n if (jsonFiles.length <= maxCount) return;\n const toDelete = jsonFiles.slice(0, jsonFiles.length - maxCount);\n for (const file of toDelete) {\n await rm(join(historyDir, file), { force: true }).catch(() => undefined);\n }\n log.debug({ noteId, deleted: toDelete.length }, 'Pruned old snapshots');\n }\n\n async deleteAllSnapshots(noteId: string): Promise<void> {\n const historyDir = resolveNoteHistoryDir(noteId);\n await rm(historyDir, { recursive: true, force: true }).catch(() => undefined);\n }\n\n async flush(): Promise<void> {\n if (!this.dirty || !this.indexCache) return;\n if (this.saveTimeout) {\n clearTimeout(this.saveTimeout);\n this.saveTimeout = null;\n }\n await this.writeIndex(this.indexCache);\n this.dirty = false;\n }\n\n private async loadIndex(): Promise<NotesIndexFile> {\n if (this.indexCache) return this.indexCache;\n const indexPath = resolveNotesIndexPath();\n try {\n const content = await readFile(indexPath, 'utf-8');\n const data = JSON.parse(content) as NotesIndexFile;\n if (!data.notes || !Array.isArray(data.notes)) {\n log.warn('Notes index invalid, resetting');\n this.indexCache = DEFAULT_INDEX;\n return this.indexCache;\n }\n this.indexCache = data;\n return data;\n } catch {\n this.indexCache = DEFAULT_INDEX;\n return this.indexCache;\n }\n }\n\n private async writeIndex(data: NotesIndexFile): Promise<void> {\n const indexPath = resolveNotesIndexPath();\n await writeTextAtomic(indexPath, JSON.stringify(data, null, 2));\n log.debug({ count: data.notes.length }, 'Notes index saved');\n }\n\n private async writeNoteItem(note: Note): Promise<void> {\n const itemPath = resolveNoteItemPath(note.id);\n await writeTextAtomic(itemPath, JSON.stringify(note, null, 2));\n }\n\n private scheduleIndexSave(data: NotesIndexFile): void {\n this.indexCache = data;\n this.dirty = true;\n if (this.saveTimeout) {\n clearTimeout(this.saveTimeout);\n }\n this.saveTimeout = setTimeout(() => {\n this.flush().catch((err) => {\n log.error({ err }, 'Failed to flush notes index');\n });\n }, DEBOUNCE_MS);\n }\n\n private async rebuildIndexFromItems(): Promise<void> {\n const itemsDir = join(resolveNotesDir(), 'items');\n let files: string[];\n try {\n files = await readdir(itemsDir);\n } catch {\n this.indexCache = DEFAULT_INDEX;\n await this.writeIndex(DEFAULT_INDEX);\n return;\n }\n\n const entries: NoteIndexEntry[] = [];\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n const noteId = file.slice(0, -'.json'.length);\n const note = await this.getNote(noteId);\n if (note) {\n entries.push(noteToIndexEntry(note));\n }\n }\n\n entries.sort((a, b) => b.createdAt - a.createdAt);\n const index: NotesIndexFile = { version: INDEX_VERSION, notes: entries };\n this.indexCache = index;\n await this.writeIndex(index);\n log.debug({ count: entries.length }, 'Notes index rebuilt');\n }\n}\n"],"mappings":";;;;;;;;;wBAIgE;aACd;AAalD,MAAM,MAAM,aAAa,aAAa;AAEtC,MAAM,gBAAgC;CAAE,SAAS;CAAG,OAAO,EAAE;CAAE;AAC/D,MAAM,gBAAgB;AACtB,MAAM,cAAc;AAEpB,SAAS,iBAAiB,MAA4B;CACpD,MAAM,EAAE,SAAS,mBAAmB,mBAAmB,kBAAkB,oBAAoB,mBAAmB,KAAK;AACrH,QAAO;EACL,IAAI,KAAK;EACT,OAAO,KAAK,SAAS,KAAA;EACrB,MAAM,KAAK;EACX,QAAQ,KAAK;EACb,WAAW,KAAK;EAChB,WAAW,KAAK;EAChB,QAAQ,KAAK,UAAU,KAAA;EACvB,MAAM,KAAK,MAAM,SAAS,KAAK,OAAO,KAAA;EACtC;EACA;EACA;EACA;EACA;EACD;;AAGH,IAAa,aAAb,MAAwB;CACtB,aAA4C;CAC5C,QAAgB;CAChB,cAA4D;CAC5D,cAAsB;CAEtB,MAAM,aAA4B;AAChC,MAAI,KAAK,YAAa;EACtB,MAAM,YAAY,uBAAuB;AACzC,MAAI;AACF,SAAM,OAAO,UAAU;AACvB,SAAM,KAAK,WAAW;AACtB,QAAK,KAAK,YAAY,WAAW,KAAK,cACpC,OAAM,KAAK,uBAAuB;UAE9B;AACN,SAAM,KAAK,WAAW,cAAc;AACpC,QAAK,aAAa;;AAEpB,OAAK,cAAc;AACnB,MAAI,MAAM,yBAAyB;;CAGrC,MAAM,QAAQ,MAA2B;EACvC,MAAM,QAAQ,MAAM,KAAK,WAAW;AACpC,QAAM,KAAK,cAAc,KAAK;AAC9B,QAAM,MAAM,KAAK,iBAAiB,KAAK,CAAC;AACxC,QAAM;AACN,OAAK,kBAAkB,MAAM;;CAG/B,MAAM,QAAQ,IAAkC;EAC9C,MAAM,WAAW,oBAAoB,GAAG;AACxC,MAAI;GACF,MAAM,UAAU,MAAM,SAAS,UAAU,QAAQ;AACjD,UAAO,KAAK,MAAM,QAAQ;WACnB,KAAK;AAGZ,QAFa,OAAO,OAAO,QAAQ,YAAY,UAAU,MACpD,IAA8B,OAAO,QAC7B,SACX,KAAI,MAAM;IAAE;IAAK;IAAI,EAAE,2BAA2B;AAEpD,UAAO;;;CAIX,MAAM,WAAW,IAAY,OAA4C;EACvE,MAAM,WAAW,MAAM,KAAK,QAAQ,GAAG;AACvC,MAAI,CAAC,SAAU,QAAO;EAEtB,MAAM,UAAgB;GACpB,GAAG;GACH,GAAG;GACH,IAAI,SAAS;GACb,WAAW,SAAS;GACpB,WAAW,KAAK,KAAK;GACtB;AAED,QAAM,KAAK,cAAc,QAAQ;EAEjC,MAAM,QAAQ,MAAM,KAAK,WAAW;EACpC,MAAM,MAAM,MAAM,MAAM,WAAW,MAAM,EAAE,OAAO,GAAG;AACrD,MAAI,QAAQ,GACV,OAAM,MAAM,OAAO,iBAAiB,QAAQ;AAE9C,QAAM;AACN,OAAK,kBAAkB,MAAM;AAE7B,SAAO;;CAGT,MAAM,WAAW,IAA8B;AAE7C,MAAI,CAAC,MADkB,KAAK,QAAQ,GAAG,CACxB,QAAO;AAGtB,QAAM,GADW,oBAAoB,GACpB,EAAE,EAAE,OAAO,MAAM,CAAC,CAAC,OAAO,QAAQ;AACjD,OAAI,KAAK;IAAE;IAAK;IAAI,EAAE,kCAAkC;IACxD;AAGF,QAAM,GADW,oBAAoB,GACpB,EAAE;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC,CAAC,YAAY,KAAA,EAAU;EAE3E,MAAM,QAAQ,MAAM,KAAK,WAAW;EACpC,MAAM,SAAS,MAAM,MAAM;AAC3B,QAAM,QAAQ,MAAM,MAAM,QAAQ,MAAM,EAAE,OAAO,GAAG;AACpD,MAAI,MAAM,MAAM,WAAW,OACzB,KAAI,MAAM,EAAE,IAAI,EAAE,gDAAgD;AAEpE,QAAM;AACN,OAAK,kBAAkB,MAAM;AAE7B,SAAO;;CAGT,MAAM,UAAU,QAAwB,EAAE,EAAuD;EAE/F,IAAI,WAAU,MADM,KAAK,WAAW,EAChB;AAEpB,MAAI,MAAM,OACR,WAAU,QAAQ,QAAQ,MAAM,EAAE,WAAW,MAAM,OAAO;MAE1D,WAAU,QAAQ,QAAQ,MAAM,EAAE,WAAW,UAAU;AAEzD,MAAI,MAAM,KACR,WAAU,QAAQ,QAAQ,MAAM,EAAE,SAAS,MAAM,KAAK;AAExD,MAAI,MAAM,IACR,WAAU,QAAQ,QAAQ,MAAM,EAAE,MAAM,SAAS,MAAM,IAAK,CAAC;AAE/D,MAAI,MAAM,WAAW,KAAA,EACnB,WAAU,QAAQ,QAAQ,MAAM,QAAQ,EAAE,OAAO,KAAK,MAAM,OAAO;AAErE,MAAI,MAAM,QAAQ;GAChB,MAAM,OAAO,MAAM,OAAO,aAAa;AACvC,aAAU,QAAQ,QAAQ,MACxB,EAAE,OAAO,aAAa,CAAC,SAAS,KAAK,IACrC,EAAE,SAAS,aAAa,CAAC,SAAS,KAAK,IACvC,EAAE,MAAM,MAAM,MAAM,EAAE,aAAa,CAAC,SAAS,KAAK,CAAC,IACnD,EAAE,iBAAiB,MAAM,SAAS,KAAK,SAAS,KAAK,CAAC,CACvD;;EAGH,MAAM,YAAY,MAAM,UAAU;EAClC,MAAM,UAAU,MAAM,cAAc,QAAQ,IAAI;AAChD,YAAU,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,OAAO,EAAE,aAAa,EAAE,cAAc,QAAQ;EAE9E,MAAM,QAAQ,QAAQ;EACtB,MAAM,SAAS,MAAM,UAAU;EAC/B,MAAM,QAAQ,KAAK,IAAI,MAAM,SAAS,IAAI,IAAI;AAG9C,SAAO;GAAE,OAFK,QAAQ,MAAM,QAAQ,SAAS,MAE/B;GAAE;GAAO;;CAGzB,MAAM,eACJ,QACA,UACA,QACiD;EACjD,MAAM,WAAW,oBAAoB,OAAO;AAC5C,QAAM,MAAM,UAAU,EAAE,WAAW,MAAM,CAAC;EAC1C,MAAM,WAAW,GAAG,YAAY,CAAC,MAAM,GAAG,EAAE,CAAC,GAAG,SAAS,QAAQ,oBAAoB,IAAI;AAEzF,QAAM,UADW,KAAK,UAAU,SACR,EAAE,OAAO;AACjC,SAAO;GAAE,cAAc;GAAU,MAAM,OAAO;GAAQ;;CAGxD,sBAAsB,QAAgB,cAA8B;AAClE,SAAO,KAAK,oBAAoB,OAAO,EAAE,aAAa;;CAGxD,MAAM,qBAAqB,QAAgB,cAAqC;AAE9E,QAAM,GADW,KAAK,sBAAsB,QAAQ,aACnC,EAAE,EAAE,OAAO,MAAM,CAAC,CAAC,OAAO,QAAQ;AACjD,OAAI,KAAK;IAAE;IAAK;IAAQ;IAAc,EAAE,wCAAwC;IAChF;;CAGJ,MAAM,aAAa,MAAY,SAAyC;EACtE,MAAM,aAAa,sBAAsB,KAAK,GAAG;AACjD,QAAM,MAAM,YAAY,EAAE,WAAW,MAAM,CAAC;EAC5C,MAAM,WAAyB;GAC7B,QAAQ,KAAK;GACb,WAAW,KAAK,KAAK;GACrB;GACA,OAAO,KAAK;GACZ,MAAM,KAAK;GACX,QAAQ,KAAK;GACb,MAAM,KAAK;GACX,MAAM,KAAK;GACX,QAAQ,KAAK;GACd;AAED,QAAM,gBADW,KAAK,YAAY,GAAG,SAAS,UAAU,OAC1B,EAAE,KAAK,UAAU,UAAU,MAAM,EAAE,CAAC;AAClE,MAAI,MAAM;GAAE,QAAQ,KAAK;GAAI;GAAS,WAAW,SAAS;GAAW,EAAE,iBAAiB;;CAG1F,MAAM,cAAc,QAA8C;EAChE,MAAM,aAAa,sBAAsB,OAAO;EAChD,IAAI;AACJ,MAAI;AACF,WAAQ,MAAM,QAAQ,WAAW;UAC3B;AACN,UAAO,EAAE;;EAEX,MAAM,UAA+B,EAAE;AACvC,OAAK,MAAM,QAAQ,OAAO;AACxB,OAAI,CAAC,KAAK,SAAS,QAAQ,CAAE;GAC7B,MAAM,YAAY,SAAS,KAAK,MAAM,GAAG,GAAgB,EAAE,GAAG;AAC9D,OAAI,CAAC,OAAO,SAAS,UAAU,CAAE;AACjC,OAAI;IACF,MAAM,UAAU,MAAM,SAAS,KAAK,YAAY,KAAK,EAAE,QAAQ;IAC/D,MAAM,WAAW,KAAK,MAAM,QAAQ;IACpC,MAAM,UAAU,SAAS,QAAQ;AACjC,YAAQ,KAAK;KACX,WAAW,SAAS;KACpB,SAAS,SAAS;KAClB,SAAS,QAAQ,MAAM,GAAG,GAAG,IAAI,KAAA;KAClC,CAAC;WACI;AACN,QAAI,MAAM;KAAE;KAAQ;KAAM,EAAE,8BAA8B;;;AAG9D,UAAQ,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,UAAU;AACjD,SAAO;;CAGT,MAAM,YAAY,QAAgB,WAAiD;EACjF,MAAM,WAAW,KAAK,sBAAsB,OAAO,EAAE,GAAG,UAAU,OAAO;AACzE,MAAI;GACF,MAAM,UAAU,MAAM,SAAS,UAAU,QAAQ;AACjD,UAAO,KAAK,MAAM,QAAQ;UACpB;AACN,UAAO;;;CAIX,MAAM,eAAe,QAAgB,UAAiC;EACpE,MAAM,aAAa,sBAAsB,OAAO;EAChD,IAAI;AACJ,MAAI;AACF,WAAQ,MAAM,QAAQ,WAAW;UAC3B;AACN;;EAEF,MAAM,YAAY,MACf,QAAQ,MAAM,EAAE,SAAS,QAAQ,CAAC,CAClC,MAAM;AACT,MAAI,UAAU,UAAU,SAAU;EAClC,MAAM,WAAW,UAAU,MAAM,GAAG,UAAU,SAAS,SAAS;AAChE,OAAK,MAAM,QAAQ,SACjB,OAAM,GAAG,KAAK,YAAY,KAAK,EAAE,EAAE,OAAO,MAAM,CAAC,CAAC,YAAY,KAAA,EAAU;AAE1E,MAAI,MAAM;GAAE;GAAQ,SAAS,SAAS;GAAQ,EAAE,uBAAuB;;CAGzE,MAAM,mBAAmB,QAA+B;AAEtD,QAAM,GADa,sBAAsB,OACtB,EAAE;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC,CAAC,YAAY,KAAA,EAAU;;CAG/E,MAAM,QAAuB;AAC3B,MAAI,CAAC,KAAK,SAAS,CAAC,KAAK,WAAY;AACrC,MAAI,KAAK,aAAa;AACpB,gBAAa,KAAK,YAAY;AAC9B,QAAK,cAAc;;AAErB,QAAM,KAAK,WAAW,KAAK,WAAW;AACtC,OAAK,QAAQ;;CAGf,MAAc,YAAqC;AACjD,MAAI,KAAK,WAAY,QAAO,KAAK;EACjC,MAAM,YAAY,uBAAuB;AACzC,MAAI;GACF,MAAM,UAAU,MAAM,SAAS,WAAW,QAAQ;GAClD,MAAM,OAAO,KAAK,MAAM,QAAQ;AAChC,OAAI,CAAC,KAAK,SAAS,CAAC,MAAM,QAAQ,KAAK,MAAM,EAAE;AAC7C,QAAI,KAAK,iCAAiC;AAC1C,SAAK,aAAa;AAClB,WAAO,KAAK;;AAEd,QAAK,aAAa;AAClB,UAAO;UACD;AACN,QAAK,aAAa;AAClB,UAAO,KAAK;;;CAIhB,MAAc,WAAW,MAAqC;AAE5D,QAAM,gBADY,uBACa,EAAE,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC;AAC/D,MAAI,MAAM,EAAE,OAAO,KAAK,MAAM,QAAQ,EAAE,oBAAoB;;CAG9D,MAAc,cAAc,MAA2B;AAErD,QAAM,gBADW,oBAAoB,KAAK,GACZ,EAAE,KAAK,UAAU,MAAM,MAAM,EAAE,CAAC;;CAGhE,kBAA0B,MAA4B;AACpD,OAAK,aAAa;AAClB,OAAK,QAAQ;AACb,MAAI,KAAK,YACP,cAAa,KAAK,YAAY;AAEhC,OAAK,cAAc,iBAAiB;AAClC,QAAK,OAAO,CAAC,OAAO,QAAQ;AAC1B,QAAI,MAAM,EAAE,KAAK,EAAE,8BAA8B;KACjD;KACD,YAAY;;CAGjB,MAAc,wBAAuC;EACnD,MAAM,WAAW,KAAK,iBAAiB,EAAE,QAAQ;EACjD,IAAI;AACJ,MAAI;AACF,WAAQ,MAAM,QAAQ,SAAS;UACzB;AACN,QAAK,aAAa;AAClB,SAAM,KAAK,WAAW,cAAc;AACpC;;EAGF,MAAM,UAA4B,EAAE;AACpC,OAAK,MAAM,QAAQ,OAAO;AACxB,OAAI,CAAC,KAAK,SAAS,QAAQ,CAAE;GAC7B,MAAM,SAAS,KAAK,MAAM,GAAG,GAAgB;GAC7C,MAAM,OAAO,MAAM,KAAK,QAAQ,OAAO;AACvC,OAAI,KACF,SAAQ,KAAK,iBAAiB,KAAK,CAAC;;AAIxC,UAAQ,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,UAAU;EACjD,MAAM,QAAwB;GAAE,SAAS;GAAe,OAAO;GAAS;AACxE,OAAK,aAAa;AAClB,QAAM,KAAK,WAAW,MAAM;AAC5B,MAAI,MAAM,EAAE,OAAO,QAAQ,QAAQ,EAAE,sBAAsB"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
export type NoteKind = 'thought' | 'todo' | 'voice' | 'media' | 'bookmark' | 'mixed';
|
|
2
|
+
export type NoteStatus = 'inbox' | 'processed' | 'archived' | 'trashed';
|
|
3
|
+
export type CaptureChannel = 'app' | 'web' | 'electron' | 'tui' | 'telegram' | 'wechat' | 'feishu';
|
|
4
|
+
export type NoteBlockType = 'paragraph' | 'heading' | 'todo' | 'bulletList' | 'numberedList' | 'quote' | 'code' | 'divider' | 'image' | 'aiSuggestion';
|
|
5
|
+
export interface BaseNoteBlock {
|
|
6
|
+
id: string;
|
|
7
|
+
type: NoteBlockType;
|
|
8
|
+
createdAt: number;
|
|
9
|
+
updatedAt: number;
|
|
10
|
+
}
|
|
11
|
+
export interface TextNoteBlock extends BaseNoteBlock {
|
|
12
|
+
type: 'paragraph' | 'heading' | 'bulletList' | 'numberedList' | 'quote' | 'code' | 'aiSuggestion';
|
|
13
|
+
text: string;
|
|
14
|
+
level?: 1 | 2 | 3;
|
|
15
|
+
indent?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface TodoNoteBlock extends BaseNoteBlock {
|
|
18
|
+
type: 'todo';
|
|
19
|
+
text: string;
|
|
20
|
+
checked: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface DividerNoteBlock extends BaseNoteBlock {
|
|
23
|
+
type: 'divider';
|
|
24
|
+
}
|
|
25
|
+
export interface ImageNoteBlock extends BaseNoteBlock {
|
|
26
|
+
type: 'image';
|
|
27
|
+
attachmentId: string;
|
|
28
|
+
alt?: string;
|
|
29
|
+
width?: number;
|
|
30
|
+
}
|
|
31
|
+
export type NoteBlock = TextNoteBlock | TodoNoteBlock | DividerNoteBlock | ImageNoteBlock;
|
|
32
|
+
export type NotePatchOperation = {
|
|
33
|
+
type: 'replaceBlocks';
|
|
34
|
+
blocks: NoteBlock[];
|
|
35
|
+
} | {
|
|
36
|
+
type: 'insertBlocksAfter';
|
|
37
|
+
afterBlockId: string;
|
|
38
|
+
blocks: NoteBlock[];
|
|
39
|
+
} | {
|
|
40
|
+
type: 'updateBlock';
|
|
41
|
+
blockId: string;
|
|
42
|
+
patch: Partial<NoteBlock>;
|
|
43
|
+
} | {
|
|
44
|
+
type: 'updateMetadata';
|
|
45
|
+
title?: string;
|
|
46
|
+
tags?: string[];
|
|
47
|
+
status?: NoteStatus;
|
|
48
|
+
};
|
|
49
|
+
export interface NoteAiPatch {
|
|
50
|
+
id: string;
|
|
51
|
+
summary: string;
|
|
52
|
+
operations: NotePatchOperation[];
|
|
53
|
+
}
|
|
54
|
+
export interface NoteAttachment {
|
|
55
|
+
id: string;
|
|
56
|
+
type: 'image' | 'video' | 'audio' | 'file';
|
|
57
|
+
mimeType: string;
|
|
58
|
+
fileName: string;
|
|
59
|
+
size: number;
|
|
60
|
+
relativePath: string;
|
|
61
|
+
transcript?: string;
|
|
62
|
+
duration?: number;
|
|
63
|
+
}
|
|
64
|
+
export interface NoteAiMeta {
|
|
65
|
+
summary?: string;
|
|
66
|
+
intent?: 'action_item' | 'idea' | 'reference' | 'question' | 'log';
|
|
67
|
+
extractedTodos?: Array<{
|
|
68
|
+
text: string;
|
|
69
|
+
deadline?: string;
|
|
70
|
+
done: boolean;
|
|
71
|
+
}>;
|
|
72
|
+
suggestedTags?: string[];
|
|
73
|
+
}
|
|
74
|
+
export interface NoteAiDeepMeta {
|
|
75
|
+
processedAt: number;
|
|
76
|
+
priority?: 'high' | 'medium' | 'low';
|
|
77
|
+
relatedNoteIds?: string[];
|
|
78
|
+
relatedGoalId?: string;
|
|
79
|
+
insights?: string;
|
|
80
|
+
}
|
|
81
|
+
export interface CaptureSource {
|
|
82
|
+
channel: CaptureChannel;
|
|
83
|
+
platform?: 'ios' | 'android';
|
|
84
|
+
}
|
|
85
|
+
export interface Note {
|
|
86
|
+
id: string;
|
|
87
|
+
title?: string;
|
|
88
|
+
kind: NoteKind;
|
|
89
|
+
status: NoteStatus;
|
|
90
|
+
text?: string;
|
|
91
|
+
blocks?: NoteBlock[];
|
|
92
|
+
attachments?: NoteAttachment[];
|
|
93
|
+
createdAt: number;
|
|
94
|
+
updatedAt: number;
|
|
95
|
+
capturedVia: CaptureSource;
|
|
96
|
+
ai?: NoteAiMeta;
|
|
97
|
+
aiDeep?: NoteAiDeepMeta;
|
|
98
|
+
tags?: string[];
|
|
99
|
+
pinned?: boolean;
|
|
100
|
+
localVersion?: number;
|
|
101
|
+
remoteVersion?: number;
|
|
102
|
+
}
|
|
103
|
+
export interface NoteIndexEntry {
|
|
104
|
+
id: string;
|
|
105
|
+
title?: string;
|
|
106
|
+
kind: NoteKind;
|
|
107
|
+
status: NoteStatus;
|
|
108
|
+
createdAt: number;
|
|
109
|
+
updatedAt: number;
|
|
110
|
+
pinned?: boolean;
|
|
111
|
+
tags?: string[];
|
|
112
|
+
snippet?: string;
|
|
113
|
+
/** First image attachment id for list thumbnails. */
|
|
114
|
+
coverAttachmentId?: string;
|
|
115
|
+
/** First audio attachment id for inline voice playback. */
|
|
116
|
+
voiceAttachmentId?: string;
|
|
117
|
+
/** Duration in seconds of the voice attachment (when available). */
|
|
118
|
+
voiceDurationSec?: number;
|
|
119
|
+
/** Lowercased attachment file names for list search. */
|
|
120
|
+
attachmentNames?: string[];
|
|
121
|
+
}
|
|
122
|
+
export interface NotesIndexFile {
|
|
123
|
+
version: number;
|
|
124
|
+
notes: NoteIndexEntry[];
|
|
125
|
+
}
|
|
126
|
+
export type SnapshotTrigger = 'edit' | 'ai_edit' | 'sync' | 'restore';
|
|
127
|
+
export interface NoteSnapshot {
|
|
128
|
+
noteId: string;
|
|
129
|
+
timestamp: number;
|
|
130
|
+
trigger: SnapshotTrigger;
|
|
131
|
+
title?: string;
|
|
132
|
+
text?: string;
|
|
133
|
+
blocks?: NoteBlock[];
|
|
134
|
+
tags?: string[];
|
|
135
|
+
kind: NoteKind;
|
|
136
|
+
status: NoteStatus;
|
|
137
|
+
}
|
|
138
|
+
export interface NoteSnapshotEntry {
|
|
139
|
+
timestamp: number;
|
|
140
|
+
trigger: SnapshotTrigger;
|
|
141
|
+
snippet?: string;
|
|
142
|
+
}
|
|
143
|
+
export interface NotesListQuery {
|
|
144
|
+
status?: NoteStatus;
|
|
145
|
+
kind?: NoteKind;
|
|
146
|
+
tag?: string;
|
|
147
|
+
pinned?: boolean;
|
|
148
|
+
search?: string;
|
|
149
|
+
limit?: number;
|
|
150
|
+
offset?: number;
|
|
151
|
+
sortBy?: 'createdAt' | 'updatedAt';
|
|
152
|
+
sortOrder?: 'asc' | 'desc';
|
|
153
|
+
}
|
|
154
|
+
export interface CreateNoteParams {
|
|
155
|
+
title?: string;
|
|
156
|
+
text?: string;
|
|
157
|
+
blocks?: NoteBlock[];
|
|
158
|
+
kind?: NoteKind;
|
|
159
|
+
tags?: string[];
|
|
160
|
+
capturedVia: CaptureSource;
|
|
161
|
+
pinned?: boolean;
|
|
162
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
-
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
4
3
|
import { dirname, join } from "node:path";
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
5
5
|
//#region src/providers/auth-runtime/auth-profile-store.ts
|
|
6
6
|
/**
|
|
7
7
|
* {@link AuthProfileStore} implementations.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { __esmMin, __exportAll } from "../../_virtual/_rolldown/runtime.js";
|
|
2
|
-
import { PROVIDER_ENV_MAP, getApiKeyFromEnv, init_env_keys } from "./env-keys.js";
|
|
3
|
-
import { CredentialResolver, hasCredentials, init_credentials, resolveApiKey } from "../auth/credentials.js";
|
|
4
2
|
import { hasProviderAuthOnDiskSync, init_sync_provider_auth } from "../auth/sync-provider-auth.js";
|
|
3
|
+
import { PROVIDER_ENV_MAP, getApiKeyFromEnv, init_env_keys } from "./env-keys.js";
|
|
5
4
|
import { ModelRegistry, getModelRegistry, init_model_registry, prewarmModelRegistry, resetModelRegistry } from "./model-registry.js";
|
|
5
|
+
import { CredentialResolver, hasCredentials, init_credentials, resolveApiKey } from "../auth/credentials.js";
|
|
6
6
|
import { getProviderRegistry, init_plugin_registry } from "./plugin-registry.js";
|
|
7
7
|
import { getModel, getModels, getProviders } from "@earendil-works/pi-ai";
|
|
8
8
|
//#region src/providers/index.ts
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { createLogger } from "../utils/logger/index.js";
|
|
3
3
|
import { init_logger } from "../utils/logger.js";
|
|
4
|
-
import { getApiKeyFromEnv, init_env_keys } from "./env-keys.js";
|
|
5
4
|
import { resolveModelsJsonPath } from "../config/paths.js";
|
|
6
5
|
import { init_resolve_config_value, resolveConfigValue, resolveHeaders } from "../config/resolve-config-value.js";
|
|
7
6
|
import { getDefaultModelValues, init_models_json, validateModelsConfig } from "../config/models-json.js";
|
|
7
|
+
import { getApiKeyFromEnv, init_env_keys } from "./env-keys.js";
|
|
8
8
|
import { existsSync, readFileSync } from "fs";
|
|
9
9
|
import { getModels, getProviders } from "@earendil-works/pi-ai";
|
|
10
10
|
//#region src/providers/model-registry.ts
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
|
|
2
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
3
2
|
import { init_logger } from "../utils/logger.js";
|
|
4
|
-
import {
|
|
3
|
+
import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
|
|
5
4
|
import { join } from "path";
|
|
6
5
|
import { existsSync } from "fs";
|
|
6
|
+
import { mkdir, readFile } from "fs/promises";
|
|
7
7
|
//#region src/session/config-store.ts
|
|
8
8
|
/**
|
|
9
9
|
* Session Config Store
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
-
import { init_logger } from "../utils/logger.js";
|
|
3
1
|
import { SessionConfigSchema, init_schema } from "../config/schema.js";
|
|
4
2
|
import { init_session_key, parseSessionKey } from "../routing/session-key.js";
|
|
3
|
+
import { createLogger } from "../utils/logger/index.js";
|
|
4
|
+
import { init_logger } from "../utils/logger.js";
|
|
5
5
|
import { evaluateSessionFreshness, resolveSessionResetPolicy } from "./reset-policy.js";
|
|
6
6
|
import { resolveChannelResetConfig, resolveSessionResetType } from "./reset-type.js";
|
|
7
7
|
import { resolveSessionLifecycleTimestamps } from "./lifecycle-timestamps.js";
|
|
@@ -3,9 +3,9 @@ import { loadEntriesFromFile } from "./load-jsonl-entries.js";
|
|
|
3
3
|
import { withTranscriptFileLock } from "./transcript-file-lock.js";
|
|
4
4
|
import { emitSessionTranscriptUpdate } from "../transcript-events.js";
|
|
5
5
|
import { buildSessionContextForLlm, isTranscriptContextEntry } from "../session-context-for-llm.js";
|
|
6
|
-
import { randomUUID } from "node:crypto";
|
|
7
|
-
import { existsSync } from "node:fs";
|
|
8
6
|
import path from "node:path";
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
8
|
+
import { randomUUID } from "node:crypto";
|
|
9
9
|
import { CURRENT_SESSION_VERSION, SessionManager } from "@earendil-works/pi-coding-agent";
|
|
10
10
|
//#region src/session/parity/jsonl-transcript-io.ts
|
|
11
11
|
init_write_file_atomic();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
|
|
2
2
|
import { readSessionsJsonFileRaw } from "./sessions-json-file-read.js";
|
|
3
3
|
import { commitSessionsJsonWrite, getSessionsJsonWriteStats, invalidateSessionsJsonCache, noteSessionsJsonWritten, readSessionsJsonCached, resetSessionsJsonCacheForTest } from "./sessions-json-cache.js";
|
|
4
|
+
import { dirname } from "node:path";
|
|
4
5
|
import { existsSync } from "node:fs";
|
|
5
6
|
import { mkdir } from "node:fs/promises";
|
|
6
|
-
import { dirname } from "node:path";
|
|
7
7
|
import lockfile from "proper-lockfile";
|
|
8
8
|
//#region src/session/parity/sessions-json-file.ts
|
|
9
9
|
init_write_file_atomic();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import path from "node:path";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
3
4
|
import { mkdir, open, readFile, rm, stat } from "node:fs/promises";
|
|
4
|
-
import path from "node:path";
|
|
5
5
|
//#region src/session/parity/transcript-file-lock.ts
|
|
6
6
|
/**
|
|
7
7
|
* Cross-process (and re-entrant same-process) advisory lock for session transcript JSONL.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { __esmMin } from "../../../_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { formatSessionArchiveTimestamp, init_artifacts } from "./artifacts.js";
|
|
3
3
|
import { init_session_id, validateSessionId } from "./session-id.js";
|
|
4
|
-
import fs from "node:fs";
|
|
5
4
|
import { dirname, relative, resolve } from "node:path";
|
|
5
|
+
import fs from "node:fs";
|
|
6
6
|
//#region src/session/parity/transcript-paths.ts
|
|
7
7
|
function resolveSessionsDir(opts) {
|
|
8
8
|
const sessionsDir = opts?.sessionsDir?.trim();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
-
import { init_logger } from "../utils/logger.js";
|
|
3
|
-
import { init_agent_scope, resolveDefaultAgentId } from "../agent/agent-scope.js";
|
|
4
|
-
import { init_paths, resolveSessionsMapPath } from "../config/paths.js";
|
|
5
1
|
import { SessionConfigSchema, init_schema } from "../config/schema.js";
|
|
2
|
+
import { init_agent_scope, resolveDefaultAgentId } from "../agent/agent-scope.js";
|
|
6
3
|
import { init_agent_session_key, normalizeAgentId, resolveAgentIdFromSessionKey } from "../routing/agent-session-key.js";
|
|
7
4
|
import { init_session_key, parseSessionKey } from "../routing/session-key.js";
|
|
5
|
+
import { createLogger } from "../utils/logger/index.js";
|
|
6
|
+
import { init_logger } from "../utils/logger.js";
|
|
7
|
+
import { init_paths, resolveSessionsMapPath } from "../config/paths.js";
|
|
8
8
|
import { readSessionsJsonFile } from "./parity/sessions-json-file.js";
|
|
9
9
|
import { normalizeThinkLevel, normalizeVerboseLevel } from "../agent/transcript/thinking-types.js";
|
|
10
10
|
import { evaluateSessionFreshness, resolveSessionResetPolicy } from "./reset-policy.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FILENAMES, init_paths } from "../config/paths.js";
|
|
2
2
|
import { SessionSearchIndex } from "./search-index.js";
|
|
3
|
-
import { stat } from "node:fs/promises";
|
|
4
3
|
import { join } from "node:path";
|
|
4
|
+
import { stat } from "node:fs/promises";
|
|
5
5
|
//#region src/session/search-index-cache.ts
|
|
6
6
|
/**
|
|
7
7
|
* Shared cache for {@link SessionSearchIndex} builds (invalidated on session writes).
|
|
@@ -2,8 +2,8 @@ import { init_transcript_paths, resolveSessionFilePath } from "./parity/transcri
|
|
|
2
2
|
import { FILENAMES, init_paths } from "../config/paths.js";
|
|
3
3
|
import { isTranscriptContextEntry } from "./session-context-for-llm.js";
|
|
4
4
|
import { readTranscriptRowsFromFile, rowsToLlmMessages } from "./parity/jsonl-transcript-io.js";
|
|
5
|
-
import { readFile } from "node:fs/promises";
|
|
6
5
|
import { join } from "node:path";
|
|
6
|
+
import { readFile } from "node:fs/promises";
|
|
7
7
|
//#region src/session/search-index.ts
|
|
8
8
|
/**
|
|
9
9
|
* In-memory inverted index over session transcripts (`sessions.json` + JSONL).
|