@psiclawops/hypermem 0.5.0 → 0.5.2

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 (163) hide show
  1. package/ARCHITECTURE.md +12 -3
  2. package/README.md +30 -6
  3. package/bin/hypermem-status.mjs +166 -0
  4. package/dist/background-indexer.d.ts +132 -0
  5. package/dist/background-indexer.d.ts.map +1 -0
  6. package/dist/background-indexer.js +1044 -0
  7. package/dist/cache.d.ts +110 -0
  8. package/dist/cache.d.ts.map +1 -0
  9. package/dist/cache.js +495 -0
  10. package/dist/compaction-fence.d.ts +89 -0
  11. package/dist/compaction-fence.d.ts.map +1 -0
  12. package/dist/compaction-fence.js +153 -0
  13. package/dist/compositor.d.ts +226 -0
  14. package/dist/compositor.d.ts.map +1 -0
  15. package/dist/compositor.js +2558 -0
  16. package/dist/content-type-classifier.d.ts +41 -0
  17. package/dist/content-type-classifier.d.ts.map +1 -0
  18. package/dist/content-type-classifier.js +181 -0
  19. package/dist/cross-agent.d.ts +62 -0
  20. package/dist/cross-agent.d.ts.map +1 -0
  21. package/dist/cross-agent.js +259 -0
  22. package/dist/db.d.ts +131 -0
  23. package/dist/db.d.ts.map +1 -0
  24. package/dist/db.js +402 -0
  25. package/dist/desired-state-store.d.ts +100 -0
  26. package/dist/desired-state-store.d.ts.map +1 -0
  27. package/dist/desired-state-store.js +222 -0
  28. package/dist/doc-chunk-store.d.ts +140 -0
  29. package/dist/doc-chunk-store.d.ts.map +1 -0
  30. package/dist/doc-chunk-store.js +391 -0
  31. package/dist/doc-chunker.d.ts +99 -0
  32. package/dist/doc-chunker.d.ts.map +1 -0
  33. package/dist/doc-chunker.js +324 -0
  34. package/dist/dreaming-promoter.d.ts +86 -0
  35. package/dist/dreaming-promoter.d.ts.map +1 -0
  36. package/dist/dreaming-promoter.js +381 -0
  37. package/dist/episode-store.d.ts +49 -0
  38. package/dist/episode-store.d.ts.map +1 -0
  39. package/dist/episode-store.js +135 -0
  40. package/dist/fact-store.d.ts +75 -0
  41. package/dist/fact-store.d.ts.map +1 -0
  42. package/dist/fact-store.js +236 -0
  43. package/dist/fleet-store.d.ts +144 -0
  44. package/dist/fleet-store.d.ts.map +1 -0
  45. package/dist/fleet-store.js +276 -0
  46. package/dist/fos-mod.d.ts +178 -0
  47. package/dist/fos-mod.d.ts.map +1 -0
  48. package/dist/fos-mod.js +416 -0
  49. package/dist/hybrid-retrieval.d.ts +64 -0
  50. package/dist/hybrid-retrieval.d.ts.map +1 -0
  51. package/dist/hybrid-retrieval.js +344 -0
  52. package/dist/image-eviction.d.ts +49 -0
  53. package/dist/image-eviction.d.ts.map +1 -0
  54. package/dist/image-eviction.js +251 -0
  55. package/dist/index.d.ts +650 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +1072 -0
  58. package/dist/keystone-scorer.d.ts +51 -0
  59. package/dist/keystone-scorer.d.ts.map +1 -0
  60. package/dist/keystone-scorer.js +52 -0
  61. package/dist/knowledge-graph.d.ts +110 -0
  62. package/dist/knowledge-graph.d.ts.map +1 -0
  63. package/dist/knowledge-graph.js +305 -0
  64. package/dist/knowledge-lint.d.ts +29 -0
  65. package/dist/knowledge-lint.d.ts.map +1 -0
  66. package/dist/knowledge-lint.js +116 -0
  67. package/dist/knowledge-store.d.ts +72 -0
  68. package/dist/knowledge-store.d.ts.map +1 -0
  69. package/dist/knowledge-store.js +247 -0
  70. package/dist/library-schema.d.ts +22 -0
  71. package/dist/library-schema.d.ts.map +1 -0
  72. package/dist/library-schema.js +1038 -0
  73. package/dist/message-store.d.ts +89 -0
  74. package/dist/message-store.d.ts.map +1 -0
  75. package/dist/message-store.js +323 -0
  76. package/dist/metrics-dashboard.d.ts +114 -0
  77. package/dist/metrics-dashboard.d.ts.map +1 -0
  78. package/dist/metrics-dashboard.js +260 -0
  79. package/dist/obsidian-exporter.d.ts +57 -0
  80. package/dist/obsidian-exporter.d.ts.map +1 -0
  81. package/dist/obsidian-exporter.js +274 -0
  82. package/dist/obsidian-watcher.d.ts +147 -0
  83. package/dist/obsidian-watcher.d.ts.map +1 -0
  84. package/dist/obsidian-watcher.js +403 -0
  85. package/dist/open-domain.d.ts +46 -0
  86. package/dist/open-domain.d.ts.map +1 -0
  87. package/dist/open-domain.js +125 -0
  88. package/dist/preference-store.d.ts +54 -0
  89. package/dist/preference-store.d.ts.map +1 -0
  90. package/dist/preference-store.js +109 -0
  91. package/dist/preservation-gate.d.ts +82 -0
  92. package/dist/preservation-gate.d.ts.map +1 -0
  93. package/dist/preservation-gate.js +150 -0
  94. package/dist/proactive-pass.d.ts +63 -0
  95. package/dist/proactive-pass.d.ts.map +1 -0
  96. package/dist/proactive-pass.js +239 -0
  97. package/dist/profiles.d.ts +44 -0
  98. package/dist/profiles.d.ts.map +1 -0
  99. package/dist/profiles.js +227 -0
  100. package/dist/provider-translator.d.ts +50 -0
  101. package/dist/provider-translator.d.ts.map +1 -0
  102. package/dist/provider-translator.js +403 -0
  103. package/dist/rate-limiter.d.ts +76 -0
  104. package/dist/rate-limiter.d.ts.map +1 -0
  105. package/dist/rate-limiter.js +179 -0
  106. package/dist/repair-tool-pairs.d.ts +38 -0
  107. package/dist/repair-tool-pairs.d.ts.map +1 -0
  108. package/dist/repair-tool-pairs.js +138 -0
  109. package/dist/retrieval-policy.d.ts +51 -0
  110. package/dist/retrieval-policy.d.ts.map +1 -0
  111. package/dist/retrieval-policy.js +77 -0
  112. package/dist/schema.d.ts +15 -0
  113. package/dist/schema.d.ts.map +1 -0
  114. package/dist/schema.js +229 -0
  115. package/dist/secret-scanner.d.ts +51 -0
  116. package/dist/secret-scanner.d.ts.map +1 -0
  117. package/dist/secret-scanner.js +248 -0
  118. package/dist/seed.d.ts +108 -0
  119. package/dist/seed.d.ts.map +1 -0
  120. package/dist/seed.js +177 -0
  121. package/dist/session-flusher.d.ts +53 -0
  122. package/dist/session-flusher.d.ts.map +1 -0
  123. package/dist/session-flusher.js +69 -0
  124. package/dist/session-topic-map.d.ts +41 -0
  125. package/dist/session-topic-map.d.ts.map +1 -0
  126. package/dist/session-topic-map.js +77 -0
  127. package/dist/spawn-context.d.ts +54 -0
  128. package/dist/spawn-context.d.ts.map +1 -0
  129. package/dist/spawn-context.js +159 -0
  130. package/dist/system-store.d.ts +73 -0
  131. package/dist/system-store.d.ts.map +1 -0
  132. package/dist/system-store.js +182 -0
  133. package/dist/temporal-store.d.ts +80 -0
  134. package/dist/temporal-store.d.ts.map +1 -0
  135. package/dist/temporal-store.js +149 -0
  136. package/dist/topic-detector.d.ts +35 -0
  137. package/dist/topic-detector.d.ts.map +1 -0
  138. package/dist/topic-detector.js +249 -0
  139. package/dist/topic-store.d.ts +45 -0
  140. package/dist/topic-store.d.ts.map +1 -0
  141. package/dist/topic-store.js +136 -0
  142. package/dist/topic-synthesizer.d.ts +51 -0
  143. package/dist/topic-synthesizer.d.ts.map +1 -0
  144. package/dist/topic-synthesizer.js +315 -0
  145. package/dist/trigger-registry.d.ts +63 -0
  146. package/dist/trigger-registry.d.ts.map +1 -0
  147. package/dist/trigger-registry.js +163 -0
  148. package/dist/types.d.ts +537 -0
  149. package/dist/types.d.ts.map +1 -0
  150. package/dist/types.js +9 -0
  151. package/dist/vector-store.d.ts +170 -0
  152. package/dist/vector-store.d.ts.map +1 -0
  153. package/dist/vector-store.js +677 -0
  154. package/dist/version.d.ts +34 -0
  155. package/dist/version.d.ts.map +1 -0
  156. package/dist/version.js +34 -0
  157. package/dist/wiki-page-emitter.d.ts +65 -0
  158. package/dist/wiki-page-emitter.d.ts.map +1 -0
  159. package/dist/wiki-page-emitter.js +258 -0
  160. package/dist/work-store.d.ts +112 -0
  161. package/dist/work-store.d.ts.map +1 -0
  162. package/dist/work-store.js +273 -0
  163. package/package.json +4 -1
