@tekmidian/pai 0.14.2 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/dist/{auto-route-CLYcToZ5.mjs → auto-route-CdvjEWs5.mjs} +4 -4
  2. package/dist/{auto-route-CLYcToZ5.mjs.map → auto-route-CdvjEWs5.mjs.map} +1 -1
  3. package/dist/{kg-extraction-C8DEUHTS.mjs → checkpoint-block-Bl0HD3U2.mjs} +442 -13
  4. package/dist/checkpoint-block-Bl0HD3U2.mjs.map +1 -0
  5. package/dist/cli/index.mjs +14 -12
  6. package/dist/cli/index.mjs.map +1 -1
  7. package/dist/cli/program.d.mts.map +1 -1
  8. package/dist/cli/program.mjs +31 -16
  9. package/dist/cli/program.mjs.map +1 -1
  10. package/dist/{clusters-BYPw7vfW.mjs → clusters-CKWDwcMX.mjs} +2 -2
  11. package/dist/{clusters-BYPw7vfW.mjs.map → clusters-CKWDwcMX.mjs.map} +1 -1
  12. package/dist/{config-C8m-tPhP.mjs → config-DGOfoGfm.mjs} +1 -1
  13. package/dist/config-DGOfoGfm.mjs.map +1 -0
  14. package/dist/daemon/index.mjs +18 -16
  15. package/dist/daemon/index.mjs.map +1 -1
  16. package/dist/{daemon-COSvHTNu.mjs → daemon-1rKbN-fd.mjs} +31 -30
  17. package/dist/{daemon-COSvHTNu.mjs.map → daemon-1rKbN-fd.mjs.map} +1 -1
  18. package/dist/daemon-mcp/index.mjs +24 -2
  19. package/dist/daemon-mcp/index.mjs.map +1 -1
  20. package/dist/db-BtuN768f.mjs +206 -0
  21. package/dist/db-BtuN768f.mjs.map +1 -0
  22. package/dist/{db-CmYbAVCD.mjs → db-CYmBWcjh.mjs} +1 -1
  23. package/dist/{db-CmYbAVCD.mjs.map → db-CYmBWcjh.mjs.map} +1 -1
  24. package/dist/{detect-KjycLtXM.mjs → detect-Bf2z-oKB.mjs} +1 -1
  25. package/dist/{detect-KjycLtXM.mjs.map → detect-Bf2z-oKB.mjs.map} +1 -1
  26. package/dist/{detector-ZiOhHszd.mjs → detector-rq9JGTmS.mjs} +2 -2
  27. package/dist/{detector-ZiOhHszd.mjs.map → detector-rq9JGTmS.mjs.map} +1 -1
  28. package/dist/{embeddings-BJPOcbik.mjs → embeddings-DGRAPAYb.mjs} +1 -1
  29. package/dist/{embeddings-BJPOcbik.mjs.map → embeddings-DGRAPAYb.mjs.map} +1 -1
  30. package/dist/{factory-Q88X1bAN.mjs → factory-HcQsQqh0.mjs} +8 -5
  31. package/dist/{factory-Q88X1bAN.mjs.map → factory-HcQsQqh0.mjs.map} +1 -1
  32. package/dist/{helpers-IjZkXBhj.mjs → helpers-crDEr6S2.mjs} +1 -1
  33. package/dist/{helpers-IjZkXBhj.mjs.map → helpers-crDEr6S2.mjs.map} +1 -1
  34. package/dist/hooks/capture-all-events.mjs.map +1 -1
  35. package/dist/hooks/capture-session-summary.mjs.map +1 -1
  36. package/dist/hooks/capture-tool-output.mjs.map +1 -1
  37. package/dist/hooks/cleanup-session-files.mjs.map +1 -1
  38. package/dist/hooks/context-compression-hook.mjs +304 -48
  39. package/dist/hooks/context-compression-hook.mjs.map +4 -4
  40. package/dist/hooks/initialize-session.mjs.map +1 -1
  41. package/dist/hooks/inject-observations.mjs.map +1 -1
  42. package/dist/hooks/load-core-context.mjs.map +1 -1
  43. package/dist/hooks/load-project-context.mjs.map +1 -1
  44. package/dist/hooks/observe.mjs.map +1 -1
  45. package/dist/hooks/post-compact-inject.mjs.map +1 -1
  46. package/dist/hooks/security-validator.mjs.map +1 -1
  47. package/dist/hooks/session-commands.mjs.map +1 -1
  48. package/dist/hooks/stop-hook.mjs +299 -43
  49. package/dist/hooks/stop-hook.mjs.map +4 -4
  50. package/dist/hooks/subagent-stop-hook.mjs.map +1 -1
  51. package/dist/hooks/sync-todo-to-md.mjs.map +1 -1
  52. package/dist/hooks/update-tab-on-action.mjs.map +1 -1
  53. package/dist/hooks/update-tab-titles.mjs.map +1 -1
  54. package/dist/hooks/whisper-rules.mjs.map +1 -1
  55. package/dist/index.d.mts +0 -9
  56. package/dist/index.d.mts.map +1 -1
  57. package/dist/index.mjs +10 -9
  58. package/dist/indexer-AEcT8wHf.mjs +1 -0
  59. package/dist/{indexer-backend-Cm5RS7y0.mjs → indexer-backend-BQZXoarl.mjs} +3 -3
  60. package/dist/{indexer-backend-Cm5RS7y0.mjs.map → indexer-backend-BQZXoarl.mjs.map} +1 -1
  61. package/dist/{ipc-client-CoyUHPod.mjs → ipc-client-vO2GV325.mjs} +1 -1
  62. package/dist/{ipc-client-CoyUHPod.mjs.map → ipc-client-vO2GV325.mjs.map} +1 -1
  63. package/dist/{kg-entity-LXblD7LZ.mjs → kg-entity-DbOMPdF9.mjs} +1 -1
  64. package/dist/{kg-entity-LXblD7LZ.mjs.map → kg-entity-DbOMPdF9.mjs.map} +1 -1
  65. package/dist/{latent-ideas-RyC6eyqI.mjs → latent-ideas-C6IFFT0-.mjs} +4 -4
  66. package/dist/{latent-ideas-RyC6eyqI.mjs.map → latent-ideas-C6IFFT0-.mjs.map} +1 -1
  67. package/dist/{main-resolver-uFxNiDy7.mjs → main-resolver-DimnS2qP.mjs} +22 -22
  68. package/dist/{main-resolver-uFxNiDy7.mjs.map → main-resolver-DimnS2qP.mjs.map} +1 -1
  69. package/dist/{migrate-B02wDDgS.mjs → migrate-fLD6rAdO.mjs} +2 -2
  70. package/dist/{migrate-B02wDDgS.mjs.map → migrate-fLD6rAdO.mjs.map} +1 -1
  71. package/dist/{neighborhood-CklGIB8r.mjs → neighborhood-CzRNG2Oy.mjs} +2 -2
  72. package/dist/{neighborhood-CklGIB8r.mjs.map → neighborhood-CzRNG2Oy.mjs.map} +1 -1
  73. package/dist/{note-context-qvZlVXVO.mjs → note-context-CrfMbr4R.mjs} +1 -1
  74. package/dist/{note-context-qvZlVXVO.mjs.map → note-context-CrfMbr4R.mjs.map} +1 -1
  75. package/dist/{pai-marker-HVBwwBW-.mjs → pai-marker-B20KqhA8.mjs} +44 -2
  76. package/dist/pai-marker-B20KqhA8.mjs.map +1 -0
  77. package/dist/{pick-gne3kOJG.mjs → pick-B3zEYjin.mjs} +2316 -483
  78. package/dist/pick-B3zEYjin.mjs.map +1 -0
  79. package/dist/{postgres-B451Hnkm.mjs → postgres-zjKqPl4X.mjs} +2 -2
  80. package/dist/{postgres-B451Hnkm.mjs.map → postgres-zjKqPl4X.mjs.map} +1 -1
  81. package/dist/{query-feedback-fapbqRgh.mjs → query-feedback-BoY8_Dbb.mjs} +1 -1
  82. package/dist/{query-feedback-fapbqRgh.mjs.map → query-feedback-BoY8_Dbb.mjs.map} +1 -1
  83. package/dist/{reranker-C08R99zn.mjs → reranker-CMNZcfVx.mjs} +1 -1
  84. package/dist/{reranker-C08R99zn.mjs.map → reranker-CMNZcfVx.mjs.map} +1 -1
  85. package/dist/{search-HcdKtMla.mjs → search-i2nlQ-JM.mjs} +3 -3
  86. package/dist/{search-HcdKtMla.mjs.map → search-i2nlQ-JM.mjs.map} +1 -1
  87. package/dist/skills/End/SKILL.md +78 -0
  88. package/dist/skills/Pause/SKILL.md +77 -0
  89. package/dist/skills/Tasks/SKILL.md +22 -0
  90. package/dist/{sqlite-DQpY1Esi.mjs → sqlite-ChSCYwiC.mjs} +3 -3
  91. package/dist/{sqlite-DQpY1Esi.mjs.map → sqlite-ChSCYwiC.mjs.map} +1 -1
  92. package/dist/{state-BIlxNRUn.mjs → state-BXIdbxDs.mjs} +1 -1
  93. package/dist/{state-BIlxNRUn.mjs.map → state-BXIdbxDs.mjs.map} +1 -1
  94. package/dist/{stop-words-BwplsQ3z.mjs → stop-words-BaMEGVeY.mjs} +1 -1
  95. package/dist/{stop-words-BwplsQ3z.mjs.map → stop-words-BaMEGVeY.mjs.map} +1 -1
  96. package/dist/{sync-uPR4g438.mjs → sync-CmBKOL3K.mjs} +6 -205
  97. package/dist/sync-CmBKOL3K.mjs.map +1 -0
  98. package/dist/{themes-Cg8oG9Ra.mjs → themes-nvRM8v84.mjs} +3 -3
  99. package/dist/{themes-Cg8oG9Ra.mjs.map → themes-nvRM8v84.mjs.map} +1 -1
  100. package/dist/{tools-Op3C2Nm6.mjs → tools-CznjzfYz.mjs} +26 -26
  101. package/dist/{tools-Op3C2Nm6.mjs.map → tools-CznjzfYz.mjs.map} +1 -1
  102. package/dist/{trace-CLK-NPkb.mjs → trace-B8oz1ok0.mjs} +1 -1
  103. package/dist/{trace-CLK-NPkb.mjs.map → trace-B8oz1ok0.mjs.map} +1 -1
  104. package/dist/{utils-CqqgB0dH.mjs → utils-BAxjW3j8.mjs} +1 -1
  105. package/dist/{utils-CqqgB0dH.mjs.map → utils-BAxjW3j8.mjs.map} +1 -1
  106. package/dist/{vault-indexer-Dn_BccVK.mjs → vault-indexer-DrttVeEk.mjs} +2 -2
  107. package/dist/{vault-indexer-Dn_BccVK.mjs.map → vault-indexer-DrttVeEk.mjs.map} +1 -1
  108. package/dist/{work-queue-worker-BwouhVkb.mjs → work-queue-worker-BPXLkEik.mjs} +47 -30
  109. package/dist/work-queue-worker-BPXLkEik.mjs.map +1 -0
  110. package/dist/{zettelkasten-NwBD1NsT.mjs → zettelkasten-CTlt1dGv.mjs} +4 -4
  111. package/dist/{zettelkasten-NwBD1NsT.mjs.map → zettelkasten-CTlt1dGv.mjs.map} +1 -1
  112. package/docs/commands/README.md +17 -0
  113. package/docs/commands/backup.md +1 -1
  114. package/docs/commands/clear-names.md +1 -1
  115. package/docs/commands/daemon.md +1 -1
  116. package/docs/commands/db.md +1 -1
  117. package/docs/commands/end.md +4 -1
  118. package/docs/commands/help.md +1 -1
  119. package/docs/commands/kg.md +1 -1
  120. package/docs/commands/mcp.md +1 -1
  121. package/docs/commands/memory.md +1 -1
  122. package/docs/commands/notify.md +1 -1
  123. package/docs/commands/observation.md +1 -1
  124. package/docs/commands/obsidian.md +1 -1
  125. package/docs/commands/pause.md +4 -1
  126. package/docs/commands/project.md +1 -1
  127. package/docs/commands/projects.md +1 -1
  128. package/docs/commands/registry.md +18 -1
  129. package/docs/commands/restore.md +1 -1
  130. package/docs/commands/session.md +271 -0
  131. package/docs/commands/sessions.md +1 -1
  132. package/docs/commands/setup.md +1 -1
  133. package/docs/commands/shell-init.md +1 -1
  134. package/docs/commands/skill.md +1 -1
  135. package/docs/commands/task.md +2 -1
  136. package/docs/commands/topic.md +1 -1
  137. package/docs/commands/update.md +1 -1
  138. package/docs/commands/zettel.md +1 -1
  139. package/package.json +1 -1
  140. package/scripts/build-hooks.mjs +32 -3
  141. package/src/hooks/ts/lib/project-utils/todo.test.ts +132 -0
  142. package/src/hooks/ts/lib/project-utils/todo.ts +60 -34
  143. package/dist/config-C8m-tPhP.mjs.map +0 -1
  144. package/dist/kg-extraction-C8DEUHTS.mjs.map +0 -1
  145. package/dist/pai-marker-HVBwwBW-.mjs.map +0 -1
  146. package/dist/pick-gne3kOJG.mjs.map +0 -1
  147. package/dist/sync-uPR4g438.mjs.map +0 -1
  148. package/dist/work-queue-worker-BwouhVkb.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-DGOfoGfm.mjs","names":[],"sources":["../src/notifications/types.ts","../src/tasks/types.ts","../src/daemon/config.ts"],"sourcesContent":["/**\n * types.ts — Unified Notification Framework type definitions\n *\n * Defines the channel registry, event routing, and configuration schema\n * for PAI's notification subsystem.\n */\n\n// ---------------------------------------------------------------------------\n// Channel identifiers\n// ---------------------------------------------------------------------------\n\nexport type ChannelId = \"ntfy\" | \"whatsapp\" | \"macos\" | \"voice\" | \"cli\";\n\n// ---------------------------------------------------------------------------\n// Notification event types\n// ---------------------------------------------------------------------------\n\n/**\n * The semantic type of a notification event.\n * Used to route events to the appropriate channels.\n */\nexport type NotificationEvent =\n | \"error\"\n | \"progress\"\n | \"completion\"\n | \"info\"\n | \"debug\";\n\n// ---------------------------------------------------------------------------\n// Notification mode\n// ---------------------------------------------------------------------------\n\n/**\n * The current notification mode.\n *\n * - \"auto\" — Use the per-event routing table (default)\n * - \"voice\" — All events go to voice (WhatsApp TTS)\n * - \"whatsapp\" — All events go to WhatsApp text\n * - \"ntfy\" — All events go to ntfy.sh\n * - \"macos\" — All events go to macOS notifications\n * - \"cli\" — All events go to CLI stdout only\n * - \"off\" — Suppress all notifications\n */\nexport type NotificationMode =\n | \"auto\"\n | \"voice\"\n | \"whatsapp\"\n | \"ntfy\"\n | \"macos\"\n | \"cli\"\n | \"off\";\n\n// ---------------------------------------------------------------------------\n// Per-channel configuration\n// ---------------------------------------------------------------------------\n\nexport interface NtfyChannelConfig {\n enabled: boolean;\n /** ntfy.sh topic URL, e.g. \"https://ntfy.sh/my-topic\" */\n url?: string;\n /** ntfy priority: min | low | default | high | urgent */\n priority?: \"min\" | \"low\" | \"default\" | \"high\" | \"urgent\";\n}\n\nexport interface WhatsAppChannelConfig {\n enabled: boolean;\n /** Optional recipient (phone, JID, or contact name). Omit for self-chat. */\n recipient?: string;\n}\n\nexport interface MacOsChannelConfig {\n enabled: boolean;\n}\n\nexport interface VoiceChannelConfig {\n enabled: boolean;\n /** Kokoro voice name, e.g. \"bm_george\", \"af_bella\". Default: \"bm_george\" */\n voiceName?: string;\n}\n\nexport interface CliChannelConfig {\n enabled: boolean;\n}\n\nexport interface ChannelConfigs {\n ntfy: NtfyChannelConfig;\n whatsapp: WhatsAppChannelConfig;\n macos: MacOsChannelConfig;\n voice: VoiceChannelConfig;\n cli: CliChannelConfig;\n}\n\n// ---------------------------------------------------------------------------\n// Routing table\n// ---------------------------------------------------------------------------\n\n/**\n * Maps each event type to the ordered list of channels that should receive it.\n * Only channels that are enabled in `channels` and present in this list are used.\n */\nexport type RoutingTable = {\n [K in NotificationEvent]: ChannelId[];\n};\n\nexport const DEFAULT_ROUTING: RoutingTable = {\n error: [\"whatsapp\", \"macos\", \"ntfy\", \"cli\"],\n completion: [\"whatsapp\", \"macos\", \"ntfy\", \"cli\"],\n info: [\"cli\"],\n progress: [\"cli\"],\n debug: [],\n};\n\n// ---------------------------------------------------------------------------\n// Top-level notification config (embedded in PaiDaemonConfig)\n// ---------------------------------------------------------------------------\n\nexport interface NotificationConfig {\n /** Current routing mode. Default: \"auto\" */\n mode: NotificationMode;\n /** Per-channel configuration */\n channels: ChannelConfigs;\n /** Event → channel routing (used in \"auto\" mode) */\n routing: RoutingTable;\n}\n\nexport const DEFAULT_CHANNELS: ChannelConfigs = {\n ntfy: {\n enabled: false,\n url: undefined,\n priority: \"default\",\n },\n whatsapp: {\n enabled: true,\n recipient: undefined,\n },\n macos: {\n enabled: true,\n },\n voice: {\n enabled: false,\n voiceName: \"bm_george\",\n },\n cli: {\n enabled: true,\n },\n};\n\nexport const DEFAULT_NOTIFICATION_CONFIG: NotificationConfig = {\n mode: \"auto\",\n channels: DEFAULT_CHANNELS,\n routing: DEFAULT_ROUTING,\n};\n\n// ---------------------------------------------------------------------------\n// Notification payload\n// ---------------------------------------------------------------------------\n\nexport interface NotificationPayload {\n /** Semantic event type — used for routing */\n event: NotificationEvent;\n /** The notification message body */\n message: string;\n /** Optional title (used by macOS, ntfy) */\n title?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Provider interface\n// ---------------------------------------------------------------------------\n\nexport interface NotificationProvider {\n readonly channelId: ChannelId;\n /**\n * Send a notification.\n * Returns true on success, false on failure (failure is non-fatal).\n */\n send(payload: NotificationPayload, config: NotificationConfig): Promise<boolean>;\n}\n\n// ---------------------------------------------------------------------------\n// Send result\n// ---------------------------------------------------------------------------\n\nexport interface SendResult {\n channelsAttempted: ChannelId[];\n channelsSucceeded: ChannelId[];\n channelsFailed: ChannelId[];\n mode: NotificationMode;\n}\n","/**\n * types.ts — Task Bus type definitions\n *\n * Defines the provider registry, ownership resolution, and configuration schema\n * for PAI's cross-session task subsystem.\n *\n * The task bus routes work between PAI sessions through an external tracker.\n * A session files a task; a routine reads it later and dispatches it to the\n * session that owns it — spawning one if none is running.\n *\n * See Notes/docs/task-bus.md for the architecture and its constraints.\n */\n\n// ---------------------------------------------------------------------------\n// Provider identifiers\n// ---------------------------------------------------------------------------\n\nexport type ProviderId = \"todoist\";\n\n// ---------------------------------------------------------------------------\n// Ownership\n// ---------------------------------------------------------------------------\n\n/**\n * Prefix marking a tracker label as a PAI ownership assertion.\n * A task labelled `pai:acme-api` is owned by the `acme-api` project.\n */\nexport const OWNER_LABEL_PREFIX = \"pai:\";\n\n/**\n * How a task's owner was determined. Recorded so the routine can explain\n * itself, and so a mis-resolution is diagnosable rather than silent.\n *\n * - \"label\" — an explicit `pai:<project>` label (authoritative)\n * - \"container\" — the enclosing sub-project name matched a PAI alias (fallback)\n * - \"none\" — unresolved; the task stays in the findings inbox\n */\nexport type OwnerSource = \"label\" | \"container\" | \"none\";\n\nexport interface TaskOwner {\n /** Resolved PAI project short name, e.g. \"acme-api\". Null when UNROUTED. */\n project: string | null;\n /** Absolute path to the project root. Null when UNROUTED. */\n rootPath: string | null;\n source: OwnerSource;\n /**\n * The raw string that resolution was attempted against, kept for diagnostics\n * when `source` is \"none\" — e.g. a \"Reading List 📚\" container matches no\n * PAI project, which is expected rather than a fault.\n */\n rawHint?: string;\n}\n\n/** An unresolved owner. UNROUTED is a normal state, not an error. */\nexport const UNROUTED: TaskOwner = {\n project: null,\n rootPath: null,\n source: \"none\",\n};\n\n// ---------------------------------------------------------------------------\n// Tasks\n// ---------------------------------------------------------------------------\n\nexport type TaskPriority = \"p1\" | \"p2\" | \"p3\" | \"p4\";\n\nexport interface Task {\n /** Provider-native task ID. Opaque; never parsed. */\n id: string;\n title: string;\n /**\n * Full procedure AND reasoning — enough that the task is actionable months\n * later, or by the user alone, without re-deriving anything. Enforced at\n * filing time rather than left to discipline.\n */\n body: string;\n owner: TaskOwner;\n /** ISO 8601 date or datetime. Null when the task has no due date. */\n due: string | null;\n priority: TaskPriority;\n labels: string[];\n /**\n * Stable reference to the artifact this task is about. Prefer a `hook://`\n * URL over a filesystem path — it survives renames and moves, and opens in\n * DEVONthink To Go on iOS.\n */\n sourceUrl?: string;\n /** True for organizational headers that cannot be completed. */\n isHeader?: boolean;\n}\n\n/** A task being filed. `owner` is a project short name, resolved on write. */\nexport interface NewTask {\n title: string;\n body: string;\n owner?: string | null;\n due?: string;\n priority?: TaskPriority;\n labels?: string[];\n sourceUrl?: string;\n /**\n * Sub-project to file into, created if absent.\n *\n * The convention is one sub-project per PAI project under the bus root. It\n * previously existed only in the shape of the data, so every session had to\n * re-derive it — and a session that inferred cautiously filed flat instead,\n * which is exactly the pile the convention prevents.\n */\n into?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Provider interface\n// ---------------------------------------------------------------------------\n\nexport interface ListOptions {\n /** Only tasks due on or before this ISO date. Omit for all open tasks. */\n dueBefore?: string;\n /** Restrict to one resolved owner. Omit for every owner. */\n owner?: string;\n /** Include tasks that resolved to UNROUTED. Default: true. */\n includeUnrouted?: boolean;\n limit?: number;\n}\n\nexport interface TaskProvider {\n readonly providerId: ProviderId;\n\n /**\n * False when no credential is configured. The bus degrades to a no-op\n * rather than failing — a user without a tracker still gets working PAI.\n */\n isConfigured(): boolean;\n\n listOpen(opts: ListOptions): Promise<Task[]>;\n add(task: NewTask): Promise<Task>;\n complete(id: string): Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Configuration\n// ---------------------------------------------------------------------------\n\nexport interface TodoistProviderConfig {\n enabled: boolean;\n /**\n * API token. Resolution order is apiKey → TODOIST_API_KEY env → unconfigured.\n *\n * Never read this from another tool's config file. PAI ships as a product;\n * scraping ~/.claude.json for a key belonging to the Todoist MCP is not\n * acceptable even though the key is sitting there.\n */\n apiKey?: string;\n /**\n * Tracker project ID that roots the bus (the \"Claude 🤖\" project).\n *\n * Stored as an ID, never a name. Todoist's project search silently returns\n * zero results for names containing emoji — resolving by name would report\n * \"no tasks\" instead of failing, which is the exact class of silent failure\n * this subsystem exists to surface.\n */\n rootProjectId?: string;\n /** Section ID for the findings inbox. Tasks land here when UNROUTED. */\n findingsSectionId?: string;\n}\n\nexport interface TaskConfig {\n /** Master switch. When false the bus is inert. */\n enabled: boolean;\n providers: {\n todoist: TodoistProviderConfig;\n };\n /**\n * Dispatch work to the owning session automatically, spawning one if absent.\n * Requires AIBroker. When false — or when AIBroker is unavailable — PAI\n * reports which project owns each task and leaves acting to the user.\n */\n autoDispatch: boolean;\n\n /**\n * Seconds AIBroker may spend on a single dispatch, spawn included.\n *\n * Passed down to the transport so both sides share one deadline. Raise it on\n * a loaded machine where sessions are slow to start accepting input.\n */\n dispatchTimeoutSecs?: number;\n}\n\nexport const DEFAULT_TASK_CONFIG: TaskConfig = {\n enabled: false,\n providers: {\n todoist: {\n enabled: false,\n },\n },\n autoDispatch: false,\n};\n\n// ---------------------------------------------------------------------------\n// Dispatch results\n// ---------------------------------------------------------------------------\n\n/**\n * What happened to one task during a dispatch run.\n *\n * - \"delivered\" — sent to an already-running session, and confirmed submitted\n * - \"spawned\" — none running; one was launched, came up, and received it\n * - \"unrouted\" — no owner resolved; left in the findings inbox\n * - \"unlaunchable\" — an owner resolved but no PAI alias exists to launch it\n * - \"unreachable\" — a session was launched but never became ready to accept input\n * - \"skipped\" — autoDispatch is off, or no transport; reported only\n *\n * `unlaunchable` and `unreachable` are distinct because the fixes differ:\n * the first is a setup gap (register an alias), the second is a runtime\n * failure (find out why the session did not come up). Collapsing them would\n * send users looking in the wrong place.\n *\n * None of these are errors. A task that could not be delivered is a routing\n * result to report, not an exception to throw.\n */\nexport type DispatchOutcome =\n | \"delivered\"\n | \"spawned\"\n | \"unrouted\"\n | \"unlaunchable\"\n | \"unreachable\"\n | \"skipped\";\n\nexport interface DispatchResult {\n task: Task;\n outcome: DispatchOutcome;\n /** Session the task reached, when it reached one. */\n session?: string;\n /** Why the task did not reach a session. Present on failure outcomes. */\n reason?: string;\n}\n","/**\n * config.ts — Configuration loader for PAI Daemon\n *\n * Loads config from ~/.config/pai/config.json (XDG convention).\n * Deep-merges with defaults so partial configs work fine.\n * Expands ~ in path values at runtime.\n */\n\nimport { existsSync, readFileSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { homedir, userInfo } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { NotificationConfig } from \"../notifications/types.js\";\nimport { DEFAULT_NOTIFICATION_CONFIG } from \"../notifications/types.js\";\nimport type { TaskConfig } from \"../tasks/types.js\";\nimport { DEFAULT_TASK_CONFIG } from \"../tasks/types.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SearchConfig {\n /** Default search mode: 'keyword', 'semantic', or 'hybrid'. Default: 'keyword'. */\n mode: \"keyword\" | \"semantic\" | \"hybrid\";\n /** Enable cross-encoder reranking by default. Default: true. */\n rerank: boolean;\n /** Recency boost half-life in days. 0 = off. Default: 90. */\n recencyBoostDays: number;\n /** Default max results. Default: 10. */\n defaultLimit: number;\n /** Default snippet length for MCP results. Default: 200. */\n snippetLength: number;\n}\n\nexport interface PostgresConfig {\n /** Connection string — if set, overrides individual host/port/etc. fields */\n connectionString?: string;\n /** Postgres host (default: \"localhost\") */\n host?: string;\n /** Postgres port (default: 5432) */\n port?: number;\n /** Postgres database name (default: \"pai\") */\n database?: string;\n /** Postgres user (default: \"pai\") */\n user?: string;\n /** Postgres password (default: \"pai\") */\n password?: string;\n /** Maximum pool connections (default: 5) */\n maxConnections?: number;\n /** Connection timeout in ms (default: 5000) */\n connectionTimeoutMs?: number;\n}\n\nexport interface PaiDaemonConfig {\n /** Unix Domain Socket path for IPC */\n socketPath: string;\n\n /** Index schedule interval in seconds (default: 300 = 5 minutes) */\n indexIntervalSecs: number;\n\n /** Embedding schedule interval in seconds (default: 600 = 10 minutes) */\n embedIntervalSecs: number;\n\n /** Storage backend: \"sqlite\" (default) or \"postgres\" */\n storageBackend: \"sqlite\" | \"postgres\";\n\n /** PostgreSQL connection config (used when storageBackend = \"postgres\") */\n postgres?: PostgresConfig;\n\n /** Embedding model name (used for semantic/hybrid search) */\n embeddingModel: string;\n\n /** Log level */\n logLevel: \"debug\" | \"info\" | \"warn\" | \"error\";\n\n /** Obsidian vault root path for zettelkasten indexing. If set, vault indexing runs alongside project indexing. */\n vaultPath?: string;\n\n /** Registry project_id to use for vault chunks in memory_chunks. Default: auto-detected. */\n vaultProjectId?: number;\n\n /** Notification subsystem configuration */\n notifications: NotificationConfig;\n\n /** Search defaults — applied when MCP tool or CLI doesn't specify a value */\n search: SearchConfig;\n\n /** Task bus — optional external tracker for cross-session work */\n tasks: TaskConfig;\n}\n\n// ---------------------------------------------------------------------------\n// Per-user Postgres isolation\n// ---------------------------------------------------------------------------\n\n/** Derive a per-user Postgres database name: pai_<username> */\nfunction perUserDbName(): string {\n const username = userInfo().username;\n // Sanitize: only allow alphanumeric and underscore for Postgres identifiers\n const safe = username.replace(/[^a-zA-Z0-9_]/g, \"_\").toLowerCase();\n return `pai_${safe}`;\n}\n\n/** Derive the per-user connection string */\nfunction perUserConnectionString(): string {\n const db = perUserDbName();\n return `postgresql://pai:pai@localhost:5432/${db}`;\n}\n\n// ---------------------------------------------------------------------------\n// Defaults\n// ---------------------------------------------------------------------------\n\nexport const DEFAULTS: PaiDaemonConfig = {\n socketPath: \"/tmp/pai.sock\",\n indexIntervalSecs: 300,\n embedIntervalSecs: 600,\n storageBackend: \"sqlite\",\n postgres: {\n connectionString: perUserConnectionString(),\n maxConnections: 5,\n connectionTimeoutMs: 5000,\n },\n embeddingModel: \"Snowflake/snowflake-arctic-embed-m-v1.5\",\n logLevel: \"info\",\n notifications: DEFAULT_NOTIFICATION_CONFIG,\n tasks: DEFAULT_TASK_CONFIG,\n search: {\n mode: \"keyword\",\n rerank: true,\n recencyBoostDays: 90,\n defaultLimit: 10,\n snippetLength: 200,\n },\n};\n\n/** Config template — generated at runtime so the DB name is per-user */\nfunction configTemplate(): string {\n return `{\n \"socketPath\": \"/tmp/pai.sock\",\n \"indexIntervalSecs\": 300,\n \"embedIntervalSecs\": 600,\n \"storageBackend\": \"sqlite\",\n \"postgres\": {\n \"connectionString\": \"${perUserConnectionString()}\",\n \"maxConnections\": 5,\n \"connectionTimeoutMs\": 5000\n },\n \"embeddingModel\": \"Snowflake/snowflake-arctic-embed-m-v1.5\",\n \"logLevel\": \"info\",\n \"vaultPath\": \"\",\n \"vaultProjectId\": 0,\n \"search\": {\n \"mode\": \"keyword\",\n \"rerank\": true,\n \"recencyBoostDays\": 90,\n \"defaultLimit\": 10,\n \"snippetLength\": 200\n }\n}\n`;\n}\n\n// ---------------------------------------------------------------------------\n// Path helpers\n// ---------------------------------------------------------------------------\n\n/** Expand a leading ~ to the real home directory */\nexport function expandHome(p: string): string {\n if (p === \"~\" || p.startsWith(\"~/\") || p.startsWith(\"~\\\\\")) {\n return join(homedir(), p.slice(1));\n }\n return p;\n}\n\nexport const CONFIG_DIR = join(homedir(), \".config\", \"pai\");\nexport const CONFIG_FILE = join(CONFIG_DIR, \"config.json\");\n\n// ---------------------------------------------------------------------------\n// Deep merge (handles nested objects, not arrays)\n// ---------------------------------------------------------------------------\n\nfunction deepMerge<T extends object>(\n target: T,\n source: Record<string, unknown>\n): T {\n const result = { ...target };\n for (const key of Object.keys(source)) {\n const srcVal = source[key];\n if (srcVal === undefined || srcVal === null) continue;\n const tgtVal = (target as Record<string, unknown>)[key];\n if (\n typeof srcVal === \"object\" &&\n !Array.isArray(srcVal) &&\n typeof tgtVal === \"object\" &&\n tgtVal !== null &&\n !Array.isArray(tgtVal)\n ) {\n (result as Record<string, unknown>)[key] = deepMerge(\n tgtVal as object,\n srcVal as Record<string, unknown>\n );\n } else {\n (result as Record<string, unknown>)[key] = srcVal;\n }\n }\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Config loader\n// ---------------------------------------------------------------------------\n\n/**\n * Load configuration from ~/.config/pai/config.json.\n * Returns defaults merged with any values found in the file.\n */\nexport function loadConfig(): PaiDaemonConfig {\n if (!existsSync(CONFIG_FILE)) {\n return { ...DEFAULTS };\n }\n\n let raw: string;\n try {\n raw = readFileSync(CONFIG_FILE, \"utf-8\");\n } catch (e) {\n process.stderr.write(\n `[pai-daemon] Could not read config file at ${CONFIG_FILE}: ${e}\\n`\n );\n return { ...DEFAULTS };\n }\n\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch (e) {\n process.stderr.write(\n `[pai-daemon] Config file is not valid JSON: ${e}\\n`\n );\n return { ...DEFAULTS };\n }\n\n // Compat: config.json may use \"obsidianVaultPath\" (legacy key) instead of \"vaultPath\".\n // Map it across so the daemon picks it up correctly.\n if (parsed.obsidianVaultPath && !parsed.vaultPath) {\n parsed.vaultPath = parsed.obsidianVaultPath;\n process.stderr.write(\n `[pai-daemon] Config: mapped obsidianVaultPath → vaultPath (${parsed.vaultPath})\\n`\n );\n }\n\n return deepMerge(DEFAULTS, parsed);\n}\n\n/**\n * Ensure ~/.config/pai/ exists and write a default config.json template\n * if none exists yet. Call this only from the `serve` command.\n */\nexport function ensureConfigDir(): void {\n if (!existsSync(CONFIG_DIR)) {\n mkdirSync(CONFIG_DIR, { recursive: true });\n process.stderr.write(\n `[pai-daemon] Created config directory: ${CONFIG_DIR}\\n`\n );\n }\n\n if (!existsSync(CONFIG_FILE)) {\n try {\n writeFileSync(CONFIG_FILE, configTemplate(), \"utf-8\");\n process.stderr.write(\n `[pai-daemon] Wrote default config to: ${CONFIG_FILE}\\n`\n );\n } catch (e) {\n process.stderr.write(\n `[pai-daemon] Could not write default config: ${e}\\n`\n );\n }\n }\n}\n"],"mappings":"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"}
