hippo-memory 1.17.0 → 1.19.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/bin/hippo.js +2 -2
- package/dist/api.d.ts +43 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +109 -7
- package/dist/api.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +109 -11
- package/dist/cli.js.map +1 -1
- package/dist/connectors/github/backfill.js +4 -4
- package/dist/connectors/github/cli-impl.js +6 -6
- package/dist/connectors/github/dlq.js +14 -14
- package/dist/connectors/slack/backfill.js +1 -1
- package/dist/connectors/slack/dlq.js +10 -10
- package/dist/connectors/slack/workspaces.js +4 -4
- package/dist/customer-notes.d.ts.map +1 -1
- package/dist/customer-notes.js +5 -1
- package/dist/customer-notes.js.map +1 -1
- package/dist/dag.js +6 -6
- package/dist/dashboard.js +7 -7
- package/dist/decisions.d.ts.map +1 -1
- package/dist/decisions.js +9 -1
- package/dist/decisions.js.map +1 -1
- package/dist/goals.d.ts +11 -0
- package/dist/goals.d.ts.map +1 -1
- package/dist/goals.js +61 -49
- package/dist/goals.js.map +1 -1
- package/dist/graph-extract.d.ts.map +1 -1
- package/dist/graph-extract.js +32 -12
- package/dist/graph-extract.js.map +1 -1
- package/dist/graph.d.ts +46 -3
- package/dist/graph.d.ts.map +1 -1
- package/dist/graph.js +116 -8
- package/dist/graph.js.map +1 -1
- package/dist/hooks.js +24 -24
- package/dist/physics-state.js +27 -27
- package/dist/policies.d.ts.map +1 -1
- package/dist/policies.js +5 -1
- package/dist/policies.js.map +1 -1
- package/dist/predictions.js +67 -67
- package/dist/project-briefs.d.ts.map +1 -1
- package/dist/project-briefs.js +6 -1
- package/dist/project-briefs.js.map +1 -1
- package/dist/refine-llm.js +13 -13
- package/dist/search.d.ts +33 -0
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +7 -0
- package/dist/server.js.map +1 -1
- package/dist/sleep-redact.d.ts +1 -0
- package/dist/sleep-redact.d.ts.map +1 -1
- package/dist/sleep-redact.js +6 -0
- package/dist/sleep-redact.js.map +1 -1
- package/dist/src/api.js +109 -7
- package/dist/src/api.js.map +1 -1
- package/dist/src/cli.js +109 -11
- package/dist/src/cli.js.map +1 -1
- package/dist/src/connectors/github/backfill.js +4 -4
- package/dist/src/connectors/github/cli-impl.js +6 -6
- package/dist/src/connectors/github/dlq.js +14 -14
- package/dist/src/connectors/slack/backfill.js +1 -1
- package/dist/src/connectors/slack/dlq.js +10 -10
- package/dist/src/connectors/slack/workspaces.js +4 -4
- package/dist/src/customer-notes.js +5 -1
- package/dist/src/customer-notes.js.map +1 -1
- package/dist/src/dag.js +6 -6
- package/dist/src/dashboard.js +7 -7
- package/dist/src/decisions.js +9 -1
- package/dist/src/decisions.js.map +1 -1
- package/dist/src/goals.js +61 -49
- package/dist/src/goals.js.map +1 -1
- package/dist/src/graph-extract.js +32 -12
- package/dist/src/graph-extract.js.map +1 -1
- package/dist/src/graph.js +116 -8
- package/dist/src/graph.js.map +1 -1
- package/dist/src/hooks.js +24 -24
- package/dist/src/physics-state.js +27 -27
- package/dist/src/policies.js +5 -1
- package/dist/src/policies.js.map +1 -1
- package/dist/src/predictions.js +67 -67
- package/dist/src/project-briefs.js +6 -1
- package/dist/src/project-briefs.js.map +1 -1
- package/dist/src/refine-llm.js +13 -13
- package/dist/src/search.js.map +1 -1
- package/dist/src/server.js +7 -0
- package/dist/src/server.js.map +1 -1
- package/dist/src/sleep-redact.js +6 -0
- package/dist/src/sleep-redact.js.map +1 -1
- package/dist/src/store.js +261 -260
- package/dist/src/store.js.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/working-memory.js +19 -19
- package/dist/store.d.ts +6 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +261 -260
- package/dist/store.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/working-memory.js +19 -19
- package/dist-ui/index.html +12 -12
- package/extensions/openclaw-plugin/index.ts +650 -650
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/dist/benchmarks/e1.3/scenarios.json +0 -2587
package/dist/store.js
CHANGED
|
@@ -535,13 +535,13 @@ function loadSearchRows(db, query, limit, tenantId, scopeFilter) {
|
|
|
535
535
|
// F1 (v1.7.0): MEMORY_SEARCH_COLUMNS adds bm25_score as the trailing
|
|
536
536
|
// result column. Every other column is m.<col> AS <col> so rowToEntry
|
|
537
537
|
// sees the same shape it always has.
|
|
538
|
-
const rows = db.prepare(`
|
|
539
|
-
SELECT ${MEMORY_SEARCH_COLUMNS}
|
|
540
|
-
FROM memories m
|
|
541
|
-
JOIN memories_fts f ON f.id = m.id
|
|
542
|
-
WHERE memories_fts MATCH ?${tenantPredicate}${archivedClauseAlias}${scopeClauseAlias}
|
|
543
|
-
ORDER BY bm25(memories_fts), m.updated_at DESC
|
|
544
|
-
LIMIT ?
|
|
538
|
+
const rows = db.prepare(`
|
|
539
|
+
SELECT ${MEMORY_SEARCH_COLUMNS}
|
|
540
|
+
FROM memories m
|
|
541
|
+
JOIN memories_fts f ON f.id = m.id
|
|
542
|
+
WHERE memories_fts MATCH ?${tenantPredicate}${archivedClauseAlias}${scopeClauseAlias}
|
|
543
|
+
ORDER BY bm25(memories_fts), m.updated_at DESC
|
|
544
|
+
LIMIT ?
|
|
545
545
|
`).all(ftsQuery, ...tenantParams, ...scopeParams, limit);
|
|
546
546
|
if (rows.length > 0)
|
|
547
547
|
return rows;
|
|
@@ -556,12 +556,12 @@ function loadSearchRows(db, query, limit, tenantId, scopeFilter) {
|
|
|
556
556
|
const like = `%${escapeLike(term)}%`;
|
|
557
557
|
return [like, like];
|
|
558
558
|
});
|
|
559
|
-
const rows = db.prepare(`
|
|
560
|
-
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
561
|
-
FROM memories
|
|
562
|
-
WHERE (${where})${tenantPredicateNoAlias}${archivedClauseNoAlias}${scopeClauseNoAlias}
|
|
563
|
-
ORDER BY updated_at DESC, created DESC
|
|
564
|
-
LIMIT ?
|
|
559
|
+
const rows = db.prepare(`
|
|
560
|
+
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
561
|
+
FROM memories
|
|
562
|
+
WHERE (${where})${tenantPredicateNoAlias}${archivedClauseNoAlias}${scopeClauseNoAlias}
|
|
563
|
+
ORDER BY updated_at DESC, created DESC
|
|
564
|
+
LIMIT ?
|
|
565
565
|
`).all(...params, ...tenantParams, ...scopeParams, limit);
|
|
566
566
|
if (rows.length > 0)
|
|
567
567
|
return rows;
|
|
@@ -674,60 +674,60 @@ function loadLegacyStatsFile(hippoRoot) {
|
|
|
674
674
|
}
|
|
675
675
|
}
|
|
676
676
|
function upsertEntryRow(db, entry) {
|
|
677
|
-
db.prepare(`
|
|
678
|
-
INSERT INTO memories(
|
|
679
|
-
id, created, last_retrieved, retrieval_count, strength, half_life_days, layer,
|
|
680
|
-
tags_json, emotional_valence, schema_fit, source, outcome_score,
|
|
681
|
-
outcome_positive, outcome_negative,
|
|
682
|
-
conflicts_with_json, pinned, confidence, content,
|
|
683
|
-
parents_json, starred,
|
|
684
|
-
trace_outcome, source_session_id,
|
|
685
|
-
valid_from, superseded_by,
|
|
686
|
-
extracted_from,
|
|
687
|
-
dag_level, dag_parent_id,
|
|
688
|
-
kind, scope, owner, artifact_ref,
|
|
689
|
-
tenant_id,
|
|
690
|
-
descendant_count, earliest_at, latest_at,
|
|
691
|
-
dag_level_3_built_at,
|
|
692
|
-
updated_at
|
|
693
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
694
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
695
|
-
created = excluded.created,
|
|
696
|
-
last_retrieved = excluded.last_retrieved,
|
|
697
|
-
retrieval_count = excluded.retrieval_count,
|
|
698
|
-
strength = excluded.strength,
|
|
699
|
-
half_life_days = excluded.half_life_days,
|
|
700
|
-
layer = excluded.layer,
|
|
701
|
-
tags_json = excluded.tags_json,
|
|
702
|
-
emotional_valence = excluded.emotional_valence,
|
|
703
|
-
schema_fit = excluded.schema_fit,
|
|
704
|
-
source = excluded.source,
|
|
705
|
-
outcome_score = excluded.outcome_score,
|
|
706
|
-
outcome_positive = excluded.outcome_positive,
|
|
707
|
-
outcome_negative = excluded.outcome_negative,
|
|
708
|
-
conflicts_with_json = excluded.conflicts_with_json,
|
|
709
|
-
pinned = excluded.pinned,
|
|
710
|
-
confidence = excluded.confidence,
|
|
711
|
-
content = excluded.content,
|
|
712
|
-
parents_json = excluded.parents_json,
|
|
713
|
-
starred = excluded.starred,
|
|
714
|
-
trace_outcome = excluded.trace_outcome,
|
|
715
|
-
source_session_id = excluded.source_session_id,
|
|
716
|
-
valid_from = excluded.valid_from,
|
|
717
|
-
superseded_by = excluded.superseded_by,
|
|
718
|
-
extracted_from = excluded.extracted_from,
|
|
719
|
-
dag_level = excluded.dag_level,
|
|
720
|
-
dag_parent_id = excluded.dag_parent_id,
|
|
721
|
-
kind = excluded.kind,
|
|
722
|
-
scope = excluded.scope,
|
|
723
|
-
owner = excluded.owner,
|
|
724
|
-
artifact_ref = excluded.artifact_ref,
|
|
725
|
-
tenant_id = excluded.tenant_id,
|
|
726
|
-
descendant_count = excluded.descendant_count,
|
|
727
|
-
earliest_at = excluded.earliest_at,
|
|
728
|
-
latest_at = excluded.latest_at,
|
|
729
|
-
dag_level_3_built_at = excluded.dag_level_3_built_at,
|
|
730
|
-
updated_at = datetime('now')
|
|
677
|
+
db.prepare(`
|
|
678
|
+
INSERT INTO memories(
|
|
679
|
+
id, created, last_retrieved, retrieval_count, strength, half_life_days, layer,
|
|
680
|
+
tags_json, emotional_valence, schema_fit, source, outcome_score,
|
|
681
|
+
outcome_positive, outcome_negative,
|
|
682
|
+
conflicts_with_json, pinned, confidence, content,
|
|
683
|
+
parents_json, starred,
|
|
684
|
+
trace_outcome, source_session_id,
|
|
685
|
+
valid_from, superseded_by,
|
|
686
|
+
extracted_from,
|
|
687
|
+
dag_level, dag_parent_id,
|
|
688
|
+
kind, scope, owner, artifact_ref,
|
|
689
|
+
tenant_id,
|
|
690
|
+
descendant_count, earliest_at, latest_at,
|
|
691
|
+
dag_level_3_built_at,
|
|
692
|
+
updated_at
|
|
693
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
694
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
695
|
+
created = excluded.created,
|
|
696
|
+
last_retrieved = excluded.last_retrieved,
|
|
697
|
+
retrieval_count = excluded.retrieval_count,
|
|
698
|
+
strength = excluded.strength,
|
|
699
|
+
half_life_days = excluded.half_life_days,
|
|
700
|
+
layer = excluded.layer,
|
|
701
|
+
tags_json = excluded.tags_json,
|
|
702
|
+
emotional_valence = excluded.emotional_valence,
|
|
703
|
+
schema_fit = excluded.schema_fit,
|
|
704
|
+
source = excluded.source,
|
|
705
|
+
outcome_score = excluded.outcome_score,
|
|
706
|
+
outcome_positive = excluded.outcome_positive,
|
|
707
|
+
outcome_negative = excluded.outcome_negative,
|
|
708
|
+
conflicts_with_json = excluded.conflicts_with_json,
|
|
709
|
+
pinned = excluded.pinned,
|
|
710
|
+
confidence = excluded.confidence,
|
|
711
|
+
content = excluded.content,
|
|
712
|
+
parents_json = excluded.parents_json,
|
|
713
|
+
starred = excluded.starred,
|
|
714
|
+
trace_outcome = excluded.trace_outcome,
|
|
715
|
+
source_session_id = excluded.source_session_id,
|
|
716
|
+
valid_from = excluded.valid_from,
|
|
717
|
+
superseded_by = excluded.superseded_by,
|
|
718
|
+
extracted_from = excluded.extracted_from,
|
|
719
|
+
dag_level = excluded.dag_level,
|
|
720
|
+
dag_parent_id = excluded.dag_parent_id,
|
|
721
|
+
kind = excluded.kind,
|
|
722
|
+
scope = excluded.scope,
|
|
723
|
+
owner = excluded.owner,
|
|
724
|
+
artifact_ref = excluded.artifact_ref,
|
|
725
|
+
tenant_id = excluded.tenant_id,
|
|
726
|
+
descendant_count = excluded.descendant_count,
|
|
727
|
+
earliest_at = excluded.earliest_at,
|
|
728
|
+
latest_at = excluded.latest_at,
|
|
729
|
+
dag_level_3_built_at = excluded.dag_level_3_built_at,
|
|
730
|
+
updated_at = datetime('now')
|
|
731
731
|
`).run(entry.id, entry.created, entry.last_retrieved, entry.retrieval_count, entry.strength, entry.half_life_days, entry.layer, JSON.stringify(entry.tags ?? []), entry.emotional_valence, entry.schema_fit, entry.source, entry.outcome_score, entry.outcome_positive ?? 0, entry.outcome_negative ?? 0, JSON.stringify(entry.conflicts_with ?? []), entry.pinned ? 1 : 0, entry.confidence, entry.content, JSON.stringify(entry.parents ?? []), entry.starred ? 1 : 0, entry.trace_outcome ?? null, entry.source_session_id ?? null, entry.valid_from ?? entry.created, entry.superseded_by ?? null, entry.extracted_from ?? null, entry.dag_level ?? 0, entry.dag_parent_id ?? null, entry.kind ?? 'distilled', entry.scope ?? null, entry.owner ?? null, entry.artifact_ref ?? null, entry.tenantId ?? 'default', entry.descendant_count ?? 0, entry.earliest_at ?? null, entry.latest_at ?? null, entry.dag_level_3_built_at ?? null);
|
|
732
732
|
syncFtsRow(db, entry);
|
|
733
733
|
}
|
|
@@ -794,11 +794,11 @@ function syncMirrorFiles(hippoRoot, db) {
|
|
|
794
794
|
for (const entry of entries.map(rowToEntry)) {
|
|
795
795
|
writeMarkdownMirror(hippoRoot, entry);
|
|
796
796
|
}
|
|
797
|
-
const conflicts = db.prepare(`
|
|
798
|
-
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
799
|
-
FROM memory_conflicts
|
|
800
|
-
WHERE status = 'open'
|
|
801
|
-
ORDER BY updated_at DESC, id DESC
|
|
797
|
+
const conflicts = db.prepare(`
|
|
798
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
799
|
+
FROM memory_conflicts
|
|
800
|
+
WHERE status = 'open'
|
|
801
|
+
ORDER BY updated_at DESC, id DESC
|
|
802
802
|
`).all();
|
|
803
803
|
writeConflictMirrors(hippoRoot, conflicts.map(rowToMemoryConflict));
|
|
804
804
|
writeIndexMirror(hippoRoot, buildIndexFromDb(db));
|
|
@@ -852,6 +852,7 @@ export function writeEntry(hippoRoot, entry, opts) {
|
|
|
852
852
|
const db = openHippoDb(hippoRoot);
|
|
853
853
|
try {
|
|
854
854
|
writeEntryDbOnly(db, entry, opts);
|
|
855
|
+
opts?.afterCommit?.();
|
|
855
856
|
writeEntryMirrors(hippoRoot, db, entry);
|
|
856
857
|
}
|
|
857
858
|
finally {
|
|
@@ -1427,16 +1428,16 @@ export function saveActiveTaskSnapshot(hippoRoot, tenantId, snapshot) {
|
|
|
1427
1428
|
try {
|
|
1428
1429
|
db.exec('BEGIN');
|
|
1429
1430
|
db.prepare(`UPDATE task_snapshots SET status = 'superseded', updated_at = ? WHERE status = 'active' AND tenant_id = ?`).run(now, tenantId);
|
|
1430
|
-
const result = db.prepare(`
|
|
1431
|
-
INSERT INTO task_snapshots(task, summary, next_step, status, source, session_id, scope, tenant_id, created_at, updated_at)
|
|
1432
|
-
VALUES (?, ?, ?, 'active', ?, ?, ?, ?, ?, ?)
|
|
1431
|
+
const result = db.prepare(`
|
|
1432
|
+
INSERT INTO task_snapshots(task, summary, next_step, status, source, session_id, scope, tenant_id, created_at, updated_at)
|
|
1433
|
+
VALUES (?, ?, ?, 'active', ?, ?, ?, ?, ?, ?)
|
|
1433
1434
|
`).run(snapshot.task, snapshot.summary, snapshot.next_step, snapshot.source ?? 'cli', snapshot.session_id ?? null, snapshot.scope ?? null, tenantId, now, now);
|
|
1434
1435
|
db.exec('COMMIT');
|
|
1435
1436
|
const id = Number(result.lastInsertRowid ?? 0);
|
|
1436
|
-
const row = db.prepare(`
|
|
1437
|
-
SELECT id, task, summary, next_step, status, source, session_id, scope, created_at, updated_at
|
|
1438
|
-
FROM task_snapshots
|
|
1439
|
-
WHERE id = ?
|
|
1437
|
+
const row = db.prepare(`
|
|
1438
|
+
SELECT id, task, summary, next_step, status, source, session_id, scope, created_at, updated_at
|
|
1439
|
+
FROM task_snapshots
|
|
1440
|
+
WHERE id = ?
|
|
1440
1441
|
`).get(id);
|
|
1441
1442
|
if (!row) {
|
|
1442
1443
|
throw new Error('Failed to reload saved active task snapshot');
|
|
@@ -1463,12 +1464,12 @@ export function loadActiveTaskSnapshot(hippoRoot, tenantId) {
|
|
|
1463
1464
|
initStore(hippoRoot);
|
|
1464
1465
|
const db = openHippoDb(hippoRoot);
|
|
1465
1466
|
try {
|
|
1466
|
-
const row = db.prepare(`
|
|
1467
|
-
SELECT id, task, summary, next_step, status, source, session_id, scope, created_at, updated_at
|
|
1468
|
-
FROM task_snapshots
|
|
1469
|
-
WHERE status = 'active' AND tenant_id = ?
|
|
1470
|
-
ORDER BY updated_at DESC, id DESC
|
|
1471
|
-
LIMIT 1
|
|
1467
|
+
const row = db.prepare(`
|
|
1468
|
+
SELECT id, task, summary, next_step, status, source, session_id, scope, created_at, updated_at
|
|
1469
|
+
FROM task_snapshots
|
|
1470
|
+
WHERE status = 'active' AND tenant_id = ?
|
|
1471
|
+
ORDER BY updated_at DESC, id DESC
|
|
1472
|
+
LIMIT 1
|
|
1472
1473
|
`).get(tenantId);
|
|
1473
1474
|
if (!row) {
|
|
1474
1475
|
removeActiveTaskMirror(hippoRoot, tenantId);
|
|
@@ -1509,26 +1510,26 @@ export function appendSessionEvent(hippoRoot, tenantId, event) {
|
|
|
1509
1510
|
// v1.2: scope is wired through. Default-deny in api.recall + cmdRecall
|
|
1510
1511
|
// continuity reads applies to slack:private:* and 'unknown:legacy' rows.
|
|
1511
1512
|
try {
|
|
1512
|
-
const result = db.prepare(`
|
|
1513
|
-
INSERT INTO session_events(session_id, task, event_type, content, source, scope, metadata_json, tenant_id, created_at)
|
|
1514
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1513
|
+
const result = db.prepare(`
|
|
1514
|
+
INSERT INTO session_events(session_id, task, event_type, content, source, scope, metadata_json, tenant_id, created_at)
|
|
1515
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1515
1516
|
`).run(event.session_id, event.task ?? null, event.event_type, event.content, event.source ?? 'cli', event.scope ?? null, JSON.stringify(event.metadata ?? {}), tenantId, now);
|
|
1516
1517
|
const id = Number(result.lastInsertRowid ?? 0);
|
|
1517
|
-
const row = db.prepare(`
|
|
1518
|
-
SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
|
|
1519
|
-
FROM session_events
|
|
1520
|
-
WHERE id = ?
|
|
1518
|
+
const row = db.prepare(`
|
|
1519
|
+
SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
|
|
1520
|
+
FROM session_events
|
|
1521
|
+
WHERE id = ?
|
|
1521
1522
|
`).get(id);
|
|
1522
1523
|
if (!row) {
|
|
1523
1524
|
throw new Error('Failed to reload saved session event');
|
|
1524
1525
|
}
|
|
1525
1526
|
const loaded = rowToSessionEvent(row);
|
|
1526
|
-
const recentRows = db.prepare(`
|
|
1527
|
-
SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
|
|
1528
|
-
FROM session_events
|
|
1529
|
-
WHERE session_id = ? AND tenant_id = ?
|
|
1530
|
-
ORDER BY created_at DESC, id DESC
|
|
1531
|
-
LIMIT ?
|
|
1527
|
+
const recentRows = db.prepare(`
|
|
1528
|
+
SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
|
|
1529
|
+
FROM session_events
|
|
1530
|
+
WHERE session_id = ? AND tenant_id = ?
|
|
1531
|
+
ORDER BY created_at DESC, id DESC
|
|
1532
|
+
LIMIT ?
|
|
1532
1533
|
`).all(loaded.session_id, tenantId, 20);
|
|
1533
1534
|
const recent = recentRows.map(rowToSessionEvent).reverse();
|
|
1534
1535
|
writeRecentSessionMirror(hippoRoot, tenantId, recent);
|
|
@@ -1556,12 +1557,12 @@ export function listSessionEvents(hippoRoot, tenantId, options = {}) {
|
|
|
1556
1557
|
const limit = Math.max(1, Math.trunc(options.limit ?? 8));
|
|
1557
1558
|
params.push(limit);
|
|
1558
1559
|
const where = `WHERE ${clauses.join(' AND ')}`;
|
|
1559
|
-
const rows = db.prepare(`
|
|
1560
|
-
SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
|
|
1561
|
-
FROM session_events
|
|
1562
|
-
${where}
|
|
1563
|
-
ORDER BY created_at DESC, id DESC
|
|
1564
|
-
LIMIT ?
|
|
1560
|
+
const rows = db.prepare(`
|
|
1561
|
+
SELECT id, session_id, task, event_type, content, source, scope, metadata_json, created_at
|
|
1562
|
+
FROM session_events
|
|
1563
|
+
${where}
|
|
1564
|
+
ORDER BY created_at DESC, id DESC
|
|
1565
|
+
LIMIT ?
|
|
1565
1566
|
`).all(...params);
|
|
1566
1567
|
return rows.map(rowToSessionEvent).reverse();
|
|
1567
1568
|
}
|
|
@@ -1578,9 +1579,9 @@ export function findPromotableSessions(hippoRoot, tenantId, sinceMs) {
|
|
|
1578
1579
|
initStore(hippoRoot);
|
|
1579
1580
|
const db = openHippoDb(hippoRoot);
|
|
1580
1581
|
try {
|
|
1581
|
-
const rows = db.prepare(`
|
|
1582
|
-
SELECT DISTINCT session_id FROM session_events
|
|
1583
|
-
WHERE event_type = 'session_complete' AND created_at >= ? AND tenant_id = ?
|
|
1582
|
+
const rows = db.prepare(`
|
|
1583
|
+
SELECT DISTINCT session_id FROM session_events
|
|
1584
|
+
WHERE event_type = 'session_complete' AND created_at >= ? AND tenant_id = ?
|
|
1584
1585
|
`).all(new Date(sinceMs).toISOString(), tenantId);
|
|
1585
1586
|
return rows;
|
|
1586
1587
|
}
|
|
@@ -1597,10 +1598,10 @@ export function traceExistsForSession(hippoRoot, tenantId, session_id) {
|
|
|
1597
1598
|
initStore(hippoRoot);
|
|
1598
1599
|
const db = openHippoDb(hippoRoot);
|
|
1599
1600
|
try {
|
|
1600
|
-
const row = db.prepare(`
|
|
1601
|
-
SELECT 1 FROM memories
|
|
1602
|
-
WHERE source_session_id = ? AND layer = 'trace' AND tenant_id = ?
|
|
1603
|
-
LIMIT 1
|
|
1601
|
+
const row = db.prepare(`
|
|
1602
|
+
SELECT 1 FROM memories
|
|
1603
|
+
WHERE source_session_id = ? AND layer = 'trace' AND tenant_id = ?
|
|
1604
|
+
LIMIT 1
|
|
1604
1605
|
`).get(session_id, tenantId);
|
|
1605
1606
|
return !!row;
|
|
1606
1607
|
}
|
|
@@ -1623,38 +1624,38 @@ export function listMemoryConflicts(hippoRoot, status = 'open', tenantId) {
|
|
|
1623
1624
|
// each in-tenant, so neither a normal cross-tenant pair nor a stale
|
|
1624
1625
|
// pre-fix row surfaces (consistent with resolveConflict).
|
|
1625
1626
|
rows = allStatuses
|
|
1626
|
-
? db.prepare(`
|
|
1627
|
-
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
1628
|
-
mc.status, mc.detected_at, mc.updated_at
|
|
1629
|
-
FROM memory_conflicts mc
|
|
1630
|
-
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
1631
|
-
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
1632
|
-
WHERE ma.tenant_id = ? AND mb.tenant_id = ?
|
|
1633
|
-
ORDER BY mc.updated_at DESC, mc.id DESC
|
|
1627
|
+
? db.prepare(`
|
|
1628
|
+
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
1629
|
+
mc.status, mc.detected_at, mc.updated_at
|
|
1630
|
+
FROM memory_conflicts mc
|
|
1631
|
+
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
1632
|
+
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
1633
|
+
WHERE ma.tenant_id = ? AND mb.tenant_id = ?
|
|
1634
|
+
ORDER BY mc.updated_at DESC, mc.id DESC
|
|
1634
1635
|
`).all(tenantId, tenantId)
|
|
1635
|
-
: db.prepare(`
|
|
1636
|
-
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
1637
|
-
mc.status, mc.detected_at, mc.updated_at
|
|
1638
|
-
FROM memory_conflicts mc
|
|
1639
|
-
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
1640
|
-
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
1641
|
-
WHERE mc.status = ? AND ma.tenant_id = ? AND mb.tenant_id = ?
|
|
1642
|
-
ORDER BY mc.updated_at DESC, mc.id DESC
|
|
1636
|
+
: db.prepare(`
|
|
1637
|
+
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
1638
|
+
mc.status, mc.detected_at, mc.updated_at
|
|
1639
|
+
FROM memory_conflicts mc
|
|
1640
|
+
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
1641
|
+
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
1642
|
+
WHERE mc.status = ? AND ma.tenant_id = ? AND mb.tenant_id = ?
|
|
1643
|
+
ORDER BY mc.updated_at DESC, mc.id DESC
|
|
1643
1644
|
`).all(status, tenantId, tenantId);
|
|
1644
1645
|
}
|
|
1645
1646
|
else {
|
|
1646
1647
|
// Unscoped query — legacy direct-mode (CLI, tests, consolidate).
|
|
1647
1648
|
rows = allStatuses
|
|
1648
|
-
? db.prepare(`
|
|
1649
|
-
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1650
|
-
FROM memory_conflicts
|
|
1651
|
-
ORDER BY updated_at DESC, id DESC
|
|
1649
|
+
? db.prepare(`
|
|
1650
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1651
|
+
FROM memory_conflicts
|
|
1652
|
+
ORDER BY updated_at DESC, id DESC
|
|
1652
1653
|
`).all()
|
|
1653
|
-
: db.prepare(`
|
|
1654
|
-
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1655
|
-
FROM memory_conflicts
|
|
1656
|
-
WHERE status = ?
|
|
1657
|
-
ORDER BY updated_at DESC, id DESC
|
|
1654
|
+
: db.prepare(`
|
|
1655
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1656
|
+
FROM memory_conflicts
|
|
1657
|
+
WHERE status = ?
|
|
1658
|
+
ORDER BY updated_at DESC, id DESC
|
|
1658
1659
|
`).all(status);
|
|
1659
1660
|
}
|
|
1660
1661
|
return rows.map(rowToMemoryConflict);
|
|
@@ -1687,10 +1688,10 @@ export function replaceDetectedConflicts(hippoRoot, detected, detectedAt = new D
|
|
|
1687
1688
|
score: conflict.score,
|
|
1688
1689
|
}));
|
|
1689
1690
|
const detectedKeys = new Set(canonicalDetected.map((conflict) => `${conflict.memory_a_id}::${conflict.memory_b_id}`));
|
|
1690
|
-
const openRows = db.prepare(`
|
|
1691
|
-
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1692
|
-
FROM memory_conflicts
|
|
1693
|
-
WHERE status = 'open'
|
|
1691
|
+
const openRows = db.prepare(`
|
|
1692
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1693
|
+
FROM memory_conflicts
|
|
1694
|
+
WHERE status = 'open'
|
|
1694
1695
|
`).all();
|
|
1695
1696
|
for (const row of openRows) {
|
|
1696
1697
|
const key = `${row.memory_a_id}::${row.memory_b_id}`;
|
|
@@ -1709,20 +1710,20 @@ export function replaceDetectedConflicts(hippoRoot, detected, detectedAt = new D
|
|
|
1709
1710
|
// Skip cross-tenant pairs — never persist a conflict spanning tenants.
|
|
1710
1711
|
if (!sameTenant(conflict.memory_a_id, conflict.memory_b_id))
|
|
1711
1712
|
continue;
|
|
1712
|
-
db.prepare(`
|
|
1713
|
-
INSERT INTO memory_conflicts(memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at)
|
|
1714
|
-
VALUES (?, ?, ?, ?, 'open', ?, ?)
|
|
1715
|
-
ON CONFLICT(memory_a_id, memory_b_id) DO UPDATE SET
|
|
1716
|
-
reason = excluded.reason,
|
|
1717
|
-
score = excluded.score,
|
|
1718
|
-
status = 'open',
|
|
1719
|
-
updated_at = excluded.updated_at
|
|
1713
|
+
db.prepare(`
|
|
1714
|
+
INSERT INTO memory_conflicts(memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at)
|
|
1715
|
+
VALUES (?, ?, ?, ?, 'open', ?, ?)
|
|
1716
|
+
ON CONFLICT(memory_a_id, memory_b_id) DO UPDATE SET
|
|
1717
|
+
reason = excluded.reason,
|
|
1718
|
+
score = excluded.score,
|
|
1719
|
+
status = 'open',
|
|
1720
|
+
updated_at = excluded.updated_at
|
|
1720
1721
|
`).run(conflict.memory_a_id, conflict.memory_b_id, conflict.reason, conflict.score, detectedAt, detectedAt);
|
|
1721
1722
|
}
|
|
1722
|
-
const openConflicts = db.prepare(`
|
|
1723
|
-
SELECT memory_a_id, memory_b_id
|
|
1724
|
-
FROM memory_conflicts
|
|
1725
|
-
WHERE status = 'open'
|
|
1723
|
+
const openConflicts = db.prepare(`
|
|
1724
|
+
SELECT memory_a_id, memory_b_id
|
|
1725
|
+
FROM memory_conflicts
|
|
1726
|
+
WHERE status = 'open'
|
|
1726
1727
|
`).all();
|
|
1727
1728
|
const refMap = new Map();
|
|
1728
1729
|
for (const row of openConflicts) {
|
|
@@ -1776,17 +1777,17 @@ export function resolveConflict(hippoRoot, conflictId, keepId, forgetLoser = fal
|
|
|
1776
1777
|
const memArgs = tenantId !== undefined ? [tenantId] : [];
|
|
1777
1778
|
try {
|
|
1778
1779
|
const row = (tenantId !== undefined
|
|
1779
|
-
? db.prepare(`
|
|
1780
|
-
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
1781
|
-
mc.status, mc.detected_at, mc.updated_at
|
|
1782
|
-
FROM memory_conflicts mc
|
|
1783
|
-
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
1784
|
-
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
1785
|
-
WHERE mc.id = ? AND ma.tenant_id = ? AND mb.tenant_id = ?
|
|
1780
|
+
? db.prepare(`
|
|
1781
|
+
SELECT mc.id, mc.memory_a_id, mc.memory_b_id, mc.reason, mc.score,
|
|
1782
|
+
mc.status, mc.detected_at, mc.updated_at
|
|
1783
|
+
FROM memory_conflicts mc
|
|
1784
|
+
JOIN memories ma ON ma.id = mc.memory_a_id
|
|
1785
|
+
JOIN memories mb ON mb.id = mc.memory_b_id
|
|
1786
|
+
WHERE mc.id = ? AND ma.tenant_id = ? AND mb.tenant_id = ?
|
|
1786
1787
|
`).get(conflictId, tenantId, tenantId)
|
|
1787
|
-
: db.prepare(`
|
|
1788
|
-
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1789
|
-
FROM memory_conflicts WHERE id = ?
|
|
1788
|
+
: db.prepare(`
|
|
1789
|
+
SELECT id, memory_a_id, memory_b_id, reason, score, status, detected_at, updated_at
|
|
1790
|
+
FROM memory_conflicts WHERE id = ?
|
|
1790
1791
|
`).get(conflictId));
|
|
1791
1792
|
if (!row)
|
|
1792
1793
|
return null;
|
|
@@ -1856,15 +1857,15 @@ export function saveSessionHandoff(hippoRoot, tenantId, handoff) {
|
|
|
1856
1857
|
// v1.2: scope is wired through. Read-side default-deny in api.recall +
|
|
1857
1858
|
// cmdRecall continuity excludes slack:private:* and 'unknown:legacy'.
|
|
1858
1859
|
try {
|
|
1859
|
-
const result = db.prepare(`
|
|
1860
|
-
INSERT INTO session_handoffs(session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, tenant_id, created_at)
|
|
1861
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1860
|
+
const result = db.prepare(`
|
|
1861
|
+
INSERT INTO session_handoffs(session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, tenant_id, created_at)
|
|
1862
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1862
1863
|
`).run(handoff.sessionId, handoff.repoRoot ?? null, handoff.taskId ?? null, handoff.summary, handoff.nextAction ?? null, JSON.stringify(handoff.artifacts ?? []), handoff.scope ?? null, tenantId, now);
|
|
1863
1864
|
const id = Number(result.lastInsertRowid ?? 0);
|
|
1864
|
-
const row = db.prepare(`
|
|
1865
|
-
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1866
|
-
FROM session_handoffs
|
|
1867
|
-
WHERE id = ?
|
|
1865
|
+
const row = db.prepare(`
|
|
1866
|
+
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1867
|
+
FROM session_handoffs
|
|
1868
|
+
WHERE id = ?
|
|
1868
1869
|
`).get(id);
|
|
1869
1870
|
if (!row) {
|
|
1870
1871
|
throw new Error('Failed to reload saved session handoff');
|
|
@@ -1885,21 +1886,21 @@ export function loadLatestHandoff(hippoRoot, tenantId, sessionId) {
|
|
|
1885
1886
|
try {
|
|
1886
1887
|
let row;
|
|
1887
1888
|
if (sessionId) {
|
|
1888
|
-
row = db.prepare(`
|
|
1889
|
-
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1890
|
-
FROM session_handoffs
|
|
1891
|
-
WHERE session_id = ? AND tenant_id = ?
|
|
1892
|
-
ORDER BY created_at DESC, id DESC
|
|
1893
|
-
LIMIT 1
|
|
1889
|
+
row = db.prepare(`
|
|
1890
|
+
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1891
|
+
FROM session_handoffs
|
|
1892
|
+
WHERE session_id = ? AND tenant_id = ?
|
|
1893
|
+
ORDER BY created_at DESC, id DESC
|
|
1894
|
+
LIMIT 1
|
|
1894
1895
|
`).get(sessionId, tenantId);
|
|
1895
1896
|
}
|
|
1896
1897
|
else {
|
|
1897
|
-
row = db.prepare(`
|
|
1898
|
-
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1899
|
-
FROM session_handoffs
|
|
1900
|
-
WHERE tenant_id = ?
|
|
1901
|
-
ORDER BY created_at DESC, id DESC
|
|
1902
|
-
LIMIT 1
|
|
1898
|
+
row = db.prepare(`
|
|
1899
|
+
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1900
|
+
FROM session_handoffs
|
|
1901
|
+
WHERE tenant_id = ?
|
|
1902
|
+
ORDER BY created_at DESC, id DESC
|
|
1903
|
+
LIMIT 1
|
|
1903
1904
|
`).get(tenantId);
|
|
1904
1905
|
}
|
|
1905
1906
|
return row ? rowToSessionHandoff(row) : null;
|
|
@@ -1916,10 +1917,10 @@ export function loadHandoffById(hippoRoot, tenantId, id) {
|
|
|
1916
1917
|
initStore(hippoRoot);
|
|
1917
1918
|
const db = openHippoDb(hippoRoot);
|
|
1918
1919
|
try {
|
|
1919
|
-
const row = db.prepare(`
|
|
1920
|
-
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1921
|
-
FROM session_handoffs
|
|
1922
|
-
WHERE id = ? AND tenant_id = ?
|
|
1920
|
+
const row = db.prepare(`
|
|
1921
|
+
SELECT id, session_id, repo_root, task_id, summary, next_action, artifacts_json, scope, created_at
|
|
1922
|
+
FROM session_handoffs
|
|
1923
|
+
WHERE id = ? AND tenant_id = ?
|
|
1923
1924
|
`).get(id, tenantId);
|
|
1924
1925
|
return row ? rowToSessionHandoff(row) : null;
|
|
1925
1926
|
}
|
|
@@ -1949,13 +1950,13 @@ export function loadDirtySummaries(hippoRoot, tenantId) {
|
|
|
1949
1950
|
initStore(hippoRoot);
|
|
1950
1951
|
const db = openHippoDb(hippoRoot);
|
|
1951
1952
|
try {
|
|
1952
|
-
const rows = db.prepare(`
|
|
1953
|
-
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
1954
|
-
FROM memories
|
|
1955
|
-
WHERE summary_dirty = 1
|
|
1956
|
-
AND tenant_id = ?
|
|
1957
|
-
AND kind != 'archived'
|
|
1958
|
-
ORDER BY latest_at DESC NULLS LAST, id ASC
|
|
1953
|
+
const rows = db.prepare(`
|
|
1954
|
+
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
1955
|
+
FROM memories
|
|
1956
|
+
WHERE summary_dirty = 1
|
|
1957
|
+
AND tenant_id = ?
|
|
1958
|
+
AND kind != 'archived'
|
|
1959
|
+
ORDER BY latest_at DESC NULLS LAST, id ASC
|
|
1959
1960
|
`).all(tenantId);
|
|
1960
1961
|
return rows.map(rowToEntry);
|
|
1961
1962
|
}
|
|
@@ -1983,15 +1984,15 @@ export function markSummaryDirtyInTx(db, summaryId, tenantId, actor) {
|
|
|
1983
1984
|
// v0.30 / E5: widened dag_level=2 -> IN (2, 3). RETURNING dag_level reads
|
|
1984
1985
|
// actual level in same round trip so audit metadata stays accurate without
|
|
1985
1986
|
// a SELECT-before-UPDATE extra DB op on this hot path (5 caller sites).
|
|
1986
|
-
const result = db.prepare(`
|
|
1987
|
-
UPDATE memories
|
|
1988
|
-
SET summary_dirty = 1
|
|
1989
|
-
WHERE id = ?
|
|
1990
|
-
AND tenant_id = ?
|
|
1991
|
-
AND dag_level IN (2, 3)
|
|
1992
|
-
AND summary_dirty = 0
|
|
1993
|
-
AND kind != 'archived'
|
|
1994
|
-
RETURNING dag_level
|
|
1987
|
+
const result = db.prepare(`
|
|
1988
|
+
UPDATE memories
|
|
1989
|
+
SET summary_dirty = 1
|
|
1990
|
+
WHERE id = ?
|
|
1991
|
+
AND tenant_id = ?
|
|
1992
|
+
AND dag_level IN (2, 3)
|
|
1993
|
+
AND summary_dirty = 0
|
|
1994
|
+
AND kind != 'archived'
|
|
1995
|
+
RETURNING dag_level
|
|
1995
1996
|
`).get(summaryId, tenantId);
|
|
1996
1997
|
if (result) {
|
|
1997
1998
|
audit(db, 'summary_marked_dirty', summaryId, { dag_level: result.dag_level, source: 'E2' }, actor, tenantId);
|
|
@@ -2017,15 +2018,15 @@ export function markSummaryDirty(hippoRoot, summaryId, tenantId, actor = 'cli')
|
|
|
2017
2018
|
try {
|
|
2018
2019
|
// v0.30 / E5: widened dag_level=2 -> IN (2, 3). RETURNING dag_level reads
|
|
2019
2020
|
// actual level in same round trip.
|
|
2020
|
-
const result = db.prepare(`
|
|
2021
|
-
UPDATE memories
|
|
2022
|
-
SET summary_dirty = 1
|
|
2023
|
-
WHERE id = ?
|
|
2024
|
-
AND tenant_id = ?
|
|
2025
|
-
AND dag_level IN (2, 3)
|
|
2026
|
-
AND summary_dirty = 0
|
|
2027
|
-
AND kind != 'archived'
|
|
2028
|
-
RETURNING dag_level
|
|
2021
|
+
const result = db.prepare(`
|
|
2022
|
+
UPDATE memories
|
|
2023
|
+
SET summary_dirty = 1
|
|
2024
|
+
WHERE id = ?
|
|
2025
|
+
AND tenant_id = ?
|
|
2026
|
+
AND dag_level IN (2, 3)
|
|
2027
|
+
AND summary_dirty = 0
|
|
2028
|
+
AND kind != 'archived'
|
|
2029
|
+
RETURNING dag_level
|
|
2029
2030
|
`).get(summaryId, tenantId);
|
|
2030
2031
|
if (result) {
|
|
2031
2032
|
// audit() wraps appendAuditEvent in try/catch (v27 heal scenario).
|
|
@@ -2061,13 +2062,13 @@ export function loadAllL2Summaries(hippoRoot) {
|
|
|
2061
2062
|
initStore(hippoRoot);
|
|
2062
2063
|
const db = openHippoDb(hippoRoot);
|
|
2063
2064
|
try {
|
|
2064
|
-
const rows = db.prepare(`
|
|
2065
|
-
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
2066
|
-
FROM memories
|
|
2067
|
-
WHERE dag_level = 2
|
|
2068
|
-
AND dag_parent_id IS NULL
|
|
2069
|
-
AND kind != 'archived'
|
|
2070
|
-
ORDER BY created ASC, id ASC
|
|
2065
|
+
const rows = db.prepare(`
|
|
2066
|
+
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
2067
|
+
FROM memories
|
|
2068
|
+
WHERE dag_level = 2
|
|
2069
|
+
AND dag_parent_id IS NULL
|
|
2070
|
+
AND kind != 'archived'
|
|
2071
|
+
ORDER BY created ASC, id ASC
|
|
2071
2072
|
`).all();
|
|
2072
2073
|
return rows.map(rowToEntry);
|
|
2073
2074
|
}
|
|
@@ -2088,12 +2089,12 @@ export function loadAllDirtySummaries(hippoRoot) {
|
|
|
2088
2089
|
initStore(hippoRoot);
|
|
2089
2090
|
const db = openHippoDb(hippoRoot);
|
|
2090
2091
|
try {
|
|
2091
|
-
const rows = db.prepare(`
|
|
2092
|
-
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
2093
|
-
FROM memories
|
|
2094
|
-
WHERE summary_dirty = 1
|
|
2095
|
-
AND kind != 'archived'
|
|
2096
|
-
ORDER BY latest_at DESC NULLS LAST, id ASC
|
|
2092
|
+
const rows = db.prepare(`
|
|
2093
|
+
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
2094
|
+
FROM memories
|
|
2095
|
+
WHERE summary_dirty = 1
|
|
2096
|
+
AND kind != 'archived'
|
|
2097
|
+
ORDER BY latest_at DESC NULLS LAST, id ASC
|
|
2097
2098
|
`).all();
|
|
2098
2099
|
return rows.map(rowToEntry);
|
|
2099
2100
|
}
|
|
@@ -2113,13 +2114,13 @@ export function loadChildrenOfSummary(hippoRoot, summaryId, tenantId) {
|
|
|
2113
2114
|
initStore(hippoRoot);
|
|
2114
2115
|
const db = openHippoDb(hippoRoot);
|
|
2115
2116
|
try {
|
|
2116
|
-
const rows = db.prepare(`
|
|
2117
|
-
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
2118
|
-
FROM memories
|
|
2119
|
-
WHERE dag_parent_id = ?
|
|
2120
|
-
AND tenant_id = ?
|
|
2121
|
-
AND kind != 'archived'
|
|
2122
|
-
ORDER BY created ASC
|
|
2117
|
+
const rows = db.prepare(`
|
|
2118
|
+
SELECT ${MEMORY_SELECT_COLUMNS}
|
|
2119
|
+
FROM memories
|
|
2120
|
+
WHERE dag_parent_id = ?
|
|
2121
|
+
AND tenant_id = ?
|
|
2122
|
+
AND kind != 'archived'
|
|
2123
|
+
ORDER BY created ASC
|
|
2123
2124
|
`).all(summaryId, tenantId);
|
|
2124
2125
|
return rows.map(rowToEntry);
|
|
2125
2126
|
}
|
|
@@ -2147,28 +2148,28 @@ export function applyRebuildResult(hippoRoot, summary, patch) {
|
|
|
2147
2148
|
// ONE prepared UPDATE per branch. Test #8 inspects the SQL string.
|
|
2148
2149
|
// v0.30 / E5: widened dag_level=2 -> IN (2, 3) on both branches.
|
|
2149
2150
|
const sql = patch.bumpRebuildCount
|
|
2150
|
-
? `UPDATE memories
|
|
2151
|
-
SET content = ?,
|
|
2152
|
-
descendant_count = ?,
|
|
2153
|
-
earliest_at = ?,
|
|
2154
|
-
latest_at = ?,
|
|
2155
|
-
last_rebuilt_at = ?,
|
|
2156
|
-
rebuild_count = COALESCE(rebuild_count, 0) + 1,
|
|
2157
|
-
summary_dirty = 0
|
|
2158
|
-
WHERE id = ?
|
|
2159
|
-
AND tenant_id = ?
|
|
2160
|
-
AND dag_level IN (2, 3)
|
|
2161
|
-
AND summary_dirty = 1
|
|
2151
|
+
? `UPDATE memories
|
|
2152
|
+
SET content = ?,
|
|
2153
|
+
descendant_count = ?,
|
|
2154
|
+
earliest_at = ?,
|
|
2155
|
+
latest_at = ?,
|
|
2156
|
+
last_rebuilt_at = ?,
|
|
2157
|
+
rebuild_count = COALESCE(rebuild_count, 0) + 1,
|
|
2158
|
+
summary_dirty = 0
|
|
2159
|
+
WHERE id = ?
|
|
2160
|
+
AND tenant_id = ?
|
|
2161
|
+
AND dag_level IN (2, 3)
|
|
2162
|
+
AND summary_dirty = 1
|
|
2162
2163
|
AND kind != 'archived'`
|
|
2163
|
-
: `UPDATE memories
|
|
2164
|
-
SET descendant_count = ?,
|
|
2165
|
-
earliest_at = ?,
|
|
2166
|
-
latest_at = ?,
|
|
2167
|
-
summary_dirty = 0
|
|
2168
|
-
WHERE id = ?
|
|
2169
|
-
AND tenant_id = ?
|
|
2170
|
-
AND dag_level IN (2, 3)
|
|
2171
|
-
AND summary_dirty = 1
|
|
2164
|
+
: `UPDATE memories
|
|
2165
|
+
SET descendant_count = ?,
|
|
2166
|
+
earliest_at = ?,
|
|
2167
|
+
latest_at = ?,
|
|
2168
|
+
summary_dirty = 0
|
|
2169
|
+
WHERE id = ?
|
|
2170
|
+
AND tenant_id = ?
|
|
2171
|
+
AND dag_level IN (2, 3)
|
|
2172
|
+
AND summary_dirty = 1
|
|
2172
2173
|
AND kind != 'archived'`;
|
|
2173
2174
|
const result = patch.bumpRebuildCount
|
|
2174
2175
|
? db.prepare(sql).run(patch.content, patch.descendant_count, patch.earliest_at, patch.latest_at, nowIso, summary.id, summary.tenantId)
|
|
@@ -2236,15 +2237,15 @@ export function clearSummaryDirtyAfterBuild(hippoRoot, summaryId, tenantId, acto
|
|
|
2236
2237
|
try {
|
|
2237
2238
|
// v0.30 / E5: widened dag_level=2 -> IN (2, 3). RETURNING dag_level reads
|
|
2238
2239
|
// actual level so audit metadata stays accurate without an extra SELECT.
|
|
2239
|
-
const result = db.prepare(`
|
|
2240
|
-
UPDATE memories
|
|
2241
|
-
SET summary_dirty = 0
|
|
2242
|
-
WHERE id = ?
|
|
2243
|
-
AND tenant_id = ?
|
|
2244
|
-
AND dag_level IN (2, 3)
|
|
2245
|
-
AND summary_dirty = 1
|
|
2246
|
-
AND kind != 'archived'
|
|
2247
|
-
RETURNING dag_level
|
|
2240
|
+
const result = db.prepare(`
|
|
2241
|
+
UPDATE memories
|
|
2242
|
+
SET summary_dirty = 0
|
|
2243
|
+
WHERE id = ?
|
|
2244
|
+
AND tenant_id = ?
|
|
2245
|
+
AND dag_level IN (2, 3)
|
|
2246
|
+
AND summary_dirty = 1
|
|
2247
|
+
AND kind != 'archived'
|
|
2248
|
+
RETURNING dag_level
|
|
2248
2249
|
`).get(summaryId, tenantId);
|
|
2249
2250
|
if (result) {
|
|
2250
2251
|
// v0.30 / E5: source param distinguishes buildDag-clean (L2) from
|