@soleri/core 2.1.0 → 2.5.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/dist/brain/brain.d.ts +10 -1
- package/dist/brain/brain.d.ts.map +1 -1
- package/dist/brain/brain.js +116 -13
- package/dist/brain/brain.js.map +1 -1
- package/dist/brain/intelligence.d.ts +36 -1
- package/dist/brain/intelligence.d.ts.map +1 -1
- package/dist/brain/intelligence.js +119 -14
- package/dist/brain/intelligence.js.map +1 -1
- package/dist/brain/types.d.ts +34 -2
- package/dist/brain/types.d.ts.map +1 -1
- package/dist/cognee/client.d.ts +3 -0
- package/dist/cognee/client.d.ts.map +1 -1
- package/dist/cognee/client.js +17 -0
- package/dist/cognee/client.js.map +1 -1
- package/dist/cognee/sync-manager.d.ts +94 -0
- package/dist/cognee/sync-manager.d.ts.map +1 -0
- package/dist/cognee/sync-manager.js +293 -0
- package/dist/cognee/sync-manager.js.map +1 -0
- package/dist/control/identity-manager.d.ts +22 -0
- package/dist/control/identity-manager.d.ts.map +1 -0
- package/dist/control/identity-manager.js +233 -0
- package/dist/control/identity-manager.js.map +1 -0
- package/dist/control/intent-router.d.ts +32 -0
- package/dist/control/intent-router.d.ts.map +1 -0
- package/dist/control/intent-router.js +242 -0
- package/dist/control/intent-router.js.map +1 -0
- package/dist/control/types.d.ts +68 -0
- package/dist/control/types.d.ts.map +1 -0
- package/dist/control/types.js +9 -0
- package/dist/control/types.js.map +1 -0
- package/dist/curator/curator.d.ts +37 -1
- package/dist/curator/curator.d.ts.map +1 -1
- package/dist/curator/curator.js +199 -1
- package/dist/curator/curator.js.map +1 -1
- package/dist/errors/classify.d.ts +13 -0
- package/dist/errors/classify.d.ts.map +1 -0
- package/dist/errors/classify.js +97 -0
- package/dist/errors/classify.js.map +1 -0
- package/dist/errors/index.d.ts +6 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +4 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/errors/retry.d.ts +40 -0
- package/dist/errors/retry.d.ts.map +1 -0
- package/dist/errors/retry.js +97 -0
- package/dist/errors/retry.js.map +1 -0
- package/dist/errors/types.d.ts +48 -0
- package/dist/errors/types.d.ts.map +1 -0
- package/dist/errors/types.js +59 -0
- package/dist/errors/types.js.map +1 -0
- package/dist/facades/types.d.ts +1 -1
- package/dist/governance/governance.d.ts +42 -0
- package/dist/governance/governance.d.ts.map +1 -0
- package/dist/governance/governance.js +488 -0
- package/dist/governance/governance.js.map +1 -0
- package/dist/governance/index.d.ts +3 -0
- package/dist/governance/index.d.ts.map +1 -0
- package/dist/governance/index.js +2 -0
- package/dist/governance/index.js.map +1 -0
- package/dist/governance/types.d.ts +102 -0
- package/dist/governance/types.d.ts.map +1 -0
- package/dist/governance/types.js +3 -0
- package/dist/governance/types.js.map +1 -0
- package/dist/index.d.ts +52 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +47 -1
- package/dist/index.js.map +1 -1
- package/dist/intake/content-classifier.d.ts +14 -0
- package/dist/intake/content-classifier.d.ts.map +1 -0
- package/dist/intake/content-classifier.js +125 -0
- package/dist/intake/content-classifier.js.map +1 -0
- package/dist/intake/dedup-gate.d.ts +17 -0
- package/dist/intake/dedup-gate.d.ts.map +1 -0
- package/dist/intake/dedup-gate.js +66 -0
- package/dist/intake/dedup-gate.js.map +1 -0
- package/dist/intake/intake-pipeline.d.ts +63 -0
- package/dist/intake/intake-pipeline.d.ts.map +1 -0
- package/dist/intake/intake-pipeline.js +373 -0
- package/dist/intake/intake-pipeline.js.map +1 -0
- package/dist/intake/types.d.ts +65 -0
- package/dist/intake/types.d.ts.map +1 -0
- package/dist/intake/types.js +3 -0
- package/dist/intake/types.js.map +1 -0
- package/dist/intelligence/loader.js +1 -1
- package/dist/intelligence/loader.js.map +1 -1
- package/dist/intelligence/types.d.ts +3 -1
- package/dist/intelligence/types.d.ts.map +1 -1
- package/dist/logging/logger.d.ts +37 -0
- package/dist/logging/logger.d.ts.map +1 -0
- package/dist/logging/logger.js +145 -0
- package/dist/logging/logger.js.map +1 -0
- package/dist/logging/types.d.ts +19 -0
- package/dist/logging/types.d.ts.map +1 -0
- package/dist/logging/types.js +2 -0
- package/dist/logging/types.js.map +1 -0
- package/dist/loop/loop-manager.d.ts +100 -0
- package/dist/loop/loop-manager.d.ts.map +1 -0
- package/dist/loop/loop-manager.js +379 -0
- package/dist/loop/loop-manager.js.map +1 -0
- package/dist/loop/types.d.ts +103 -0
- package/dist/loop/types.d.ts.map +1 -0
- package/dist/loop/types.js +11 -0
- package/dist/loop/types.js.map +1 -0
- package/dist/persistence/index.d.ts +3 -0
- package/dist/persistence/index.d.ts.map +1 -0
- package/dist/persistence/index.js +2 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/persistence/sqlite-provider.d.ts +25 -0
- package/dist/persistence/sqlite-provider.d.ts.map +1 -0
- package/dist/persistence/sqlite-provider.js +59 -0
- package/dist/persistence/sqlite-provider.js.map +1 -0
- package/dist/persistence/types.d.ts +36 -0
- package/dist/persistence/types.d.ts.map +1 -0
- package/dist/persistence/types.js +8 -0
- package/dist/persistence/types.js.map +1 -0
- package/dist/planning/gap-analysis.d.ts +72 -0
- package/dist/planning/gap-analysis.d.ts.map +1 -0
- package/dist/planning/gap-analysis.js +442 -0
- package/dist/planning/gap-analysis.js.map +1 -0
- package/dist/planning/gap-types.d.ts +29 -0
- package/dist/planning/gap-types.d.ts.map +1 -0
- package/dist/planning/gap-types.js +28 -0
- package/dist/planning/gap-types.js.map +1 -0
- package/dist/planning/planner.d.ts +421 -4
- package/dist/planning/planner.d.ts.map +1 -1
- package/dist/planning/planner.js +949 -21
- package/dist/planning/planner.js.map +1 -1
- package/dist/playbooks/generic/brainstorming.d.ts +9 -0
- package/dist/playbooks/generic/brainstorming.d.ts.map +1 -0
- package/dist/playbooks/generic/brainstorming.js +105 -0
- package/dist/playbooks/generic/brainstorming.js.map +1 -0
- package/dist/playbooks/generic/code-review.d.ts +11 -0
- package/dist/playbooks/generic/code-review.d.ts.map +1 -0
- package/dist/playbooks/generic/code-review.js +176 -0
- package/dist/playbooks/generic/code-review.js.map +1 -0
- package/dist/playbooks/generic/subagent-execution.d.ts +9 -0
- package/dist/playbooks/generic/subagent-execution.d.ts.map +1 -0
- package/dist/playbooks/generic/subagent-execution.js +68 -0
- package/dist/playbooks/generic/subagent-execution.js.map +1 -0
- package/dist/playbooks/generic/systematic-debugging.d.ts +9 -0
- package/dist/playbooks/generic/systematic-debugging.d.ts.map +1 -0
- package/dist/playbooks/generic/systematic-debugging.js +87 -0
- package/dist/playbooks/generic/systematic-debugging.js.map +1 -0
- package/dist/playbooks/generic/tdd.d.ts +9 -0
- package/dist/playbooks/generic/tdd.d.ts.map +1 -0
- package/dist/playbooks/generic/tdd.js +70 -0
- package/dist/playbooks/generic/tdd.js.map +1 -0
- package/dist/playbooks/generic/verification.d.ts +9 -0
- package/dist/playbooks/generic/verification.d.ts.map +1 -0
- package/dist/playbooks/generic/verification.js +74 -0
- package/dist/playbooks/generic/verification.js.map +1 -0
- package/dist/playbooks/index.d.ts +4 -0
- package/dist/playbooks/index.d.ts.map +1 -0
- package/dist/playbooks/index.js +5 -0
- package/dist/playbooks/index.js.map +1 -0
- package/dist/playbooks/playbook-registry.d.ts +42 -0
- package/dist/playbooks/playbook-registry.d.ts.map +1 -0
- package/dist/playbooks/playbook-registry.js +227 -0
- package/dist/playbooks/playbook-registry.js.map +1 -0
- package/dist/playbooks/playbook-seeder.d.ts +47 -0
- package/dist/playbooks/playbook-seeder.d.ts.map +1 -0
- package/dist/playbooks/playbook-seeder.js +104 -0
- package/dist/playbooks/playbook-seeder.js.map +1 -0
- package/dist/playbooks/playbook-types.d.ts +132 -0
- package/dist/playbooks/playbook-types.d.ts.map +1 -0
- package/dist/playbooks/playbook-types.js +12 -0
- package/dist/playbooks/playbook-types.js.map +1 -0
- package/dist/project/project-registry.d.ts +79 -0
- package/dist/project/project-registry.d.ts.map +1 -0
- package/dist/project/project-registry.js +274 -0
- package/dist/project/project-registry.js.map +1 -0
- package/dist/project/types.d.ts +28 -0
- package/dist/project/types.d.ts.map +1 -0
- package/dist/project/types.js +5 -0
- package/dist/project/types.js.map +1 -0
- package/dist/prompts/index.d.ts +4 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +3 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/parser.d.ts +17 -0
- package/dist/prompts/parser.d.ts.map +1 -0
- package/dist/prompts/parser.js +47 -0
- package/dist/prompts/parser.js.map +1 -0
- package/dist/prompts/template-manager.d.ts +25 -0
- package/dist/prompts/template-manager.d.ts.map +1 -0
- package/dist/prompts/template-manager.js +71 -0
- package/dist/prompts/template-manager.js.map +1 -0
- package/dist/prompts/types.d.ts +26 -0
- package/dist/prompts/types.d.ts.map +1 -0
- package/dist/prompts/types.js +5 -0
- package/dist/prompts/types.js.map +1 -0
- package/dist/runtime/admin-extra-ops.d.ts +15 -0
- package/dist/runtime/admin-extra-ops.d.ts.map +1 -0
- package/dist/runtime/admin-extra-ops.js +595 -0
- package/dist/runtime/admin-extra-ops.js.map +1 -0
- package/dist/runtime/admin-ops.d.ts +15 -0
- package/dist/runtime/admin-ops.d.ts.map +1 -0
- package/dist/runtime/admin-ops.js +329 -0
- package/dist/runtime/admin-ops.js.map +1 -0
- package/dist/runtime/capture-ops.d.ts +15 -0
- package/dist/runtime/capture-ops.d.ts.map +1 -0
- package/dist/runtime/capture-ops.js +363 -0
- package/dist/runtime/capture-ops.js.map +1 -0
- package/dist/runtime/cognee-sync-ops.d.ts +12 -0
- package/dist/runtime/cognee-sync-ops.d.ts.map +1 -0
- package/dist/runtime/cognee-sync-ops.js +55 -0
- package/dist/runtime/cognee-sync-ops.js.map +1 -0
- package/dist/runtime/core-ops.d.ts +9 -3
- package/dist/runtime/core-ops.d.ts.map +1 -1
- package/dist/runtime/core-ops.js +693 -10
- package/dist/runtime/core-ops.js.map +1 -1
- package/dist/runtime/curator-extra-ops.d.ts +9 -0
- package/dist/runtime/curator-extra-ops.d.ts.map +1 -0
- package/dist/runtime/curator-extra-ops.js +71 -0
- package/dist/runtime/curator-extra-ops.js.map +1 -0
- package/dist/runtime/domain-ops.d.ts.map +1 -1
- package/dist/runtime/domain-ops.js +61 -15
- package/dist/runtime/domain-ops.js.map +1 -1
- package/dist/runtime/grading-ops.d.ts +14 -0
- package/dist/runtime/grading-ops.d.ts.map +1 -0
- package/dist/runtime/grading-ops.js +105 -0
- package/dist/runtime/grading-ops.js.map +1 -0
- package/dist/runtime/intake-ops.d.ts +14 -0
- package/dist/runtime/intake-ops.d.ts.map +1 -0
- package/dist/runtime/intake-ops.js +110 -0
- package/dist/runtime/intake-ops.js.map +1 -0
- package/dist/runtime/loop-ops.d.ts +14 -0
- package/dist/runtime/loop-ops.d.ts.map +1 -0
- package/dist/runtime/loop-ops.js +251 -0
- package/dist/runtime/loop-ops.js.map +1 -0
- package/dist/runtime/memory-cross-project-ops.d.ts +12 -0
- package/dist/runtime/memory-cross-project-ops.d.ts.map +1 -0
- package/dist/runtime/memory-cross-project-ops.js +165 -0
- package/dist/runtime/memory-cross-project-ops.js.map +1 -0
- package/dist/runtime/memory-extra-ops.d.ts +13 -0
- package/dist/runtime/memory-extra-ops.d.ts.map +1 -0
- package/dist/runtime/memory-extra-ops.js +173 -0
- package/dist/runtime/memory-extra-ops.js.map +1 -0
- package/dist/runtime/orchestrate-ops.d.ts +17 -0
- package/dist/runtime/orchestrate-ops.d.ts.map +1 -0
- package/dist/runtime/orchestrate-ops.js +246 -0
- package/dist/runtime/orchestrate-ops.js.map +1 -0
- package/dist/runtime/planning-extra-ops.d.ts +25 -0
- package/dist/runtime/planning-extra-ops.d.ts.map +1 -0
- package/dist/runtime/planning-extra-ops.js +663 -0
- package/dist/runtime/planning-extra-ops.js.map +1 -0
- package/dist/runtime/playbook-ops.d.ts +14 -0
- package/dist/runtime/playbook-ops.d.ts.map +1 -0
- package/dist/runtime/playbook-ops.js +141 -0
- package/dist/runtime/playbook-ops.js.map +1 -0
- package/dist/runtime/project-ops.d.ts +15 -0
- package/dist/runtime/project-ops.d.ts.map +1 -0
- package/dist/runtime/project-ops.js +186 -0
- package/dist/runtime/project-ops.js.map +1 -0
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +65 -3
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/types.d.ts +29 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/vault-extra-ops.d.ts +10 -0
- package/dist/runtime/vault-extra-ops.d.ts.map +1 -0
- package/dist/runtime/vault-extra-ops.js +536 -0
- package/dist/runtime/vault-extra-ops.js.map +1 -0
- package/dist/telemetry/telemetry.d.ts +48 -0
- package/dist/telemetry/telemetry.d.ts.map +1 -0
- package/dist/telemetry/telemetry.js +87 -0
- package/dist/telemetry/telemetry.js.map +1 -0
- package/dist/vault/playbook.d.ts +34 -0
- package/dist/vault/playbook.d.ts.map +1 -0
- package/dist/vault/playbook.js +60 -0
- package/dist/vault/playbook.js.map +1 -0
- package/dist/vault/vault.d.ts +97 -4
- package/dist/vault/vault.d.ts.map +1 -1
- package/dist/vault/vault.js +424 -65
- package/dist/vault/vault.js.map +1 -1
- package/package.json +7 -3
- package/src/__tests__/admin-extra-ops.test.ts +467 -0
- package/src/__tests__/admin-ops.test.ts +271 -0
- package/src/__tests__/brain-intelligence.test.ts +205 -0
- package/src/__tests__/brain.test.ts +134 -3
- package/src/__tests__/capture-ops.test.ts +509 -0
- package/src/__tests__/cognee-integration.test.ts +80 -0
- package/src/__tests__/cognee-sync-manager.test.ts +103 -0
- package/src/__tests__/core-ops.test.ts +292 -2
- package/src/__tests__/curator-extra-ops.test.ts +381 -0
- package/src/__tests__/domain-ops.test.ts +66 -0
- package/src/__tests__/errors.test.ts +388 -0
- package/src/__tests__/governance.test.ts +522 -0
- package/src/__tests__/grading-ops.test.ts +361 -0
- package/src/__tests__/identity-manager.test.ts +243 -0
- package/src/__tests__/intake-pipeline.test.ts +162 -0
- package/src/__tests__/intent-router.test.ts +222 -0
- package/src/__tests__/logger.test.ts +200 -0
- package/src/__tests__/loop-ops.test.ts +469 -0
- package/src/__tests__/memory-cross-project-ops.test.ts +248 -0
- package/src/__tests__/memory-extra-ops.test.ts +352 -0
- package/src/__tests__/orchestrate-ops.test.ts +289 -0
- package/src/__tests__/persistence.test.ts +225 -0
- package/src/__tests__/planner.test.ts +416 -7
- package/src/__tests__/planning-extra-ops.test.ts +706 -0
- package/src/__tests__/playbook-registry.test.ts +326 -0
- package/src/__tests__/playbook-seeder.test.ts +163 -0
- package/src/__tests__/playbook.test.ts +389 -0
- package/src/__tests__/project-ops.test.ts +381 -0
- package/src/__tests__/template-manager.test.ts +222 -0
- package/src/__tests__/vault-extra-ops.test.ts +482 -0
- package/src/brain/brain.ts +185 -16
- package/src/brain/intelligence.ts +179 -10
- package/src/brain/types.ts +40 -2
- package/src/cognee/client.ts +18 -0
- package/src/cognee/sync-manager.ts +389 -0
- package/src/control/identity-manager.ts +354 -0
- package/src/control/intent-router.ts +326 -0
- package/src/control/types.ts +102 -0
- package/src/curator/curator.ts +295 -1
- package/src/errors/classify.ts +102 -0
- package/src/errors/index.ts +5 -0
- package/src/errors/retry.ts +132 -0
- package/src/errors/types.ts +81 -0
- package/src/governance/governance.ts +698 -0
- package/src/governance/index.ts +18 -0
- package/src/governance/types.ts +111 -0
- package/src/index.ts +213 -2
- package/src/intake/content-classifier.ts +146 -0
- package/src/intake/dedup-gate.ts +92 -0
- package/src/intake/intake-pipeline.ts +503 -0
- package/src/intake/types.ts +69 -0
- package/src/intelligence/loader.ts +1 -1
- package/src/intelligence/types.ts +3 -1
- package/src/logging/logger.ts +154 -0
- package/src/logging/types.ts +21 -0
- package/src/loop/loop-manager.ts +448 -0
- package/src/loop/types.ts +115 -0
- package/src/persistence/index.ts +7 -0
- package/src/persistence/sqlite-provider.ts +62 -0
- package/src/persistence/types.ts +44 -0
- package/src/planning/gap-analysis.ts +775 -0
- package/src/planning/gap-types.ts +61 -0
- package/src/planning/planner.ts +1273 -24
- package/src/playbooks/generic/brainstorming.ts +110 -0
- package/src/playbooks/generic/code-review.ts +181 -0
- package/src/playbooks/generic/subagent-execution.ts +74 -0
- package/src/playbooks/generic/systematic-debugging.ts +92 -0
- package/src/playbooks/generic/tdd.ts +75 -0
- package/src/playbooks/generic/verification.ts +79 -0
- package/src/playbooks/index.ts +27 -0
- package/src/playbooks/playbook-registry.ts +284 -0
- package/src/playbooks/playbook-seeder.ts +119 -0
- package/src/playbooks/playbook-types.ts +162 -0
- package/src/project/project-registry.ts +370 -0
- package/src/project/types.ts +31 -0
- package/src/prompts/index.ts +3 -0
- package/src/prompts/parser.ts +59 -0
- package/src/prompts/template-manager.ts +77 -0
- package/src/prompts/types.ts +28 -0
- package/src/runtime/admin-extra-ops.ts +652 -0
- package/src/runtime/admin-ops.ts +340 -0
- package/src/runtime/capture-ops.ts +404 -0
- package/src/runtime/cognee-sync-ops.ts +63 -0
- package/src/runtime/core-ops.ts +787 -9
- package/src/runtime/curator-extra-ops.ts +85 -0
- package/src/runtime/domain-ops.ts +67 -15
- package/src/runtime/grading-ops.ts +130 -0
- package/src/runtime/intake-ops.ts +126 -0
- package/src/runtime/loop-ops.ts +277 -0
- package/src/runtime/memory-cross-project-ops.ts +191 -0
- package/src/runtime/memory-extra-ops.ts +186 -0
- package/src/runtime/orchestrate-ops.ts +278 -0
- package/src/runtime/planning-extra-ops.ts +718 -0
- package/src/runtime/playbook-ops.ts +169 -0
- package/src/runtime/project-ops.ts +202 -0
- package/src/runtime/runtime.ts +77 -3
- package/src/runtime/types.ts +29 -0
- package/src/runtime/vault-extra-ops.ts +606 -0
- package/src/telemetry/telemetry.ts +118 -0
- package/src/vault/playbook.ts +87 -0
- package/src/vault/vault.ts +575 -98
package/dist/vault/vault.js
CHANGED
|
@@ -1,21 +1,39 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { mkdirSync } from 'node:fs';
|
|
3
|
-
import { dirname } from 'node:path';
|
|
1
|
+
import { SQLitePersistenceProvider } from '../persistence/sqlite-provider.js';
|
|
4
2
|
export class Vault {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
provider;
|
|
4
|
+
sqliteProvider;
|
|
5
|
+
syncManager = null;
|
|
6
|
+
/**
|
|
7
|
+
* Create a Vault with a PersistenceProvider or a SQLite path (backward compat).
|
|
8
|
+
*/
|
|
9
|
+
constructor(providerOrPath = ':memory:') {
|
|
10
|
+
if (typeof providerOrPath === 'string') {
|
|
11
|
+
const sqlite = new SQLitePersistenceProvider(providerOrPath);
|
|
12
|
+
this.provider = sqlite;
|
|
13
|
+
this.sqliteProvider = sqlite;
|
|
14
|
+
// SQLite-specific pragmas
|
|
15
|
+
this.provider.run('PRAGMA journal_mode = WAL');
|
|
16
|
+
this.provider.run('PRAGMA foreign_keys = ON');
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
this.provider = providerOrPath;
|
|
20
|
+
this.sqliteProvider =
|
|
21
|
+
providerOrPath instanceof SQLitePersistenceProvider ? providerOrPath : null;
|
|
22
|
+
}
|
|
12
23
|
this.initialize();
|
|
13
24
|
}
|
|
25
|
+
setSyncManager(mgr) {
|
|
26
|
+
this.syncManager = mgr;
|
|
27
|
+
}
|
|
28
|
+
/** Backward-compatible factory. */
|
|
29
|
+
static createWithSQLite(dbPath = ':memory:') {
|
|
30
|
+
return new Vault(dbPath);
|
|
31
|
+
}
|
|
14
32
|
initialize() {
|
|
15
|
-
this.
|
|
33
|
+
this.provider.execSql(`
|
|
16
34
|
CREATE TABLE IF NOT EXISTS entries (
|
|
17
35
|
id TEXT PRIMARY KEY,
|
|
18
|
-
type TEXT NOT NULL CHECK(type IN ('pattern', 'anti-pattern', 'rule')),
|
|
36
|
+
type TEXT NOT NULL CHECK(type IN ('pattern', 'anti-pattern', 'rule', 'playbook')),
|
|
19
37
|
domain TEXT NOT NULL,
|
|
20
38
|
title TEXT NOT NULL,
|
|
21
39
|
severity TEXT NOT NULL CHECK(severity IN ('critical', 'warning', 'suggestion')),
|
|
@@ -83,24 +101,83 @@ export class Vault {
|
|
|
83
101
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
84
102
|
query TEXT NOT NULL,
|
|
85
103
|
entry_id TEXT NOT NULL,
|
|
86
|
-
action TEXT NOT NULL CHECK(action IN ('accepted', 'dismissed')),
|
|
104
|
+
action TEXT NOT NULL CHECK(action IN ('accepted', 'dismissed', 'modified', 'failed')),
|
|
105
|
+
source TEXT NOT NULL DEFAULT 'search',
|
|
106
|
+
confidence REAL NOT NULL DEFAULT 0.6,
|
|
107
|
+
duration INTEGER,
|
|
108
|
+
context TEXT NOT NULL DEFAULT '{}',
|
|
109
|
+
reason TEXT,
|
|
87
110
|
created_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
88
111
|
);
|
|
89
112
|
CREATE INDEX IF NOT EXISTS idx_brain_feedback_query ON brain_feedback(query);
|
|
90
113
|
`);
|
|
114
|
+
this.migrateBrainSchema();
|
|
115
|
+
this.migrateTemporalSchema();
|
|
116
|
+
}
|
|
117
|
+
migrateTemporalSchema() {
|
|
118
|
+
try {
|
|
119
|
+
this.provider.run('ALTER TABLE entries ADD COLUMN valid_from INTEGER');
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// Column already exists
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
this.provider.run('ALTER TABLE entries ADD COLUMN valid_until INTEGER');
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Column already exists
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
migrateBrainSchema() {
|
|
132
|
+
const columns = this.provider.all('PRAGMA table_info(brain_feedback)');
|
|
133
|
+
const hasSource = columns.some((c) => c.name === 'source');
|
|
134
|
+
if (!hasSource && columns.length > 0) {
|
|
135
|
+
this.provider.transaction(() => {
|
|
136
|
+
this.provider.run(`
|
|
137
|
+
CREATE TABLE brain_feedback_new (
|
|
138
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
139
|
+
query TEXT NOT NULL,
|
|
140
|
+
entry_id TEXT NOT NULL,
|
|
141
|
+
action TEXT NOT NULL CHECK(action IN ('accepted', 'dismissed', 'modified', 'failed')),
|
|
142
|
+
source TEXT NOT NULL DEFAULT 'search',
|
|
143
|
+
confidence REAL NOT NULL DEFAULT 0.6,
|
|
144
|
+
duration INTEGER,
|
|
145
|
+
context TEXT NOT NULL DEFAULT '{}',
|
|
146
|
+
reason TEXT,
|
|
147
|
+
created_at INTEGER NOT NULL DEFAULT (unixepoch())
|
|
148
|
+
)
|
|
149
|
+
`);
|
|
150
|
+
this.provider.run(`
|
|
151
|
+
INSERT INTO brain_feedback_new (id, query, entry_id, action, created_at)
|
|
152
|
+
SELECT id, query, entry_id, action, created_at FROM brain_feedback
|
|
153
|
+
`);
|
|
154
|
+
this.provider.run('DROP TABLE brain_feedback');
|
|
155
|
+
this.provider.run('ALTER TABLE brain_feedback_new RENAME TO brain_feedback');
|
|
156
|
+
this.provider.run('CREATE INDEX IF NOT EXISTS idx_brain_feedback_query ON brain_feedback(query)');
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const sessionCols = this.provider.all('PRAGMA table_info(brain_sessions)');
|
|
161
|
+
if (sessionCols.length > 0 && !sessionCols.some((c) => c.name === 'extracted_at')) {
|
|
162
|
+
this.provider.run('ALTER TABLE brain_sessions ADD COLUMN extracted_at TEXT');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// brain_sessions table doesn't exist yet — BrainIntelligence will create it
|
|
167
|
+
}
|
|
91
168
|
}
|
|
92
169
|
seed(entries) {
|
|
93
|
-
const
|
|
94
|
-
INSERT INTO entries (id,type,domain,title,severity,description,context,example,counter_example,why,tags,applies_to)
|
|
95
|
-
VALUES (@id,@type,@domain,@title,@severity,@description,@context,@example,@counterExample,@why,@tags,@appliesTo)
|
|
170
|
+
const sql = `
|
|
171
|
+
INSERT INTO entries (id,type,domain,title,severity,description,context,example,counter_example,why,tags,applies_to,valid_from,valid_until)
|
|
172
|
+
VALUES (@id,@type,@domain,@title,@severity,@description,@context,@example,@counterExample,@why,@tags,@appliesTo,@validFrom,@validUntil)
|
|
96
173
|
ON CONFLICT(id) DO UPDATE SET type=excluded.type,domain=excluded.domain,title=excluded.title,severity=excluded.severity,
|
|
97
174
|
description=excluded.description,context=excluded.context,example=excluded.example,counter_example=excluded.counter_example,
|
|
98
|
-
why=excluded.why,tags=excluded.tags,applies_to=excluded.applies_to,updated_at=unixepoch()
|
|
99
|
-
|
|
100
|
-
|
|
175
|
+
why=excluded.why,tags=excluded.tags,applies_to=excluded.applies_to,valid_from=excluded.valid_from,valid_until=excluded.valid_until,updated_at=unixepoch()
|
|
176
|
+
`;
|
|
177
|
+
return this.provider.transaction(() => {
|
|
101
178
|
let count = 0;
|
|
102
|
-
for (const entry of
|
|
103
|
-
|
|
179
|
+
for (const entry of entries) {
|
|
180
|
+
this.provider.run(sql, {
|
|
104
181
|
id: entry.id,
|
|
105
182
|
type: entry.type,
|
|
106
183
|
domain: entry.domain,
|
|
@@ -113,12 +190,16 @@ export class Vault {
|
|
|
113
190
|
why: entry.why ?? null,
|
|
114
191
|
tags: JSON.stringify(entry.tags),
|
|
115
192
|
appliesTo: JSON.stringify(entry.appliesTo ?? []),
|
|
193
|
+
validFrom: entry.validFrom ?? null,
|
|
194
|
+
validUntil: entry.validUntil ?? null,
|
|
116
195
|
});
|
|
117
196
|
count++;
|
|
197
|
+
if (this.syncManager) {
|
|
198
|
+
this.syncManager.enqueue('ingest', entry.id, entry);
|
|
199
|
+
}
|
|
118
200
|
}
|
|
119
201
|
return count;
|
|
120
202
|
});
|
|
121
|
-
return tx(entries);
|
|
122
203
|
}
|
|
123
204
|
search(query, options) {
|
|
124
205
|
const limit = options?.limit ?? 10;
|
|
@@ -136,11 +217,15 @@ export class Vault {
|
|
|
136
217
|
filters.push('e.severity = @severity');
|
|
137
218
|
fp.severity = options.severity;
|
|
138
219
|
}
|
|
220
|
+
if (!options?.includeExpired) {
|
|
221
|
+
const now = Math.floor(Date.now() / 1000);
|
|
222
|
+
filters.push('(e.valid_until IS NULL OR e.valid_until > @now)');
|
|
223
|
+
filters.push('(e.valid_from IS NULL OR e.valid_from <= @now)');
|
|
224
|
+
fp.now = now;
|
|
225
|
+
}
|
|
139
226
|
const wc = filters.length > 0 ? `AND ${filters.join(' AND ')}` : '';
|
|
140
227
|
try {
|
|
141
|
-
const rows = this.
|
|
142
|
-
.prepare(`SELECT e.*, -rank as score FROM entries_fts fts JOIN entries e ON e.rowid = fts.rowid WHERE entries_fts MATCH @query ${wc} ORDER BY score DESC LIMIT @limit`)
|
|
143
|
-
.all({ query, limit, ...fp });
|
|
228
|
+
const rows = this.provider.all(`SELECT e.*, -rank as score FROM entries_fts fts JOIN entries e ON e.rowid = fts.rowid WHERE entries_fts MATCH @query ${wc} ORDER BY score DESC LIMIT @limit`, { query, limit, ...fp });
|
|
144
229
|
return rows.map(rowToSearchResult);
|
|
145
230
|
}
|
|
146
231
|
catch {
|
|
@@ -148,7 +233,9 @@ export class Vault {
|
|
|
148
233
|
}
|
|
149
234
|
}
|
|
150
235
|
get(id) {
|
|
151
|
-
const row = this.
|
|
236
|
+
const row = this.provider.get('SELECT * FROM entries WHERE id = ?', [
|
|
237
|
+
id,
|
|
238
|
+
]);
|
|
152
239
|
return row ? rowToEntry(row) : null;
|
|
153
240
|
}
|
|
154
241
|
list(options) {
|
|
@@ -173,41 +260,153 @@ export class Vault {
|
|
|
173
260
|
});
|
|
174
261
|
filters.push(`(${c.join(' OR ')})`);
|
|
175
262
|
}
|
|
263
|
+
if (!options?.includeExpired) {
|
|
264
|
+
const now = Math.floor(Date.now() / 1000);
|
|
265
|
+
filters.push('(valid_until IS NULL OR valid_until > @now)');
|
|
266
|
+
filters.push('(valid_from IS NULL OR valid_from <= @now)');
|
|
267
|
+
params.now = now;
|
|
268
|
+
}
|
|
176
269
|
const wc = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : '';
|
|
177
|
-
const rows = this.
|
|
178
|
-
.prepare(`SELECT * FROM entries ${wc} ORDER BY severity, domain, title LIMIT @limit OFFSET @offset`)
|
|
179
|
-
.all({ ...params, limit: options?.limit ?? 50, offset: options?.offset ?? 0 });
|
|
270
|
+
const rows = this.provider.all(`SELECT * FROM entries ${wc} ORDER BY severity, domain, title LIMIT @limit OFFSET @offset`, { ...params, limit: options?.limit ?? 50, offset: options?.offset ?? 0 });
|
|
180
271
|
return rows.map(rowToEntry);
|
|
181
272
|
}
|
|
182
273
|
stats() {
|
|
183
|
-
const total = this.
|
|
274
|
+
const total = this.provider.get('SELECT COUNT(*) as count FROM entries').count;
|
|
184
275
|
return {
|
|
185
276
|
totalEntries: total,
|
|
186
|
-
byType: gc(this.
|
|
187
|
-
byDomain: gc(this.
|
|
188
|
-
bySeverity: gc(this.
|
|
277
|
+
byType: gc(this.provider, 'type'),
|
|
278
|
+
byDomain: gc(this.provider, 'domain'),
|
|
279
|
+
bySeverity: gc(this.provider, 'severity'),
|
|
189
280
|
};
|
|
190
281
|
}
|
|
191
282
|
add(entry) {
|
|
192
283
|
this.seed([entry]);
|
|
193
284
|
}
|
|
194
285
|
remove(id) {
|
|
195
|
-
|
|
286
|
+
const deleted = this.provider.run('DELETE FROM entries WHERE id = ?', [id]).changes > 0;
|
|
287
|
+
if (deleted && this.syncManager) {
|
|
288
|
+
this.syncManager.enqueue('delete', id);
|
|
289
|
+
}
|
|
290
|
+
return deleted;
|
|
291
|
+
}
|
|
292
|
+
update(id, fields) {
|
|
293
|
+
const existing = this.get(id);
|
|
294
|
+
if (!existing)
|
|
295
|
+
return null;
|
|
296
|
+
const merged = { ...existing, ...fields };
|
|
297
|
+
this.seed([merged]);
|
|
298
|
+
return this.get(id);
|
|
299
|
+
}
|
|
300
|
+
setTemporal(id, validFrom, validUntil) {
|
|
301
|
+
const sets = [];
|
|
302
|
+
const params = { id };
|
|
303
|
+
if (validFrom !== undefined) {
|
|
304
|
+
sets.push('valid_from = @validFrom');
|
|
305
|
+
params.validFrom = validFrom;
|
|
306
|
+
}
|
|
307
|
+
if (validUntil !== undefined) {
|
|
308
|
+
sets.push('valid_until = @validUntil');
|
|
309
|
+
params.validUntil = validUntil;
|
|
310
|
+
}
|
|
311
|
+
if (sets.length === 0)
|
|
312
|
+
return false;
|
|
313
|
+
sets.push('updated_at = unixepoch()');
|
|
314
|
+
return (this.provider.run(`UPDATE entries SET ${sets.join(', ')} WHERE id = @id`, params).changes > 0);
|
|
315
|
+
}
|
|
316
|
+
findExpiring(withinDays) {
|
|
317
|
+
const now = Math.floor(Date.now() / 1000);
|
|
318
|
+
const cutoff = now + withinDays * 86400;
|
|
319
|
+
const rows = this.provider.all('SELECT * FROM entries WHERE valid_until IS NOT NULL AND valid_until > @now AND valid_until <= @cutoff ORDER BY valid_until ASC', { now, cutoff });
|
|
320
|
+
return rows.map(rowToEntry);
|
|
321
|
+
}
|
|
322
|
+
findExpired(limit = 50) {
|
|
323
|
+
const now = Math.floor(Date.now() / 1000);
|
|
324
|
+
const rows = this.provider.all('SELECT * FROM entries WHERE valid_until IS NOT NULL AND valid_until <= @now ORDER BY valid_until DESC LIMIT @limit', { now, limit });
|
|
325
|
+
return rows.map(rowToEntry);
|
|
326
|
+
}
|
|
327
|
+
bulkRemove(ids) {
|
|
328
|
+
return this.provider.transaction(() => {
|
|
329
|
+
let count = 0;
|
|
330
|
+
for (const id of ids) {
|
|
331
|
+
count += this.provider.run('DELETE FROM entries WHERE id = ?', [id]).changes;
|
|
332
|
+
if (this.syncManager) {
|
|
333
|
+
this.syncManager.enqueue('delete', id);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return count;
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
getTags() {
|
|
340
|
+
const rows = this.provider.all('SELECT tags FROM entries');
|
|
341
|
+
const counts = new Map();
|
|
342
|
+
for (const row of rows) {
|
|
343
|
+
const tags = JSON.parse(row.tags || '[]');
|
|
344
|
+
for (const tag of tags) {
|
|
345
|
+
counts.set(tag, (counts.get(tag) ?? 0) + 1);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return Array.from(counts.entries())
|
|
349
|
+
.map(([tag, count]) => ({ tag, count }))
|
|
350
|
+
.sort((a, b) => b.count - a.count);
|
|
351
|
+
}
|
|
352
|
+
getDomains() {
|
|
353
|
+
return this.provider.all('SELECT domain, COUNT(*) as count FROM entries GROUP BY domain ORDER BY count DESC');
|
|
354
|
+
}
|
|
355
|
+
getRecent(limit = 20) {
|
|
356
|
+
const rows = this.provider.all('SELECT * FROM entries ORDER BY updated_at DESC LIMIT ?', [limit]);
|
|
357
|
+
return rows.map(rowToEntry);
|
|
358
|
+
}
|
|
359
|
+
exportAll() {
|
|
360
|
+
const rows = this.provider.all('SELECT * FROM entries ORDER BY domain, title');
|
|
361
|
+
const entries = rows.map(rowToEntry);
|
|
362
|
+
return { entries, exportedAt: Math.floor(Date.now() / 1000), count: entries.length };
|
|
363
|
+
}
|
|
364
|
+
getAgeReport() {
|
|
365
|
+
const rows = this.provider.all('SELECT created_at, updated_at FROM entries');
|
|
366
|
+
const now = Math.floor(Date.now() / 1000);
|
|
367
|
+
const bucketDefs = [
|
|
368
|
+
{ label: 'today', minDays: 0, maxDays: 1 },
|
|
369
|
+
{ label: 'this_week', minDays: 1, maxDays: 7 },
|
|
370
|
+
{ label: 'this_month', minDays: 7, maxDays: 30 },
|
|
371
|
+
{ label: 'this_quarter', minDays: 30, maxDays: 90 },
|
|
372
|
+
{ label: 'older', minDays: 90, maxDays: Infinity },
|
|
373
|
+
];
|
|
374
|
+
const counts = new Array(bucketDefs.length).fill(0);
|
|
375
|
+
let oldest = null;
|
|
376
|
+
let newest = null;
|
|
377
|
+
for (const row of rows) {
|
|
378
|
+
const ts = row.created_at;
|
|
379
|
+
if (oldest === null || ts < oldest)
|
|
380
|
+
oldest = ts;
|
|
381
|
+
if (newest === null || ts > newest)
|
|
382
|
+
newest = ts;
|
|
383
|
+
const ageDays = (now - ts) / 86400;
|
|
384
|
+
for (let i = 0; i < bucketDefs.length; i++) {
|
|
385
|
+
if (ageDays >= bucketDefs[i].minDays && ageDays < bucketDefs[i].maxDays) {
|
|
386
|
+
counts[i]++;
|
|
387
|
+
break;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return {
|
|
392
|
+
total: rows.length,
|
|
393
|
+
buckets: bucketDefs.map((b, i) => ({ ...b, count: counts[i] })),
|
|
394
|
+
oldestTimestamp: oldest,
|
|
395
|
+
newestTimestamp: newest,
|
|
396
|
+
};
|
|
196
397
|
}
|
|
197
398
|
registerProject(path, name) {
|
|
198
399
|
const projectName = name ?? path.replace(/\/$/, '').split('/').pop() ?? path;
|
|
199
400
|
const existing = this.getProject(path);
|
|
200
401
|
if (existing) {
|
|
201
|
-
this.
|
|
202
|
-
.prepare('UPDATE projects SET last_seen_at = unixepoch(), session_count = session_count + 1 WHERE path = ?')
|
|
203
|
-
.run(path);
|
|
402
|
+
this.provider.run('UPDATE projects SET last_seen_at = unixepoch(), session_count = session_count + 1 WHERE path = ?', [path]);
|
|
204
403
|
return this.getProject(path);
|
|
205
404
|
}
|
|
206
|
-
this.
|
|
405
|
+
this.provider.run('INSERT INTO projects (path, name) VALUES (?, ?)', [path, projectName]);
|
|
207
406
|
return this.getProject(path);
|
|
208
407
|
}
|
|
209
408
|
getProject(path) {
|
|
210
|
-
const row = this.
|
|
409
|
+
const row = this.provider.get('SELECT * FROM projects WHERE path = ?', [path]);
|
|
211
410
|
if (!row)
|
|
212
411
|
return null;
|
|
213
412
|
return {
|
|
@@ -219,9 +418,7 @@ export class Vault {
|
|
|
219
418
|
};
|
|
220
419
|
}
|
|
221
420
|
listProjects() {
|
|
222
|
-
const rows = this.
|
|
223
|
-
.prepare('SELECT * FROM projects ORDER BY last_seen_at DESC')
|
|
224
|
-
.all();
|
|
421
|
+
const rows = this.provider.all('SELECT * FROM projects ORDER BY last_seen_at DESC');
|
|
225
422
|
return rows.map((row) => ({
|
|
226
423
|
path: row.path,
|
|
227
424
|
name: row.name,
|
|
@@ -232,9 +429,7 @@ export class Vault {
|
|
|
232
429
|
}
|
|
233
430
|
captureMemory(memory) {
|
|
234
431
|
const id = `mem-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
235
|
-
this.
|
|
236
|
-
.prepare(`INSERT INTO memories (id, project_path, type, context, summary, topics, files_modified, tools_used) VALUES (@id, @projectPath, @type, @context, @summary, @topics, @filesModified, @toolsUsed)`)
|
|
237
|
-
.run({
|
|
432
|
+
this.provider.run(`INSERT INTO memories (id, project_path, type, context, summary, topics, files_modified, tools_used) VALUES (@id, @projectPath, @type, @context, @summary, @topics, @filesModified, @toolsUsed)`, {
|
|
238
433
|
id,
|
|
239
434
|
projectPath: memory.projectPath,
|
|
240
435
|
type: memory.type,
|
|
@@ -260,9 +455,7 @@ export class Vault {
|
|
|
260
455
|
}
|
|
261
456
|
const wc = filters.length > 0 ? `AND ${filters.join(' AND ')}` : '';
|
|
262
457
|
try {
|
|
263
|
-
const rows = this.
|
|
264
|
-
.prepare(`SELECT m.* FROM memories_fts fts JOIN memories m ON m.rowid = fts.rowid WHERE memories_fts MATCH @query ${wc} ORDER BY rank LIMIT @limit`)
|
|
265
|
-
.all({ query, limit, ...fp });
|
|
458
|
+
const rows = this.provider.all(`SELECT m.* FROM memories_fts fts JOIN memories m ON m.rowid = fts.rowid WHERE memories_fts MATCH @query ${wc} ORDER BY rank LIMIT @limit`, { query, limit, ...fp });
|
|
266
459
|
return rows.map(rowToMemory);
|
|
267
460
|
}
|
|
268
461
|
catch {
|
|
@@ -281,19 +474,13 @@ export class Vault {
|
|
|
281
474
|
params.projectPath = options.projectPath;
|
|
282
475
|
}
|
|
283
476
|
const wc = `WHERE ${filters.join(' AND ')}`;
|
|
284
|
-
const rows = this.
|
|
285
|
-
.prepare(`SELECT * FROM memories ${wc} ORDER BY created_at DESC LIMIT @limit OFFSET @offset`)
|
|
286
|
-
.all({ ...params, limit: options?.limit ?? 50, offset: options?.offset ?? 0 });
|
|
477
|
+
const rows = this.provider.all(`SELECT * FROM memories ${wc} ORDER BY created_at DESC LIMIT @limit OFFSET @offset`, { ...params, limit: options?.limit ?? 50, offset: options?.offset ?? 0 });
|
|
287
478
|
return rows.map(rowToMemory);
|
|
288
479
|
}
|
|
289
480
|
memoryStats() {
|
|
290
|
-
const total = this.
|
|
291
|
-
const byTypeRows = this.
|
|
292
|
-
|
|
293
|
-
.all();
|
|
294
|
-
const byProjectRows = this.db
|
|
295
|
-
.prepare('SELECT project_path as key, COUNT(*) as count FROM memories WHERE archived_at IS NULL GROUP BY project_path')
|
|
296
|
-
.all();
|
|
481
|
+
const total = this.provider.get('SELECT COUNT(*) as count FROM memories WHERE archived_at IS NULL').count;
|
|
482
|
+
const byTypeRows = this.provider.all('SELECT type as key, COUNT(*) as count FROM memories WHERE archived_at IS NULL GROUP BY type');
|
|
483
|
+
const byProjectRows = this.provider.all('SELECT project_path as key, COUNT(*) as count FROM memories WHERE archived_at IS NULL GROUP BY project_path');
|
|
297
484
|
return {
|
|
298
485
|
total,
|
|
299
486
|
byType: Object.fromEntries(byTypeRows.map((r) => [r.key, r.count])),
|
|
@@ -301,20 +488,190 @@ export class Vault {
|
|
|
301
488
|
};
|
|
302
489
|
}
|
|
303
490
|
getMemory(id) {
|
|
304
|
-
const row = this.
|
|
491
|
+
const row = this.provider.get('SELECT * FROM memories WHERE id = ?', [
|
|
492
|
+
id,
|
|
493
|
+
]);
|
|
305
494
|
return row ? rowToMemory(row) : null;
|
|
306
495
|
}
|
|
496
|
+
deleteMemory(id) {
|
|
497
|
+
return this.provider.run('DELETE FROM memories WHERE id = ?', [id]).changes > 0;
|
|
498
|
+
}
|
|
499
|
+
memoryStatsDetailed(options) {
|
|
500
|
+
const filters = [];
|
|
501
|
+
const params = {};
|
|
502
|
+
if (options?.projectPath) {
|
|
503
|
+
filters.push('project_path = @projectPath');
|
|
504
|
+
params.projectPath = options.projectPath;
|
|
505
|
+
}
|
|
506
|
+
if (options?.fromDate) {
|
|
507
|
+
filters.push('created_at >= @fromDate');
|
|
508
|
+
params.fromDate = options.fromDate;
|
|
509
|
+
}
|
|
510
|
+
if (options?.toDate) {
|
|
511
|
+
filters.push('created_at <= @toDate');
|
|
512
|
+
params.toDate = options.toDate;
|
|
513
|
+
}
|
|
514
|
+
const wc = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : '';
|
|
515
|
+
const total = this.provider.get(`SELECT COUNT(*) as count FROM memories ${wc}${wc ? ' AND' : ' WHERE'} archived_at IS NULL`, params).count;
|
|
516
|
+
const archivedCount = this.provider.get(`SELECT COUNT(*) as count FROM memories ${wc}${wc ? ' AND' : ' WHERE'} archived_at IS NOT NULL`, params).count;
|
|
517
|
+
const byTypeRows = this.provider.all(`SELECT type as key, COUNT(*) as count FROM memories ${wc}${wc ? ' AND' : ' WHERE'} archived_at IS NULL GROUP BY type`, params);
|
|
518
|
+
const byProjectRows = this.provider.all(`SELECT project_path as key, COUNT(*) as count FROM memories ${wc}${wc ? ' AND' : ' WHERE'} archived_at IS NULL GROUP BY project_path`, params);
|
|
519
|
+
const dateRange = this.provider.get(`SELECT MIN(created_at) as oldest, MAX(created_at) as newest FROM memories ${wc}${wc ? ' AND' : ' WHERE'} archived_at IS NULL`, params);
|
|
520
|
+
return {
|
|
521
|
+
total,
|
|
522
|
+
byType: Object.fromEntries(byTypeRows.map((r) => [r.key, r.count])),
|
|
523
|
+
byProject: Object.fromEntries(byProjectRows.map((r) => [r.key, r.count])),
|
|
524
|
+
oldest: dateRange.oldest,
|
|
525
|
+
newest: dateRange.newest,
|
|
526
|
+
archivedCount,
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
exportMemories(options) {
|
|
530
|
+
const filters = [];
|
|
531
|
+
const params = {};
|
|
532
|
+
if (!options?.includeArchived) {
|
|
533
|
+
filters.push('archived_at IS NULL');
|
|
534
|
+
}
|
|
535
|
+
if (options?.projectPath) {
|
|
536
|
+
filters.push('project_path = @projectPath');
|
|
537
|
+
params.projectPath = options.projectPath;
|
|
538
|
+
}
|
|
539
|
+
if (options?.type) {
|
|
540
|
+
filters.push('type = @type');
|
|
541
|
+
params.type = options.type;
|
|
542
|
+
}
|
|
543
|
+
const wc = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : '';
|
|
544
|
+
const rows = this.provider.all(`SELECT * FROM memories ${wc} ORDER BY created_at ASC`, Object.keys(params).length > 0 ? params : undefined);
|
|
545
|
+
return rows.map(rowToMemory);
|
|
546
|
+
}
|
|
547
|
+
importMemories(memories) {
|
|
548
|
+
const sql = `
|
|
549
|
+
INSERT OR IGNORE INTO memories (id, project_path, type, context, summary, topics, files_modified, tools_used, created_at, archived_at)
|
|
550
|
+
VALUES (@id, @projectPath, @type, @context, @summary, @topics, @filesModified, @toolsUsed, @createdAt, @archivedAt)
|
|
551
|
+
`;
|
|
552
|
+
let imported = 0;
|
|
553
|
+
let skipped = 0;
|
|
554
|
+
this.provider.transaction(() => {
|
|
555
|
+
for (const m of memories) {
|
|
556
|
+
const result = this.provider.run(sql, {
|
|
557
|
+
id: m.id,
|
|
558
|
+
projectPath: m.projectPath,
|
|
559
|
+
type: m.type,
|
|
560
|
+
context: m.context,
|
|
561
|
+
summary: m.summary,
|
|
562
|
+
topics: JSON.stringify(m.topics),
|
|
563
|
+
filesModified: JSON.stringify(m.filesModified),
|
|
564
|
+
toolsUsed: JSON.stringify(m.toolsUsed),
|
|
565
|
+
createdAt: m.createdAt,
|
|
566
|
+
archivedAt: m.archivedAt,
|
|
567
|
+
});
|
|
568
|
+
if (result.changes > 0)
|
|
569
|
+
imported++;
|
|
570
|
+
else
|
|
571
|
+
skipped++;
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
return { imported, skipped };
|
|
575
|
+
}
|
|
576
|
+
pruneMemories(olderThanDays) {
|
|
577
|
+
const cutoff = Math.floor(Date.now() / 1000) - olderThanDays * 86400;
|
|
578
|
+
const result = this.provider.run('DELETE FROM memories WHERE created_at < ? AND archived_at IS NULL', [cutoff]);
|
|
579
|
+
return { pruned: result.changes };
|
|
580
|
+
}
|
|
581
|
+
deduplicateMemories() {
|
|
582
|
+
const dupeRows = this.provider.all(`
|
|
583
|
+
SELECT m1.id as id1, m2.id as id2
|
|
584
|
+
FROM memories m1
|
|
585
|
+
JOIN memories m2 ON m1.summary = m2.summary
|
|
586
|
+
AND m1.project_path = m2.project_path
|
|
587
|
+
AND m1.type = m2.type
|
|
588
|
+
AND m1.id < m2.id
|
|
589
|
+
AND m1.archived_at IS NULL
|
|
590
|
+
AND m2.archived_at IS NULL
|
|
591
|
+
`);
|
|
592
|
+
const groupMap = new Map();
|
|
593
|
+
for (const row of dupeRows) {
|
|
594
|
+
if (!groupMap.has(row.id1))
|
|
595
|
+
groupMap.set(row.id1, new Set());
|
|
596
|
+
groupMap.get(row.id1).add(row.id2);
|
|
597
|
+
}
|
|
598
|
+
const groups = [];
|
|
599
|
+
const toRemove = new Set();
|
|
600
|
+
for (const [kept, removedSet] of groupMap) {
|
|
601
|
+
const removed = [...removedSet].filter((id) => !toRemove.has(id));
|
|
602
|
+
if (removed.length > 0) {
|
|
603
|
+
groups.push({ kept, removed });
|
|
604
|
+
for (const id of removed)
|
|
605
|
+
toRemove.add(id);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
if (toRemove.size > 0) {
|
|
609
|
+
this.provider.transaction(() => {
|
|
610
|
+
for (const id of toRemove) {
|
|
611
|
+
this.provider.run('DELETE FROM memories WHERE id = ?', [id]);
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
return { removed: toRemove.size, groups };
|
|
616
|
+
}
|
|
617
|
+
memoryTopics() {
|
|
618
|
+
const rows = this.provider.all('SELECT topics FROM memories WHERE archived_at IS NULL');
|
|
619
|
+
const topicCounts = new Map();
|
|
620
|
+
for (const row of rows) {
|
|
621
|
+
const topics = JSON.parse(row.topics || '[]');
|
|
622
|
+
for (const topic of topics) {
|
|
623
|
+
topicCounts.set(topic, (topicCounts.get(topic) ?? 0) + 1);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return [...topicCounts.entries()]
|
|
627
|
+
.map(([topic, count]) => ({ topic, count }))
|
|
628
|
+
.sort((a, b) => b.count - a.count);
|
|
629
|
+
}
|
|
630
|
+
memoriesByProject() {
|
|
631
|
+
const rows = this.provider.all('SELECT project_path as project, COUNT(*) as count FROM memories WHERE archived_at IS NULL GROUP BY project_path ORDER BY count DESC');
|
|
632
|
+
return rows.map((row) => {
|
|
633
|
+
const memories = this.provider.all('SELECT * FROM memories WHERE project_path = ? AND archived_at IS NULL ORDER BY created_at DESC', [row.project]);
|
|
634
|
+
return {
|
|
635
|
+
project: row.project,
|
|
636
|
+
count: row.count,
|
|
637
|
+
memories: memories.map(rowToMemory),
|
|
638
|
+
};
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Rebuild the FTS5 index for the entries table.
|
|
643
|
+
* Useful after bulk operations or if the index gets out of sync.
|
|
644
|
+
*/
|
|
645
|
+
rebuildFtsIndex() {
|
|
646
|
+
try {
|
|
647
|
+
this.provider.run("INSERT INTO entries_fts(entries_fts) VALUES('rebuild')");
|
|
648
|
+
}
|
|
649
|
+
catch {
|
|
650
|
+
// Graceful degradation — FTS rebuild failed (e.g. table doesn't exist yet)
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Get the underlying persistence provider.
|
|
655
|
+
*/
|
|
656
|
+
getProvider() {
|
|
657
|
+
return this.provider;
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Get the raw better-sqlite3 Database (backward compat).
|
|
661
|
+
* Throws if the provider is not SQLite.
|
|
662
|
+
*/
|
|
307
663
|
getDb() {
|
|
308
|
-
|
|
664
|
+
if (this.sqliteProvider) {
|
|
665
|
+
return this.sqliteProvider.getDatabase();
|
|
666
|
+
}
|
|
667
|
+
throw new Error('getDb() is only available with SQLite provider');
|
|
309
668
|
}
|
|
310
669
|
close() {
|
|
311
|
-
this.
|
|
670
|
+
this.provider.close();
|
|
312
671
|
}
|
|
313
672
|
}
|
|
314
|
-
function gc(
|
|
315
|
-
const rows =
|
|
316
|
-
.prepare(`SELECT ${col} as key, COUNT(*) as count FROM entries GROUP BY ${col}`)
|
|
317
|
-
.all();
|
|
673
|
+
function gc(provider, col) {
|
|
674
|
+
const rows = provider.all(`SELECT ${col} as key, COUNT(*) as count FROM entries GROUP BY ${col}`);
|
|
318
675
|
return Object.fromEntries(rows.map((r) => [r.key, r.count]));
|
|
319
676
|
}
|
|
320
677
|
function rowToEntry(row) {
|
|
@@ -331,6 +688,8 @@ function rowToEntry(row) {
|
|
|
331
688
|
why: row.why ?? undefined,
|
|
332
689
|
tags: JSON.parse(row.tags || '[]'),
|
|
333
690
|
appliesTo: JSON.parse(row.applies_to || '[]'),
|
|
691
|
+
validFrom: row.valid_from ?? undefined,
|
|
692
|
+
validUntil: row.valid_until ?? undefined,
|
|
334
693
|
};
|
|
335
694
|
}
|
|
336
695
|
function rowToSearchResult(row) {
|