@@ -1,20 +1,22 @@
1
1
  #!/usr/bin/env node
2
- import "../sync-uPR4g438.mjs";
3
- import "../utils-CqqgB0dH.mjs";
4
- import "../migrate-B02wDDgS.mjs";
5
- import "../db-CmYbAVCD.mjs";
6
- import "../helpers-IjZkXBhj.mjs";
7
- import "../embeddings-BJPOcbik.mjs";
8
- import "../search-HcdKtMla.mjs";
9
- import "../kg-extraction-C8DEUHTS.mjs";
10
- import "../factory-Q88X1bAN.mjs";
11
- import { t as PaiClient } from "../ipc-client-CoyUHPod.mjs";
12
- import { i as ensureConfigDir, o as loadConfig } from "../config-C8m-tPhP.mjs";
13
- import { n as serve } from "../daemon-COSvHTNu.mjs";
14
- import "../state-BIlxNRUn.mjs";
15
- import "../tools-Op3C2Nm6.mjs";
16
- import "../detector-ZiOhHszd.mjs";
17
- import "../work-queue-worker-BwouhVkb.mjs";
2
+ import "../db-BtuN768f.mjs";
3
+ import "../utils-BAxjW3j8.mjs";
4
+ import "../migrate-fLD6rAdO.mjs";
5
+ import "../db-CYmBWcjh.mjs";
6
+ import "../helpers-crDEr6S2.mjs";
7
+ import "../sync-CmBKOL3K.mjs";
8
+ import "../embeddings-DGRAPAYb.mjs";
9
+ import "../search-i2nlQ-JM.mjs";
10
+ import "../checkpoint-block-Bl0HD3U2.mjs";
11
+ import "../indexer-AEcT8wHf.mjs";
12
+ import { t as PaiClient } from "../ipc-client-vO2GV325.mjs";
13
+ import { i as ensureConfigDir, o as loadConfig } from "../config-DGOfoGfm.mjs";
14
+ import "../factory-HcQsQqh0.mjs";
15
+ import { n as serve } from "../daemon-1rKbN-fd.mjs";
16
+ import "../state-BXIdbxDs.mjs";
17
+ import "../tools-CznjzfYz.mjs";
18
+ import "../detector-rq9JGTmS.mjs";
19
+ import "../work-queue-worker-BPXLkEik.mjs";
18
20
  import { Command } from "commander";
