hippo-memory 1.56.0 → 1.58.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/README.md +11 -0
- package/dist/agent-memories/claude-code.js +1 -1
- package/dist/agent-memories/gemini.js +1 -1
- package/dist/api-errors.d.ts +27 -0
- package/dist/api-errors.js +37 -0
- package/dist/api.d.ts +21 -14
- package/dist/api.js +97 -71
- package/dist/audit.d.ts +4 -0
- package/dist/audit.js +11 -0
- package/dist/autolearn.d.ts +1 -1
- package/dist/autolearn.js +7 -5
- package/dist/capture-contract.d.ts +47 -0
- package/dist/capture-contract.js +49 -0
- package/dist/capture-error.js +2 -1
- package/dist/capture.d.ts +0 -13
- package/dist/capture.js +5 -66
- package/dist/card-detail.d.ts +1 -1
- package/dist/card-detail.js +1 -1
- package/dist/cli/shared.d.ts +137 -0
- package/dist/cli/shared.js +834 -0
- package/dist/cli/sleep.d.ts +10 -0
- package/dist/cli/sleep.js +171 -0
- package/dist/cli.d.ts +0 -7
- package/dist/cli.js +322 -1827
- package/dist/client.js +9 -0
- package/dist/codex-patch.js +1 -1
- package/dist/compaction-record.d.ts +1 -1
- package/dist/compaction-record.js +3 -2
- package/dist/config.d.ts +5 -0
- package/dist/config.js +17 -0
- package/dist/connectors/github/dlq.js +5 -2
- package/dist/connectors/github/octokit-client.js +4 -2
- package/dist/connectors/github/webhook.d.ts +19 -0
- package/dist/connectors/github/webhook.js +313 -0
- package/dist/connectors/slack/dlq.js +6 -2
- package/dist/connectors/slack/web-client.js +7 -5
- package/dist/connectors/slack/webhook.d.ts +22 -0
- package/dist/connectors/slack/webhook.js +203 -0
- package/dist/consolidate.d.ts +10 -0
- package/dist/consolidate.js +38 -35
- package/dist/context-auto.d.ts +3 -0
- package/dist/context-auto.js +34 -0
- package/dist/customer-notes.js +16 -14
- package/dist/dag.js +3 -2
- package/dist/dashboard.js +3 -2
- package/dist/db.d.ts +12 -0
- package/dist/db.js +62 -1
- package/dist/decisions.js +11 -9
- package/dist/doctor.js +5 -0
- package/dist/embedding-provider.js +3 -3
- package/dist/embeddings.d.ts +4 -4
- package/dist/embeddings.js +72 -16
- package/dist/eval-stats.d.ts +58 -0
- package/dist/eval-stats.js +111 -0
- package/dist/extract.js +3 -2
- package/dist/goals.d.ts +49 -25
- package/dist/goals.js +39 -22
- package/dist/graph-extract.js +1 -1
- package/dist/graph-recall.d.ts +1 -1
- package/dist/graph-recall.js +1 -1
- package/dist/graph.js +1 -1
- package/dist/hooks.d.ts +1 -3
- package/dist/hooks.js +2 -4
- package/dist/http-retry.d.ts +21 -0
- package/dist/http-retry.js +50 -0
- package/dist/http-util.d.ts +39 -0
- package/dist/http-util.js +56 -0
- package/dist/importers.d.ts +2 -0
- package/dist/importers.js +16 -5
- package/dist/incidents.js +13 -11
- package/dist/index.d.ts +5 -2
- package/dist/index.js +5 -2
- package/dist/judgment.js +10 -17
- package/dist/log.d.ts +25 -0
- package/dist/log.js +48 -0
- package/dist/mcp/server.js +224 -308
- package/dist/mcp/tool-args.d.ts +21 -0
- package/dist/mcp/tool-args.js +80 -0
- package/dist/memory.d.ts +19 -0
- package/dist/memory.js +41 -2
- package/dist/overlap-index.d.ts +7 -0
- package/dist/overlap-index.js +38 -0
- package/dist/pilot-arm.d.ts +9 -0
- package/dist/pilot-arm.js +47 -0
- package/dist/policies.js +14 -12
- package/dist/predictions.js +11 -9
- package/dist/processes.js +16 -14
- package/dist/project-briefs.js +19 -16
- package/dist/project-identity.d.ts +1 -1
- package/dist/project-identity.js +25 -1
- package/dist/prompt-recall.js +1 -1
- package/dist/raw-archive.js +7 -6
- package/dist/recall-history.d.ts +5 -0
- package/dist/recall-history.js +9 -0
- package/dist/recall-pipeline.d.ts +101 -0
- package/dist/recall-pipeline.js +313 -0
- package/dist/recall-scope.d.ts +24 -1
- package/dist/recall-scope.js +29 -2
- package/dist/refine-llm.js +3 -2
- package/dist/reject-flow.js +6 -9
- package/dist/rejection.d.ts +2 -1
- package/dist/rejection.js +2 -1
- package/dist/search.d.ts +0 -20
- package/dist/search.js +16 -51
- package/dist/secret-detect.d.ts +13 -1
- package/dist/secret-detect.js +33 -1
- package/dist/server.d.ts +3 -1
- package/dist/server.js +1854 -2566
- package/dist/session-digest.js +2 -1
- package/dist/shared.js +7 -6
- package/dist/skills.js +17 -15
- package/dist/store-cards.d.ts +53 -0
- package/dist/store-cards.js +512 -0
- package/dist/store.d.ts +2 -89
- package/dist/store.js +10 -566
- package/dist/tenant.d.ts +22 -0
- package/dist/tenant.js +26 -0
- package/dist/token-ledger.d.ts +4 -2
- package/dist/token-ledger.js +2 -2
- package/dist/tokenize.d.ts +2 -0
- package/dist/tokenize.js +8 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- 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/connectors/slack/ratelimit.d.ts +0 -9
- package/dist/connectors/slack/ratelimit.js +0 -18
package/dist/goals.d.ts
CHANGED
|
@@ -79,12 +79,36 @@ export interface GetActiveGoalsOpts {
|
|
|
79
79
|
}
|
|
80
80
|
export declare function getActiveGoals(hippoRoot: string, opts: GetActiveGoalsOpts): Goal[];
|
|
81
81
|
export declare function getActiveGoalsWithDb(db: DatabaseSyncLike, opts: GetActiveGoalsOpts): Goal[];
|
|
82
|
+
/** One `goal_recall_log` row: a boosted local memory recalled while its goal was active. */
|
|
83
|
+
export interface GoalRecallLogRow {
|
|
84
|
+
goalId: string;
|
|
85
|
+
memoryId: string;
|
|
86
|
+
tenantId: string;
|
|
87
|
+
sessionId: string;
|
|
88
|
+
recalledAt: string;
|
|
89
|
+
score: number;
|
|
90
|
+
}
|
|
91
|
+
/** Options shared by {@link computeGoalStackBoost} and {@link applyGoalStackBoost}. */
|
|
92
|
+
export interface GoalStackBoostOpts {
|
|
93
|
+
sessionId: string;
|
|
94
|
+
tenantId: string;
|
|
95
|
+
limit: number;
|
|
96
|
+
/**
|
|
97
|
+
* Optional side-channel: one goal-boost `RerankStep` per boosted row, keyed by
|
|
98
|
+
* `entry.id`. A map rather than a row field because the helper re-spreads rows.
|
|
99
|
+
* Only populated when passed, so the default path allocates nothing.
|
|
100
|
+
*/
|
|
101
|
+
trace?: Map<string, RerankStep>;
|
|
102
|
+
}
|
|
103
|
+
/** The boosted, re-sorted rows and the `goal_recall_log` rows they earn. */
|
|
104
|
+
export interface GoalStackBoost<R> {
|
|
105
|
+
results: R[];
|
|
106
|
+
log: GoalRecallLogRow[];
|
|
107
|
+
}
|
|
82
108
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* lifting here lets api.recall (primary band only) AND MCP physics/hybrid
|
|
87
|
-
* call it.
|
|
109
|
+
* dlPFC goal-stack boost. Applies the multi-goal boost to entry-backed scored
|
|
110
|
+
* rows when (tenant, session) has active goals and returns the log rows to
|
|
111
|
+
* write, without writing them; {@link writeGoalRecallLog} persists them.
|
|
88
112
|
*
|
|
89
113
|
* Caller responsibilities:
|
|
90
114
|
* - Do NOT call when an explicit `goalTag` is set (caller's gate)
|
|
@@ -94,31 +118,31 @@ export declare function getActiveGoalsWithDb(db: DatabaseSyncLike, opts: GetActi
|
|
|
94
118
|
* - Recompute `tokens` after if returned rows are projected to a budgeted
|
|
95
119
|
* shape
|
|
96
120
|
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
* to preserve FK invariant on goal_recall_log.memory_id)
|
|
121
|
+
* Log rows cover the top `limit` boosted rows that live in this store's
|
|
122
|
+
* `memories` table (global-only ids are skipped to keep the FK on
|
|
123
|
+
* goal_recall_log.memory_id valid).
|
|
101
124
|
*
|
|
102
|
-
* @internal
|
|
125
|
+
* @internal Recall ranking helper. Subject to change.
|
|
126
|
+
*/
|
|
127
|
+
export declare function computeGoalStackBoost<R extends {
|
|
128
|
+
entry: MemoryEntry;
|
|
129
|
+
score: number;
|
|
130
|
+
}>(db: DatabaseSyncLike, results: R[], opts: GoalStackBoostOpts): GoalStackBoost<R>;
|
|
131
|
+
/**
|
|
132
|
+
* Writes goal-boost log rows. INSERT OR IGNORE because UNIQUE(memory_id, goal_id)
|
|
133
|
+
* makes a re-recall during the same goal life a no-op for outcome attribution.
|
|
134
|
+
*/
|
|
135
|
+
export declare function writeGoalRecallLog(db: DatabaseSyncLike, rows: readonly GoalRecallLogRow[]): void;
|
|
136
|
+
/**
|
|
137
|
+
* {@link computeGoalStackBoost} plus {@link writeGoalRecallLog} in one call, for
|
|
138
|
+
* pipelines that boost and log on the same handle.
|
|
139
|
+
*
|
|
140
|
+
* @internal Recall ranking helper. Subject to change.
|
|
103
141
|
*/
|
|
104
142
|
export declare function applyGoalStackBoost<R extends {
|
|
105
143
|
entry: MemoryEntry;
|
|
106
144
|
score: number;
|
|
107
|
-
}>(db: DatabaseSyncLike, results: R[], opts:
|
|
108
|
-
sessionId: string;
|
|
109
|
-
tenantId: string;
|
|
110
|
-
limit: number;
|
|
111
|
-
/**
|
|
112
|
-
* A7 recall-trace (optional side-channel). When supplied, the helper
|
|
113
|
-
* records one goal-boost `RerankStep` per ACTUALLY-boosted row, keyed by
|
|
114
|
-
* `entry.id`. This is a SEPARATE accumulator, NOT a field on the result
|
|
115
|
-
* row — the helper re-spreads rows and strips internal markers
|
|
116
|
-
* (`_goalMatches` below), so a row field would be dropped. The score-mul
|
|
117
|
-
* + re-sort math is untouched; the trace is only populated when this map
|
|
118
|
-
* is passed (default path never allocates → byte-identical).
|
|
119
|
-
*/
|
|
120
|
-
trace?: Map<string, RerankStep>;
|
|
121
|
-
}): R[];
|
|
145
|
+
}>(db: DatabaseSyncLike, results: R[], opts: GoalStackBoostOpts): R[];
|
|
122
146
|
export interface CompleteGoalOpts {
|
|
123
147
|
outcomeScore?: number;
|
|
124
148
|
/**
|
package/dist/goals.js
CHANGED
|
@@ -142,11 +142,9 @@ export function getActiveGoalsWithDb(db, opts) {
|
|
|
142
142
|
return rows.map(rowToGoal);
|
|
143
143
|
}
|
|
144
144
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* lifting here lets api.recall (primary band only) AND MCP physics/hybrid
|
|
149
|
-
* call it.
|
|
145
|
+
* dlPFC goal-stack boost. Applies the multi-goal boost to entry-backed scored
|
|
146
|
+
* rows when (tenant, session) has active goals and returns the log rows to
|
|
147
|
+
* write, without writing them; {@link writeGoalRecallLog} persists them.
|
|
150
148
|
*
|
|
151
149
|
* Caller responsibilities:
|
|
152
150
|
* - Do NOT call when an explicit `goalTag` is set (caller's gate)
|
|
@@ -156,18 +154,17 @@ export function getActiveGoalsWithDb(db, opts) {
|
|
|
156
154
|
* - Recompute `tokens` after if returned rows are projected to a budgeted
|
|
157
155
|
* shape
|
|
158
156
|
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
* to preserve FK invariant on goal_recall_log.memory_id)
|
|
157
|
+
* Log rows cover the top `limit` boosted rows that live in this store's
|
|
158
|
+
* `memories` table (global-only ids are skipped to keep the FK on
|
|
159
|
+
* goal_recall_log.memory_id valid).
|
|
163
160
|
*
|
|
164
|
-
* @internal
|
|
161
|
+
* @internal Recall ranking helper. Subject to change.
|
|
165
162
|
*/
|
|
166
|
-
export function
|
|
163
|
+
export function computeGoalStackBoost(db, results, opts) {
|
|
167
164
|
const { sessionId, tenantId, limit, trace } = opts;
|
|
168
165
|
const active = getActiveGoalsWithDb(db, { sessionId, tenantId });
|
|
169
166
|
if (active.length === 0)
|
|
170
|
-
return results;
|
|
167
|
+
return { results, log: [] };
|
|
171
168
|
const goalsByTag = new Map(active.map((g) => [g.goalName, g]));
|
|
172
169
|
// Load retrieval_policy rows for active goals so per-policy multipliers
|
|
173
170
|
// can compose onto the base goal-tag boost. Composed result is hard-capped
|
|
@@ -271,15 +268,8 @@ export function applyGoalStackBoost(db, results, opts) {
|
|
|
271
268
|
for (const row of localRows)
|
|
272
269
|
localIds.add(row.id);
|
|
273
270
|
}
|
|
274
|
-
// Log top-K boosted recalls. INSERT OR IGNORE because
|
|
275
|
-
// UNIQUE(memory_id, goal_id) means a re-recall during the same goal life
|
|
276
|
-
// is a no-op for outcome attribution.
|
|
277
271
|
const recalledAt = new Date().toISOString();
|
|
278
|
-
const
|
|
279
|
-
INSERT OR IGNORE INTO goal_recall_log
|
|
280
|
-
(goal_id, memory_id, tenant_id, session_id, recalled_at, score)
|
|
281
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
282
|
-
`);
|
|
272
|
+
const log = [];
|
|
283
273
|
for (const r of boosted.slice(0, limit)) {
|
|
284
274
|
if (!localIds.has(r.entry.id))
|
|
285
275
|
continue; // global -> skip log insert
|
|
@@ -290,10 +280,37 @@ export function applyGoalStackBoost(db, results, opts) {
|
|
|
290
280
|
const goal = goalsByTag.get(tag);
|
|
291
281
|
if (!goal)
|
|
292
282
|
continue;
|
|
293
|
-
|
|
283
|
+
log.push({ goalId: goal.id, memoryId: r.entry.id, tenantId, sessionId, recalledAt, score: r.score });
|
|
294
284
|
}
|
|
295
285
|
}
|
|
296
|
-
return boosted;
|
|
286
|
+
return { results: boosted, log };
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Writes goal-boost log rows. INSERT OR IGNORE because UNIQUE(memory_id, goal_id)
|
|
290
|
+
* makes a re-recall during the same goal life a no-op for outcome attribution.
|
|
291
|
+
*/
|
|
292
|
+
export function writeGoalRecallLog(db, rows) {
|
|
293
|
+
if (rows.length === 0)
|
|
294
|
+
return;
|
|
295
|
+
const insertLog = db.prepare(`
|
|
296
|
+
INSERT OR IGNORE INTO goal_recall_log
|
|
297
|
+
(goal_id, memory_id, tenant_id, session_id, recalled_at, score)
|
|
298
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
299
|
+
`);
|
|
300
|
+
for (const row of rows) {
|
|
301
|
+
insertLog.run(row.goalId, row.memoryId, row.tenantId, row.sessionId, row.recalledAt, row.score);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* {@link computeGoalStackBoost} plus {@link writeGoalRecallLog} in one call, for
|
|
306
|
+
* pipelines that boost and log on the same handle.
|
|
307
|
+
*
|
|
308
|
+
* @internal Recall ranking helper. Subject to change.
|
|
309
|
+
*/
|
|
310
|
+
export function applyGoalStackBoost(db, results, opts) {
|
|
311
|
+
const boost = computeGoalStackBoost(db, results, opts);
|
|
312
|
+
writeGoalRecallLog(db, boost.log);
|
|
313
|
+
return boost.results;
|
|
297
314
|
}
|
|
298
315
|
const POSITIVE_OUTCOME_THRESHOLD = 0.7;
|
|
299
316
|
const NEGATIVE_OUTCOME_THRESHOLD = 0.3;
|
package/dist/graph-extract.js
CHANGED
|
@@ -25,7 +25,7 @@ import { loadDecisions } from './decisions.js';
|
|
|
25
25
|
import { loadPolicies } from './policies.js';
|
|
26
26
|
import { loadCustomerNotes } from './customer-notes.js';
|
|
27
27
|
import { loadProjectBriefs } from './project-briefs.js';
|
|
28
|
-
import { assertTenantId } from './
|
|
28
|
+
import { assertTenantId } from './tenant.js';
|
|
29
29
|
/** Per-type load cap (the loaders default to 100). A type whose active or superseded
|
|
30
30
|
* set exceeds this is truncated; `ExtractResult.truncated` records it so the
|
|
31
31
|
* incompleteness is observable rather than silent. */
|
package/dist/graph-recall.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ResultCost, SearchResult } from './search.js';
|
|
2
2
|
/** Hard cap on `--hops` (a higher value just walks more of a finite graph; this bounds
|
|
3
3
|
* worst-case work and keeps the flag honest). */
|
|
4
4
|
export declare const MAX_HOPS = 3;
|
package/dist/graph-recall.js
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
* check-graph-writes lint permits this module living outside graph.ts.
|
|
38
38
|
*/
|
|
39
39
|
import { loadEntriesByIds } from './store.js';
|
|
40
|
-
import { estimateTokens } from './
|
|
40
|
+
import { estimateTokens } from './token-ledger.js';
|
|
41
41
|
import { compareEntryIdentity } from './compare.js';
|
|
42
42
|
import { loadEntitiesByMemoryId, loadEntitiesByIds, loadNeighborRelations, } from './graph.js';
|
|
43
43
|
import { passesCliRecallScopeFilter, passesScopeFilterForRecall } from './recall-scope.js';
|
package/dist/graph.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* until E3.2 multi-hop recall.
|
|
19
19
|
*/
|
|
20
20
|
import { openHippoDb, closeHippoDb } from './db.js';
|
|
21
|
-
import { assertTenantId } from './
|
|
21
|
+
import { assertTenantId } from './tenant.js';
|
|
22
22
|
const SOURCE_OBJECT_TABLE = {
|
|
23
23
|
decision: 'decisions',
|
|
24
24
|
policy: 'policies',
|
package/dist/hooks.d.ts
CHANGED
|
@@ -45,8 +45,8 @@ export interface CodexWrapperPaths {
|
|
|
45
45
|
wrapperShPath: string;
|
|
46
46
|
logFile: string;
|
|
47
47
|
runsDir: string;
|
|
48
|
+
codexHome: string;
|
|
48
49
|
historyPath: string;
|
|
49
|
-
sessionsDir: string;
|
|
50
50
|
}
|
|
51
51
|
export interface CodexWrapperInstallResult {
|
|
52
52
|
installed: boolean;
|
|
@@ -63,8 +63,6 @@ export interface CodexWrapperMetadata {
|
|
|
63
63
|
backupPath: string;
|
|
64
64
|
installMode: 'same-path' | 'cmd-shim';
|
|
65
65
|
logFile: string;
|
|
66
|
-
historyPath: string;
|
|
67
|
-
sessionsDir: string;
|
|
68
66
|
installedAt: string;
|
|
69
67
|
}
|
|
70
68
|
export interface EnsureCodexWrapperResult {
|
package/dist/hooks.js
CHANGED
|
@@ -154,7 +154,7 @@ export function defaultPreCompactLogPath() {
|
|
|
154
154
|
}
|
|
155
155
|
export function resolveCodexWrapperPaths() {
|
|
156
156
|
const home = homeDir();
|
|
157
|
-
const codexHome =
|
|
157
|
+
const codexHome = codexHomeDir(home);
|
|
158
158
|
const wrapperDir = path.join(home, '.hippo', 'bin');
|
|
159
159
|
return {
|
|
160
160
|
wrapperDir,
|
|
@@ -164,8 +164,8 @@ export function resolveCodexWrapperPaths() {
|
|
|
164
164
|
wrapperShPath: path.join(wrapperDir, 'codex'),
|
|
165
165
|
logFile: path.join(home, '.hippo', 'logs', 'codex-sleep.log'),
|
|
166
166
|
runsDir: path.join(home, '.hippo', 'runs', 'codex'),
|
|
167
|
+
codexHome,
|
|
167
168
|
historyPath: path.join(codexHome, 'history.jsonl'),
|
|
168
|
-
sessionsDir: path.join(codexHome, 'sessions'),
|
|
169
169
|
};
|
|
170
170
|
}
|
|
171
171
|
function pathEquals(a, b) {
|
|
@@ -348,8 +348,6 @@ export function installCodexWrapper(realCodexPath) {
|
|
|
348
348
|
backupPath: plan.backupPath,
|
|
349
349
|
installMode: plan.installMode,
|
|
350
350
|
logFile: paths.logFile,
|
|
351
|
-
historyPath: paths.historyPath,
|
|
352
|
-
sessionsDir: paths.sessionsDir,
|
|
353
351
|
installedAt: new Date().toISOString(),
|
|
354
352
|
};
|
|
355
353
|
fs.writeFileSync(paths.metadataPath, JSON.stringify(metadata, null, 2) + '\n', 'utf8');
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** One retry policy for outbound HTTP: a timeout on every attempt, and backoff on 429 and 5xx only. */
|
|
2
|
+
export interface RetryPolicy {
|
|
3
|
+
/** Per-attempt limit; a stalled peer ends as a thrown `TimeoutError`, never a hang. */
|
|
4
|
+
timeoutMs: number;
|
|
5
|
+
/** Total attempts including the first. */
|
|
6
|
+
attempts?: number;
|
|
7
|
+
baseDelayMs?: number;
|
|
8
|
+
/** A Retry-After longer than this hands the response back, so a caller with its own long pause keeps it. */
|
|
9
|
+
maxDelayMs?: number;
|
|
10
|
+
fetchFn?: typeof fetch;
|
|
11
|
+
sleep?: (ms: number) => Promise<void>;
|
|
12
|
+
random?: () => number;
|
|
13
|
+
}
|
|
14
|
+
/** LLM calls (consolidation refine, DAG summaries, fact extraction) share one budget; `HIPPO_LLM_TIMEOUT_MS` overrides it. */
|
|
15
|
+
export declare function llmTimeoutMs(): number;
|
|
16
|
+
export declare function isRetryableStatus(status: number): boolean;
|
|
17
|
+
/** Retry-After as milliseconds: delta-seconds or an HTTP date; null when absent or unreadable. */
|
|
18
|
+
export declare function parseRetryAfterMs(header: string | null, now?: number): number | null;
|
|
19
|
+
/** `fetch` with a per-attempt timeout and up to `attempts` tries on 429 and 5xx; the last response comes back as is and transport errors throw at once. */
|
|
20
|
+
export declare function fetchWithRetry(url: string | URL, init: RequestInit, policy: RetryPolicy): Promise<Response>;
|
|
21
|
+
//# sourceMappingURL=http-retry.d.ts.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** One retry policy for outbound HTTP: a timeout on every attempt, and backoff on 429 and 5xx only. */
|
|
2
|
+
const DEFAULT_ATTEMPTS = 3;
|
|
3
|
+
const DEFAULT_BASE_DELAY_MS = 250;
|
|
4
|
+
const DEFAULT_MAX_DELAY_MS = 8_000;
|
|
5
|
+
const DEFAULT_LLM_TIMEOUT_MS = 60_000;
|
|
6
|
+
/** LLM calls (consolidation refine, DAG summaries, fact extraction) share one budget; `HIPPO_LLM_TIMEOUT_MS` overrides it. */
|
|
7
|
+
export function llmTimeoutMs() {
|
|
8
|
+
const parsed = Number.parseInt(process.env.HIPPO_LLM_TIMEOUT_MS ?? '', 10);
|
|
9
|
+
return parsed > 0 ? parsed : DEFAULT_LLM_TIMEOUT_MS;
|
|
10
|
+
}
|
|
11
|
+
export function isRetryableStatus(status) {
|
|
12
|
+
return status === 429 || (status >= 500 && status <= 599);
|
|
13
|
+
}
|
|
14
|
+
/** Retry-After as milliseconds: delta-seconds or an HTTP date; null when absent or unreadable. */
|
|
15
|
+
export function parseRetryAfterMs(header, now = Date.now()) {
|
|
16
|
+
if (header === null || header.trim() === '')
|
|
17
|
+
return null;
|
|
18
|
+
const seconds = Number(header);
|
|
19
|
+
if (Number.isFinite(seconds))
|
|
20
|
+
return Math.max(0, seconds * 1000);
|
|
21
|
+
const at = Date.parse(header);
|
|
22
|
+
return Number.isNaN(at) ? null : Math.max(0, at - now);
|
|
23
|
+
}
|
|
24
|
+
const realSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
25
|
+
/** `fetch` with a per-attempt timeout and up to `attempts` tries on 429 and 5xx; the last response comes back as is and transport errors throw at once. */
|
|
26
|
+
export async function fetchWithRetry(url, init, policy) {
|
|
27
|
+
const fetchFn = policy.fetchFn ?? fetch;
|
|
28
|
+
const attempts = Math.max(1, policy.attempts ?? DEFAULT_ATTEMPTS);
|
|
29
|
+
const baseDelayMs = policy.baseDelayMs ?? DEFAULT_BASE_DELAY_MS;
|
|
30
|
+
const maxDelayMs = policy.maxDelayMs ?? DEFAULT_MAX_DELAY_MS;
|
|
31
|
+
const sleep = policy.sleep ?? realSleep;
|
|
32
|
+
const random = policy.random ?? Math.random;
|
|
33
|
+
for (let attempt = 1;; attempt++) {
|
|
34
|
+
const timeout = AbortSignal.timeout(policy.timeoutMs);
|
|
35
|
+
const signal = init.signal ? AbortSignal.any([init.signal, timeout]) : timeout;
|
|
36
|
+
const res = await fetchFn(url, { ...init, signal });
|
|
37
|
+
if (!isRetryableStatus(res.status) || attempt >= attempts)
|
|
38
|
+
return res;
|
|
39
|
+
const retryAfter = parseRetryAfterMs(res.headers.get('retry-after'));
|
|
40
|
+
if (retryAfter !== null && retryAfter > maxDelayMs)
|
|
41
|
+
return res;
|
|
42
|
+
// Jitter over the upper half keeps parallel callers from retrying in lockstep.
|
|
43
|
+
const ceiling = Math.min(maxDelayMs, baseDelayMs * 2 ** (attempt - 1));
|
|
44
|
+
const delay = retryAfter ?? ceiling / 2 + random() * (ceiling / 2);
|
|
45
|
+
// Frees the pooled socket before the next attempt.
|
|
46
|
+
await res.body?.cancel();
|
|
47
|
+
await sleep(delay);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=http-retry.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
3
|
+
[key: string]: JsonValue;
|
|
4
|
+
};
|
|
5
|
+
export declare function isJsonObjectRecord(value: JsonValue | undefined): value is Record<string, JsonValue>;
|
|
6
|
+
export declare function isHeaderString(value: string | string[] | undefined): value is string;
|
|
7
|
+
export declare const JSON_HEADERS: {
|
|
8
|
+
readonly 'content-type': "application/json";
|
|
9
|
+
};
|
|
10
|
+
export declare class HttpError extends Error {
|
|
11
|
+
status: number;
|
|
12
|
+
constructor(status: number, message: string);
|
|
13
|
+
}
|
|
14
|
+
export declare class BodyTooLargeError extends Error {
|
|
15
|
+
}
|
|
16
|
+
/** The status and client-facing message for one failed request. */
|
|
17
|
+
export interface ApiErrorReply {
|
|
18
|
+
status: number;
|
|
19
|
+
message: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const INTERNAL_ERROR_MESSAGE = "internal server error";
|
|
22
|
+
/** Maps by class so rewording a message never moves a status; an untyped error is a 500 whose text stays in the server log. */
|
|
23
|
+
export declare function mapApiError<E>(err: E): ApiErrorReply;
|
|
24
|
+
export declare function sendJson<T>(res: ServerResponse, status: number, body: T): void;
|
|
25
|
+
/**
|
|
26
|
+
* Read the entire request body into a Buffer. Caps at MAX_BODY_BYTES to keep
|
|
27
|
+
* a malicious or buggy client from exhausting memory. The cap is enforced
|
|
28
|
+
* mid-stream so we don't wait for an attacker to finish before erroring out.
|
|
29
|
+
*/
|
|
30
|
+
export declare function readBody(req: IncomingMessage): Promise<string>;
|
|
31
|
+
/** Per-request values a connector webhook receiver reads; ServeOpts and the /v1 RouteRequest both satisfy it. */
|
|
32
|
+
export interface WebhookRequest {
|
|
33
|
+
req: IncomingMessage;
|
|
34
|
+
res: ServerResponse;
|
|
35
|
+
opts: {
|
|
36
|
+
hippoRoot: string;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=http-util.d.ts.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ApiError } from './api-errors.js';
|
|
2
|
+
export function isJsonObjectRecord(value) {
|
|
3
|
+
return value !== undefined && value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
4
|
+
}
|
|
5
|
+
// node:http header values are `string | string[] | undefined` (never a bare
|
|
6
|
+
// unknown), so this gets its own predicate rather than reusing isJsonString.
|
|
7
|
+
export function isHeaderString(value) {
|
|
8
|
+
return typeof value === 'string';
|
|
9
|
+
}
|
|
10
|
+
// 1 MB body cap. The CLI never sends payloads near this; anything bigger is
|
|
11
|
+
// almost certainly a misconfigured client or a deliberate memory-blowup attempt.
|
|
12
|
+
const MAX_BODY_BYTES = 1024 * 1024;
|
|
13
|
+
export const JSON_HEADERS = { 'content-type': 'application/json' };
|
|
14
|
+
export class HttpError extends Error {
|
|
15
|
+
status;
|
|
16
|
+
constructor(status, message) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.status = status;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class BodyTooLargeError extends Error {
|
|
22
|
+
}
|
|
23
|
+
export const INTERNAL_ERROR_MESSAGE = 'internal server error';
|
|
24
|
+
/** Maps by class so rewording a message never moves a status; an untyped error is a 500 whose text stays in the server log. */
|
|
25
|
+
export function mapApiError(err) {
|
|
26
|
+
if (err instanceof HttpError || err instanceof ApiError)
|
|
27
|
+
return { status: err.status, message: err.message };
|
|
28
|
+
if (err instanceof BodyTooLargeError)
|
|
29
|
+
return { status: 413, message: err.message };
|
|
30
|
+
return { status: 500, message: INTERNAL_ERROR_MESSAGE };
|
|
31
|
+
}
|
|
32
|
+
export function sendJson(res, status, body) {
|
|
33
|
+
res.writeHead(status, JSON_HEADERS);
|
|
34
|
+
res.end(JSON.stringify(body));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Read the entire request body into a Buffer. Caps at MAX_BODY_BYTES to keep
|
|
38
|
+
* a malicious or buggy client from exhausting memory. The cap is enforced
|
|
39
|
+
* mid-stream so we don't wait for an attacker to finish before erroring out.
|
|
40
|
+
*/
|
|
41
|
+
export async function readBody(req) {
|
|
42
|
+
const chunks = [];
|
|
43
|
+
let total = 0;
|
|
44
|
+
for await (const chunk of req) {
|
|
45
|
+
// SAFETY: IncomingMessage never runs setEncoding() here, so every
|
|
46
|
+
// streamed chunk is a Buffer, not a decoded string.
|
|
47
|
+
const buf = chunk;
|
|
48
|
+
total += buf.length;
|
|
49
|
+
if (total > MAX_BODY_BYTES) {
|
|
50
|
+
throw new BodyTooLargeError('request body exceeds 1MB');
|
|
51
|
+
}
|
|
52
|
+
chunks.push(buf);
|
|
53
|
+
}
|
|
54
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=http-util.js.map
|
package/dist/importers.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export interface ImportResult {
|
|
|
20
20
|
/** K1 vault import: rows archived this run (changed + source-deleted). In a
|
|
21
21
|
* dryRun this is the would-be count (a true deletion-sync preview). */
|
|
22
22
|
archived?: number;
|
|
23
|
+
/** Entries stored with secret-shaped text redacted; optional for the same published-surface reason as `rejected`. */
|
|
24
|
+
redacted?: number;
|
|
23
25
|
entries: MemoryEntry[];
|
|
24
26
|
}
|
|
25
27
|
export interface ImportOptions {
|
package/dist/importers.js
CHANGED
|
@@ -13,6 +13,7 @@ import { remember, archiveRaw, isPrivateScope } from './api.js';
|
|
|
13
13
|
import { openHippoDb, closeHippoDb } from './db.js';
|
|
14
14
|
import { RejectedValueError, checkRejectionGuard } from './rejection.js';
|
|
15
15
|
import { loadConfig } from './config.js';
|
|
16
|
+
import { vetSecrets } from './secret-detect.js';
|
|
16
17
|
// ---------------------------------------------------------------------------
|
|
17
18
|
// Shared core: dedup + write
|
|
18
19
|
// ---------------------------------------------------------------------------
|
|
@@ -33,6 +34,7 @@ export function importEntries(chunks, source, tags, options) {
|
|
|
33
34
|
let imported = 0;
|
|
34
35
|
let skipped = 0;
|
|
35
36
|
let rejected = 0;
|
|
37
|
+
let redacted = 0;
|
|
36
38
|
const entries = [];
|
|
37
39
|
// AT1 P2 fix: a dry-run preview never called writeEntry, so it never
|
|
38
40
|
// checked tombstones either — every non-duplicate chunk counted as
|
|
@@ -42,7 +44,9 @@ export function importEntries(chunks, source, tags, options) {
|
|
|
42
44
|
const dryRunDb = options.dryRun ? openHippoDb(targetRoot) : null;
|
|
43
45
|
try {
|
|
44
46
|
for (const raw of chunks) {
|
|
45
|
-
const
|
|
47
|
+
const original = raw.trim();
|
|
48
|
+
const trimmed = vetSecrets(original, allTags, true).content;
|
|
49
|
+
const wasRedacted = trimmed !== original;
|
|
46
50
|
if (trimmed.length > 1000) {
|
|
47
51
|
console.error(`Warning: imported memory truncated from ${trimmed.length} to 1000 chars`);
|
|
48
52
|
}
|
|
@@ -109,8 +113,10 @@ export function importEntries(chunks, source, tags, options) {
|
|
|
109
113
|
}
|
|
110
114
|
entries.push(entry);
|
|
111
115
|
imported++;
|
|
116
|
+
if (wasRedacted)
|
|
117
|
+
redacted++;
|
|
112
118
|
}
|
|
113
|
-
return { total, imported, skipped, rejected, entries };
|
|
119
|
+
return { total, imported, skipped, rejected, redacted, entries };
|
|
114
120
|
}
|
|
115
121
|
finally {
|
|
116
122
|
if (dryRunDb)
|
|
@@ -430,6 +436,7 @@ export function importMarkdown(filePath, options) {
|
|
|
430
436
|
// AT1 P2 fix: `rejected` is now optional on ImportResult (compat) — tolerate
|
|
431
437
|
// undefined on either side of the accumulation.
|
|
432
438
|
rejected: (totalResult.rejected ?? 0) + (result.rejected ?? 0),
|
|
439
|
+
redacted: (totalResult.redacted ?? 0) + (result.redacted ?? 0),
|
|
433
440
|
entries: [...totalResult.entries, ...result.entries],
|
|
434
441
|
};
|
|
435
442
|
}
|
|
@@ -695,6 +702,7 @@ export function importVault(folderPath, options) {
|
|
|
695
702
|
let skipped = 0;
|
|
696
703
|
let rejected = 0;
|
|
697
704
|
let archived = 0;
|
|
705
|
+
let redacted = 0;
|
|
698
706
|
const entries = [];
|
|
699
707
|
const baseHalfLifeDays = loadConfig(hippoRoot).defaultHalfLifeDays;
|
|
700
708
|
// AT1 P2 fix: dry-run never called remember(), so it never probed
|
|
@@ -796,7 +804,8 @@ export function importVault(folderPath, options) {
|
|
|
796
804
|
// remember() owns the actual write. We build an `echo` of the SAME content +
|
|
797
805
|
// tags via createMemory purely for the ImportResult, then reconcile its id to
|
|
798
806
|
// remember()'s real row id so entries[] reflects the row that landed.
|
|
799
|
-
const
|
|
807
|
+
const content = vetSecrets(body, tags, true).content;
|
|
808
|
+
const echo = createMemory(content, {
|
|
800
809
|
kind: 'raw',
|
|
801
810
|
tags,
|
|
802
811
|
scope,
|
|
@@ -815,7 +824,7 @@ export function importVault(folderPath, options) {
|
|
|
815
824
|
// loud each time via the rejected count.
|
|
816
825
|
try {
|
|
817
826
|
const result = remember(ctx, {
|
|
818
|
-
content
|
|
827
|
+
content,
|
|
819
828
|
kind: 'raw',
|
|
820
829
|
artifactRef,
|
|
821
830
|
owner: 'agent:vault-import',
|
|
@@ -848,6 +857,8 @@ export function importVault(folderPath, options) {
|
|
|
848
857
|
}
|
|
849
858
|
entries.push(echo);
|
|
850
859
|
imported++;
|
|
860
|
+
if (content !== body)
|
|
861
|
+
redacted++;
|
|
851
862
|
}
|
|
852
863
|
}
|
|
853
864
|
finally {
|
|
@@ -867,7 +878,7 @@ export function importVault(folderPath, options) {
|
|
|
867
878
|
archiveRaw(ctx, row.id, `source_deleted:${artifactRef}`);
|
|
868
879
|
}
|
|
869
880
|
}
|
|
870
|
-
return { total, imported, skipped, rejected, archived, entries };
|
|
881
|
+
return { total, imported, skipped, rejected, archived, redacted, entries };
|
|
871
882
|
}
|
|
872
883
|
/** Local tolerant JSON-array parse for the loader's `tags_json` column. The
|
|
873
884
|
* store's own `parseJsonArray` is not exported; this matches its contract
|
package/dist/incidents.js
CHANGED
|
@@ -25,8 +25,10 @@
|
|
|
25
25
|
* the row, default `[]`. On save, every id must exist in the SAME tenant; a
|
|
26
26
|
* cross-tenant or nonexistent id is rejected (throw) before the insert.
|
|
27
27
|
*/
|
|
28
|
+
import { BadRequestError, ConflictError, NotFoundError } from './api-errors.js';
|
|
28
29
|
import { openHippoDb, closeHippoDb } from './db.js';
|
|
29
|
-
import { writeEntry
|
|
30
|
+
import { writeEntry } from './store.js';
|
|
31
|
+
import { assertTenantId } from './tenant.js';
|
|
30
32
|
import { createMemory, Layer } from './memory.js';
|
|
31
33
|
import { appendAuditEvent } from './audit.js';
|
|
32
34
|
import { objectHalfLifeDays } from './half-life-migration.js';
|
|
@@ -88,7 +90,7 @@ const INCIDENT_COLS = `
|
|
|
88
90
|
export function saveIncident(hippoRoot, tenantId, opts, actor = 'cli') {
|
|
89
91
|
assertTenantId('saveIncident', tenantId);
|
|
90
92
|
if (!opts.incidentText)
|
|
91
|
-
throw new
|
|
93
|
+
throw new BadRequestError('saveIncident: incidentText is required');
|
|
92
94
|
const now = new Date().toISOString();
|
|
93
95
|
const content = opts.context
|
|
94
96
|
? `${opts.incidentText}\n\nContext: ${opts.context}`
|
|
@@ -117,7 +119,7 @@ export function saveIncident(hippoRoot, tenantId, opts, actor = 'cli') {
|
|
|
117
119
|
// SAFETY: row shape matches the single `id` column named in the SELECT above.
|
|
118
120
|
const exists = db.prepare(`SELECT id FROM memories WHERE id = ? AND tenant_id = ?`).get(linkId, tenantId);
|
|
119
121
|
if (!exists) {
|
|
120
|
-
throw new
|
|
122
|
+
throw new NotFoundError(`saveIncident: linked memory ${linkId} not found for tenant ${tenantId}`);
|
|
121
123
|
}
|
|
122
124
|
validated.push(linkId);
|
|
123
125
|
}
|
|
@@ -163,7 +165,7 @@ export function saveIncident(hippoRoot, tenantId, opts, actor = 'cli') {
|
|
|
163
165
|
export function resolveIncident(hippoRoot, tenantId, id, resolutionText, actor = 'cli') {
|
|
164
166
|
assertTenantId('resolveIncident', tenantId);
|
|
165
167
|
if (!resolutionText || !resolutionText.trim()) {
|
|
166
|
-
throw new
|
|
168
|
+
throw new BadRequestError('resolveIncident: resolutionText is required (non-empty)');
|
|
167
169
|
}
|
|
168
170
|
const now = new Date().toISOString();
|
|
169
171
|
const db = openHippoDb(hippoRoot);
|
|
@@ -179,15 +181,15 @@ export function resolveIncident(hippoRoot, tenantId, id, resolutionText, actor =
|
|
|
179
181
|
// SAFETY: row shape matches the single `status` column named in the SELECT above.
|
|
180
182
|
const existing = db.prepare(`SELECT status FROM incidents WHERE id = ? AND tenant_id = ?`).get(id, tenantId);
|
|
181
183
|
if (!existing) {
|
|
182
|
-
throw new
|
|
184
|
+
throw new NotFoundError(`resolveIncident: incident ${id} not found for tenant ${tenantId}`);
|
|
183
185
|
}
|
|
184
|
-
throw new
|
|
186
|
+
throw new ConflictError(`resolveIncident: incident ${id} is not open (status='${existing.status}'); only open incidents can be resolved.`);
|
|
185
187
|
}
|
|
186
188
|
// SAFETY: row's shape matches the columns named in INCIDENT_COLS above.
|
|
187
189
|
const row = db.prepare(`SELECT ${INCIDENT_COLS} FROM incidents WHERE id = ? AND tenant_id = ?`)
|
|
188
190
|
.get(id, tenantId);
|
|
189
191
|
if (!row)
|
|
190
|
-
throw new
|
|
192
|
+
throw new NotFoundError(`resolveIncident: incident ${id} not found after UPDATE`);
|
|
191
193
|
appendAuditEvent(db, {
|
|
192
194
|
tenantId,
|
|
193
195
|
actor,
|
|
@@ -234,15 +236,15 @@ export function closeIncident(hippoRoot, tenantId, id, actor = 'cli') {
|
|
|
234
236
|
// SAFETY: row shape matches the single `status` column named in the SELECT above.
|
|
235
237
|
const existing = db.prepare(`SELECT status FROM incidents WHERE id = ? AND tenant_id = ?`).get(id, tenantId);
|
|
236
238
|
if (!existing) {
|
|
237
|
-
throw new
|
|
239
|
+
throw new NotFoundError(`closeIncident: incident ${id} not found for tenant ${tenantId}`);
|
|
238
240
|
}
|
|
239
|
-
throw new
|
|
241
|
+
throw new ConflictError(`closeIncident: incident ${id} is already closed (status='${existing.status}'); only open or resolved incidents can be closed.`);
|
|
240
242
|
}
|
|
241
243
|
// SAFETY: row's shape matches the columns named in INCIDENT_COLS above.
|
|
242
244
|
const row = db.prepare(`SELECT ${INCIDENT_COLS} FROM incidents WHERE id = ? AND tenant_id = ?`)
|
|
243
245
|
.get(id, tenantId);
|
|
244
246
|
if (!row)
|
|
245
|
-
throw new
|
|
247
|
+
throw new NotFoundError(`closeIncident: incident ${id} not found after UPDATE`);
|
|
246
248
|
appendAuditEvent(db, {
|
|
247
249
|
tenantId,
|
|
248
250
|
actor,
|
|
@@ -288,7 +290,7 @@ export function loadIncidents(hippoRoot, tenantId, opts = {}) {
|
|
|
288
290
|
let rows;
|
|
289
291
|
if (opts.status) {
|
|
290
292
|
if (!VALID_INCIDENT_STATES.has(opts.status)) {
|
|
291
|
-
throw new
|
|
293
|
+
throw new BadRequestError(`loadIncidents: status must be one of ${Array.from(VALID_INCIDENT_STATES).join('|')}; got ${opts.status}`);
|
|
292
294
|
}
|
|
293
295
|
// SAFETY: rows' shape matches the columns named in INCIDENT_COLS above.
|
|
294
296
|
rows = db.prepare(`
|
package/dist/index.d.ts
CHANGED
|
@@ -5,10 +5,13 @@ import { type CreateMemoryOptions, type MemoryEntry } from './memory.js';
|
|
|
5
5
|
export { MemoryEntry, Layer, EmotionalValence, ConfidenceLevel, DecayOptions, calculateStrength, resolveConfidence, confidenceFacets, type ConfidenceFacets, applyOutcome, generateId, computeSchemaFit } from './memory.js';
|
|
6
6
|
/** Published signature, so `baseHalfLifeDays` stays optional here; hippo's own writers use the strict one in memory.ts. */
|
|
7
7
|
export declare function createMemory(content: string, options?: Partial<CreateMemoryOptions>): MemoryEntry;
|
|
8
|
-
export { search, hybridSearch, physicsSearch,
|
|
8
|
+
export { search, hybridSearch, physicsSearch, estimateTokens, textOverlap, explainMatch, detectTemporalDirection, temporalBoost, computeTemporalRange, SearchResult, MatchExplanation } from './search.js';
|
|
9
|
+
export { tokenize } from './tokenize.js';
|
|
10
|
+
export { markRetrieved } from './memory.js';
|
|
9
11
|
export { multihopSearch } from './multihop.js';
|
|
10
12
|
export { graphExpandRecall, MAX_HOPS, DEFAULT_MAX_NEIGHBORS, type GraphExpandOpts } from './graph-recall.js';
|
|
11
|
-
export { initStore, loadAllEntries, loadSearchEntries, loadRecallSearchEntries, writeEntry, readEntry, deleteEntry, loadIndex, rebuildIndex, saveActiveTaskSnapshot, loadActiveTaskSnapshot, loadFreshActiveTaskSnapshot, SNAPSHOT_AMBIENT_MAX_AGE_MS, closeTaskSnapshotsForSession, clearActiveTaskSnapshot, appendSessionEvent, listSessionEvents, listMemoryConflicts, replaceDetectedConflicts, resolveConflict, saveSessionHandoff, loadLatestHandoff, loadHandoffById, stampHandoffOutcome, writeSessionEndHandoff, loadSessionDecayContext, SessionDecayContext,
|
|
13
|
+
export { initStore, loadAllEntries, loadSearchEntries, loadRecallSearchEntries, writeEntry, readEntry, deleteEntry, loadIndex, rebuildIndex, saveActiveTaskSnapshot, loadActiveTaskSnapshot, loadFreshActiveTaskSnapshot, SNAPSHOT_AMBIENT_MAX_AGE_MS, closeTaskSnapshotsForSession, clearActiveTaskSnapshot, appendSessionEvent, listSessionEvents, listMemoryConflicts, replaceDetectedConflicts, resolveConflict, saveSessionHandoff, loadLatestHandoff, loadHandoffById, stampHandoffOutcome, writeSessionEndHandoff, loadSessionDecayContext, SessionDecayContext, } from './store.js';
|
|
14
|
+
export { createCard, loadCard, listCards, loadCardDeps, loadCardRuns, loadCardComments, claimCard, heartbeatCard, blockCard, reviewCard, completeCard, reclaimExpiredCards, addCardComment, loadLatestHandoffForCard, } from './store-cards.js';
|
|
12
15
|
export { SessionHandoff, HandoffOutcome, HandoffEvidence, isHandoffOutcome } from './handoff.js';
|
|
13
16
|
export { Card, CardStatus, CardRun, CardComment, CardTransitions, isCardStatus, CARD_TRANSITIONS, CARD_LEASE_MS } from './card.js';
|
|
14
17
|
export { consolidate, ConsolidationResult } from './consolidate.js';
|