0xkobold 0.7.2 → 0.8.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 (252) hide show
  1. package/HEARTBEAT.md +239 -0
  2. package/IDENTITY.md +12 -0
  3. package/README.md +138 -4
  4. package/SOUL.md +21 -0
  5. package/dist/package.json +10 -5
  6. package/dist/src/agent/bootstrap-loader.js +295 -66
  7. package/dist/src/agent/bootstrap-loader.js.map +1 -1
  8. package/dist/src/agent/context-pruning.js +10 -5
  9. package/dist/src/agent/context-pruning.js.map +1 -1
  10. package/dist/src/agent/embedded-runner.js +29 -15
  11. package/dist/src/agent/embedded-runner.js.map +1 -1
  12. package/dist/src/agent/index.js +5 -2
  13. package/dist/src/agent/index.js.map +1 -1
  14. package/dist/src/agent/system-prompt.js +167 -20
  15. package/dist/src/agent/system-prompt.js.map +1 -1
  16. package/dist/src/agent/tools/spawn-agent.js +72 -5
  17. package/dist/src/agent/tools/spawn-agent.js.map +1 -1
  18. package/dist/src/channels/slack/webhook.js +2 -2
  19. package/dist/src/channels/slack/webhook.js.map +1 -1
  20. package/dist/src/channels/telegram/bot.js +4 -4
  21. package/dist/src/channels/telegram/bot.js.map +1 -1
  22. package/dist/src/channels/whatsapp/integration.js +4 -4
  23. package/dist/src/channels/whatsapp/integration.js.map +1 -1
  24. package/dist/src/cli/commands/gateway.js +9 -10
  25. package/dist/src/cli/commands/gateway.js.map +1 -1
  26. package/dist/src/cli/commands/init.js +90 -0
  27. package/dist/src/cli/commands/init.js.map +1 -1
  28. package/dist/src/cli/commands/setup.js +53 -0
  29. package/dist/src/cli/commands/setup.js.map +1 -1
  30. package/dist/src/cli/index.js +0 -0
  31. package/dist/src/config/unified-config.js +5 -0
  32. package/dist/src/config/unified-config.js.map +1 -1
  33. package/dist/src/cron/index.js +2 -0
  34. package/dist/src/cron/index.js.map +1 -1
  35. package/dist/src/cron/nl-parser.js +522 -0
  36. package/dist/src/cron/nl-parser.js.map +1 -0
  37. package/dist/src/cron/runner.js +6 -31
  38. package/dist/src/cron/runner.js.map +1 -1
  39. package/dist/src/event-bus/index.js.map +1 -1
  40. package/dist/src/extensions/core/agent-orchestrator-extension.js +200 -148
  41. package/dist/src/extensions/core/agent-orchestrator-extension.js.map +1 -1
  42. package/dist/src/extensions/core/diagnostics-extension.js +93 -56
  43. package/dist/src/extensions/core/diagnostics-extension.js.map +1 -1
  44. package/dist/src/extensions/core/draconic-safety-extension.js +256 -3
  45. package/dist/src/extensions/core/draconic-safety-extension.js.map +1 -1
  46. package/dist/src/extensions/core/heartbeat-extension.js +416 -150
  47. package/dist/src/extensions/core/heartbeat-extension.js.map +1 -1
  48. package/dist/src/extensions/core/{generative-agents-extension.js → learning-extension.js} +90 -128
  49. package/dist/src/extensions/core/learning-extension.js.map +1 -0
  50. package/dist/src/extensions/core/perennial-memory-extension.js +884 -87
  51. package/dist/src/extensions/core/perennial-memory-extension.js.map +1 -1
  52. package/dist/src/extensions/core/routed-ollama-extension.js +345 -0
  53. package/dist/src/extensions/core/routed-ollama-extension.js.map +1 -0
  54. package/dist/src/extensions/core/task-manager-extension.js +25 -2
  55. package/dist/src/extensions/core/task-manager-extension.js.map +1 -1
  56. package/dist/src/extensions/core/websearch-enhanced-extension.js +81 -23
  57. package/dist/src/extensions/core/websearch-enhanced-extension.js.map +1 -1
  58. package/dist/src/extensions/core/workspace-footer-extension.js +40 -63
  59. package/dist/src/extensions/core/workspace-footer-extension.js.map +1 -1
  60. package/dist/src/extensions/loader.js +5 -1
  61. package/dist/src/extensions/loader.js.map +1 -1
  62. package/dist/src/gateway/gateway-server.js +74 -3
  63. package/dist/src/gateway/gateway-server.js.map +1 -1
  64. package/dist/src/gateway/index.js +2 -2
  65. package/dist/src/gateway/index.js.map +1 -1
  66. package/dist/src/gateway/methods/agent.js +1 -1
  67. package/dist/src/gateway/methods/agent.js.map +1 -1
  68. package/dist/src/gateway/methods/index.js +4 -0
  69. package/dist/src/gateway/methods/index.js.map +1 -1
  70. package/dist/src/gateway/methods/node.js +261 -0
  71. package/dist/src/gateway/methods/node.js.map +1 -0
  72. package/dist/src/gateway/queue-modes.js +356 -0
  73. package/dist/src/gateway/queue-modes.js.map +1 -0
  74. package/dist/src/index.js +47 -6
  75. package/dist/src/index.js.map +1 -1
  76. package/dist/src/llm/community-analytics.js +569 -0
  77. package/dist/src/llm/community-analytics.js.map +1 -0
  78. package/dist/src/llm/index.js +28 -4
  79. package/dist/src/llm/index.js.map +1 -1
  80. package/dist/src/llm/model-discovery.js +335 -0
  81. package/dist/src/llm/model-discovery.js.map +1 -0
  82. package/dist/src/llm/model-popularity.js +566 -0
  83. package/dist/src/llm/model-popularity.js.map +1 -0
  84. package/dist/src/llm/model-scoring-db.js +553 -0
  85. package/dist/src/llm/model-scoring-db.js.map +1 -0
  86. package/dist/src/llm/multi-provider.js +258 -0
  87. package/dist/src/llm/multi-provider.js.map +1 -0
  88. package/dist/src/llm/ollama.js +133 -187
  89. package/dist/src/llm/ollama.js.map +1 -1
  90. package/dist/src/llm/router-commands.js +773 -0
  91. package/dist/src/llm/router-commands.js.map +1 -0
  92. package/dist/src/llm/router-core.js +600 -0
  93. package/dist/src/llm/router-core.js.map +1 -0
  94. package/dist/src/memory/checkpoint-manager.js +278 -0
  95. package/dist/src/memory/checkpoint-manager.js.map +1 -0
  96. package/dist/src/memory/conflict-detector.js +279 -0
  97. package/dist/src/memory/conflict-detector.js.map +1 -0
  98. package/dist/src/memory/context-graph.js +360 -0
  99. package/dist/src/memory/context-graph.js.map +1 -0
  100. package/dist/src/memory/dialectic/benchmark-cli.js +200 -0
  101. package/dist/src/memory/dialectic/benchmark-cli.js.map +1 -0
  102. package/dist/src/memory/dialectic/debug-reasoning.js +37 -0
  103. package/dist/src/memory/dialectic/debug-reasoning.js.map +1 -0
  104. package/dist/src/memory/dialectic/index.js +135 -0
  105. package/dist/src/memory/dialectic/index.js.map +1 -0
  106. package/dist/src/memory/dialectic/nudges.js +380 -0
  107. package/dist/src/memory/dialectic/nudges.js.map +1 -0
  108. package/dist/src/memory/dialectic/reasoning-engine.js +607 -0
  109. package/dist/src/memory/dialectic/reasoning-engine.js.map +1 -0
  110. package/dist/src/memory/dialectic/reasoning.js +390 -0
  111. package/dist/src/memory/dialectic/reasoning.js.map +1 -0
  112. package/dist/src/memory/dialectic/skill-creation.js +481 -0
  113. package/dist/src/memory/dialectic/skill-creation.js.map +1 -0
  114. package/dist/src/memory/dialectic/store.js +663 -0
  115. package/dist/src/memory/dialectic/store.js.map +1 -0
  116. package/dist/src/memory/dialectic/types.js +11 -0
  117. package/dist/src/memory/dialectic/types.js.map +1 -0
  118. package/dist/src/memory/index.js +24 -2
  119. package/dist/src/memory/index.js.map +1 -1
  120. package/dist/src/memory/memory-decay.js +350 -0
  121. package/dist/src/memory/memory-decay.js.map +1 -0
  122. package/dist/src/memory/memory-integration.js +5 -5
  123. package/dist/src/memory/memory-integration.js.map +1 -1
  124. package/dist/src/memory/migrate-memory-stream.js +97 -0
  125. package/dist/src/memory/migrate-memory-stream.js.map +1 -0
  126. package/dist/src/memory/session-memory-bridge.js +49 -5
  127. package/dist/src/memory/session-memory-bridge.js.map +1 -1
  128. package/dist/src/memory/session-store.js +123 -0
  129. package/dist/src/memory/session-store.js.map +1 -1
  130. package/dist/src/memory/smart-write-rules.js +164 -0
  131. package/dist/src/memory/smart-write-rules.js.map +1 -0
  132. package/dist/src/memory/tiered-memory.js +436 -0
  133. package/dist/src/memory/tiered-memory.js.map +1 -0
  134. package/dist/src/memory/types.js +6 -0
  135. package/dist/src/memory/types.js.map +1 -0
  136. package/dist/src/memory/verify-migration.js +99 -0
  137. package/dist/src/memory/verify-migration.js.map +1 -0
  138. package/dist/src/pi-config.js +11 -9
  139. package/dist/src/pi-config.js.map +1 -1
  140. package/dist/src/skills/conditional-skills.js +464 -0
  141. package/dist/src/skills/conditional-skills.js.map +1 -0
  142. package/dist/src/skills/index.js +5 -0
  143. package/dist/src/skills/index.js.map +1 -1
  144. package/dist/src/skills/loader.js +56 -0
  145. package/dist/src/skills/loader.js.map +1 -1
  146. package/dist/src/skills/skill-manage.js +417 -0
  147. package/dist/src/skills/skill-manage.js.map +1 -0
  148. package/dist/src/tui/commands/orchestration-commands.js +62 -0
  149. package/dist/src/tui/commands/orchestration-commands.js.map +1 -1
  150. package/package.json +10 -5
  151. package/skills/model-router-test.ts +65 -0
  152. package/dist/src/extensions/core/auto-security-scan-extension.js +0 -41
  153. package/dist/src/extensions/core/auto-security-scan-extension.js.map +0 -1
  154. package/dist/src/extensions/core/cloudflare-browser-extension.js +0 -389
  155. package/dist/src/extensions/core/cloudflare-browser-extension.js.map +0 -1
  156. package/dist/src/extensions/core/compaction-safeguard.js +0 -223
  157. package/dist/src/extensions/core/compaction-safeguard.js.map +0 -1
  158. package/dist/src/extensions/core/generative-agents-extension.js.map +0 -1
  159. package/dist/src/extensions/core/obsidian-bridge-extension.js +0 -488
  160. package/dist/src/extensions/core/obsidian-bridge-extension.js.map +0 -1
  161. package/dist/src/llm/router.js +0 -145
  162. package/dist/src/llm/router.js.map +0 -1
  163. package/skills/kobold-scan-skill/node_modules/.package-lock.json +0 -172
  164. package/skills/kobold-scan-skill/node_modules/ansi-styles/index.d.ts +0 -345
  165. package/skills/kobold-scan-skill/node_modules/ansi-styles/index.js +0 -163
  166. package/skills/kobold-scan-skill/node_modules/ansi-styles/license +0 -9
  167. package/skills/kobold-scan-skill/node_modules/ansi-styles/package.json +0 -56
  168. package/skills/kobold-scan-skill/node_modules/ansi-styles/readme.md +0 -152
  169. package/skills/kobold-scan-skill/node_modules/balanced-match/.github/FUNDING.yml +0 -2
  170. package/skills/kobold-scan-skill/node_modules/balanced-match/LICENSE.md +0 -21
  171. package/skills/kobold-scan-skill/node_modules/balanced-match/README.md +0 -97
  172. package/skills/kobold-scan-skill/node_modules/balanced-match/index.js +0 -62
  173. package/skills/kobold-scan-skill/node_modules/balanced-match/package.json +0 -48
  174. package/skills/kobold-scan-skill/node_modules/brace-expansion/.github/FUNDING.yml +0 -2
  175. package/skills/kobold-scan-skill/node_modules/brace-expansion/LICENSE +0 -21
  176. package/skills/kobold-scan-skill/node_modules/brace-expansion/README.md +0 -135
  177. package/skills/kobold-scan-skill/node_modules/brace-expansion/index.js +0 -203
  178. package/skills/kobold-scan-skill/node_modules/brace-expansion/package.json +0 -49
  179. package/skills/kobold-scan-skill/node_modules/chalk/index.d.ts +0 -415
  180. package/skills/kobold-scan-skill/node_modules/chalk/license +0 -9
  181. package/skills/kobold-scan-skill/node_modules/chalk/package.json +0 -68
  182. package/skills/kobold-scan-skill/node_modules/chalk/readme.md +0 -341
  183. package/skills/kobold-scan-skill/node_modules/chalk/source/index.js +0 -229
  184. package/skills/kobold-scan-skill/node_modules/chalk/source/templates.js +0 -134
  185. package/skills/kobold-scan-skill/node_modules/chalk/source/util.js +0 -39
  186. package/skills/kobold-scan-skill/node_modules/color-convert/CHANGELOG.md +0 -54
  187. package/skills/kobold-scan-skill/node_modules/color-convert/LICENSE +0 -21
  188. package/skills/kobold-scan-skill/node_modules/color-convert/README.md +0 -68
  189. package/skills/kobold-scan-skill/node_modules/color-convert/conversions.js +0 -839
  190. package/skills/kobold-scan-skill/node_modules/color-convert/index.js +0 -81
  191. package/skills/kobold-scan-skill/node_modules/color-convert/package.json +0 -48
  192. package/skills/kobold-scan-skill/node_modules/color-convert/route.js +0 -97
  193. package/skills/kobold-scan-skill/node_modules/color-name/LICENSE +0 -8
  194. package/skills/kobold-scan-skill/node_modules/color-name/README.md +0 -11
  195. package/skills/kobold-scan-skill/node_modules/color-name/index.js +0 -152
  196. package/skills/kobold-scan-skill/node_modules/color-name/package.json +0 -28
  197. package/skills/kobold-scan-skill/node_modules/commander/LICENSE +0 -22
  198. package/skills/kobold-scan-skill/node_modules/commander/Readme.md +0 -1129
  199. package/skills/kobold-scan-skill/node_modules/commander/esm.mjs +0 -16
  200. package/skills/kobold-scan-skill/node_modules/commander/index.js +0 -27
  201. package/skills/kobold-scan-skill/node_modules/commander/lib/argument.js +0 -147
  202. package/skills/kobold-scan-skill/node_modules/commander/lib/command.js +0 -2179
  203. package/skills/kobold-scan-skill/node_modules/commander/lib/error.js +0 -45
  204. package/skills/kobold-scan-skill/node_modules/commander/lib/help.js +0 -461
  205. package/skills/kobold-scan-skill/node_modules/commander/lib/option.js +0 -326
  206. package/skills/kobold-scan-skill/node_modules/commander/lib/suggestSimilar.js +0 -100
  207. package/skills/kobold-scan-skill/node_modules/commander/package-support.json +0 -16
  208. package/skills/kobold-scan-skill/node_modules/commander/package.json +0 -80
  209. package/skills/kobold-scan-skill/node_modules/commander/typings/index.d.ts +0 -891
  210. package/skills/kobold-scan-skill/node_modules/fs.realpath/LICENSE +0 -43
  211. package/skills/kobold-scan-skill/node_modules/fs.realpath/README.md +0 -33
  212. package/skills/kobold-scan-skill/node_modules/fs.realpath/index.js +0 -66
  213. package/skills/kobold-scan-skill/node_modules/fs.realpath/old.js +0 -303
  214. package/skills/kobold-scan-skill/node_modules/fs.realpath/package.json +0 -26
  215. package/skills/kobold-scan-skill/node_modules/glob/LICENSE +0 -15
  216. package/skills/kobold-scan-skill/node_modules/glob/README.md +0 -399
  217. package/skills/kobold-scan-skill/node_modules/glob/common.js +0 -244
  218. package/skills/kobold-scan-skill/node_modules/glob/glob.js +0 -790
  219. package/skills/kobold-scan-skill/node_modules/glob/package.json +0 -55
  220. package/skills/kobold-scan-skill/node_modules/glob/sync.js +0 -486
  221. package/skills/kobold-scan-skill/node_modules/has-flag/index.d.ts +0 -39
  222. package/skills/kobold-scan-skill/node_modules/has-flag/index.js +0 -8
  223. package/skills/kobold-scan-skill/node_modules/has-flag/license +0 -9
  224. package/skills/kobold-scan-skill/node_modules/has-flag/package.json +0 -46
  225. package/skills/kobold-scan-skill/node_modules/has-flag/readme.md +0 -89
  226. package/skills/kobold-scan-skill/node_modules/inflight/LICENSE +0 -15
  227. package/skills/kobold-scan-skill/node_modules/inflight/README.md +0 -37
  228. package/skills/kobold-scan-skill/node_modules/inflight/inflight.js +0 -54
  229. package/skills/kobold-scan-skill/node_modules/inflight/package.json +0 -29
  230. package/skills/kobold-scan-skill/node_modules/inherits/LICENSE +0 -16
  231. package/skills/kobold-scan-skill/node_modules/inherits/README.md +0 -42
  232. package/skills/kobold-scan-skill/node_modules/inherits/inherits.js +0 -9
  233. package/skills/kobold-scan-skill/node_modules/inherits/inherits_browser.js +0 -27
  234. package/skills/kobold-scan-skill/node_modules/inherits/package.json +0 -29
  235. package/skills/kobold-scan-skill/node_modules/minimatch/LICENSE +0 -15
  236. package/skills/kobold-scan-skill/node_modules/minimatch/README.md +0 -259
  237. package/skills/kobold-scan-skill/node_modules/minimatch/lib/path.js +0 -4
  238. package/skills/kobold-scan-skill/node_modules/minimatch/minimatch.js +0 -944
  239. package/skills/kobold-scan-skill/node_modules/minimatch/package.json +0 -35
  240. package/skills/kobold-scan-skill/node_modules/once/LICENSE +0 -15
  241. package/skills/kobold-scan-skill/node_modules/once/README.md +0 -79
  242. package/skills/kobold-scan-skill/node_modules/once/once.js +0 -42
  243. package/skills/kobold-scan-skill/node_modules/once/package.json +0 -33
  244. package/skills/kobold-scan-skill/node_modules/supports-color/browser.js +0 -5
  245. package/skills/kobold-scan-skill/node_modules/supports-color/index.js +0 -135
  246. package/skills/kobold-scan-skill/node_modules/supports-color/license +0 -9
  247. package/skills/kobold-scan-skill/node_modules/supports-color/package.json +0 -53
  248. package/skills/kobold-scan-skill/node_modules/supports-color/readme.md +0 -76
  249. package/skills/kobold-scan-skill/node_modules/wrappy/LICENSE +0 -15
  250. package/skills/kobold-scan-skill/node_modules/wrappy/README.md +0 -36
  251. package/skills/kobold-scan-skill/node_modules/wrappy/package.json +0 -29
  252. package/skills/kobold-scan-skill/node_modules/wrappy/wrappy.js +0 -33