19
21
 
20
22
  //#region src/daemon/index.ts
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/daemon/index.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * PAI Daemon — Entry point\n *\n * Commands:\n * serve — Start the PAI daemon (foreground, managed by launchd in production)\n * status — Query daemon status via IPC\n * index — Trigger an immediate index run via IPC\n */\n\nimport { Command } from \"commander\";\nimport { loadConfig, ensureConfigDir } from \"./config.js\";\nimport { serve } from \"./daemon.js\";\nimport { PaiClient } from \"./ipc-client.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"pai-daemon\")\n .description(\"PAI Daemon — background service for PAI Knowledge OS\")\n .version(\"0.1.0\");\n\n// ---------------------------------------------------------------------------\n// serve\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"serve\")\n .description(\"Start the PAI daemon in the foreground\")\n .action(async () => {\n ensureConfigDir();\n const config = loadConfig();\n await serve(config);\n });\n\n// ---------------------------------------------------------------------------\n// status\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"status\")\n .description(\"Query the running daemon status\")\n .action(async () => {\n const config = loadConfig();\n const client = new PaiClient(config.socketPath);\n\n try {\n const status = await client.status();\n console.log(JSON.stringify(status, null, 2));\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n console.error(`Error: ${msg}`);\n process.exit(1);\n }\n });\n\n// ---------------------------------------------------------------------------\n// index\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"index\")\n .description(\"Trigger an immediate index run in the running daemon\")\n .action(async () => {\n const config = loadConfig();\n const client = new PaiClient(config.socketPath);\n\n try {\n await client.triggerIndex();\n console.log(\"Index triggered. Check daemon logs for progress.\");\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n console.error(`Error: ${msg}`);\n process.exit(1);\n }\n });\n\n// ---------------------------------------------------------------------------\n// Parse\n// ---------------------------------------------------------------------------\n\nprogram.parse(process.argv);\n\nif (process.argv.length <= 2) {\n program.help();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeA,MAAM,UAAU,IAAI,SAAS;AAE7B,QACG,KAAK,aAAa,CAClB,YAAY,uDAAuD,CACnE,QAAQ,QAAQ;AAMnB,QACG,QAAQ,QAAQ,CAChB,YAAY,yCAAyC,CACrD,OAAO,YAAY;AAClB,kBAAiB;AAEjB,OAAM,MADS,YAAY,CACR;EACnB;AAMJ,QACG,QAAQ,SAAS,CACjB,YAAY,kCAAkC,CAC9C,OAAO,YAAY;CAElB,MAAM,SAAS,IAAI,UADJ,YAAY,CACS,WAAW;AAE/C,KAAI;EACF,MAAM,SAAS,MAAM,OAAO,QAAQ;AACpC,UAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC;UACrC,GAAG;EACV,MAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;AACtD,UAAQ,MAAM,UAAU,MAAM;AAC9B,UAAQ,KAAK,EAAE;;EAEjB;AAMJ,QACG,QAAQ,QAAQ,CAChB,YAAY,uDAAuD,CACnE,OAAO,YAAY;CAElB,MAAM,SAAS,IAAI,UADJ,YAAY,CACS,WAAW;AAE/C,KAAI;AACF,QAAM,OAAO,cAAc;AAC3B,UAAQ,IAAI,mDAAmD;UACxD,GAAG;EACV,MAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;AACtD,UAAQ,MAAM,UAAU,MAAM;AAC9B,UAAQ,KAAK,EAAE;;EAEjB;AAMJ,QAAQ,MAAM,QAAQ,KAAK;AAE3B,IAAI,QAAQ,KAAK,UAAU,EACzB,SAAQ,MAAM"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/daemon/index.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * PAI Daemon — Entry point\n *\n * Commands:\n * serve — Start the PAI daemon (foreground, managed by launchd in production)\n * status — Query daemon status via IPC\n * index — Trigger an immediate index run via IPC\n */\n\nimport { Command } from \"commander\";\nimport { loadConfig, ensureConfigDir } from \"./config.js\";\nimport { serve } from \"./daemon.js\";\nimport { PaiClient } from \"./ipc-client.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"pai-daemon\")\n .description(\"PAI Daemon — background service for PAI Knowledge OS\")\n .version(\"0.1.0\");\n\n// ---------------------------------------------------------------------------\n// serve\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"serve\")\n .description(\"Start the PAI daemon in the foreground\")\n .action(async () => {\n ensureConfigDir();\n const config = loadConfig();\n await serve(config);\n });\n\n// ---------------------------------------------------------------------------\n// status\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"status\")\n .description(\"Query the running daemon status\")\n .action(async () => {\n const config = loadConfig();\n const client = new PaiClient(config.socketPath);\n\n try {\n const status = await client.status();\n console.log(JSON.stringify(status, null, 2));\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n console.error(`Error: ${msg}`);\n process.exit(1);\n }\n });\n\n// ---------------------------------------------------------------------------\n// index\n// ---------------------------------------------------------------------------\n\nprogram\n .command(\"index\")\n .description(\"Trigger an immediate index run in the running daemon\")\n .action(async () => {\n const config = loadConfig();\n const client = new PaiClient(config.socketPath);\n\n try {\n await client.triggerIndex();\n console.log(\"Index triggered. Check daemon logs for progress.\");\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n console.error(`Error: ${msg}`);\n process.exit(1);\n }\n });\n\n// ---------------------------------------------------------------------------\n// Parse\n// ---------------------------------------------------------------------------\n\nprogram.parse(process.argv);\n\nif (process.argv.length <= 2) {\n program.help();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeA,MAAM,UAAU,IAAI,SAAS;AAE7B,QACG,KAAK,aAAa,CAClB,YAAY,uDAAuD,CACnE,QAAQ,QAAQ;AAMnB,QACG,QAAQ,QAAQ,CAChB,YAAY,yCAAyC,CACrD,OAAO,YAAY;AAClB,kBAAiB;AAEjB,OAAM,MADS,YAAY,CACR;EACnB;AAMJ,QACG,QAAQ,SAAS,CACjB,YAAY,kCAAkC,CAC9C,OAAO,YAAY;CAElB,MAAM,SAAS,IAAI,UADJ,YAAY,CACS,WAAW;AAE/C,KAAI;EACF,MAAM,SAAS,MAAM,OAAO,QAAQ;AACpC,UAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,EAAE,CAAC;UACrC,GAAG;EACV,MAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;AACtD,UAAQ,MAAM,UAAU,MAAM;AAC9B,UAAQ,KAAK,EAAE;;EAEjB;AAMJ,QACG,QAAQ,QAAQ,CAChB,YAAY,uDAAuD,CACnE,OAAO,YAAY;CAElB,MAAM,SAAS,IAAI,UADJ,YAAY,CACS,WAAW;AAE/C,KAAI;AACF,QAAM,OAAO,cAAc;AAC3B,UAAQ,IAAI,mDAAmD;UACxD,GAAG;EACV,MAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;AACtD,UAAQ,MAAM,UAAU,MAAM;AAC9B,UAAQ,KAAK,EAAE;;EAEjB;AAMJ,QAAQ,MAAM,QAAQ,KAAK;AAE3B,IAAI,QAAQ,KAAK,UAAU,EACzB,SAAQ,MAAM"}
@@ -1,14 +1,15 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-95iHPtFO.mjs";
2
- import { a as openRegistry, n as indexAll } from "./sync-uPR4g438.mjs";
3
- import { n as openFederation } from "./db-CmYbAVCD.mjs";
4
- import { d as sha256 } from "./helpers-IjZkXBhj.mjs";
5
- import { t as configureEmbeddingModel } from "./embeddings-BJPOcbik.mjs";
6
- import { t as createStorageBackend } from "./factory-Q88X1bAN.mjs";
7
- import { l as DEFAULT_NOTIFICATION_CONFIG, n as CONFIG_FILE, t as CONFIG_DIR } from "./config-C8m-tPhP.mjs";
8
- import { C as setStorageBackend, E as startTime, O as storageBackend, S as setStartTime, T as shutdownRequested, _ as setLastIndexTime, a as indexSchedulerTimer, b as setRegistryDb, c as lastVaultIndexTime, d as setDaemonConfig, f as setEmbedInProgress, g as setLastEmbedTime, h as setIndexSchedulerTimer, i as indexInProgress, k as vaultIndexInProgress, l as notificationConfig, m as setIndexInProgress, n as embedInProgress, o as lastEmbedTime, p as setEmbedSchedulerTimer, r as embedSchedulerTimer, s as lastIndexTime, t as daemonConfig, u as registryDb, v as setLastVaultIndexTime, w as setVaultIndexInProgress, x as setShutdownRequested, y as setNotificationConfig } from "./state-BIlxNRUn.mjs";
9
- import { a as toolMemoryWakeup, c as toolSessionRoute, d as toolProjectInfo, f as toolProjectList, h as toolMemorySearch, i as toolMemoryTaxonomy, l as toolProjectDetect, m as toolMemoryGet, n as toolMemoryKgSearch, o as toolRegistrySearch, p as toolProjectTodo, r as toolMemoryFeedback, s as toolSessionList, u as toolProjectHealth } from "./tools-Op3C2Nm6.mjs";
10
- import { t as detectTopicShift } from "./detector-ZiOhHszd.mjs";
11
- import { a as enqueue, n as startWorker, o as getStats, r as stopWorker, s as loadQueue, t as notifyNewWork } from "./work-queue-worker-BwouhVkb.mjs";
2
+ import { n as openRegistry } from "./db-BtuN768f.mjs";
3
+ import { n as openFederation } from "./db-CYmBWcjh.mjs";
4
+ import { d as sha256 } from "./helpers-crDEr6S2.mjs";
5
+ import { n as indexAll } from "./sync-CmBKOL3K.mjs";
6
+ import { t as configureEmbeddingModel } from "./embeddings-DGRAPAYb.mjs";
7
+ import { l as DEFAULT_NOTIFICATION_CONFIG, n as CONFIG_FILE, t as CONFIG_DIR } from "./config-DGOfoGfm.mjs";
8
+ import { t as createStorageBackend } from "./factory-HcQsQqh0.mjs";
9
+ import { C as setStorageBackend, E as startTime, O as storageBackend, S as setStartTime, T as shutdownRequested, _ as setLastIndexTime, a as indexSchedulerTimer, b as setRegistryDb, c as lastVaultIndexTime, d as setDaemonConfig, f as setEmbedInProgress, g as setLastEmbedTime, h as setIndexSchedulerTimer, i as indexInProgress, k as vaultIndexInProgress, l as notificationConfig, m as setIndexInProgress, n as embedInProgress, o as lastEmbedTime, p as setEmbedSchedulerTimer, r as embedSchedulerTimer, s as lastIndexTime, t as daemonConfig, u as registryDb, v as setLastVaultIndexTime, w as setVaultIndexInProgress, x as setShutdownRequested, y as setNotificationConfig } from "./state-BXIdbxDs.mjs";
10
+ import { a as toolMemoryWakeup, c as toolSessionRoute, d as toolProjectInfo, f as toolProjectList, h as toolMemorySearch, i as toolMemoryTaxonomy, l as toolProjectDetect, m as toolMemoryGet, n as toolMemoryKgSearch, o as toolRegistrySearch, p as toolProjectTodo, r as toolMemoryFeedback, s as toolSessionList, u as toolProjectHealth } from "./tools-CznjzfYz.mjs";
11
+ import { t as detectTopicShift } from "./detector-rq9JGTmS.mjs";
12
+ import { a as enqueue, n as startWorker, o as getStats, r as stopWorker, s as loadQueue, t as notifyNewWork } from "./work-queue-worker-BPXLkEik.mjs";
12
13
  import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
