@psiclawops/hypermem 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/background-indexer.d.ts +132 -0
- package/dist/background-indexer.d.ts.map +1 -0
- package/dist/background-indexer.js +1044 -0
- package/dist/cache.d.ts +110 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +495 -0
- package/dist/compaction-fence.d.ts +89 -0
- package/dist/compaction-fence.d.ts.map +1 -0
- package/dist/compaction-fence.js +153 -0
- package/dist/compositor.d.ts +226 -0
- package/dist/compositor.d.ts.map +1 -0
- package/dist/compositor.js +2558 -0
- package/dist/content-type-classifier.d.ts +41 -0
- package/dist/content-type-classifier.d.ts.map +1 -0
- package/dist/content-type-classifier.js +181 -0
- package/dist/cross-agent.d.ts +62 -0
- package/dist/cross-agent.d.ts.map +1 -0
- package/dist/cross-agent.js +259 -0
- package/dist/db.d.ts +131 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +402 -0
- package/dist/desired-state-store.d.ts +100 -0
- package/dist/desired-state-store.d.ts.map +1 -0
- package/dist/desired-state-store.js +222 -0
- package/dist/doc-chunk-store.d.ts +140 -0
- package/dist/doc-chunk-store.d.ts.map +1 -0
- package/dist/doc-chunk-store.js +391 -0
- package/dist/doc-chunker.d.ts +99 -0
- package/dist/doc-chunker.d.ts.map +1 -0
- package/dist/doc-chunker.js +324 -0
- package/dist/dreaming-promoter.d.ts +86 -0
- package/dist/dreaming-promoter.d.ts.map +1 -0
- package/dist/dreaming-promoter.js +381 -0
- package/dist/episode-store.d.ts +49 -0
- package/dist/episode-store.d.ts.map +1 -0
- package/dist/episode-store.js +135 -0
- package/dist/fact-store.d.ts +75 -0
- package/dist/fact-store.d.ts.map +1 -0
- package/dist/fact-store.js +236 -0
- package/dist/fleet-store.d.ts +144 -0
- package/dist/fleet-store.d.ts.map +1 -0
- package/dist/fleet-store.js +276 -0
- package/dist/fos-mod.d.ts +178 -0
- package/dist/fos-mod.d.ts.map +1 -0
- package/dist/fos-mod.js +416 -0
- package/dist/hybrid-retrieval.d.ts +64 -0
- package/dist/hybrid-retrieval.d.ts.map +1 -0
- package/dist/hybrid-retrieval.js +344 -0
- package/dist/image-eviction.d.ts +49 -0
- package/dist/image-eviction.d.ts.map +1 -0
- package/dist/image-eviction.js +251 -0
- package/dist/index.d.ts +650 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1072 -0
- package/dist/keystone-scorer.d.ts +51 -0
- package/dist/keystone-scorer.d.ts.map +1 -0
- package/dist/keystone-scorer.js +52 -0
- package/dist/knowledge-graph.d.ts +110 -0
- package/dist/knowledge-graph.d.ts.map +1 -0
- package/dist/knowledge-graph.js +305 -0
- package/dist/knowledge-lint.d.ts +29 -0
- package/dist/knowledge-lint.d.ts.map +1 -0
- package/dist/knowledge-lint.js +116 -0
- package/dist/knowledge-store.d.ts +72 -0
- package/dist/knowledge-store.d.ts.map +1 -0
- package/dist/knowledge-store.js +247 -0
- package/dist/library-schema.d.ts +22 -0
- package/dist/library-schema.d.ts.map +1 -0
- package/dist/library-schema.js +1038 -0
- package/dist/message-store.d.ts +89 -0
- package/dist/message-store.d.ts.map +1 -0
- package/dist/message-store.js +323 -0
- package/dist/metrics-dashboard.d.ts +114 -0
- package/dist/metrics-dashboard.d.ts.map +1 -0
- package/dist/metrics-dashboard.js +260 -0
- package/dist/obsidian-exporter.d.ts +57 -0
- package/dist/obsidian-exporter.d.ts.map +1 -0
- package/dist/obsidian-exporter.js +274 -0
- package/dist/obsidian-watcher.d.ts +147 -0
- package/dist/obsidian-watcher.d.ts.map +1 -0
- package/dist/obsidian-watcher.js +403 -0
- package/dist/open-domain.d.ts +46 -0
- package/dist/open-domain.d.ts.map +1 -0
- package/dist/open-domain.js +125 -0
- package/dist/preference-store.d.ts +54 -0
- package/dist/preference-store.d.ts.map +1 -0
- package/dist/preference-store.js +109 -0
- package/dist/preservation-gate.d.ts +82 -0
- package/dist/preservation-gate.d.ts.map +1 -0
- package/dist/preservation-gate.js +150 -0
- package/dist/proactive-pass.d.ts +63 -0
- package/dist/proactive-pass.d.ts.map +1 -0
- package/dist/proactive-pass.js +239 -0
- package/dist/profiles.d.ts +44 -0
- package/dist/profiles.d.ts.map +1 -0
- package/dist/profiles.js +227 -0
- package/dist/provider-translator.d.ts +50 -0
- package/dist/provider-translator.d.ts.map +1 -0
- package/dist/provider-translator.js +403 -0
- package/dist/rate-limiter.d.ts +76 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +179 -0
- package/dist/repair-tool-pairs.d.ts +38 -0
- package/dist/repair-tool-pairs.d.ts.map +1 -0
- package/dist/repair-tool-pairs.js +138 -0
- package/dist/retrieval-policy.d.ts +51 -0
- package/dist/retrieval-policy.d.ts.map +1 -0
- package/dist/retrieval-policy.js +77 -0
- package/dist/schema.d.ts +15 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +229 -0
- package/dist/secret-scanner.d.ts +51 -0
- package/dist/secret-scanner.d.ts.map +1 -0
- package/dist/secret-scanner.js +248 -0
- package/dist/seed.d.ts +108 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +177 -0
- package/dist/session-flusher.d.ts +53 -0
- package/dist/session-flusher.d.ts.map +1 -0
- package/dist/session-flusher.js +69 -0
- package/dist/session-topic-map.d.ts +41 -0
- package/dist/session-topic-map.d.ts.map +1 -0
- package/dist/session-topic-map.js +77 -0
- package/dist/spawn-context.d.ts +54 -0
- package/dist/spawn-context.d.ts.map +1 -0
- package/dist/spawn-context.js +159 -0
- package/dist/system-store.d.ts +73 -0
- package/dist/system-store.d.ts.map +1 -0
- package/dist/system-store.js +182 -0
- package/dist/temporal-store.d.ts +80 -0
- package/dist/temporal-store.d.ts.map +1 -0
- package/dist/temporal-store.js +149 -0
- package/dist/topic-detector.d.ts +35 -0
- package/dist/topic-detector.d.ts.map +1 -0
- package/dist/topic-detector.js +249 -0
- package/dist/topic-store.d.ts +45 -0
- package/dist/topic-store.d.ts.map +1 -0
- package/dist/topic-store.js +136 -0
- package/dist/topic-synthesizer.d.ts +51 -0
- package/dist/topic-synthesizer.d.ts.map +1 -0
- package/dist/topic-synthesizer.js +315 -0
- package/dist/trigger-registry.d.ts +63 -0
- package/dist/trigger-registry.d.ts.map +1 -0
- package/dist/trigger-registry.js +163 -0
- package/dist/types.d.ts +533 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/vector-store.d.ts +170 -0
- package/dist/vector-store.d.ts.map +1 -0
- package/dist/vector-store.js +677 -0
- package/dist/version.d.ts +34 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +34 -0
- package/dist/wiki-page-emitter.d.ts +65 -0
- package/dist/wiki-page-emitter.d.ts.map +1 -0
- package/dist/wiki-page-emitter.js +258 -0
- package/dist/work-store.d.ts +112 -0
- package/dist/work-store.d.ts.map +1 -0
- package/dist/work-store.js +273 -0
- package/package.json +1 -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.0";
|
|
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.0";
|
|
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.0";
|
|
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"}
|
package/dist/version.js
ADDED
|
@@ -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.0';
|
|
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.0';
|
|
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.0',
|
|
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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"}
|