@@ -0,0 +1,663 @@
1
+ /**
2
+ * Dialectic Store
3
+ *
4
+ * SQLite storage for dialectic memory components:
5
+ * - Peers (users, agents, projects, ideas)
6
+ * - Observations (what happened)
7
+ * - Contradictions (conflicts between observations)
8
+ * - Syntheses (resolved understanding)
9
+ * - Representations (inferred preferences, goals, constraints, values)
10
+ * - Nudges (scheduled reflections)
11
+ */
12
+ import { Database } from "bun:sqlite";
13
+ import * as fs from "node:fs/promises";
14
+ import * as path from "node:path";
15
+ import { homedir } from "node:os";
16
+ import { randomUUID } from "node:crypto";
17
+ const DB_DIR = path.join(homedir(), ".0xkobold", "dialectic");
18
+ const DB_PATH = path.join(DB_DIR, "dialectic.db");
19
+ const CURRENT_SCHEMA_VERSION = 1;
20
+ // ═════════════════════════════════════════════════════════════════
21
+ // SCHEMA
22
+ // ═════════════════════════════════════════════════════════════════
23
+ const SCHEMA_V1 = `
24
+ -- Metadata
25
+ CREATE TABLE IF NOT EXISTS _metadata (
26
+ key TEXT PRIMARY KEY,
27
+ value TEXT
28
+ );
29
+ INSERT OR REPLACE INTO _metadata VALUES ('schema_version', '1');
30
+ INSERT OR REPLACE INTO _metadata VALUES ('created_at', datetime('now'));
31
+
32
+ -- Peers: Entities that persist and change over time
33
+ CREATE TABLE IF NOT EXISTS peers (
34
+ id TEXT PRIMARY KEY,
35
+ type TEXT NOT NULL CHECK(type IN ('user', 'agent', 'project', 'idea')),
36
+ name TEXT NOT NULL,
37
+ metadata TEXT, -- JSON
38
+ created_at TEXT NOT NULL,
39
+ last_updated TEXT NOT NULL
40
+ );
41
+ CREATE INDEX IF NOT EXISTS idx_peers_type ON peers(type);
42
+ CREATE INDEX IF NOT EXISTS idx_peers_name ON peers(name);
43
+
44
+ -- Observations: Raw input to dialectic reasoning
45
+ CREATE TABLE IF NOT EXISTS observations (
46
+ id TEXT PRIMARY KEY,
47
+ peer_id TEXT NOT NULL,
48
+ content TEXT NOT NULL,
49
+ category TEXT NOT NULL CHECK(category IN ('behavior', 'statement', 'preference', 'goal', 'constraint', 'value', 'error', 'success')),
50
+ timestamp TEXT NOT NULL,
51
+ source_type TEXT NOT NULL CHECK(source_type IN ('message', 'tool_call', 'event', 'reflection')),
52
+ source_id TEXT NOT NULL,
53
+ session_id TEXT,
54
+ project_id TEXT,
55
+ FOREIGN KEY (peer_id) REFERENCES peers(id)
56
+ );
57
+ CREATE INDEX IF NOT EXISTS idx_observations_peer ON observations(peer_id);
58
+ CREATE INDEX IF NOT EXISTS idx_observations_category ON observations(category);
59
+ CREATE INDEX IF NOT EXISTS idx_observations_timestamp ON observations(timestamp);
60
+
61
+ -- Contradictions: Conflicts between observations
62
+ CREATE TABLE IF NOT EXISTS contradictions (
63
+ id TEXT PRIMARY KEY,
64
+ peer_id TEXT NOT NULL,
65
+ observation_a TEXT NOT NULL,
66
+ observation_b TEXT NOT NULL,
67
+ resolution TEXT NOT NULL CHECK(resolution IN ('newer_wins', 'context', 'refinement', 'correction', 'both_true', 'unknown')),
68
+ resolution_note TEXT,
69
+ confidence REAL DEFAULT 0.5,
70
+ detected_at TEXT NOT NULL,
71
+ resolved_at TEXT,
72
+ FOREIGN KEY (peer_id) REFERENCES peers(id)
73
+ );
74
+ CREATE INDEX IF NOT EXISTS idx_contradictions_peer ON contradictions(peer_id);
75
+ CREATE INDEX IF NOT EXISTS idx_contradictions_resolved ON contradictions(resolved_at);
76
+
77
+ -- Syntheses: Resolved understanding from dialectic reasoning
78
+ CREATE TABLE IF NOT EXISTS syntheses (
79
+ id TEXT PRIMARY KEY,
80
+ peer_id TEXT NOT NULL,
81
+ content TEXT NOT NULL,
82
+ derived_from TEXT NOT NULL, -- JSON array of observation IDs
83
+ resolved_contradictions TEXT, -- JSON array of contradiction IDs
84
+ confidence REAL DEFAULT 0.5,
85
+ timestamp TEXT NOT NULL,
86
+ superseded_by TEXT,
87
+ FOREIGN KEY (peer_id) REFERENCES peers(id)
88
+ );
89
+ CREATE INDEX IF NOT EXISTS idx_syntheses_peer ON syntheses(peer_id);
90
+
91
+ -- Inferred Preferences: What the peer prefers
92
+ CREATE TABLE IF NOT EXISTS inferred_preferences (
93
+ id TEXT PRIMARY KEY,
94
+ peer_id TEXT NOT NULL,
95
+ topic TEXT NOT NULL,
96
+ preference TEXT NOT NULL,
97
+ evidence TEXT NOT NULL, -- JSON array of observation IDs
98
+ confidence REAL DEFAULT 0.5,
99
+ last_updated TEXT NOT NULL,
100
+ contradicted BOOLEAN DEFAULT FALSE,
101
+ contradicted_by TEXT,
102
+ FOREIGN KEY (peer_id) REFERENCES peers(id)
103
+ );
104
+ CREATE INDEX IF NOT EXISTS idx_preferences_peer ON inferred_preferences(peer_id);
105
+ CREATE INDEX IF NOT EXISTS idx_preferences_topic ON inferred_preferences(topic);
106
+
107
+ -- Inferred Goals: What the peer is trying to achieve
108
+ CREATE TABLE IF NOT EXISTS inferred_goals (
109
+ id TEXT PRIMARY KEY,
110
+ peer_id TEXT NOT NULL,
111
+ description TEXT NOT NULL,
112
+ status TEXT NOT NULL CHECK(status IN ('active', 'completed', 'abandoned', 'unknown')),
113
+ priority TEXT NOT NULL CHECK(priority IN ('high', 'medium', 'low')),
114
+ evidence TEXT NOT NULL,
115
+ confidence REAL DEFAULT 0.5,
116
+ first_observed TEXT NOT NULL,
117
+ last_updated TEXT NOT NULL,
118
+ FOREIGN KEY (peer_id) REFERENCES peers(id)
119
+ );
120
+ CREATE INDEX IF NOT EXISTS idx_goals_peer ON inferred_goals(peer_id);
121
+ CREATE INDEX IF NOT EXISTS idx_goals_status ON inferred_goals(status);
122
+
123
+ -- Inferred Constraints: What the peer cannot/will not do
124
+ CREATE TABLE IF NOT EXISTS inferred_constraints (
125
+ id TEXT PRIMARY KEY,
126
+ peer_id TEXT NOT NULL,
127
+ description TEXT NOT NULL,
128
+ type TEXT NOT NULL CHECK(type IN ('hard', 'soft', 'preference')),
129
+ evidence TEXT NOT NULL,
130
+ confidence REAL DEFAULT 0.5,
131
+ last_updated TEXT NOT NULL,
132
+ FOREIGN KEY (peer_id) REFERENCES peers(id)
133
+ );
134
+ CREATE INDEX IF NOT EXISTS idx_constraints_peer ON inferred_constraints(peer_id);
135
+
136
+ -- Inferred Values: What the peer cares about intrinsically
137
+ CREATE TABLE IF NOT EXISTS inferred_values (
138
+ id TEXT PRIMARY KEY,
139
+ peer_id TEXT NOT NULL,
140
+ value TEXT NOT NULL,
141
+ context TEXT,
142
+ evidence TEXT NOT NULL,
143
+ confidence REAL DEFAULT 0.5,
144
+ last_updated TEXT NOT NULL,
145
+ FOREIGN KEY (peer_id) REFERENCES peers(id)
146
+ );
147
+ CREATE INDEX IF NOT EXISTS idx_values_peer ON inferred_values(peer_id);
148
+
149
+ -- Nudges: Scheduled reflections and actions
150
+ CREATE TABLE IF NOT EXISTS nudges (
151
+ id TEXT PRIMARY KEY,
152
+ trigger_type TEXT NOT NULL CHECK(trigger_type IN ('time', 'event', 'threshold')),
153
+ trigger_data TEXT NOT NULL, -- JSON
154
+ question TEXT NOT NULL,
155
+ action_type TEXT NOT NULL,
156
+ action_data TEXT NOT NULL, -- JSON
157
+ priority TEXT NOT NULL CHECK(priority IN ('low', 'medium', 'high')),
158
+ created_at TEXT NOT NULL,
159
+ run_at TEXT,
160
+ completed_at TEXT,
161
+ result TEXT
162
+ );
163
+ CREATE INDEX IF NOT EXISTS idx_nudges_pending ON nudges(completed_at) WHERE completed_at IS NULL;
164
+ `;
165
+ // ═════════════════════════════════════════════════════════════════
166
+ // STORE CLASS
167
+ // ═════════════════════════════════════════════════════════════════
168
+ export class DialecticStore {
169
+ db;
170
+ constructor(db) {
171
+ if (db) {
172
+ this.db = db;
173
+ // Initialize schema for provided databases (including :memory:)
174
+ this.initSchema();
175
+ }
176
+ else {
177
+ this.db = this.initDatabase();
178
+ }
179
+ }
180
+ /**
181
+ * Initialize schema on an existing database
182
+ */
183
+ initSchema() {
184
+ // Check if schema exists
185
+ try {
186
+ const result = this.db.query("SELECT value FROM _metadata WHERE key = 'schema_version'").get();
187
+ if (result?.value === "1") {
188
+ return; // Schema already initialized
189
+ }
190
+ }
191
+ catch {
192
+ // Schema doesn't exist, create it
193
+ }
194
+ console.log("[DialecticStore] Initializing schema v1");
195
+ this.db.exec(SCHEMA_V1);
196
+ }
197
+ initDatabase() {
198
+ // Ensure directory exists
199
+ fs.mkdir(DB_DIR, { recursive: true }).catch(() => { });
200
+ const db = new Database(DB_PATH);
201
+ db.exec("PRAGMA journal_mode = WAL;");
202
+ db.exec("PRAGMA synchronous = NORMAL;");
203
+ // Check schema version
204
+ let version = "0";
205
+ try {
206
+ const result = db.query("SELECT value FROM _metadata WHERE key = 'schema_version'").get();
207
+ version = result?.value || "0";
208
+ }
209
+ catch {
210
+ version = "0";
211
+ }
212
+ // Run migrations
213
+ if (version === "0") {
214
+ console.log("[DialecticStore] Initializing schema v1");
215
+ db.exec(SCHEMA_V1);
216
+ }
217
+ return db;
218
+ }
219
+ // ─────────────────────────────────────────────────────────────────
220
+ // PEERS
221
+ // ─────────────────────────────────────────────────────────────────
222
+ createPeer(type, name, metadata) {
223
+ const id = `peer_${type}_${name.toLowerCase().replace(/[^a-z0-9]/g, "_")}`;
224
+ const now = new Date().toISOString();
225
+ this.db.query(`
226
+ INSERT OR REPLACE INTO peers (id, type, name, metadata, created_at, last_updated)
227
+ VALUES (?, ?, ?, ?, ?, ?)
228
+ `).run(id, type, name, metadata ? JSON.stringify(metadata) : null, now, now);
229
+ return { id, type, name, createdAt: now, lastUpdated: now, metadata };
230
+ }
231
+ getPeer(id) {
232
+ const row = this.db.query(`SELECT * FROM peers WHERE id = ?`).get(id);
233
+ if (!row)
234
+ return undefined;
235
+ return {
236
+ id: row.id,
237
+ type: row.type,
238
+ name: row.name,
239
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
240
+ createdAt: row.created_at,
241
+ lastUpdated: row.last_updated,
242
+ };
243
+ }
244
+ getPeerByName(name, type) {
245
+ const query = type
246
+ ? `SELECT * FROM peers WHERE name = ? AND type = ?`
247
+ : `SELECT * FROM peers WHERE name = ?`;
248
+ const params = type ? [name, type] : [name];
249
+ const row = this.db.query(query).get(...params);
250
+ if (!row)
251
+ return undefined;
252
+ return {
253
+ id: row.id,
254
+ type: row.type,
255
+ name: row.name,
256
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
257
+ createdAt: row.created_at,
258
+ lastUpdated: row.last_updated,
259
+ };
260
+ }
261
+ listPeers(type) {
262
+ const query = type
263
+ ? `SELECT * FROM peers WHERE type = ? ORDER BY last_updated DESC`
264
+ : `SELECT * FROM peers ORDER BY last_updated DESC`;
265
+ const params = type ? [type] : [];
266
+ const rows = this.db.query(query).all(...params);
267
+ return rows.map(row => ({
268
+ id: row.id,
269
+ type: row.type,
270
+ name: row.name,
271
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
272
+ createdAt: row.created_at,
273
+ lastUpdated: row.last_updated,
274
+ }));
275
+ }
276
+ // ─────────────────────────────────────────────────────────────────
277
+ // OBSERVATIONS
278
+ // ─────────────────────────────────────────────────────────────────
279
+ addObservation(peerId, content, category, sourceType, sourceId, sessionId, projectId) {
280
+ const id = `obs_${Date.now()}_${randomUUID().slice(0, 8)}`;
281
+ const timestamp = new Date().toISOString();
282
+ this.db.query(`
283
+ INSERT INTO observations (id, peer_id, content, category, timestamp, source_type, source_id, session_id, project_id)
284
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
285
+ `).run(id, peerId, content, category, timestamp, sourceType, sourceId, sessionId || null, projectId || null);
286
+ // Update peer's last_updated
287
+ this.db.query(`UPDATE peers SET last_updated = ? WHERE id = ?`).run(timestamp, peerId);
288
+ return {
289
+ id,
290
+ peerId,
291
+ content,
292
+ category,
293
+ timestamp,
294
+ sourceType,
295
+ sourceId,
296
+ sessionId,
297
+ projectId,
298
+ };
299
+ }
300
+ getObservations(peerId, limit = 100) {
301
+ const rows = this.db.query(`
302
+ SELECT * FROM observations WHERE peer_id = ? ORDER BY timestamp DESC LIMIT ?
303
+ `).all(peerId, limit);
304
+ return rows.map(row => ({
305
+ id: row.id,
306
+ peerId: row.peer_id,
307
+ content: row.content,
308
+ category: row.category,
309
+ timestamp: row.timestamp,
310
+ sourceType: row.source_type,
311
+ sourceId: row.source_id,
312
+ sessionId: row.session_id,
313
+ projectId: row.project_id,
314
+ }));
315
+ }
316
+ getRecentObservations(peerId, since) {
317
+ const rows = this.db.query(`
318
+ SELECT * FROM observations WHERE peer_id = ? AND timestamp > ? ORDER BY timestamp DESC
319
+ `).all(peerId, since.toISOString());
320
+ return rows.map(row => ({
321
+ id: row.id,
322
+ peerId: row.peer_id,
323
+ content: row.content,
324
+ category: row.category,
325
+ timestamp: row.timestamp,
326
+ sourceType: row.source_type,
327
+ sourceId: row.source_id,
328
+ sessionId: row.session_id,
329
+ projectId: row.project_id,
330
+ }));
331
+ }
332
+ // ─────────────────────────────────────────────────────────────────
333
+ // CONTRADICTIONS
334
+ // ─────────────────────────────────────────────────────────────────
335
+ addContradiction(peerId, observationA, observationB, resolution = "unknown", resolutionNote = "", confidence = 0.5) {
336
+ const id = `contra_${Date.now()}_${randomUUID().slice(0, 8)}`;
337
+ const detectedAt = new Date().toISOString();
338
+ this.db.query(`
339
+ INSERT INTO contradictions (id, peer_id, observation_a, observation_b, resolution, resolution_note, confidence, detected_at)
340
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
341
+ `).run(id, peerId, observationA, observationB, resolution, resolutionNote, confidence, detectedAt);
342
+ return {
343
+ id,
344
+ peerId,
345
+ observationA,
346
+ observationB,
347
+ resolution,
348
+ resolutionNote,
349
+ confidence,
350
+ detectedAt,
351
+ };
352
+ }
353
+ resolveContradiction(id, resolution, note) {
354
+ const resolvedAt = new Date().toISOString();
355
+ this.db.query(`
356
+ UPDATE contradictions SET resolution = ?, resolution_note = ?, resolved_at = ? WHERE id = ?
357
+ `).run(resolution, note, resolvedAt, id);
358
+ }
359
+ getUnresolvedContradictions(peerId) {
360
+ const rows = this.db.query(`
361
+ SELECT * FROM contradictions WHERE peer_id = ? AND resolved_at IS NULL ORDER BY detected_at DESC
362
+ `).all(peerId);
363
+ return rows.map(row => ({
364
+ id: row.id,
365
+ peerId: row.peer_id,
366
+ observationA: row.observation_a,
367
+ observationB: row.observation_b,
368
+ resolution: row.resolution,
369
+ resolutionNote: row.resolution_note,
370
+ confidence: row.confidence,
371
+ detectedAt: row.detected_at,
372
+ resolvedAt: row.resolved_at,
373
+ }));
374
+ }
375
+ // ─────────────────────────────────────────────────────────────────
376
+ // SYNTHESES
377
+ // ─────────────────────────────────────────────────────────────────
378
+ addSynthesis(peerId, content, derivedFrom, resolvedContradictions, confidence = 0.5) {
379
+ const id = `synth_${Date.now()}_${randomUUID().slice(0, 8)}`;
380
+ const timestamp = new Date().toISOString();
381
+ this.db.query(`
382
+ INSERT INTO syntheses (id, peer_id, content, derived_from, resolved_contradictions, confidence, timestamp)
383
+ VALUES (?, ?, ?, ?, ?, ?, ?)
384
+ `).run(id, peerId, content, JSON.stringify(derivedFrom), JSON.stringify(resolvedContradictions), confidence, timestamp);
385
+ return {
386
+ id,
387
+ peerId,
388
+ content,
389
+ derivedFrom,
390
+ resolvedContradictions,
391
+ confidence,
392
+ timestamp,
393
+ };
394
+ }
395
+ getSyntheses(peerId, limit = 10) {
396
+ const rows = this.db.query(`
397
+ SELECT * FROM syntheses WHERE peer_id = ? AND superseded_by IS NULL ORDER BY timestamp DESC LIMIT ?
398
+ `).all(peerId, limit);
399
+ return rows.map(row => ({
400
+ id: row.id,
401
+ peerId: row.peer_id,
402
+ content: row.content,
403
+ derivedFrom: JSON.parse(row.derived_from),
404
+ resolvedContradictions: JSON.parse(row.resolved_contradictions),
405
+ confidence: row.confidence,
406
+ timestamp: row.timestamp,
407
+ supersededBy: row.superseded_by,
408
+ }));
409
+ }
410
+ // ─────────────────────────────────────────────────────────────────
411
+ // INFERRED PREFERENCES
412
+ // ─────────────────────────────────────────────────────────────────
413
+ addPreference(peerId, topic, preference, evidence, confidence = 0.5) {
414
+ const id = `pref_${topic}_${randomUUID().slice(0, 8)}`;
415
+ const now = new Date().toISOString();
416
+ this.db.query(`
417
+ INSERT OR REPLACE INTO inferred_preferences (id, peer_id, topic, preference, evidence, confidence, last_updated)
418
+ VALUES (?, ?, ?, ?, ?, ?, ?)
419
+ `).run(id, peerId, topic, preference, JSON.stringify(evidence), confidence, now);
420
+ return {
421
+ id,
422
+ peerId,
423
+ topic,
424
+ preference,
425
+ evidence,
426
+ confidence,
427
+ lastUpdated: now,
428
+ };
429
+ }
430
+ getPreferences(peerId) {
431
+ const rows = this.db.query(`
432
+ SELECT * FROM inferred_preferences WHERE peer_id = ? AND contradicted = FALSE ORDER BY confidence DESC
433
+ `).all(peerId);
434
+ return rows.map(row => ({
435
+ id: row.id,
436
+ peerId: row.peer_id,
437
+ topic: row.topic,
438
+ preference: row.preference,
439
+ evidence: JSON.parse(row.evidence),
440
+ confidence: row.confidence,
441
+ lastUpdated: row.last_updated,
442
+ contradicted: row.contradicted === 1,
443
+ contradictedBy: row.contradicted_by,
444
+ }));
445
+ }
446
+ // ─────────────────────────────────────────────────────────────────
447
+ // INFERRED GOALS
448
+ // ─────────────────────────────────────────────────────────────────
449
+ addGoal(peerId, description, status = "active", priority = "medium", evidence = [], confidence = 0.5) {
450
+ const id = `goal_${Date.now()}_${randomUUID().slice(0, 8)}`;
451
+ const now = new Date().toISOString();
452
+ this.db.query(`
453
+ INSERT INTO inferred_goals (id, peer_id, description, status, priority, evidence, confidence, first_observed, last_updated)
454
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
455
+ `).run(id, peerId, description, status, priority, JSON.stringify(evidence), confidence, now, now);
456
+ return {
457
+ id,
458
+ peerId,
459
+ description,
460
+ status,
461
+ priority,
462
+ evidence,
463
+ confidence,
464
+ firstObserved: now,
465
+ lastUpdated: now,
466
+ };
467
+ }
468
+ getGoals(peerId, status) {
469
+ const query = status
470
+ ? `SELECT * FROM inferred_goals WHERE peer_id = ? AND status = ? ORDER BY priority, confidence DESC`
471
+ : `SELECT * FROM inferred_goals WHERE peer_id = ? ORDER BY priority, confidence DESC`;
472
+ const params = status ? [peerId, status] : [peerId];
473
+ const rows = this.db.query(query).all(...params);
474
+ return rows.map(row => ({
475
+ id: row.id,
476
+ peerId: row.peer_id,
477
+ description: row.description,
478
+ status: row.status,
479
+ priority: row.priority,
480
+ evidence: JSON.parse(row.evidence),
481
+ confidence: row.confidence,
482
+ firstObserved: row.first_observed,
483
+ lastUpdated: row.last_updated,
484
+ }));
485
+ }
486
+ // ─────────────────────────────────────────────────────────────────
487
+ // INFERRED CONSTRAINTS
488
+ // ─────────────────────────────────────────────────────────────────
489
+ addConstraint(peerId, description, type = "soft", evidence = [], confidence = 0.5) {
490
+ const id = `const_${Date.now()}_${randomUUID().slice(0, 8)}`;
491
+ const now = new Date().toISOString();
492
+ this.db.query(`
493
+ INSERT INTO inferred_constraints (id, peer_id, description, type, evidence, confidence, last_updated)
494
+ VALUES (?, ?, ?, ?, ?, ?, ?)
495
+ `).run(id, peerId, description, type, JSON.stringify(evidence), confidence, now);
496
+ return {
497
+ id,
498
+ peerId,
499
+ description,
500
+ type,
501
+ evidence,
502
+ confidence,
503
+ lastUpdated: now,
504
+ };
505
+ }
506
+ getConstraints(peerId) {
507
+ const rows = this.db.query(`
508
+ SELECT * FROM inferred_constraints WHERE peer_id = ? ORDER BY type, confidence DESC
509
+ `).all(peerId);
510
+ return rows.map(row => ({
511
+ id: row.id,
512
+ peerId: row.peer_id,
513
+ description: row.description,
514
+ type: row.type,
515
+ evidence: JSON.parse(row.evidence),
516
+ confidence: row.confidence,
517
+ lastUpdated: row.last_updated,
518
+ }));
519
+ }
520
+ // ─────────────────────────────────────────────────────────────────
521
+ // INFERRED VALUES
522
+ // ─────────────────────────────────────────────────────────────────
523
+ addValue(peerId, value, context, evidence, confidence = 0.5) {
524
+ const id = `val_${Date.now()}_${randomUUID().slice(0, 8)}`;
525
+ const now = new Date().toISOString();
526
+ this.db.query(`
527
+ INSERT INTO inferred_values (id, peer_id, value, context, evidence, confidence, last_updated)
528
+ VALUES (?, ?, ?, ?, ?, ?, ?)
529
+ `).run(id, peerId, value, context, JSON.stringify(evidence), confidence, now);
530
+ return {
531
+ id,
532
+ peerId,
533
+ value,
534
+ context,
535
+ evidence,
536
+ confidence,
537
+ lastUpdated: now,
538
+ };
539
+ }
540
+ getValues(peerId) {
541
+ const rows = this.db.query(`
542
+ SELECT * FROM inferred_values WHERE peer_id = ? ORDER BY confidence DESC
543
+ `).all(peerId);
544
+ return rows.map(row => ({
545
+ id: row.id,
546
+ peerId: row.peer_id,
547
+ value: row.value,
548
+ context: row.context,
549
+ evidence: JSON.parse(row.evidence),
550
+ confidence: row.confidence,
551
+ lastUpdated: row.last_updated,
552
+ }));
553
+ }
554
+ // ─────────────────────────────────────────────────────────────────
555
+ // REPRESENTATIONS (Aggregate)
556
+ // ─────────────────────────────────────────────────────────────────
557
+ getRepresentation(peerId) {
558
+ const peer = this.getPeer(peerId);
559
+ if (!peer)
560
+ return undefined;
561
+ const preferences = this.getPreferences(peerId);
562
+ const goals = this.getGoals(peerId);
563
+ const constraints = this.getConstraints(peerId);
564
+ const values = this.getValues(peerId);
565
+ const observations = this.getObservations(peerId, 50);
566
+ const contradictions = this.getUnresolvedContradictions(peerId);
567
+ const synthesis = this.getSyntheses(peerId);
568
+ // Calculate overall confidence
569
+ const allConfidences = [
570
+ ...preferences.map(p => p.confidence),
571
+ ...goals.map(g => g.confidence),
572
+ ...constraints.map(c => c.confidence),
573
+ ...values.map(v => v.confidence),
574
+ ...synthesis.map(s => s.confidence),
575
+ ];
576
+ const avgConfidence = allConfidences.length > 0
577
+ ? allConfidences.reduce((a, b) => a + b, 0) / allConfidences.length
578
+ : 0.5;
579
+ return {
580
+ id: `repr_${peerId}`,
581
+ peerId,
582
+ peerType: peer.type,
583
+ preferences,
584
+ goals,
585
+ constraints,
586
+ values,
587
+ observations,
588
+ contradictions,
589
+ synthesis,
590
+ confidence: avgConfidence,
591
+ lastUpdated: peer.lastUpdated,
592
+ };
593
+ }
594
+ // ─────────────────────────────────────────────────────────────────
595
+ // NUDGES
596
+ // ─────────────────────────────────────────────────────────────────
597
+ addNudge(trigger, question, action, priority = "medium") {
598
+ const id = `nudge_${Date.now()}_${randomUUID().slice(0, 8)}`;
599
+ const createdAt = new Date().toISOString();
600
+ this.db.query(`
601
+ INSERT INTO nudges (id, trigger_type, trigger_data, question, action_type, action_data, priority, created_at)
602
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
603
+ `).run(id, trigger.type, JSON.stringify(trigger), question, action.type, JSON.stringify(action), priority, createdAt);
604
+ return {
605
+ id,
606
+ trigger,
607
+ question,
608
+ action,
609
+ priority,
610
+ createdAt,
611
+ };
612
+ }
613
+ getPendingNudges(limit = 10) {
614
+ const rows = this.db.query(`
615
+ SELECT * FROM nudges WHERE completed_at IS NULL ORDER BY priority, created_at LIMIT ?
616
+ `).all(limit);
617
+ return rows.map(row => ({
618
+ id: row.id,
619
+ trigger: JSON.parse(row.trigger_data),
620
+ question: row.question,
621
+ action: JSON.parse(row.action_data),
622
+ priority: row.priority,
623
+ createdAt: row.created_at,
624
+ runAt: row.run_at,
625
+ completedAt: row.completed_at,
626
+ result: row.result,
627
+ }));
628
+ }
629
+ completeNudge(id, result) {
630
+ const completedAt = new Date().toISOString();
631
+ this.db.query(`
632
+ UPDATE nudges SET completed_at = ?, result = ? WHERE id = ?
633
+ `).run(completedAt, result, id);
634
+ }
635
+ // ─────────────────────────────────────────────────────────────────
636
+ // UTILITY
637
+ // ─────────────────────────────────────────────────────────────────
638
+ close() {
639
+ this.db.close();
640
+ }
641
+ getStats() {
642
+ return {
643
+ peers: this.db.query(`SELECT COUNT(*) as n FROM peers`).get().n,
644
+ observations: this.db.query(`SELECT COUNT(*) as n FROM observations`).get().n,
645
+ contradictions: this.db.query(`SELECT COUNT(*) as n FROM contradictions`).get().n,
646
+ syntheses: this.db.query(`SELECT COUNT(*) as n FROM syntheses`).get().n,
647
+ preferences: this.db.query(`SELECT COUNT(*) as n FROM inferred_preferences`).get().n,
648
+ goals: this.db.query(`SELECT COUNT(*) as n FROM inferred_goals`).get().n,
649
+ constraints: this.db.query(`SELECT COUNT(*) as n FROM inferred_constraints`).get().n,
650
+ values: this.db.query(`SELECT COUNT(*) as n FROM inferred_values`).get().n,
651
+ nudges: this.db.query(`SELECT COUNT(*) as n FROM nudges`).get().n,
652
+ };
653
+ }
654
+ }
655
+ // Singleton
656
+ let store = null;
657
+ export function getDialecticStore() {
658
+ if (!store) {
659
+ store = new DialecticStore();
660
+ }
661
+ return store;
662
+ }
663
+ //# sourceMappingURL=store.js.map