13
14
  import { setPriority } from "node:os";
14
15
  import { randomUUID } from "node:crypto";
@@ -111,7 +112,7 @@ async function runIndex() {
111
112
  try {
112
113
  process.stderr.write("[pai-daemon] Starting scheduled index run...\n");
113
114
  if (storageBackend.backendType === "sqlite") {
114
- const { SQLiteBackend } = await import("./sqlite-DQpY1Esi.mjs");
115
+ const { SQLiteBackend } = await import("./sqlite-ChSCYwiC.mjs");
115
116
  if (storageBackend instanceof SQLiteBackend) {
116
117
  const { projects, result } = await indexAll(storageBackend.getRawDb(), registryDb);
117
118
  const elapsed = Date.now() - t0;
@@ -119,7 +120,7 @@ async function runIndex() {
119
120
  process.stderr.write(`[pai-daemon] Index complete: ${projects} projects, ${result.filesProcessed} files, ${result.chunksCreated} chunks (${elapsed}ms)\n`);
120
121
  }
121
122
  } else {
122
- const { indexAllWithBackend } = await import("./indexer-backend-Cm5RS7y0.mjs");
123
+ const { indexAllWithBackend } = await import("./indexer-backend-BQZXoarl.mjs");
123
124
  const { projects, result } = await indexAllWithBackend(storageBackend, registryDb);
124
125
  const elapsed = Date.now() - t0;
125
126
  setLastIndexTime(Date.now());
@@ -146,7 +147,7 @@ async function runVaultIndex() {
146
147
  process.stderr.write("[pai-daemon] Index/embed in progress, deferring vault index.\n");
147
148
  return;
148
149
  }
149
- const { lastVaultIndexTime } = await import("./state-BIlxNRUn.mjs").then((n) => n.D);
150
+ const { lastVaultIndexTime } = await import("./state-BXIdbxDs.mjs").then((n) => n.D);
150
151
  if (lastVaultIndexTime > 0 && Date.now() - lastVaultIndexTime < VAULT_INDEX_MIN_INTERVAL_MS) return;
151
152
  let vaultProjectId = daemonConfig.vaultProjectId;
152
153
  if (!vaultProjectId) {
@@ -158,7 +159,7 @@ async function runVaultIndex() {
158
159
  const t0 = Date.now();
159
160
  process.stderr.write("[pai-daemon] Starting vault index run...\n");
160
161
  try {
161
- const { indexVault } = await import("./vault-indexer-Dn_BccVK.mjs");
162
+ const { indexVault } = await import("./vault-indexer-DrttVeEk.mjs");
162
163
  const r = await indexVault(storageBackend, vaultProjectId, daemonConfig.vaultPath);
163
164
  const elapsed = Date.now() - t0;
164
165
  setLastVaultIndexTime(Date.now());
@@ -211,12 +212,12 @@ async function runEmbed() {
211
212
  const rows = registryDb.prepare("SELECT id, slug FROM projects WHERE status = 'active'").all();
212
213
  for (const r of rows) projectNames.set(r.id, r.slug);
213
214
  } catch {}
214
- const { embedChunksWithBackend } = await import("./indexer-backend-Cm5RS7y0.mjs");
215
+ const { embedChunksWithBackend } = await import("./indexer-backend-BQZXoarl.mjs");
215
216
  const count = await embedChunksWithBackend(storageBackend, () => shutdownRequested, projectNames);
216
217
  let vaultEmbedCount = 0;
217
218
  if (daemonConfig.vaultPath) try {
218
- const { SQLiteBackend } = await import("./sqlite-DQpY1Esi.mjs");
219
- const { openFederation } = await import("./db-CmYbAVCD.mjs").then((n) => n.t);
219
+ const { SQLiteBackend } = await import("./sqlite-ChSCYwiC.mjs");
220
+ const { openFederation } = await import("./db-CYmBWcjh.mjs").then((n) => n.t);
220
221
  const federationDb = openFederation();
221
222
  const vaultSqliteBackend = new SQLiteBackend(federationDb);
222
223
  const vaultProjectNames = new Map(projectNames);
@@ -270,12 +271,12 @@ const REGISTRY_SCAN_STARTUP_DELAY_MS = 1e4;
270
271
  function startRegistryScanScheduler() {
271
272
  process.stderr.write("[pai-daemon] Registry scan scheduler: every 30min (first in 10s)\n");
272
273
  setTimeout(() => {
273
- import("./work-queue-worker-BwouhVkb.mjs").then((n) => n.i).then(({ enqueueRegistryScan }) => enqueueRegistryScan()).catch((e) => {
274
+ import("./work-queue-worker-BPXLkEik.mjs").then((n) => n.i).then(({ enqueueRegistryScan }) => enqueueRegistryScan()).catch((e) => {
274
275
  process.stderr.write(`[pai-daemon] Startup registry scan error: ${e}\n`);
275
276
  });
276
277
  }, REGISTRY_SCAN_STARTUP_DELAY_MS);
277
278
  const timer = setInterval(() => {
278
- import("./work-queue-worker-BwouhVkb.mjs").then((n) => n.i).then(({ enqueueRegistryScan }) => enqueueRegistryScan()).catch((e) => {
279
+ import("./work-queue-worker-BPXLkEik.mjs").then((n) => n.i).then(({ enqueueRegistryScan }) => enqueueRegistryScan()).catch((e) => {
279
280
  process.stderr.write(`[pai-daemon] Scheduled registry scan error: ${e}\n`);
280
281
  });
281
282
  }, REGISTRY_SCAN_INTERVAL_MS);
@@ -805,7 +806,7 @@ async function dispatchTool(method, params) {
805
806
  case "zettel_themes":
806
807
  case "zettel_god_notes":
807
808
  case "zettel_communities": {
808
- const { toolZettelExplore, toolZettelHealth, toolZettelSurprise, toolZettelSuggest, toolZettelConverse, toolZettelThemes, toolZettelGodNotes, toolZettelCommunities } = await import("./tools-Op3C2Nm6.mjs").then((n) => n.t);
809
+ const { toolZettelExplore, toolZettelHealth, toolZettelSurprise, toolZettelSuggest, toolZettelConverse, toolZettelThemes, toolZettelGodNotes, toolZettelCommunities } = await import("./tools-CznjzfYz.mjs").then((n) => n.t);
809
810
  switch (method) {
810
811
  case "zettel_explore": return toolZettelExplore(storageBackend, p);
811
812
  case "zettel_health": return toolZettelHealth(storageBackend, p);
@@ -819,27 +820,27 @@ async function dispatchTool(method, params) {
819
820
  break;
820
821
  }
821
822
  case "graph_clusters": {
822
- const { handleGraphClusters } = await import("./clusters-BYPw7vfW.mjs");
823
+ const { handleGraphClusters } = await import("./clusters-CKWDwcMX.mjs");
823
824
  return handleGraphClusters(storageBackend.getPool?.() ?? null, storageBackend, p);
824
825
  }
825
826
  case "graph_neighborhood": {
826
- const { handleGraphNeighborhood } = await import("./neighborhood-CklGIB8r.mjs");
827
+ const { handleGraphNeighborhood } = await import("./neighborhood-CzRNG2Oy.mjs");
827
828
  return handleGraphNeighborhood(storageBackend.getPool?.() ?? null, storageBackend, p);
828
829
  }
829
830
  case "graph_note_context": {
830
- const { handleGraphNoteContext } = await import("./note-context-qvZlVXVO.mjs");
831
+ const { handleGraphNoteContext } = await import("./note-context-CrfMbr4R.mjs");
831
832
  return handleGraphNoteContext(storageBackend.getPool?.() ?? null, storageBackend, p);
832
833
  }
833
834
  case "graph_trace": {
834
- const { handleGraphTrace } = await import("./trace-CLK-NPkb.mjs");
835
+ const { handleGraphTrace } = await import("./trace-B8oz1ok0.mjs");
835
836
  return handleGraphTrace(storageBackend, p);
836
837
  }
837
838
  case "graph_latent_ideas": {
838
- const { handleGraphLatentIdeas } = await import("./latent-ideas-RyC6eyqI.mjs");
839
+ const { handleGraphLatentIdeas } = await import("./latent-ideas-C6IFFT0-.mjs");
839
840
  return handleGraphLatentIdeas(storageBackend, p);
840
841
  }
841
842
  case "idea_materialize": {
842
- const { handleIdeaMaterialize } = await import("./latent-ideas-RyC6eyqI.mjs");
843
+ const { handleIdeaMaterialize } = await import("./latent-ideas-C6IFFT0-.mjs");
843
844
  if (!daemonConfig.vaultPath) throw new Error("idea_materialize requires vaultPath to be configured in the daemon config");
844
845
  return handleIdeaMaterialize(p, daemonConfig.vaultPath);
845
846
  }
@@ -847,7 +848,7 @@ async function dispatchTool(method, params) {
847
848
  case "kg_query":
848
849
  case "kg_invalidate":
849
850
  case "kg_contradictions": {
850
- const { toolKgAdd, toolKgQuery, toolKgInvalidate, toolKgContradictions } = await import("./tools-Op3C2Nm6.mjs").then((n) => n.t);
851
+ const { toolKgAdd, toolKgQuery, toolKgInvalidate, toolKgContradictions } = await import("./tools-CznjzfYz.mjs").then((n) => n.t);
851
852
  const pgPool = storageBackend.getPool?.() ?? null;
852
853
  if (!pgPool) throw new Error(`${method} requires a Postgres storage backend`);
853
854
  switch (method) {
@@ -859,7 +860,7 @@ async function dispatchTool(method, params) {
859
860
  break;
860
861
  }
861
862
  case "memory_tunnels": {
862
- const { toolMemoryTunnels } = await import("./tools-Op3C2Nm6.mjs").then((n) => n.t);
863
+ const { toolMemoryTunnels } = await import("./tools-CznjzfYz.mjs").then((n) => n.t);
863
864
  return toolMemoryTunnels(registryDb, storageBackend, p);
864
865
  }
865
866
  case "memory_feedback": {
@@ -1509,7 +1510,7 @@ async function serve(config) {
1509
1510
  process.stderr.write("[pai-daemon] Starting daemon...\n");
1510
1511
  process.stderr.write(`[pai-daemon] Socket: ${config.socketPath}\n`);
1511
1512
  process.stderr.write(`[pai-daemon] Storage backend: ${config.storageBackend}\n`);
1512
- const { notificationConfig } = await import("./state-BIlxNRUn.mjs").then((n) => n.D);
1513
+ const { notificationConfig } = await import("./state-BXIdbxDs.mjs").then((n) => n.D);
1513
1514
  process.stderr.write(`[pai-daemon] Notification mode: ${notificationConfig.mode}\n`);
1514
1515
  try {
1515
1516
  setPriority(process.pid, 10);
@@ -1577,4 +1578,4 @@ var daemon_exports = /* @__PURE__ */ __exportAll({ serve: () => serve });
1577
1578
 
1578
1579
  //#endregion
1579
1580
  export { serve as n, daemon_exports as t };
1580
- //# sourceMappingURL=daemon-COSvHTNu.mjs.map
1581
+ //# sourceMappingURL=daemon-1rKbN-fd.mjs.map