@soleri/core 9.2.0 → 9.3.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.
- package/data/flows/build.flow.yaml +8 -9
- package/data/flows/deliver.flow.yaml +9 -10
- package/data/flows/design.flow.yaml +3 -4
- package/data/flows/enhance.flow.yaml +5 -6
- package/data/flows/explore.flow.yaml +3 -4
- package/data/flows/fix.flow.yaml +5 -6
- package/data/flows/plan.flow.yaml +4 -5
- package/data/flows/review.flow.yaml +3 -4
- package/dist/curator/curator.d.ts.map +1 -1
- package/dist/curator/curator.js +98 -22
- package/dist/curator/curator.js.map +1 -1
- package/dist/engine/bin/soleri-engine.js.map +1 -1
- package/dist/engine/module-manifest.d.ts.map +1 -1
- package/dist/engine/module-manifest.js +21 -1
- package/dist/engine/module-manifest.js.map +1 -1
- package/dist/engine/register-engine.d.ts.map +1 -1
- package/dist/engine/register-engine.js +25 -1
- package/dist/engine/register-engine.js.map +1 -1
- package/dist/flows/gate-evaluator.js.map +1 -1
- package/dist/operator/operator-profile.d.ts.map +1 -1
- package/dist/operator/operator-profile.js +11 -5
- package/dist/operator/operator-profile.js.map +1 -1
- package/dist/operator/operator-signals.d.ts.map +1 -1
- package/dist/operator/operator-signals.js.map +1 -1
- package/dist/planning/evidence-collector.js.map +1 -1
- package/dist/planning/gap-passes.d.ts.map +1 -1
- package/dist/planning/gap-passes.js +23 -6
- package/dist/planning/gap-passes.js.map +1 -1
- package/dist/planning/gap-patterns.d.ts.map +1 -1
- package/dist/planning/gap-patterns.js +57 -11
- package/dist/planning/gap-patterns.js.map +1 -1
- package/dist/planning/github-projection.d.ts.map +1 -1
- package/dist/planning/github-projection.js +39 -20
- package/dist/planning/github-projection.js.map +1 -1
- package/dist/planning/impact-analyzer.d.ts.map +1 -1
- package/dist/planning/impact-analyzer.js +20 -18
- package/dist/planning/impact-analyzer.js.map +1 -1
- package/dist/planning/plan-lifecycle.d.ts.map +1 -1
- package/dist/planning/plan-lifecycle.js +22 -9
- package/dist/planning/plan-lifecycle.js.map +1 -1
- package/dist/planning/planner.d.ts.map +1 -1
- package/dist/planning/planner.js +60 -17
- package/dist/planning/planner.js.map +1 -1
- package/dist/planning/rationalization-detector.d.ts.map +1 -1
- package/dist/planning/rationalization-detector.js.map +1 -1
- package/dist/planning/reconciliation-engine.d.ts.map +1 -1
- package/dist/planning/reconciliation-engine.js.map +1 -1
- package/dist/planning/task-verifier.d.ts.map +1 -1
- package/dist/planning/task-verifier.js +14 -6
- package/dist/planning/task-verifier.js.map +1 -1
- package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
- package/dist/runtime/admin-setup-ops.js +2 -1
- package/dist/runtime/admin-setup-ops.js.map +1 -1
- package/dist/runtime/branching-ops.d.ts +12 -0
- package/dist/runtime/branching-ops.d.ts.map +1 -0
- package/dist/runtime/branching-ops.js +100 -0
- package/dist/runtime/branching-ops.js.map +1 -0
- package/dist/runtime/context-health.d.ts.map +1 -1
- package/dist/runtime/context-health.js.map +1 -1
- package/dist/runtime/facades/branching-facade.d.ts +7 -0
- package/dist/runtime/facades/branching-facade.d.ts.map +1 -0
- package/dist/runtime/facades/branching-facade.js +8 -0
- package/dist/runtime/facades/branching-facade.js.map +1 -0
- package/dist/runtime/facades/chat-service-ops.d.ts.map +1 -1
- package/dist/runtime/facades/chat-service-ops.js +3 -1
- package/dist/runtime/facades/chat-service-ops.js.map +1 -1
- package/dist/runtime/facades/chat-transport-ops.d.ts.map +1 -1
- package/dist/runtime/facades/chat-transport-ops.js.map +1 -1
- package/dist/runtime/facades/index.d.ts.map +1 -1
- package/dist/runtime/facades/index.js +42 -0
- package/dist/runtime/facades/index.js.map +1 -1
- package/dist/runtime/facades/intake-facade.d.ts +9 -0
- package/dist/runtime/facades/intake-facade.d.ts.map +1 -0
- package/dist/runtime/facades/intake-facade.js +11 -0
- package/dist/runtime/facades/intake-facade.js.map +1 -0
- package/dist/runtime/facades/links-facade.d.ts +9 -0
- package/dist/runtime/facades/links-facade.d.ts.map +1 -0
- package/dist/runtime/facades/links-facade.js +10 -0
- package/dist/runtime/facades/links-facade.js.map +1 -0
- package/dist/runtime/facades/operator-facade.d.ts.map +1 -1
- package/dist/runtime/facades/operator-facade.js.map +1 -1
- package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
- package/dist/runtime/facades/plan-facade.js +4 -1
- package/dist/runtime/facades/plan-facade.js.map +1 -1
- package/dist/runtime/facades/tier-facade.d.ts +7 -0
- package/dist/runtime/facades/tier-facade.d.ts.map +1 -0
- package/dist/runtime/facades/tier-facade.js +8 -0
- package/dist/runtime/facades/tier-facade.js.map +1 -0
- package/dist/runtime/facades/vault-facade.d.ts +9 -1
- package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
- package/dist/runtime/facades/vault-facade.js +44 -187
- package/dist/runtime/facades/vault-facade.js.map +1 -1
- package/dist/runtime/github-integration.d.ts.map +1 -1
- package/dist/runtime/github-integration.js +11 -4
- package/dist/runtime/github-integration.js.map +1 -1
- package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
- package/dist/runtime/orchestrate-ops.js +32 -10
- package/dist/runtime/orchestrate-ops.js.map +1 -1
- package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
- package/dist/runtime/planning-extra-ops.js.map +1 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +3 -1
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/session-briefing.d.ts.map +1 -1
- package/dist/runtime/session-briefing.js +5 -1
- package/dist/runtime/session-briefing.js.map +1 -1
- package/dist/runtime/tier-ops.d.ts +13 -0
- package/dist/runtime/tier-ops.d.ts.map +1 -0
- package/dist/runtime/tier-ops.js +110 -0
- package/dist/runtime/tier-ops.js.map +1 -0
- package/dist/skills/sync-skills.d.ts.map +1 -1
- package/dist/skills/sync-skills.js +1 -1
- package/dist/skills/sync-skills.js.map +1 -1
- package/dist/vault/linking.d.ts.map +1 -1
- package/dist/vault/linking.js +41 -5
- package/dist/vault/linking.js.map +1 -1
- package/dist/vault/vault-entries.d.ts.map +1 -1
- package/dist/vault/vault-entries.js +68 -26
- package/dist/vault/vault-entries.js.map +1 -1
- package/dist/vault/vault-maintenance.d.ts.map +1 -1
- package/dist/vault/vault-maintenance.js +6 -2
- package/dist/vault/vault-maintenance.js.map +1 -1
- package/dist/vault/vault-markdown-sync.d.ts.map +1 -1
- package/dist/vault/vault-markdown-sync.js.map +1 -1
- package/dist/vault/vault-memories.d.ts.map +1 -1
- package/dist/vault/vault-memories.js +3 -1
- package/dist/vault/vault-memories.js.map +1 -1
- package/dist/vault/vault-schema.js +36 -10
- package/dist/vault/vault-schema.js.map +1 -1
- package/dist/vault/vault.d.ts.map +1 -1
- package/dist/vault/vault.js +5 -1
- package/dist/vault/vault.js.map +1 -1
- package/package.json +7 -7
- package/src/agency/agency-manager.test.ts +60 -40
- package/src/agency/default-rules.test.ts +17 -9
- package/src/capabilities/registry.test.ts +2 -12
- package/src/chat/agent-loop.test.ts +33 -43
- package/src/chat/mcp-bridge.test.ts +7 -2
- package/src/claudemd/inject.test.ts +2 -12
- package/src/context/context-engine.test.ts +96 -51
- package/src/control/intent-router.test.ts +3 -3
- package/src/curator/classifier.test.ts +14 -8
- package/src/curator/contradiction-detector.test.ts +30 -5
- package/src/curator/curator.ts +278 -56
- package/src/curator/duplicate-detector.test.ts +77 -15
- package/src/curator/quality-gate.test.ts +71 -31
- package/src/curator/tag-manager.test.ts +12 -4
- package/src/domain-packs/knowledge-installer.test.ts +2 -10
- package/src/domain-packs/token-resolver.test.ts +1 -3
- package/src/domain-packs/types.test.ts +16 -2
- package/src/enforcement/registry.test.ts +2 -8
- package/src/engine/bin/soleri-engine.ts +3 -1
- package/src/engine/module-manifest.test.ts +5 -4
- package/src/engine/module-manifest.ts +21 -1
- package/src/engine/register-engine.test.ts +6 -1
- package/src/engine/register-engine.ts +26 -3
- package/src/errors/classify.test.ts +6 -2
- package/src/errors/retry.test.ts +1 -4
- package/src/facades/facade-factory.test.ts +110 -64
- package/src/flows/epilogue.test.ts +16 -10
- package/src/flows/gate-evaluator.test.ts +12 -6
- package/src/flows/gate-evaluator.ts +1 -3
- package/src/governance/governance.test.ts +137 -21
- package/src/health/health-registry.test.ts +8 -1
- package/src/intake/content-classifier.test.ts +121 -51
- package/src/intake/dedup-gate.test.ts +38 -22
- package/src/intake/intake-pipeline.test.ts +5 -3
- package/src/intake/text-ingester.test.ts +26 -20
- package/src/llm/key-pool.test.ts +1 -3
- package/src/llm/llm-client.test.ts +1 -4
- package/src/llm/oauth-discovery.test.ts +16 -16
- package/src/llm/utils.test.ts +62 -18
- package/src/logging/logger.test.ts +4 -1
- package/src/loop/loop-manager.test.ts +2 -6
- package/src/migrations/migration-runner.edge-cases.test.ts +2 -7
- package/src/operator/operator-profile-extended.test.ts +15 -5
- package/src/operator/operator-profile.test.ts +26 -8
- package/src/operator/operator-profile.ts +38 -22
- package/src/operator/operator-signals-extended.test.ts +35 -23
- package/src/operator/operator-signals.test.ts +6 -10
- package/src/operator/operator-signals.ts +2 -1
- package/src/operator/prompts/hook-precompact-operator-dispatch.md +10 -6
- package/src/operator/prompts/subagent-soft-signal-extractor.md +5 -0
- package/src/operator/prompts/subagent-synthesis-cognition.md +19 -10
- package/src/operator/prompts/subagent-synthesis-communication.md +13 -7
- package/src/operator/prompts/subagent-synthesis-technical.md +19 -9
- package/src/operator/prompts/subagent-synthesis-trust.md +27 -21
- package/src/persona/defaults.test.ts +1 -5
- package/src/planning/evidence-collector.test.ts +147 -38
- package/src/planning/evidence-collector.ts +1 -4
- package/src/planning/gap-analysis-alternatives.test.ts +41 -11
- package/src/planning/gap-passes.test.ts +215 -33
- package/src/planning/gap-passes.ts +115 -46
- package/src/planning/gap-patterns.test.ts +87 -13
- package/src/planning/gap-patterns.ts +114 -31
- package/src/planning/github-projection.test.ts +6 -1
- package/src/planning/github-projection.ts +41 -20
- package/src/planning/impact-analyzer.test.ts +10 -23
- package/src/planning/impact-analyzer.ts +33 -46
- package/src/planning/plan-lifecycle.test.ts +103 -36
- package/src/planning/plan-lifecycle.ts +49 -18
- package/src/planning/planner.test.ts +12 -2
- package/src/planning/planner.ts +198 -58
- package/src/planning/rationalization-detector.test.ts +5 -20
- package/src/planning/rationalization-detector.ts +14 -16
- package/src/planning/reconciliation-engine.test.ts +20 -3
- package/src/planning/reconciliation-engine.ts +1 -2
- package/src/planning/task-verifier.test.ts +59 -27
- package/src/planning/task-verifier.ts +15 -9
- package/src/playbooks/playbook-executor.test.ts +1 -3
- package/src/plugins/plugin-loader.test.ts +19 -14
- package/src/plugins/plugin-registry.test.ts +45 -33
- package/src/project/project-registry.test.ts +23 -12
- package/src/prompts/template-manager.test.ts +4 -1
- package/src/queue/job-queue.test.ts +10 -14
- package/src/runtime/admin-extra-ops.test.ts +5 -19
- package/src/runtime/admin-ops.test.ts +1 -3
- package/src/runtime/admin-setup-ops.test.ts +3 -4
- package/src/runtime/admin-setup-ops.ts +9 -2
- package/src/runtime/archive-ops.test.ts +4 -1
- package/src/runtime/branching-ops.test.ts +144 -0
- package/src/runtime/branching-ops.ts +107 -0
- package/src/runtime/capture-ops.test.ts +7 -21
- package/src/runtime/chain-ops.test.ts +16 -6
- package/src/runtime/claude-md-helpers.test.ts +1 -3
- package/src/runtime/context-health.test.ts +1 -3
- package/src/runtime/context-health.ts +1 -3
- package/src/runtime/curator-extra-ops.test.ts +3 -1
- package/src/runtime/domain-ops.test.ts +46 -36
- package/src/runtime/facades/admin-facade.test.ts +1 -4
- package/src/runtime/facades/archive-facade.test.ts +21 -7
- package/src/runtime/facades/brain-facade.test.ts +176 -72
- package/src/runtime/facades/branching-facade.test.ts +43 -0
- package/src/runtime/facades/branching-facade.ts +11 -0
- package/src/runtime/facades/chat-facade.test.ts +81 -28
- package/src/runtime/facades/chat-service-ops.test.ts +178 -73
- package/src/runtime/facades/chat-service-ops.ts +3 -1
- package/src/runtime/facades/chat-session-ops.test.ts +25 -10
- package/src/runtime/facades/chat-transport-ops.test.ts +101 -34
- package/src/runtime/facades/chat-transport-ops.ts +0 -1
- package/src/runtime/facades/context-facade.test.ts +19 -4
- package/src/runtime/facades/control-facade.test.ts +3 -3
- package/src/runtime/facades/index.ts +42 -0
- package/src/runtime/facades/intake-facade.test.ts +215 -0
- package/src/runtime/facades/intake-facade.ts +14 -0
- package/src/runtime/facades/links-facade.test.ts +203 -0
- package/src/runtime/facades/links-facade.ts +13 -0
- package/src/runtime/facades/loop-facade.test.ts +22 -5
- package/src/runtime/facades/memory-facade.test.ts +19 -5
- package/src/runtime/facades/operator-facade.test.ts +17 -4
- package/src/runtime/facades/operator-facade.ts +11 -3
- package/src/runtime/facades/orchestrate-facade.test.ts +7 -1
- package/src/runtime/facades/plan-facade.test.ts +29 -12
- package/src/runtime/facades/plan-facade.ts +7 -2
- package/src/runtime/facades/tier-facade.test.ts +47 -0
- package/src/runtime/facades/tier-facade.ts +11 -0
- package/src/runtime/facades/vault-facade.test.ts +174 -242
- package/src/runtime/facades/vault-facade.ts +55 -199
- package/src/runtime/github-integration.ts +11 -8
- package/src/runtime/grading-ops.test.ts +39 -8
- package/src/runtime/intake-ops.test.ts +69 -16
- package/src/runtime/loop-ops.test.ts +16 -6
- package/src/runtime/memory-cross-project-ops.test.ts +25 -14
- package/src/runtime/orchestrate-ops.ts +54 -27
- package/src/runtime/pack-ops.test.ts +23 -6
- package/src/runtime/planning-extra-ops.test.ts +17 -7
- package/src/runtime/planning-extra-ops.ts +3 -1
- package/src/runtime/playbook-ops.test.ts +26 -3
- package/src/runtime/plugin-ops.test.ts +83 -25
- package/src/runtime/project-ops.test.ts +26 -6
- package/src/runtime/runtime.ts +3 -1
- package/src/runtime/session-briefing.test.ts +183 -54
- package/src/runtime/session-briefing.ts +8 -2
- package/src/runtime/sync-ops.test.ts +3 -12
- package/src/runtime/telemetry-ops.test.ts +31 -6
- package/src/runtime/tier-ops.test.ts +159 -0
- package/src/runtime/tier-ops.ts +119 -0
- package/src/runtime/vault-extra-ops.test.ts +32 -8
- package/src/runtime/vault-sharing-ops.test.ts +1 -4
- package/src/skills/sync-skills.ts +2 -12
- package/src/transport/ws-server.test.ts +7 -4
- package/src/vault/__tests__/vault-characterization.test.ts +492 -81
- package/src/vault/linking.test.ts +50 -17
- package/src/vault/linking.ts +48 -7
- package/src/vault/obsidian-sync.test.ts +6 -3
- package/src/vault/scope-detector.test.ts +1 -3
- package/src/vault/vault-branching.test.ts +9 -7
- package/src/vault/vault-entries.ts +209 -65
- package/src/vault/vault-maintenance.ts +7 -12
- package/src/vault/vault-manager.test.ts +10 -10
- package/src/vault/vault-markdown-sync.ts +4 -1
- package/src/vault/vault-memories.ts +7 -7
- package/src/vault/vault-schema.ts +72 -15
- package/src/vault/vault.ts +55 -9
- package/src/brain/strength-scorer.ts +0 -404
- package/src/engine/index.ts +0 -21
- package/src/persona/index.ts +0 -9
- package/src/vault/vault-interfaces.ts +0 -56
|
@@ -15,14 +15,33 @@ export interface AutoLinkConfig {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/** Updatable fields on an entry. */
|
|
18
|
-
export type EntryUpdateFields = Partial<
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
export type EntryUpdateFields = Partial<
|
|
19
|
+
Pick<
|
|
20
|
+
IntelligenceEntry,
|
|
21
|
+
| 'title'
|
|
22
|
+
| 'description'
|
|
23
|
+
| 'context'
|
|
24
|
+
| 'example'
|
|
25
|
+
| 'counterExample'
|
|
26
|
+
| 'why'
|
|
27
|
+
| 'tags'
|
|
28
|
+
| 'appliesTo'
|
|
29
|
+
| 'severity'
|
|
30
|
+
| 'type'
|
|
31
|
+
| 'domain'
|
|
32
|
+
| 'validFrom'
|
|
33
|
+
| 'validUntil'
|
|
34
|
+
>
|
|
35
|
+
>;
|
|
21
36
|
|
|
22
37
|
/** Search/list filter options. */
|
|
23
38
|
export interface EntryFilterOptions {
|
|
24
|
-
domain?: string;
|
|
25
|
-
|
|
39
|
+
domain?: string;
|
|
40
|
+
type?: string;
|
|
41
|
+
severity?: string;
|
|
42
|
+
origin?: 'agent' | 'pack' | 'user';
|
|
43
|
+
limit?: number;
|
|
44
|
+
includeExpired?: boolean;
|
|
26
45
|
}
|
|
27
46
|
|
|
28
47
|
export function autoLink(entryId: string, config: AutoLinkConfig): void {
|
|
@@ -32,10 +51,16 @@ export function autoLink(entryId: string, config: AutoLinkConfig): void {
|
|
|
32
51
|
for (const s of suggestions) {
|
|
33
52
|
config.linkManager.addLink(entryId, s.entryId, s.suggestedType, `auto: ${s.reason}`);
|
|
34
53
|
}
|
|
35
|
-
} catch {
|
|
54
|
+
} catch {
|
|
55
|
+
/* best-effort */
|
|
56
|
+
}
|
|
36
57
|
}
|
|
37
58
|
|
|
38
|
-
export function seed(
|
|
59
|
+
export function seed(
|
|
60
|
+
provider: PersistenceProvider,
|
|
61
|
+
entries: IntelligenceEntry[],
|
|
62
|
+
alc: AutoLinkConfig,
|
|
63
|
+
): number {
|
|
39
64
|
const sql = `
|
|
40
65
|
INSERT INTO entries (id,type,domain,title,severity,description,context,example,counter_example,why,tags,applies_to,valid_from,valid_until,content_hash,tier,origin)
|
|
41
66
|
VALUES (@id,@type,@domain,@title,@severity,@description,@context,@example,@counterExample,@why,@tags,@appliesTo,@validFrom,@validUntil,@contentHash,@tier,@origin)
|
|
@@ -48,13 +73,23 @@ export function seed(provider: PersistenceProvider, entries: IntelligenceEntry[]
|
|
|
48
73
|
let count = 0;
|
|
49
74
|
for (const entry of entries) {
|
|
50
75
|
provider.run(sql, {
|
|
51
|
-
id: entry.id,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
76
|
+
id: entry.id,
|
|
77
|
+
type: entry.type,
|
|
78
|
+
domain: entry.domain,
|
|
79
|
+
title: entry.title,
|
|
80
|
+
severity: entry.severity,
|
|
81
|
+
description: entry.description,
|
|
82
|
+
context: entry.context ?? null,
|
|
83
|
+
example: entry.example ?? null,
|
|
84
|
+
counterExample: entry.counterExample ?? null,
|
|
85
|
+
why: entry.why ?? null,
|
|
86
|
+
tags: JSON.stringify(entry.tags),
|
|
87
|
+
appliesTo: JSON.stringify(entry.appliesTo ?? []),
|
|
88
|
+
validFrom: entry.validFrom ?? null,
|
|
89
|
+
validUntil: entry.validUntil ?? null,
|
|
90
|
+
contentHash: computeContentHash(entry),
|
|
91
|
+
tier: entry.tier ?? 'agent',
|
|
92
|
+
origin: entry.origin ?? 'agent',
|
|
58
93
|
});
|
|
59
94
|
count++;
|
|
60
95
|
}
|
|
@@ -67,10 +102,13 @@ export function seed(provider: PersistenceProvider, entries: IntelligenceEntry[]
|
|
|
67
102
|
}
|
|
68
103
|
|
|
69
104
|
export function seedDedup(
|
|
70
|
-
provider: PersistenceProvider,
|
|
105
|
+
provider: PersistenceProvider,
|
|
106
|
+
entries: IntelligenceEntry[],
|
|
107
|
+
alc: AutoLinkConfig,
|
|
71
108
|
): Array<{ id: string; action: 'inserted' | 'duplicate'; existingId?: string }> {
|
|
72
109
|
return provider.transaction(() => {
|
|
73
|
-
const results: Array<{ id: string; action: 'inserted' | 'duplicate'; existingId?: string }> =
|
|
110
|
+
const results: Array<{ id: string; action: 'inserted' | 'duplicate'; existingId?: string }> =
|
|
111
|
+
[];
|
|
74
112
|
for (const entry of entries) {
|
|
75
113
|
const hash = computeContentHash(entry);
|
|
76
114
|
const existing = findByContentHash(provider, hash);
|
|
@@ -86,24 +124,44 @@ export function seedDedup(
|
|
|
86
124
|
}
|
|
87
125
|
|
|
88
126
|
export function installPack(
|
|
89
|
-
provider: PersistenceProvider,
|
|
127
|
+
provider: PersistenceProvider,
|
|
128
|
+
entries: IntelligenceEntry[],
|
|
129
|
+
alc: AutoLinkConfig,
|
|
90
130
|
): { installed: number; skipped: number } {
|
|
91
|
-
let installed = 0,
|
|
131
|
+
let installed = 0,
|
|
132
|
+
skipped = 0;
|
|
92
133
|
const tagged = entries.map((e) => ({ ...e, origin: 'pack' as const }));
|
|
93
134
|
for (const r of seedDedup(provider, tagged, alc)) {
|
|
94
|
-
if (r.action === 'inserted') installed++;
|
|
135
|
+
if (r.action === 'inserted') installed++;
|
|
136
|
+
else skipped++;
|
|
95
137
|
}
|
|
96
138
|
return { installed, skipped };
|
|
97
139
|
}
|
|
98
140
|
|
|
99
|
-
export function search(
|
|
141
|
+
export function search(
|
|
142
|
+
provider: PersistenceProvider,
|
|
143
|
+
query: string,
|
|
144
|
+
options?: EntryFilterOptions,
|
|
145
|
+
): SearchResult[] {
|
|
100
146
|
const limit = options?.limit ?? 10;
|
|
101
147
|
const filters: string[] = [];
|
|
102
148
|
const fp: Record<string, unknown> = {};
|
|
103
|
-
if (options?.domain) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
149
|
+
if (options?.domain) {
|
|
150
|
+
filters.push('e.domain = @domain');
|
|
151
|
+
fp.domain = options.domain;
|
|
152
|
+
}
|
|
153
|
+
if (options?.type) {
|
|
154
|
+
filters.push('e.type = @type');
|
|
155
|
+
fp.type = options.type;
|
|
156
|
+
}
|
|
157
|
+
if (options?.severity) {
|
|
158
|
+
filters.push('e.severity = @severity');
|
|
159
|
+
fp.severity = options.severity;
|
|
160
|
+
}
|
|
161
|
+
if (options?.origin) {
|
|
162
|
+
filters.push('e.origin = @origin');
|
|
163
|
+
fp.origin = options.origin;
|
|
164
|
+
}
|
|
107
165
|
if (!options?.includeExpired) {
|
|
108
166
|
const now = Math.floor(Date.now() / 1000);
|
|
109
167
|
filters.push('(e.valid_until IS NULL OR e.valid_until > @now)');
|
|
@@ -125,7 +183,9 @@ export function search(provider: PersistenceProvider, query: string, options?: E
|
|
|
125
183
|
{ query, limit, ...fp },
|
|
126
184
|
);
|
|
127
185
|
return rows.map(rowToSearchResult);
|
|
128
|
-
} catch {
|
|
186
|
+
} catch {
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
129
189
|
}
|
|
130
190
|
}
|
|
131
191
|
|
|
@@ -140,12 +200,27 @@ export function list(
|
|
|
140
200
|
): IntelligenceEntry[] {
|
|
141
201
|
const filters: string[] = [];
|
|
142
202
|
const params: Record<string, unknown> = {};
|
|
143
|
-
if (options?.domain) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
203
|
+
if (options?.domain) {
|
|
204
|
+
filters.push('domain = @domain');
|
|
205
|
+
params.domain = options.domain;
|
|
206
|
+
}
|
|
207
|
+
if (options?.type) {
|
|
208
|
+
filters.push('type = @type');
|
|
209
|
+
params.type = options.type;
|
|
210
|
+
}
|
|
211
|
+
if (options?.severity) {
|
|
212
|
+
filters.push('severity = @severity');
|
|
213
|
+
params.severity = options.severity;
|
|
214
|
+
}
|
|
215
|
+
if (options?.origin) {
|
|
216
|
+
filters.push('origin = @origin');
|
|
217
|
+
params.origin = options.origin;
|
|
218
|
+
}
|
|
147
219
|
if (options?.tags?.length) {
|
|
148
|
-
const c = options.tags.map((t, i) => {
|
|
220
|
+
const c = options.tags.map((t, i) => {
|
|
221
|
+
params[`tag${i}`] = `%"${t}"%`;
|
|
222
|
+
return `tags LIKE @tag${i}`;
|
|
223
|
+
});
|
|
149
224
|
filters.push(`(${c.join(' OR ')})`);
|
|
150
225
|
}
|
|
151
226
|
if (!options?.includeExpired) {
|
|
@@ -164,10 +239,19 @@ export function list(
|
|
|
164
239
|
|
|
165
240
|
export function stats(provider: PersistenceProvider): VaultStats {
|
|
166
241
|
const total = provider.get<{ count: number }>('SELECT COUNT(*) as count FROM entries')!.count;
|
|
167
|
-
return {
|
|
242
|
+
return {
|
|
243
|
+
totalEntries: total,
|
|
244
|
+
byType: gc(provider, 'type'),
|
|
245
|
+
byDomain: gc(provider, 'domain'),
|
|
246
|
+
bySeverity: gc(provider, 'severity'),
|
|
247
|
+
};
|
|
168
248
|
}
|
|
169
249
|
|
|
170
|
-
export function add(
|
|
250
|
+
export function add(
|
|
251
|
+
provider: PersistenceProvider,
|
|
252
|
+
entry: IntelligenceEntry,
|
|
253
|
+
alc: AutoLinkConfig,
|
|
254
|
+
): void {
|
|
171
255
|
seed(provider, [entry], alc);
|
|
172
256
|
}
|
|
173
257
|
|
|
@@ -175,38 +259,64 @@ export function remove(provider: PersistenceProvider, id: string): boolean {
|
|
|
175
259
|
return provider.run('DELETE FROM entries WHERE id = ?', [id]).changes > 0;
|
|
176
260
|
}
|
|
177
261
|
|
|
178
|
-
export function update(
|
|
262
|
+
export function update(
|
|
263
|
+
provider: PersistenceProvider,
|
|
264
|
+
id: string,
|
|
265
|
+
fields: EntryUpdateFields,
|
|
266
|
+
alc: AutoLinkConfig,
|
|
267
|
+
): IntelligenceEntry | null {
|
|
179
268
|
const existing = get(provider, id);
|
|
180
269
|
if (!existing) return null;
|
|
181
270
|
seed(provider, [{ ...existing, ...fields }], alc);
|
|
182
271
|
return get(provider, id);
|
|
183
272
|
}
|
|
184
273
|
|
|
185
|
-
export function setTemporal(
|
|
274
|
+
export function setTemporal(
|
|
275
|
+
provider: PersistenceProvider,
|
|
276
|
+
id: string,
|
|
277
|
+
validFrom?: number,
|
|
278
|
+
validUntil?: number,
|
|
279
|
+
): boolean {
|
|
186
280
|
const sets: string[] = [];
|
|
187
281
|
const params: Record<string, unknown> = { id };
|
|
188
|
-
if (validFrom !== undefined) {
|
|
189
|
-
|
|
282
|
+
if (validFrom !== undefined) {
|
|
283
|
+
sets.push('valid_from = @validFrom');
|
|
284
|
+
params.validFrom = validFrom;
|
|
285
|
+
}
|
|
286
|
+
if (validUntil !== undefined) {
|
|
287
|
+
sets.push('valid_until = @validUntil');
|
|
288
|
+
params.validUntil = validUntil;
|
|
289
|
+
}
|
|
190
290
|
if (sets.length === 0) return false;
|
|
191
291
|
sets.push('updated_at = unixepoch()');
|
|
192
292
|
return provider.run(`UPDATE entries SET ${sets.join(', ')} WHERE id = @id`, params).changes > 0;
|
|
193
293
|
}
|
|
194
294
|
|
|
195
|
-
export function findExpiring(
|
|
295
|
+
export function findExpiring(
|
|
296
|
+
provider: PersistenceProvider,
|
|
297
|
+
withinDays: number,
|
|
298
|
+
): IntelligenceEntry[] {
|
|
196
299
|
const now = Math.floor(Date.now() / 1000);
|
|
197
300
|
const cutoff = now + withinDays * 86400;
|
|
198
|
-
return provider
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
301
|
+
return provider
|
|
302
|
+
.all<Record<string, unknown>>(
|
|
303
|
+
'SELECT * FROM entries WHERE valid_until IS NOT NULL AND valid_until > @now AND valid_until <= @cutoff ORDER BY valid_until ASC',
|
|
304
|
+
{ now, cutoff },
|
|
305
|
+
)
|
|
306
|
+
.map(rowToEntry);
|
|
202
307
|
}
|
|
203
308
|
|
|
204
|
-
export function findExpired(
|
|
309
|
+
export function findExpired(
|
|
310
|
+
provider: PersistenceProvider,
|
|
311
|
+
limit: number = 50,
|
|
312
|
+
): IntelligenceEntry[] {
|
|
205
313
|
const now = Math.floor(Date.now() / 1000);
|
|
206
|
-
return provider
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
314
|
+
return provider
|
|
315
|
+
.all<Record<string, unknown>>(
|
|
316
|
+
'SELECT * FROM entries WHERE valid_until IS NOT NULL AND valid_until <= @now ORDER BY valid_until DESC LIMIT @limit',
|
|
317
|
+
{ now, limit },
|
|
318
|
+
)
|
|
319
|
+
.map(rowToEntry);
|
|
210
320
|
}
|
|
211
321
|
|
|
212
322
|
export function bulkRemove(provider: PersistenceProvider, ids: string[]): number {
|
|
@@ -225,45 +335,75 @@ export function getTags(provider: PersistenceProvider): Array<{ tag: string; cou
|
|
|
225
335
|
counts.set(tag, (counts.get(tag) ?? 0) + 1);
|
|
226
336
|
}
|
|
227
337
|
}
|
|
228
|
-
return Array.from(counts.entries())
|
|
338
|
+
return Array.from(counts.entries())
|
|
339
|
+
.map(([tag, count]) => ({ tag, count }))
|
|
340
|
+
.sort((a, b) => b.count - a.count);
|
|
229
341
|
}
|
|
230
342
|
|
|
231
|
-
export function getDomains(
|
|
232
|
-
|
|
343
|
+
export function getDomains(
|
|
344
|
+
provider: PersistenceProvider,
|
|
345
|
+
): Array<{ domain: string; count: number }> {
|
|
346
|
+
return provider.all(
|
|
347
|
+
'SELECT domain, COUNT(*) as count FROM entries GROUP BY domain ORDER BY count DESC',
|
|
348
|
+
);
|
|
233
349
|
}
|
|
234
350
|
|
|
235
351
|
export function getRecent(provider: PersistenceProvider, limit: number = 20): IntelligenceEntry[] {
|
|
236
|
-
return provider
|
|
352
|
+
return provider
|
|
353
|
+
.all<Record<string, unknown>>('SELECT * FROM entries ORDER BY updated_at DESC LIMIT ?', [limit])
|
|
354
|
+
.map(rowToEntry);
|
|
237
355
|
}
|
|
238
356
|
|
|
239
357
|
export function findByContentHash(provider: PersistenceProvider, hash: string): string | null {
|
|
240
|
-
return
|
|
358
|
+
return (
|
|
359
|
+
provider.get<{ id: string }>('SELECT id FROM entries WHERE content_hash = @hash', { hash })
|
|
360
|
+
?.id ?? null
|
|
361
|
+
);
|
|
241
362
|
}
|
|
242
363
|
|
|
243
|
-
export function contentHashStats(provider: PersistenceProvider): {
|
|
364
|
+
export function contentHashStats(provider: PersistenceProvider): {
|
|
365
|
+
total: number;
|
|
366
|
+
hashed: number;
|
|
367
|
+
uniqueHashes: number;
|
|
368
|
+
} {
|
|
244
369
|
const total = provider.get<{ c: number }>('SELECT COUNT(*) as c FROM entries')?.c ?? 0;
|
|
245
|
-
const hashed =
|
|
246
|
-
|
|
370
|
+
const hashed =
|
|
371
|
+
provider.get<{ c: number }>('SELECT COUNT(*) as c FROM entries WHERE content_hash IS NOT NULL')
|
|
372
|
+
?.c ?? 0;
|
|
373
|
+
const uniqueHashes =
|
|
374
|
+
provider.get<{ c: number }>(
|
|
375
|
+
'SELECT COUNT(DISTINCT content_hash) as c FROM entries WHERE content_hash IS NOT NULL',
|
|
376
|
+
)?.c ?? 0;
|
|
247
377
|
return { total, hashed, uniqueHashes };
|
|
248
378
|
}
|
|
249
379
|
|
|
250
380
|
// ── Helpers ──────────────────────────────────────────────────────────────
|
|
251
381
|
|
|
252
382
|
function gc(provider: PersistenceProvider, col: string): Record<string, number> {
|
|
253
|
-
const rows = provider.all<{ key: string; count: number }>(
|
|
383
|
+
const rows = provider.all<{ key: string; count: number }>(
|
|
384
|
+
`SELECT ${col} as key, COUNT(*) as count FROM entries GROUP BY ${col}`,
|
|
385
|
+
);
|
|
254
386
|
return Object.fromEntries(rows.map((r) => [r.key, r.count]));
|
|
255
387
|
}
|
|
256
388
|
|
|
257
389
|
export function rowToEntry(row: Record<string, unknown>): IntelligenceEntry {
|
|
258
390
|
return {
|
|
259
|
-
id: row.id as string,
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
391
|
+
id: row.id as string,
|
|
392
|
+
type: row.type as IntelligenceEntry['type'],
|
|
393
|
+
domain: row.domain as IntelligenceEntry['domain'],
|
|
394
|
+
title: row.title as string,
|
|
395
|
+
severity: row.severity as IntelligenceEntry['severity'],
|
|
396
|
+
description: row.description as string,
|
|
397
|
+
context: (row.context as string) ?? undefined,
|
|
398
|
+
example: (row.example as string) ?? undefined,
|
|
399
|
+
counterExample: (row.counter_example as string) ?? undefined,
|
|
400
|
+
why: (row.why as string) ?? undefined,
|
|
401
|
+
tags: JSON.parse((row.tags as string) || '[]'),
|
|
402
|
+
appliesTo: JSON.parse((row.applies_to as string) || '[]'),
|
|
403
|
+
tier: (row.tier as IntelligenceEntry['tier']) ?? undefined,
|
|
404
|
+
origin: (row.origin as IntelligenceEntry['origin']) ?? undefined,
|
|
405
|
+
validFrom: (row.valid_from as number) ?? undefined,
|
|
406
|
+
validUntil: (row.valid_until as number) ?? undefined,
|
|
267
407
|
};
|
|
268
408
|
}
|
|
269
409
|
|
|
@@ -274,8 +414,12 @@ export function rowToSearchResult(row: Record<string, unknown>): SearchResult {
|
|
|
274
414
|
|
|
275
415
|
/** Build FTS5 query from natural language: terms joined with OR for broad matching. */
|
|
276
416
|
export function buildFtsQuery(query: string): string {
|
|
277
|
-
const terms = query
|
|
278
|
-
.
|
|
417
|
+
const terms = query
|
|
418
|
+
.toLowerCase()
|
|
419
|
+
.split(/\s+/)
|
|
420
|
+
.filter((t) => t.length >= 2)
|
|
421
|
+
.map((t) => t.replace(/[^a-z0-9]/g, ''))
|
|
422
|
+
.filter(Boolean);
|
|
279
423
|
if (terms.length === 0) return query;
|
|
280
424
|
if (terms.length === 1) return terms[0];
|
|
281
425
|
return terms.join(' OR ');
|
|
@@ -111,10 +111,9 @@ export function archive(
|
|
|
111
111
|
const reason = options.reason ?? `Archived: older than ${options.olderThanDays} days`;
|
|
112
112
|
|
|
113
113
|
return provider.transaction(() => {
|
|
114
|
-
const candidates = provider.all<{ id: string }>(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
);
|
|
114
|
+
const candidates = provider.all<{ id: string }>('SELECT id FROM entries WHERE updated_at < ?', [
|
|
115
|
+
cutoff,
|
|
116
|
+
]);
|
|
118
117
|
|
|
119
118
|
if (candidates.length === 0) return { archived: 0 };
|
|
120
119
|
|
|
@@ -173,14 +172,10 @@ export function registerProject(
|
|
|
173
172
|
return getProject(provider, path)!;
|
|
174
173
|
}
|
|
175
174
|
|
|
176
|
-
export function getProject(
|
|
177
|
-
provider
|
|
178
|
-
|
|
179
|
-
)
|
|
180
|
-
const row = provider.get<Record<string, unknown>>(
|
|
181
|
-
'SELECT * FROM projects WHERE path = ?',
|
|
182
|
-
[path],
|
|
183
|
-
);
|
|
175
|
+
export function getProject(provider: PersistenceProvider, path: string): ProjectInfo | null {
|
|
176
|
+
const row = provider.get<Record<string, unknown>>('SELECT * FROM projects WHERE path = ?', [
|
|
177
|
+
path,
|
|
178
|
+
]);
|
|
184
179
|
if (!row) return null;
|
|
185
180
|
return {
|
|
186
181
|
path: row.path as string,
|
|
@@ -7,13 +7,17 @@ vi.mock('./vault.js', () => {
|
|
|
7
7
|
const MockVault = function (this: Record<string, unknown>, path: string) {
|
|
8
8
|
this._path = path;
|
|
9
9
|
this.search = vi.fn().mockReturnValue([]);
|
|
10
|
-
this.stats = vi
|
|
10
|
+
this.stats = vi
|
|
11
|
+
.fn()
|
|
12
|
+
.mockReturnValue({ totalEntries: 0, byType: {}, byDomain: {}, bySeverity: {} });
|
|
11
13
|
this.close = vi.fn();
|
|
12
|
-
} as unknown as typeof import('./vault.js')['Vault'];
|
|
14
|
+
} as unknown as (typeof import('./vault.js'))['Vault'];
|
|
13
15
|
return { Vault: MockVault };
|
|
14
16
|
});
|
|
15
17
|
|
|
16
|
-
function makeManager(
|
|
18
|
+
function makeManager(
|
|
19
|
+
weights?: Partial<Record<'agent' | 'project' | 'team', number>>,
|
|
20
|
+
): VaultManager {
|
|
17
21
|
return new VaultManager({ agentId: 'test-agent', weights });
|
|
18
22
|
}
|
|
19
23
|
|
|
@@ -74,7 +78,7 @@ describe('VaultManager', () => {
|
|
|
74
78
|
|
|
75
79
|
it('throws when connecting duplicate named vault', () => {
|
|
76
80
|
mgr.connect('shared', '/tmp/shared.db');
|
|
77
|
-
expect(() => mgr.connect('shared', '/tmp/other.db')).toThrow(
|
|
81
|
+
expect(() => mgr.connect('shared', '/tmp/other.db')).toThrow('already connected');
|
|
78
82
|
});
|
|
79
83
|
|
|
80
84
|
it('disconnects a named vault', () => {
|
|
@@ -122,14 +126,10 @@ describe('VaultManager', () => {
|
|
|
122
126
|
it('deduplicates entries keeping highest weighted score', () => {
|
|
123
127
|
const entry = { id: 'e1', title: 'Shared' };
|
|
124
128
|
const agentVault = mgr.open('agent', '/tmp/a.db');
|
|
125
|
-
(agentVault.search as ReturnType<typeof vi.fn>).mockReturnValue([
|
|
126
|
-
{ entry, score: 0.5 },
|
|
127
|
-
]);
|
|
129
|
+
(agentVault.search as ReturnType<typeof vi.fn>).mockReturnValue([{ entry, score: 0.5 }]);
|
|
128
130
|
|
|
129
131
|
const teamVault = mgr.open('team', '/tmp/t.db');
|
|
130
|
-
(teamVault.search as ReturnType<typeof vi.fn>).mockReturnValue([
|
|
131
|
-
{ entry, score: 0.8 },
|
|
132
|
-
]);
|
|
132
|
+
(teamVault.search as ReturnType<typeof vi.fn>).mockReturnValue([{ entry, score: 0.8 }]);
|
|
133
133
|
|
|
134
134
|
const results = mgr.search('test');
|
|
135
135
|
// Agent: 0.5 * 1.0 = 0.5, Team: 0.8 * 0.6 = 0.48 → agent wins
|
|
@@ -105,7 +105,10 @@ export async function syncAllToMarkdown(
|
|
|
105
105
|
for (const entry of entries) {
|
|
106
106
|
const domain = entry.domain || '_general';
|
|
107
107
|
const slug = titleToSlug(entry.title);
|
|
108
|
-
if (!slug) {
|
|
108
|
+
if (!slug) {
|
|
109
|
+
skipped++;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
109
112
|
|
|
110
113
|
const filePath = join(knowledgeDir, 'vault', domain, `${slug}.md`);
|
|
111
114
|
if (existsSync(filePath)) {
|
|
@@ -228,16 +228,16 @@ export function pruneMemories(
|
|
|
228
228
|
olderThanDays: number,
|
|
229
229
|
): { pruned: number } {
|
|
230
230
|
const cutoff = Math.floor(Date.now() / 1000) - olderThanDays * 86400;
|
|
231
|
-
const result = provider.run(
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
);
|
|
231
|
+
const result = provider.run('DELETE FROM memories WHERE created_at < ? AND archived_at IS NULL', [
|
|
232
|
+
cutoff,
|
|
233
|
+
]);
|
|
235
234
|
return { pruned: result.changes };
|
|
236
235
|
}
|
|
237
236
|
|
|
238
|
-
export function deduplicateMemories(
|
|
239
|
-
|
|
240
|
-
|
|
237
|
+
export function deduplicateMemories(provider: PersistenceProvider): {
|
|
238
|
+
removed: number;
|
|
239
|
+
groups: Array<{ kept: string; removed: string[] }>;
|
|
240
|
+
} {
|
|
241
241
|
const dupeRows = provider.all<{ id1: string; id2: string }>(`
|
|
242
242
|
SELECT m1.id as id1, m2.id as id2
|
|
243
243
|
FROM memories m1
|
|
@@ -87,7 +87,9 @@ function createCoreTables(provider: PersistenceProvider): void {
|
|
|
87
87
|
);`);
|
|
88
88
|
|
|
89
89
|
// Add memory columns if missing
|
|
90
|
-
const memCols = provider
|
|
90
|
+
const memCols = provider
|
|
91
|
+
.all<{ name: string }>('PRAGMA table_info(memories)')
|
|
92
|
+
.map((r: { name: string }) => r.name);
|
|
91
93
|
if (!memCols.includes('intent')) {
|
|
92
94
|
provider.execSql(`
|
|
93
95
|
ALTER TABLE memories ADD COLUMN intent TEXT;
|
|
@@ -134,8 +136,12 @@ function migrateBrainSchema(provider: PersistenceProvider): void {
|
|
|
134
136
|
const hasSource = columns.some((c: { name: string }) => c.name === 'source');
|
|
135
137
|
if (!hasSource && columns.length > 0) {
|
|
136
138
|
provider.transaction(() => {
|
|
137
|
-
provider.run(
|
|
138
|
-
|
|
139
|
+
provider.run(
|
|
140
|
+
`CREATE TABLE brain_feedback_new (id INTEGER PRIMARY KEY AUTOINCREMENT, query TEXT NOT NULL, entry_id TEXT NOT NULL, action TEXT NOT NULL CHECK(action IN ('accepted', 'dismissed', 'modified', 'failed')), source TEXT NOT NULL DEFAULT 'search', confidence REAL NOT NULL DEFAULT 0.6, duration INTEGER, context TEXT NOT NULL DEFAULT '{}', reason TEXT, created_at INTEGER NOT NULL DEFAULT (unixepoch()))`,
|
|
141
|
+
);
|
|
142
|
+
provider.run(
|
|
143
|
+
`INSERT INTO brain_feedback_new (id, query, entry_id, action, created_at) SELECT id, query, entry_id, action, created_at FROM brain_feedback`,
|
|
144
|
+
);
|
|
139
145
|
provider.run('DROP TABLE brain_feedback');
|
|
140
146
|
provider.run('ALTER TABLE brain_feedback_new RENAME TO brain_feedback');
|
|
141
147
|
provider.run('CREATE INDEX IF NOT EXISTS idx_brain_feedback_query ON brain_feedback(query)');
|
|
@@ -143,39 +149,90 @@ function migrateBrainSchema(provider: PersistenceProvider): void {
|
|
|
143
149
|
}
|
|
144
150
|
try {
|
|
145
151
|
const sessionCols = provider.all<{ name: string }>('PRAGMA table_info(brain_sessions)');
|
|
146
|
-
if (
|
|
152
|
+
if (
|
|
153
|
+
sessionCols.length > 0 &&
|
|
154
|
+
!sessionCols.some((c: { name: string }) => c.name === 'extracted_at')
|
|
155
|
+
) {
|
|
147
156
|
provider.run('ALTER TABLE brain_sessions ADD COLUMN extracted_at TEXT');
|
|
148
157
|
}
|
|
149
|
-
} catch {
|
|
158
|
+
} catch {
|
|
159
|
+
/* brain_sessions doesn't exist yet */
|
|
160
|
+
}
|
|
150
161
|
}
|
|
151
162
|
|
|
152
163
|
function migrateTemporalSchema(provider: PersistenceProvider): void {
|
|
153
|
-
try {
|
|
154
|
-
|
|
164
|
+
try {
|
|
165
|
+
provider.run('ALTER TABLE entries ADD COLUMN valid_from INTEGER');
|
|
166
|
+
} catch {
|
|
167
|
+
/* exists */
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
provider.run('ALTER TABLE entries ADD COLUMN valid_until INTEGER');
|
|
171
|
+
} catch {
|
|
172
|
+
/* exists */
|
|
173
|
+
}
|
|
155
174
|
}
|
|
156
175
|
|
|
157
176
|
function migrateOriginColumn(provider: PersistenceProvider): void {
|
|
158
|
-
try {
|
|
177
|
+
try {
|
|
178
|
+
provider.run(
|
|
179
|
+
"ALTER TABLE entries ADD COLUMN origin TEXT NOT NULL DEFAULT 'user' CHECK(origin IN ('agent', 'pack', 'user'))",
|
|
180
|
+
);
|
|
181
|
+
} catch {
|
|
182
|
+
/* exists */
|
|
183
|
+
}
|
|
159
184
|
provider.execSql('CREATE INDEX IF NOT EXISTS idx_entries_origin ON entries(origin)');
|
|
160
185
|
}
|
|
161
186
|
|
|
162
187
|
function migrateContentHash(provider: PersistenceProvider): void {
|
|
163
|
-
try {
|
|
164
|
-
|
|
165
|
-
|
|
188
|
+
try {
|
|
189
|
+
provider.run('ALTER TABLE entries ADD COLUMN content_hash TEXT');
|
|
190
|
+
} catch {
|
|
191
|
+
/* exists */
|
|
192
|
+
}
|
|
193
|
+
provider.execSql(
|
|
194
|
+
'CREATE INDEX IF NOT EXISTS idx_entries_content_hash ON entries(content_hash) WHERE content_hash IS NOT NULL',
|
|
195
|
+
);
|
|
196
|
+
const unhashed = provider.all<{
|
|
197
|
+
id: string;
|
|
198
|
+
type: string;
|
|
199
|
+
domain: string;
|
|
200
|
+
title: string;
|
|
201
|
+
description: string;
|
|
202
|
+
tags: string;
|
|
203
|
+
example: string | null;
|
|
204
|
+
counter_example: string | null;
|
|
205
|
+
}>(
|
|
166
206
|
'SELECT id, type, domain, title, description, tags, example, counter_example FROM entries WHERE content_hash IS NULL',
|
|
167
207
|
);
|
|
168
208
|
if (unhashed.length > 0) {
|
|
169
209
|
provider.transaction(() => {
|
|
170
210
|
for (const row of unhashed) {
|
|
171
|
-
const hash = computeContentHash({
|
|
172
|
-
|
|
211
|
+
const hash = computeContentHash({
|
|
212
|
+
type: row.type,
|
|
213
|
+
domain: row.domain,
|
|
214
|
+
title: row.title,
|
|
215
|
+
description: row.description,
|
|
216
|
+
tags: JSON.parse(row.tags),
|
|
217
|
+
example: row.example ?? undefined,
|
|
218
|
+
counterExample: row.counter_example ?? undefined,
|
|
219
|
+
});
|
|
220
|
+
provider.run('UPDATE entries SET content_hash = @hash WHERE id = @id', {
|
|
221
|
+
hash,
|
|
222
|
+
id: row.id,
|
|
223
|
+
});
|
|
173
224
|
}
|
|
174
225
|
});
|
|
175
226
|
}
|
|
176
227
|
}
|
|
177
228
|
|
|
178
229
|
function migrateTierColumn(provider: PersistenceProvider): void {
|
|
179
|
-
try {
|
|
180
|
-
|
|
230
|
+
try {
|
|
231
|
+
provider.run("ALTER TABLE entries ADD COLUMN tier TEXT DEFAULT 'agent'");
|
|
232
|
+
} catch {
|
|
233
|
+
/* exists */
|
|
234
|
+
}
|
|
235
|
+
provider.execSql(
|
|
236
|
+
'CREATE INDEX IF NOT EXISTS idx_entries_tier ON entries(tier) WHERE tier IS NOT NULL',
|
|
237
|
+
);
|
|
181
238
|
}
|