@@ -0,0 +1,34 @@
1
+ /** Release version — matches package.json and is stamped into library.db on every startup. */
2
+ export declare const ENGINE_VERSION = "0.5.1";
3
+ /** Minimum Node.js version required — matches package.json engines field. */
4
+ export declare const MIN_NODE_VERSION = "22.0.0";
5
+ /** @deprecated No longer used — Redis was replaced with SQLite :memory: CacheLayer. */
6
+ export declare const MIN_REDIS_VERSION = "7.0.0";
7
+ /** sqlite-vec version bundled with this release. */
8
+ export declare const SQLITE_VEC_VERSION = "0.1.9";
9
+ /**
10
+ * Main DB (hypermem.db) schema version.
11
+ * Re-exported here for convenience; authoritative value lives in schema.ts.
12
+ */
13
+ export declare const MAIN_SCHEMA_VERSION = 6;
14
+ /**
15
+ * Library DB (library.db) schema version.
16
+ * Re-exported here for convenience; authoritative value lives in library-schema.ts.
17
+ */
18
+ export declare const LIBRARY_SCHEMA_VERSION_EXPORT = 12;
19
+ /**
20
+ * Compatibility version — the single number operators and consumers check.
21
+ * Maps to: main schema v6, library schema v12.
22
+ * Matches ENGINE_VERSION for the 0.5.0 release.
23
+ */
24
+ export declare const HYPERMEM_COMPAT_VERSION = "0.5.1";
25
+ /**
26
+ * Schema compatibility map — machine-readable version requirements.
27
+ * Use this to verify DB schemas match the running engine.
28
+ */
29
+ export declare const SCHEMA_COMPAT: {
30
+ readonly compatVersion: "0.5.1";
31
+ readonly mainSchema: 6;
32
+ readonly librarySchema: 12;
33
+ };
34
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,6EAA6E;AAC7E,eAAO,MAAM,gBAAgB,WAAW,CAAC;AAEzC,uFAAuF;AACvF,eAAO,MAAM,iBAAiB,UAAU,CAAC;AAEzC,oDAAoD;AACpD,eAAO,MAAM,kBAAkB,UAAU,CAAC;AAE1C;;;GAGG;AACH,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC;;;GAGG;AACH,eAAO,MAAM,6BAA6B,KAAK,CAAC;AAEhD;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,UAAU,CAAC;AAE/C;;;GAGG;AACH,eAAO,MAAM,aAAa;;;;CAIhB,CAAC"}
@@ -0,0 +1,34 @@
1
+ /** Release version — matches package.json and is stamped into library.db on every startup. */
2
+ export const ENGINE_VERSION = '0.5.1';
3
+ /** Minimum Node.js version required — matches package.json engines field. */
4
+ export const MIN_NODE_VERSION = '22.0.0';
5
+ /** @deprecated No longer used — Redis was replaced with SQLite :memory: CacheLayer. */
6
+ export const MIN_REDIS_VERSION = '7.0.0';
7
+ /** sqlite-vec version bundled with this release. */
8
+ export const SQLITE_VEC_VERSION = '0.1.9';
9
+ /**
10
+ * Main DB (hypermem.db) schema version.
11
+ * Re-exported here for convenience; authoritative value lives in schema.ts.
12
+ */
13
+ export const MAIN_SCHEMA_VERSION = 6;
14
+ /**
15
+ * Library DB (library.db) schema version.
16
+ * Re-exported here for convenience; authoritative value lives in library-schema.ts.
17
+ */
18
+ export const LIBRARY_SCHEMA_VERSION_EXPORT = 12;
19
+ /**
20
+ * Compatibility version — the single number operators and consumers check.
21
+ * Maps to: main schema v6, library schema v12.
22
+ * Matches ENGINE_VERSION for the 0.5.0 release.
23
+ */
24
+ export const HYPERMEM_COMPAT_VERSION = '0.5.1';
25
+ /**
26
+ * Schema compatibility map — machine-readable version requirements.
27
+ * Use this to verify DB schemas match the running engine.
28
+ */
29
+ export const SCHEMA_COMPAT = {
30
+ compatVersion: '0.5.1',
31
+ mainSchema: 6,
32
+ librarySchema: 12,
33
+ };
34
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1,65 @@
1
+ /**
2
+ * wiki-page-emitter.ts
3
+ *
4
+ * Query-time API for the hypermem wiki layer.
5
+ * Retrieves synthesized topic pages, resolves cross-links,
6
+ * and triggers on-demand synthesis when pages are stale/missing.
7
+ */
8
+ import type { DatabaseSync } from 'node:sqlite';
9
+ import { type SynthesisConfig } from './topic-synthesizer.js';
10
+ export interface WikiPage {
11
+ topicName: string;
12
+ content: string;
13
+ version: number;
14
+ updatedAt: string;
15
+ crossLinks: WikiLink[];
16
+ }
17
+ export interface WikiLink {
18
+ topicName: string;
19
+ linkType: string;
20
+ direction: 'from' | 'to';
21
+ }
22
+ export interface WikiPageSummary {
23
+ topicName: string;
24
+ updatedAt: string;
25
+ messageCount: number;
26
+ version: number;
27
+ }
28
+ export declare class WikiPageEmitter {
29
+ private readonly libraryDb;
30
+ private readonly getMessageDb;
31
+ private readonly synthConfig?;
32
+ private readonly knowledgeStore;
33
+ private readonly synthesizer;
34
+ private readonly regrowthThreshold;
35
+ constructor(libraryDb: DatabaseSync, getMessageDb: (agentId: string) => DatabaseSync | null, synthConfig?: Partial<SynthesisConfig> | undefined);
36
+ /**
37
+ * Fetch the version number for an active knowledge entry.
38
+ */
39
+ private getVersion;
40
+ /**
41
+ * Get a wiki page for a topic.
42
+ * If no page exists, or page is stale (topic has grown by >= regrowthThreshold
43
+ * since last synthesis), trigger a synthesis pass first.
44
+ * Returns null if topic has no messages or doesn't exist.
45
+ */
46
+ getPage(agentId: string, topicName: string): WikiPage | null;
47
+ /**
48
+ * List all synthesized pages for an agent — the table of contents.
49
+ */
50
+ listPages(agentId: string, opts?: {
51
+ limit?: number;
52
+ domain?: string;
53
+ }): WikiPageSummary[];
54
+ /**
55
+ * Get a page's cross-links from knowledge_links table.
56
+ * Resolves both directions (from and to).
57
+ */
58
+ private resolveLinks;
59
+ /**
60
+ * Force re-synthesis of a specific topic regardless of staleness.
61
+ * Returns the new page or null if topic not found.
62
+ */
63
+ forceSynthesize(agentId: string, topicName: string): WikiPage | null;
64
+ }
65
+ //# sourceMappingURL=wiki-page-emitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki-page-emitter.d.ts","sourceRoot":"","sources":["../src/wiki-page-emitter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,OAAO,EAAoB,KAAK,eAAe,EAAgC,MAAM,wBAAwB,CAAC;AAI9G,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,QAAQ,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAeD,qBAAa,eAAe;IAMxB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAP/B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAChD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAmB;IAC/C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;gBAGxB,SAAS,EAAE,YAAY,EACvB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,YAAY,GAAG,IAAI,EACtD,WAAW,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,YAAA;IAOzD;;OAEG;IACH,OAAO,CAAC,UAAU;IAclB;;;;;OAKG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAgE5D;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,eAAe,EAAE;IAgCzF;;;OAGG;IACH,OAAO,CAAC,YAAY;IAiEpB;;;OAGG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;CAyCrE"}
@@ -0,0 +1,258 @@
1
+ /**
2
+ * wiki-page-emitter.ts
3
+ *
4
+ * Query-time API for the hypermem wiki layer.
5
+ * Retrieves synthesized topic pages, resolves cross-links,
6
+ * and triggers on-demand synthesis when pages are stale/missing.
7
+ */
8
+ import { KnowledgeStore } from './knowledge-store.js';
9
+ import { TopicSynthesizer, SYNTHESIS_REGROWTH_THRESHOLD } from './topic-synthesizer.js';
10
+ // ─── Helpers ────────────────────────────────────────────────────
11
+ /**
12
+ * Parse message_count stored in source_ref ("topic:<id>:mc:<count>").
13
+ */
14
+ function parseStoredMessageCount(sourceRef) {
15
+ if (!sourceRef)
16
+ return 0;
17
+ const match = sourceRef.match(/:mc:(\d+)$/);
18
+ return match ? parseInt(match[1], 10) : 0;
19
+ }
20
+ // ─── WikiPageEmitter ────────────────────────────────────────────
21
+ export class WikiPageEmitter {
22
+ libraryDb;
23
+ getMessageDb;
24
+ synthConfig;
25
+ knowledgeStore;
26
+ synthesizer;
27
+ regrowthThreshold;
28
+ constructor(libraryDb, getMessageDb, synthConfig) {
29
+ this.libraryDb = libraryDb;
30
+ this.getMessageDb = getMessageDb;
31
+ this.synthConfig = synthConfig;
32
+ this.knowledgeStore = new KnowledgeStore(libraryDb);
33
+ this.synthesizer = new TopicSynthesizer(libraryDb, getMessageDb, synthConfig);
34
+ this.regrowthThreshold = synthConfig?.SYNTHESIS_REGROWTH_THRESHOLD ?? SYNTHESIS_REGROWTH_THRESHOLD;
35
+ }
36
+ /**
37
+ * Fetch the version number for an active knowledge entry.
38
+ */
39
+ getVersion(agentId, topicName) {
40
+ try {
41
+ const row = this.libraryDb.prepare(`
42
+ SELECT version FROM knowledge
43
+ WHERE agent_id = ? AND domain = 'topic-synthesis' AND key = ?
44
+ AND superseded_by IS NULL
45
+ LIMIT 1
46
+ `).get(agentId, topicName);
47
+ return row?.version ?? 1;
48
+ }
49
+ catch {
50
+ return 1;
51
+ }
52
+ }
53
+ /**
54
+ * Get a wiki page for a topic.
55
+ * If no page exists, or page is stale (topic has grown by >= regrowthThreshold
56
+ * since last synthesis), trigger a synthesis pass first.
57
+ * Returns null if topic has no messages or doesn't exist.
58
+ */
59
+ getPage(agentId, topicName) {
60
+ // Look up topic to check current message_count and existence
61
+ let topicRow;
62
+ try {
63
+ topicRow = this.libraryDb.prepare(`
64
+ SELECT id, message_count FROM topics
65
+ WHERE agent_id = ? AND name = ?
66
+ LIMIT 1
67
+ `).get(agentId, topicName);
68
+ }
69
+ catch {
70
+ // Topics table may not exist or topic not found
71
+ }
72
+ // Check existing synthesis
73
+ const existing = this.knowledgeStore.get(agentId, 'topic-synthesis', topicName);
74
+ if (existing) {
75
+ // Check staleness if we have topic data
76
+ if (topicRow) {
77
+ const storedMc = parseStoredMessageCount(existing.sourceRef);
78
+ const growth = topicRow.message_count - storedMc;
79
+ if (growth >= this.regrowthThreshold) {
80
+ // Stale — re-synthesize by running a targeted tick
81
+ // TopicSynthesizer.tick() picks up topics that have grown enough
82
+ this.synthesizer.tick(agentId);
83
+ }
84
+ }
85
+ }
86
+ else {
87
+ // No page at all — trigger synthesis regardless of staleness threshold
88
+ if (!topicRow)
89
+ return null;
90
+ const messageDb = this.getMessageDb(agentId);
91
+ if (!messageDb)
92
+ return null;
93
+ // Check if there are actually messages for this topic before attempting synthesis
94
+ let msgCount = 0;
95
+ try {
96
+ const row = messageDb.prepare('SELECT COUNT(*) AS cnt FROM messages WHERE topic_id = ?').get(String(topicRow.id));
97
+ msgCount = row?.cnt ?? 0;
98
+ }
99
+ catch {
100
+ // messages table query failed
101
+ }
102
+ if (msgCount === 0)
103
+ return null;
104
+ this.synthesizer.tick(agentId);
105
+ }
106
+ // Re-fetch after possible synthesis
107
+ const knowledge = this.knowledgeStore.get(agentId, 'topic-synthesis', topicName);
108
+ if (!knowledge)
109
+ return null;
110
+ const crossLinks = this.resolveLinks(agentId, knowledge.id);
111
+ return {
112
+ topicName,
113
+ content: knowledge.content,
114
+ version: this.getVersion(agentId, topicName),
115
+ updatedAt: knowledge.updatedAt,
116
+ crossLinks,
117
+ };
118
+ }
119
+ /**
120
+ * List all synthesized pages for an agent — the table of contents.
121
+ */
122
+ listPages(agentId, opts) {
123
+ const domain = opts?.domain ?? 'topic-synthesis';
124
+ const limit = opts?.limit ?? 100;
125
+ let rows;
126
+ try {
127
+ rows = this.libraryDb.prepare(`
128
+ SELECT key, updated_at, version, source_ref
129
+ FROM knowledge
130
+ WHERE agent_id = ?
131
+ AND domain = ?
132
+ AND superseded_by IS NULL
133
+ ORDER BY updated_at DESC
134
+ LIMIT ?
135
+ `).all(agentId, domain, limit);
136
+ }
137
+ catch {
138
+ return [];
139
+ }
140
+ return rows.map(row => ({
141
+ topicName: row.key,
142
+ updatedAt: row.updated_at,
143
+ messageCount: parseStoredMessageCount(row.source_ref),
144
+ version: row.version,
145
+ }));
146
+ }
147
+ /**
148
+ * Get a page's cross-links from knowledge_links table.
149
+ * Resolves both directions (from and to).
150
+ */
151
+ resolveLinks(agentId, knowledgeId) {
152
+ const links = [];
153
+ // Outgoing links (from this knowledge entry to another)
154
+ let fromRows = [];
155
+ try {
156
+ fromRows = this.libraryDb.prepare(`
157
+ SELECT kl.to_id, kl.link_type
158
+ FROM knowledge_links kl
159
+ WHERE kl.from_type = 'knowledge' AND kl.from_id = ?
160
+ AND kl.to_type = 'knowledge'
161
+ `).all(knowledgeId);
162
+ }
163
+ catch {
164
+ // knowledge_links may not exist
165
+ }
166
+ for (const row of fromRows) {
167
+ // Look up the topic name from the target knowledge row
168
+ let targetKey = null;
169
+ try {
170
+ const targetRow = this.libraryDb.prepare(`
171
+ SELECT key FROM knowledge
172
+ WHERE id = ? AND agent_id = ? AND domain = 'topic-synthesis'
173
+ `).get(row.to_id, agentId);
174
+ targetKey = targetRow?.key ?? null;
175
+ }
176
+ catch {
177
+ // Ignore
178
+ }
179
+ if (targetKey) {
180
+ links.push({ topicName: targetKey, linkType: row.link_type, direction: 'from' });
181
+ }
182
+ }
183
+ // Incoming links (from other knowledge entries to this one)
184
+ let toRows = [];
185
+ try {
186
+ toRows = this.libraryDb.prepare(`
187
+ SELECT kl.from_id, kl.link_type
188
+ FROM knowledge_links kl
189
+ WHERE kl.to_type = 'knowledge' AND kl.to_id = ?
190
+ AND kl.from_type = 'knowledge'
191
+ `).all(knowledgeId);
192
+ }
193
+ catch {
194
+ // Ignore
195
+ }
196
+ for (const row of toRows) {
197
+ let sourceKey = null;
198
+ try {
199
+ const sourceRow = this.libraryDb.prepare(`
200
+ SELECT key FROM knowledge
201
+ WHERE id = ? AND agent_id = ? AND domain = 'topic-synthesis'
202
+ `).get(row.from_id, agentId);
203
+ sourceKey = sourceRow?.key ?? null;
204
+ }
205
+ catch {
206
+ // Ignore
207
+ }
208
+ if (sourceKey) {
209
+ links.push({ topicName: sourceKey, linkType: row.link_type, direction: 'to' });
210
+ }
211
+ }
212
+ return links;
213
+ }
214
+ /**
215
+ * Force re-synthesis of a specific topic regardless of staleness.
216
+ * Returns the new page or null if topic not found.
217
+ */
218
+ forceSynthesize(agentId, topicName) {
219
+ // Verify topic exists
220
+ let topicId;
221
+ try {
222
+ const row = this.libraryDb.prepare(`
223
+ SELECT id FROM topics WHERE agent_id = ? AND name = ? LIMIT 1
224
+ `).get(agentId, topicName);
225
+ topicId = row?.id;
226
+ }
227
+ catch {
228
+ // Topics table may not exist
229
+ }
230
+ if (topicId === undefined)
231
+ return null;
232
+ // Invalidate existing synthesis by setting superseded_by so tick() will re-synthesize
233
+ // Strategy: temporarily lower the stored message_count to force re-synthesis.
234
+ // Actually, simplest approach: call tick() after removing the existing knowledge entry.
235
+ // But KnowledgeStore doesn't have a delete method. Instead, we can use the upsert
236
+ // with forced content change to invalidate, then call tick().
237
+ //
238
+ // Better approach: use a fresh synthesizer with regrowthThreshold=0 so any growth triggers.
239
+ const forceSynth = new TopicSynthesizer(this.libraryDb, this.getMessageDb, {
240
+ ...this.synthConfig,
241
+ SYNTHESIS_REGROWTH_THRESHOLD: 0,
242
+ SYNTHESIS_STALE_MINUTES: 0, // bypass staleness time gate too
243
+ });
244
+ forceSynth.tick(agentId);
245
+ const knowledge = this.knowledgeStore.get(agentId, 'topic-synthesis', topicName);
246
+ if (!knowledge)
247
+ return null;
248
+ const crossLinks = this.resolveLinks(agentId, knowledge.id);
249
+ return {
250
+ topicName,
251
+ content: knowledge.content,
252
+ version: this.getVersion(agentId, topicName),
253
+ updatedAt: knowledge.updatedAt,
254
+ crossLinks,
255
+ };
256
+ }
257
+ }
258
+ //# sourceMappingURL=wiki-page-emitter.js.map
@@ -0,0 +1,112 @@
1
+ /**
2
+ * hypermem Work Item Store
3
+ *
4
+ * Fleet kanban board in SQL. Replaces WORKQUEUE.md.
5
+ * Lives in the central library DB.
6
+ */
7
+ import type { DatabaseSync } from 'node:sqlite';
8
+ export type WorkStatus = 'incoming' | 'active' | 'blocked' | 'review' | 'completed' | 'cancelled';
9
+ export interface WorkItem {
10
+ id: string;
11
+ title: string;
12
+ description: string | null;
13
+ status: WorkStatus;
14
+ priority: number;
15
+ agentId: string | null;
16
+ createdBy: string;
17
+ domain: string | null;
18
+ parentId: string | null;
19
+ blockedBy: string | null;
20
+ sessionKey: string | null;
21
+ createdAt: string;
22
+ updatedAt: string;
23
+ startedAt: string | null;
24
+ completedAt: string | null;
25
+ dueAt: string | null;
26
+ metadata: Record<string, unknown> | null;
27
+ }
28
+ export interface WorkEvent {
29
+ id: number;
30
+ workItemId: string;
31
+ eventType: string;
32
+ oldStatus: string | null;
33
+ newStatus: string | null;
34
+ agentId: string | null;
35
+ comment: string | null;
36
+ createdAt: string;
37
+ }
38
+ export declare class WorkStore {
39
+ private readonly db;
40
+ constructor(db: DatabaseSync);
41
+ /**
42
+ * Create a new work item.
43
+ */
44
+ create(data: {
45
+ title: string;
46
+ description?: string;
47
+ priority?: number;
48
+ agentId?: string;
49
+ createdBy: string;
50
+ domain?: string;
51
+ parentId?: string;
52
+ dueAt?: string;
53
+ metadata?: Record<string, unknown>;
54
+ }): WorkItem;
55
+ /**
56
+ * Update the status of a work item.
57
+ */
58
+ updateStatus(id: string, newStatus: WorkStatus, agentId?: string, comment?: string): WorkItem | null;
59
+ /**
60
+ * Assign a work item to an agent.
61
+ */
62
+ assign(id: string, agentId: string, assignedBy?: string): WorkItem | null;
63
+ /**
64
+ * Block a work item.
65
+ */
66
+ block(id: string, blockedBy: string, agentId?: string, reason?: string): WorkItem | null;
67
+ /**
68
+ * Get a work item by ID.
69
+ */
70
+ getItem(id: string): WorkItem | null;
71
+ /**
72
+ * Get active work for an agent.
73
+ */
74
+ getAgentWork(agentId: string, status?: WorkStatus): WorkItem[];
75
+ /**
76
+ * Get the fleet kanban — all active work grouped by status.
77
+ */
78
+ getKanban(opts?: {
79
+ domain?: string;
80
+ agentId?: string;
81
+ }): WorkItem[];
82
+ /**
83
+ * Get blocked items across the fleet.
84
+ */
85
+ getBlocked(): WorkItem[];
86
+ /**
87
+ * Get completion stats for the fleet.
88
+ */
89
+ getStats(opts?: {
90
+ agentId?: string;
91
+ since?: string;
92
+ }): {
93
+ total: number;
94
+ incoming: number;
95
+ active: number;
96
+ blocked: number;
97
+ review: number;
98
+ completed: number;
99
+ cancelled: number;
100
+ avgDurationHours: number | null;
101
+ };
102
+ /**
103
+ * Get events for a work item.
104
+ */
105
+ getEvents(workItemId: string, limit?: number): WorkEvent[];
106
+ /**
107
+ * Search work items.
108
+ */
109
+ search(query: string, limit?: number): WorkItem[];
110
+ private recordEvent;
111
+ }
112
+ //# sourceMappingURL=work-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"work-store.d.ts","sourceRoot":"","sources":["../src/work-store.ts"],"names":[],"mappings":"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"}