hippo-memory 0.36.0 → 0.37.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 +16 -0
- package/dist/api.d.ts +20 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +23 -3
- package/dist/api.js.map +1 -1
- package/dist/benchmarks/e1.3/incident-recall-eval.js +74 -0
- package/dist/benchmarks/e1.3/incident-recall-eval.js.map +1 -0
- package/dist/benchmarks/e1.3/scenarios.json +2587 -0
- package/dist/benchmarks/e1.3/slack-1000-event-smoke.js +102 -0
- package/dist/benchmarks/e1.3/slack-1000-event-smoke.js.map +1 -0
- package/dist/cli.js +82 -0
- package/dist/cli.js.map +1 -1
- package/dist/connectors/slack/backfill.d.ts +42 -0
- package/dist/connectors/slack/backfill.d.ts.map +1 -0
- package/dist/connectors/slack/backfill.js +76 -0
- package/dist/connectors/slack/backfill.js.map +1 -0
- package/dist/connectors/slack/deletion.d.ts +14 -0
- package/dist/connectors/slack/deletion.d.ts.map +1 -0
- package/dist/connectors/slack/deletion.js +46 -0
- package/dist/connectors/slack/deletion.js.map +1 -0
- package/dist/connectors/slack/dlq.d.ts +21 -0
- package/dist/connectors/slack/dlq.d.ts.map +1 -0
- package/dist/connectors/slack/dlq.js +23 -0
- package/dist/connectors/slack/dlq.js.map +1 -0
- package/dist/connectors/slack/idempotency.d.ts +5 -0
- package/dist/connectors/slack/idempotency.d.ts.map +1 -0
- package/dist/connectors/slack/idempotency.js +13 -0
- package/dist/connectors/slack/idempotency.js.map +1 -0
- package/dist/connectors/slack/ingest.d.ts +27 -0
- package/dist/connectors/slack/ingest.d.ts.map +1 -0
- package/dist/connectors/slack/ingest.js +48 -0
- package/dist/connectors/slack/ingest.js.map +1 -0
- package/dist/connectors/slack/ratelimit.d.ts +9 -0
- package/dist/connectors/slack/ratelimit.d.ts.map +1 -0
- package/dist/connectors/slack/ratelimit.js +18 -0
- package/dist/connectors/slack/ratelimit.js.map +1 -0
- package/dist/connectors/slack/scope.d.ts +16 -0
- package/dist/connectors/slack/scope.d.ts.map +1 -0
- package/dist/connectors/slack/scope.js +13 -0
- package/dist/connectors/slack/scope.js.map +1 -0
- package/dist/connectors/slack/signature.d.ts +12 -0
- package/dist/connectors/slack/signature.d.ts.map +1 -0
- package/dist/connectors/slack/signature.js +20 -0
- package/dist/connectors/slack/signature.js.map +1 -0
- package/dist/connectors/slack/tenant-routing.d.ts +13 -0
- package/dist/connectors/slack/tenant-routing.d.ts.map +1 -0
- package/dist/connectors/slack/tenant-routing.js +17 -0
- package/dist/connectors/slack/tenant-routing.js.map +1 -0
- package/dist/connectors/slack/transform.d.ts +20 -0
- package/dist/connectors/slack/transform.d.ts.map +1 -0
- package/dist/connectors/slack/transform.js +31 -0
- package/dist/connectors/slack/transform.js.map +1 -0
- package/dist/connectors/slack/types.d.ts +35 -0
- package/dist/connectors/slack/types.d.ts.map +1 -0
- package/dist/connectors/slack/types.js +23 -0
- package/dist/connectors/slack/types.js.map +1 -0
- package/dist/connectors/slack/web-client.d.ts +12 -0
- package/dist/connectors/slack/web-client.d.ts.map +1 -0
- package/dist/connectors/slack/web-client.js +43 -0
- package/dist/connectors/slack/web-client.js.map +1 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +46 -1
- package/dist/db.js.map +1 -1
- package/dist/importers.js +3 -3
- package/dist/importers.js.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +174 -2
- package/dist/server.js.map +1 -1
- package/dist/src/ambient.js +147 -0
- package/dist/src/ambient.js.map +1 -0
- package/dist/src/api.js +343 -0
- package/dist/src/api.js.map +1 -0
- package/dist/src/audit.js +152 -0
- package/dist/src/audit.js.map +1 -0
- package/dist/src/auth.js +65 -0
- package/dist/src/auth.js.map +1 -0
- package/dist/src/autolearn.js +143 -0
- package/dist/src/autolearn.js.map +1 -0
- package/dist/src/capture.js +512 -0
- package/dist/src/capture.js.map +1 -0
- package/dist/src/cli.js +4971 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/client.js +181 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/config.js +108 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/connectors/slack/backfill.js +76 -0
- package/dist/src/connectors/slack/backfill.js.map +1 -0
- package/dist/src/connectors/slack/deletion.js +46 -0
- package/dist/src/connectors/slack/deletion.js.map +1 -0
- package/dist/src/connectors/slack/dlq.js +23 -0
- package/dist/src/connectors/slack/dlq.js.map +1 -0
- package/dist/src/connectors/slack/idempotency.js +13 -0
- package/dist/src/connectors/slack/idempotency.js.map +1 -0
- package/dist/src/connectors/slack/ingest.js +48 -0
- package/dist/src/connectors/slack/ingest.js.map +1 -0
- package/dist/src/connectors/slack/ratelimit.js +18 -0
- package/dist/src/connectors/slack/ratelimit.js.map +1 -0
- package/dist/src/connectors/slack/scope.js +13 -0
- package/dist/src/connectors/slack/scope.js.map +1 -0
- package/dist/src/connectors/slack/signature.js +20 -0
- package/dist/src/connectors/slack/signature.js.map +1 -0
- package/dist/src/connectors/slack/tenant-routing.js +17 -0
- package/dist/src/connectors/slack/tenant-routing.js.map +1 -0
- package/dist/src/connectors/slack/transform.js +31 -0
- package/dist/src/connectors/slack/transform.js.map +1 -0
- package/dist/src/connectors/slack/types.js +23 -0
- package/dist/src/connectors/slack/types.js.map +1 -0
- package/dist/src/connectors/slack/web-client.js +43 -0
- package/dist/src/connectors/slack/web-client.js.map +1 -0
- package/dist/src/consolidate.js +517 -0
- package/dist/src/consolidate.js.map +1 -0
- package/dist/src/dag.js +104 -0
- package/dist/src/dag.js.map +1 -0
- package/dist/src/dashboard.js +409 -0
- package/dist/src/dashboard.js.map +1 -0
- package/dist/src/db.js +584 -0
- package/dist/src/db.js.map +1 -0
- package/dist/src/embeddings.js +344 -0
- package/dist/src/embeddings.js.map +1 -0
- package/dist/src/eval-suite.js +289 -0
- package/dist/src/eval-suite.js.map +1 -0
- package/dist/src/eval.js +187 -0
- package/dist/src/eval.js.map +1 -0
- package/dist/src/extract.js +87 -0
- package/dist/src/extract.js.map +1 -0
- package/dist/src/handoff.js +30 -0
- package/dist/src/handoff.js.map +1 -0
- package/dist/src/hooks.js +582 -0
- package/dist/src/hooks.js.map +1 -0
- package/dist/src/importers.js +399 -0
- package/dist/src/importers.js.map +1 -0
- package/dist/src/index.js +25 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/invalidation.js +94 -0
- package/dist/src/invalidation.js.map +1 -0
- package/dist/src/mcp/framing.js +45 -0
- package/dist/src/mcp/framing.js.map +1 -0
- package/dist/src/mcp/server.js +510 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/memory.js +280 -0
- package/dist/src/memory.js.map +1 -0
- package/dist/src/multihop.js +32 -0
- package/dist/src/multihop.js.map +1 -0
- package/dist/src/path-context.js +32 -0
- package/dist/src/path-context.js.map +1 -0
- package/dist/src/physics-config.js +26 -0
- package/dist/src/physics-config.js.map +1 -0
- package/dist/src/physics-state.js +163 -0
- package/dist/src/physics-state.js.map +1 -0
- package/dist/src/physics.js +361 -0
- package/dist/src/physics.js.map +1 -0
- package/dist/src/postinstall.js +68 -0
- package/dist/src/postinstall.js.map +1 -0
- package/dist/src/raw-archive.js +72 -0
- package/dist/src/raw-archive.js.map +1 -0
- package/dist/src/refine-llm.js +147 -0
- package/dist/src/refine-llm.js.map +1 -0
- package/dist/src/replay.js +117 -0
- package/dist/src/replay.js.map +1 -0
- package/dist/src/salience.js +74 -0
- package/dist/src/salience.js.map +1 -0
- package/dist/src/scheduler.js +67 -0
- package/dist/src/scheduler.js.map +1 -0
- package/dist/src/scope.js +35 -0
- package/dist/src/scope.js.map +1 -0
- package/dist/src/search.js +801 -0
- package/dist/src/search.js.map +1 -0
- package/dist/src/server-detect.js +70 -0
- package/dist/src/server-detect.js.map +1 -0
- package/dist/src/server.js +784 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/shared.js +309 -0
- package/dist/src/shared.js.map +1 -0
- package/dist/src/sso.js +22 -0
- package/dist/src/sso.js.map +1 -0
- package/dist/src/store.js +1390 -0
- package/dist/src/store.js.map +1 -0
- package/dist/src/tenant.js +17 -0
- package/dist/src/tenant.js.map +1 -0
- package/dist/src/trace.js +64 -0
- package/dist/src/trace.js.map +1 -0
- package/dist/src/working-memory.js +149 -0
- package/dist/src/working-memory.js.map +1 -0
- package/dist/src/yaml.js +98 -0
- package/dist/src/yaml.js.map +1 -0
- package/dist/store.d.ts +9 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +30 -2
- package/dist/store.js.map +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 +2 -2
- package/dist/import.d.ts +0 -31
- package/dist/import.d.ts.map +0 -1
- package/dist/import.js +0 -307
- package/dist/import.js.map +0 -1
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
const STOP_WORDS = new Set([
|
|
2
|
+
'the', 'a', 'an', 'is', 'was', 'are', 'were', 'be', 'been', 'being',
|
|
3
|
+
'to', 'of', 'in', 'for', 'on', 'with', 'at', 'by', 'from', 'it',
|
|
4
|
+
'this', 'that', 'and', 'or', 'but', 'not', 'no', 'so', 'if', 'do',
|
|
5
|
+
'did', 'does', 'has', 'had', 'have', 'will', 'would', 'could', 'should',
|
|
6
|
+
'may', 'might', 'can', 'shall', 'we', 'i', 'you', 'they', 'he', 'she',
|
|
7
|
+
'my', 'our', 'your', 'its', 'his', 'her', 'their', 'up', 'out', 'just',
|
|
8
|
+
'also', 'then', 'than', 'some', 'all', 'any', 'each', 'very', 'too',
|
|
9
|
+
]);
|
|
10
|
+
const VAGUE_ONLY = /^[\w\s,.'"-]+$/;
|
|
11
|
+
function substantiveWordCount(text) {
|
|
12
|
+
return text
|
|
13
|
+
.toLowerCase()
|
|
14
|
+
.split(/\s+/)
|
|
15
|
+
.filter(w => w.length > 2 && !STOP_WORDS.has(w))
|
|
16
|
+
.length;
|
|
17
|
+
}
|
|
18
|
+
function isVersionBump(text) {
|
|
19
|
+
const t = text.trim();
|
|
20
|
+
// release/bump/prep/tag + version
|
|
21
|
+
if (/^(?:bump|release|prep|tag)\s+(?:to\s+)?v?\d+\.\d+/i.test(t))
|
|
22
|
+
return true;
|
|
23
|
+
// bare semver ("0.24.1", "v1.2.3")
|
|
24
|
+
if (/^v?\d+\.\d+\.\d+\s*$/i.test(t))
|
|
25
|
+
return true;
|
|
26
|
+
// chore: release 1.2.3 / chore(ci): bump v1.2.3
|
|
27
|
+
if (/^chore(?:\([^)]+\))?:\s*(?:release|bump|version|tag|prep)\b/i.test(t))
|
|
28
|
+
return true;
|
|
29
|
+
// Merge commits
|
|
30
|
+
if (/^(?:Merge branch|Merge pull request)\b/i.test(t))
|
|
31
|
+
return true;
|
|
32
|
+
// WIP sentinels
|
|
33
|
+
if (/^WIP\b/i.test(t))
|
|
34
|
+
return true;
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
function isFragment(text) {
|
|
38
|
+
const trimmed = text.trim();
|
|
39
|
+
if (trimmed.startsWith('to ') && trimmed.length < 50)
|
|
40
|
+
return true;
|
|
41
|
+
if (trimmed.startsWith('for ') && trimmed.length < 50)
|
|
42
|
+
return true;
|
|
43
|
+
if (trimmed.startsWith('and ') && trimmed.length < 50)
|
|
44
|
+
return true;
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
function hasNoSpecificity(text) {
|
|
48
|
+
const words = text.toLowerCase().split(/\s+/);
|
|
49
|
+
const hasNumber = /\d/.test(text);
|
|
50
|
+
const hasProperNoun = /[A-Z][a-z]{2,}/.test(text);
|
|
51
|
+
const hasPath = /[/\\.]/.test(text);
|
|
52
|
+
const hasCode = /[`_{}()\[\]]/.test(text);
|
|
53
|
+
if (hasNumber || hasProperNoun || hasPath || hasCode)
|
|
54
|
+
return false;
|
|
55
|
+
return words.length < 8 && VAGUE_ONLY.test(text);
|
|
56
|
+
}
|
|
57
|
+
export function auditMemory(entry) {
|
|
58
|
+
const content = entry.content.trim();
|
|
59
|
+
if (content.length < 3) {
|
|
60
|
+
return { memoryId: entry.id, content, severity: 'error', reason: 'too short (< 3 chars)' };
|
|
61
|
+
}
|
|
62
|
+
if (content.length < 10) {
|
|
63
|
+
return { memoryId: entry.id, content, severity: 'error', reason: 'too short (< 10 chars)' };
|
|
64
|
+
}
|
|
65
|
+
if (isVersionBump(content)) {
|
|
66
|
+
return { memoryId: entry.id, content, severity: 'error', reason: 'release/commit noise, not a useful memory' };
|
|
67
|
+
}
|
|
68
|
+
if (isFragment(content)) {
|
|
69
|
+
return { memoryId: entry.id, content, severity: 'warning', reason: 'sentence fragment — lacks context' };
|
|
70
|
+
}
|
|
71
|
+
const substantive = substantiveWordCount(content);
|
|
72
|
+
if (substantive < 2) {
|
|
73
|
+
return { memoryId: entry.id, content, severity: 'warning', reason: `only ${substantive} substantive word(s) — too vague` };
|
|
74
|
+
}
|
|
75
|
+
if (content.length < 40 && hasNoSpecificity(content)) {
|
|
76
|
+
return { memoryId: entry.id, content, severity: 'warning', reason: 'no specific details (names, paths, numbers, code)' };
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
export function auditMemories(entries) {
|
|
81
|
+
const issues = [];
|
|
82
|
+
for (const entry of entries) {
|
|
83
|
+
const issue = auditMemory(entry);
|
|
84
|
+
if (issue)
|
|
85
|
+
issues.push(issue);
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
total: entries.length,
|
|
89
|
+
issues,
|
|
90
|
+
clean: entries.length - issues.length,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export function isContentWorthStoring(content) {
|
|
94
|
+
const trimmed = content.trim();
|
|
95
|
+
if (trimmed.length < 10)
|
|
96
|
+
return false;
|
|
97
|
+
if (isVersionBump(trimmed))
|
|
98
|
+
return false;
|
|
99
|
+
if (isFragment(trimmed))
|
|
100
|
+
return false;
|
|
101
|
+
if (substantiveWordCount(trimmed) < 2)
|
|
102
|
+
return false;
|
|
103
|
+
if (trimmed.length < 40 && hasNoSpecificity(trimmed))
|
|
104
|
+
return false;
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
// node:sqlite returns INTEGER columns as bigint when the value exceeds
|
|
108
|
+
// Number.MAX_SAFE_INTEGER. Audit metadata can carry such values (row ids,
|
|
109
|
+
// counts), and JSON.stringify cannot serialize bigint without a replacer.
|
|
110
|
+
// Mirrors the bigintSafeReplacer in src/raw-archive.ts.
|
|
111
|
+
function bigintSafeReplacer(_key, value) {
|
|
112
|
+
return typeof value === 'bigint' ? value.toString() : value;
|
|
113
|
+
}
|
|
114
|
+
export function appendAuditEvent(db, opts) {
|
|
115
|
+
db.prepare(`INSERT INTO audit_log (ts, tenant_id, actor, op, target_id, metadata_json) VALUES (?, ?, ?, ?, ?, ?)`).run(new Date().toISOString(), opts.tenantId, opts.actor, opts.op, opts.targetId ?? null, JSON.stringify(opts.metadata ?? {}, bigintSafeReplacer));
|
|
116
|
+
}
|
|
117
|
+
export function queryAuditEvents(db, opts) {
|
|
118
|
+
const where = ['tenant_id = ?'];
|
|
119
|
+
const params = [opts.tenantId];
|
|
120
|
+
if (opts.op) {
|
|
121
|
+
where.push('op = ?');
|
|
122
|
+
params.push(opts.op);
|
|
123
|
+
}
|
|
124
|
+
if (opts.since) {
|
|
125
|
+
where.push('ts >= ?');
|
|
126
|
+
params.push(opts.since);
|
|
127
|
+
}
|
|
128
|
+
const limit = Math.max(1, Math.min(opts.limit ?? 100, 10000));
|
|
129
|
+
const rows = db
|
|
130
|
+
.prepare(`SELECT id, ts, tenant_id, actor, op, target_id, metadata_json
|
|
131
|
+
FROM audit_log WHERE ${where.join(' AND ')} ORDER BY ts DESC, id DESC LIMIT ?`)
|
|
132
|
+
.all(...params, limit);
|
|
133
|
+
return rows.map((r) => ({
|
|
134
|
+
id: r.id,
|
|
135
|
+
ts: r.ts,
|
|
136
|
+
tenantId: r.tenant_id,
|
|
137
|
+
actor: r.actor,
|
|
138
|
+
op: r.op,
|
|
139
|
+
targetId: r.target_id,
|
|
140
|
+
metadata: safeJsonParse(r.metadata_json),
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
function safeJsonParse(raw) {
|
|
144
|
+
try {
|
|
145
|
+
const v = JSON.parse(raw);
|
|
146
|
+
return typeof v === 'object' && v !== null ? v : {};
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return {};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/audit.ts"],"names":[],"mappings":"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"}
|
package/dist/src/auth.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { randomBytes, scryptSync, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
const KEY_PREFIX = 'hk_';
|
|
3
|
+
const ID_LEN = 24; // base32 chars after prefix
|
|
4
|
+
const SECRET_LEN = 32; // base32 chars after dot
|
|
5
|
+
const SCRYPT_KEYLEN = 32;
|
|
6
|
+
const BASE32 = 'abcdefghijklmnopqrstuvwxyz234567';
|
|
7
|
+
function randBase32(n) {
|
|
8
|
+
const bytes = randomBytes(n);
|
|
9
|
+
let out = '';
|
|
10
|
+
for (let i = 0; i < n; i++)
|
|
11
|
+
out += BASE32[bytes[i] % 32];
|
|
12
|
+
return out;
|
|
13
|
+
}
|
|
14
|
+
function hashKey(plaintext) {
|
|
15
|
+
// Format: scrypt$<saltHex>$<hashHex>
|
|
16
|
+
const salt = randomBytes(16);
|
|
17
|
+
const hash = scryptSync(plaintext, salt, SCRYPT_KEYLEN);
|
|
18
|
+
return `scrypt$${salt.toString('hex')}$${hash.toString('hex')}`;
|
|
19
|
+
}
|
|
20
|
+
function verifyKey(plaintext, stored) {
|
|
21
|
+
const parts = stored.split('$');
|
|
22
|
+
if (parts.length !== 3 || parts[0] !== 'scrypt')
|
|
23
|
+
return false;
|
|
24
|
+
const salt = Buffer.from(parts[1], 'hex');
|
|
25
|
+
const expected = Buffer.from(parts[2], 'hex');
|
|
26
|
+
const actual = scryptSync(plaintext, salt, expected.length);
|
|
27
|
+
return expected.length === actual.length && timingSafeEqual(expected, actual);
|
|
28
|
+
}
|
|
29
|
+
export function createApiKey(db, opts) {
|
|
30
|
+
const keyId = `${KEY_PREFIX}${randBase32(ID_LEN)}`;
|
|
31
|
+
const secret = randBase32(SECRET_LEN);
|
|
32
|
+
const plaintext = `${keyId}.${secret}`;
|
|
33
|
+
const hash = hashKey(plaintext);
|
|
34
|
+
db.prepare(`INSERT INTO api_keys (key_id, key_hash, tenant_id, label, created_at) VALUES (?, ?, ?, ?, ?)`).run(keyId, hash, opts.tenantId, opts.label ?? null, new Date().toISOString());
|
|
35
|
+
return { keyId, plaintext };
|
|
36
|
+
}
|
|
37
|
+
export function validateApiKey(db, plaintext) {
|
|
38
|
+
const dot = plaintext.indexOf('.');
|
|
39
|
+
if (dot < 0)
|
|
40
|
+
return { valid: false };
|
|
41
|
+
const keyId = plaintext.slice(0, dot);
|
|
42
|
+
const row = db
|
|
43
|
+
.prepare(`SELECT key_hash, tenant_id, revoked_at FROM api_keys WHERE key_id = ?`)
|
|
44
|
+
.get(keyId);
|
|
45
|
+
if (!row || row.revoked_at)
|
|
46
|
+
return { valid: false };
|
|
47
|
+
if (!verifyKey(plaintext, row.key_hash))
|
|
48
|
+
return { valid: false };
|
|
49
|
+
return { valid: true, tenantId: row.tenant_id, keyId };
|
|
50
|
+
}
|
|
51
|
+
export function revokeApiKey(db, keyId) {
|
|
52
|
+
db.prepare(`UPDATE api_keys SET revoked_at = ? WHERE key_id = ? AND revoked_at IS NULL`)
|
|
53
|
+
.run(new Date().toISOString(), keyId);
|
|
54
|
+
}
|
|
55
|
+
export function listApiKeys(db, opts) {
|
|
56
|
+
const sql = opts.active
|
|
57
|
+
? `SELECT key_id, tenant_id, label, created_at, revoked_at FROM api_keys WHERE revoked_at IS NULL ORDER BY id DESC`
|
|
58
|
+
: `SELECT key_id, tenant_id, label, created_at, revoked_at FROM api_keys ORDER BY id DESC`;
|
|
59
|
+
const rows = db.prepare(sql).all();
|
|
60
|
+
return rows.map(r => ({
|
|
61
|
+
keyId: r.key_id, tenantId: r.tenant_id, label: r.label,
|
|
62
|
+
createdAt: r.created_at, revokedAt: r.revoked_at,
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-learn from errors and git history.
|
|
3
|
+
* Agents learn from failures without explicit hippo remember calls.
|
|
4
|
+
*/
|
|
5
|
+
import { execSync, execFileSync, spawn } from 'child_process';
|
|
6
|
+
import { createMemory, Layer } from './memory.js';
|
|
7
|
+
import { loadAllEntries } from './store.js';
|
|
8
|
+
import { textOverlap } from './search.js';
|
|
9
|
+
/**
|
|
10
|
+
* Create a MemoryEntry capturing a command failure.
|
|
11
|
+
* Content format: "Command '<cmd>' failed: <truncated stderr>"
|
|
12
|
+
*/
|
|
13
|
+
export function captureError(exitCode, stderr, command) {
|
|
14
|
+
// Truncate to first 500 chars to avoid storing megabytes of build logs
|
|
15
|
+
const wasTruncated = stderr.length > 500;
|
|
16
|
+
const truncated = stderr.slice(0, 500).trim();
|
|
17
|
+
const suffix = wasTruncated ? ' [truncated]' : '';
|
|
18
|
+
// Strip leading env var assignments (KEY=val or key=val) before the actual command name
|
|
19
|
+
const safeCmd = command.replace(/^([A-Za-z_][A-Za-z0-9_]*=\S+\s+)+/, '').trim() || '(redacted)';
|
|
20
|
+
const content = `Command '${safeCmd}' failed (exit ${exitCode}): ${truncated}${suffix}`;
|
|
21
|
+
// Derive a sanitized tag from the command name (first word, strip path)
|
|
22
|
+
const cmdBase = safeCmd.split(/\s+/)[0].replace(/[^a-zA-Z0-9-]/g, '');
|
|
23
|
+
const tags = ['error', 'autolearn'];
|
|
24
|
+
if (cmdBase)
|
|
25
|
+
tags.push(cmdBase.toLowerCase().slice(0, 30));
|
|
26
|
+
return createMemory(content, {
|
|
27
|
+
layer: Layer.Episodic,
|
|
28
|
+
tags,
|
|
29
|
+
source: 'autolearn',
|
|
30
|
+
confidence: 'observed',
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Parse git log output for actionable lessons.
|
|
35
|
+
* Looks for fix:, revert:, bug:, error:, hotfix: commit messages.
|
|
36
|
+
*/
|
|
37
|
+
export function extractLessons(gitLog, customPatterns) {
|
|
38
|
+
const lessons = [];
|
|
39
|
+
const lines = gitLog.split('\n');
|
|
40
|
+
// Patterns that indicate a lesson to learn from
|
|
41
|
+
// Covers: fix, revert, bug, error, hotfix, refactor, perf, chore, breaking, deprecate
|
|
42
|
+
const prefixes = customPatterns?.join('|') ?? 'fix|revert|bug|error|hotfix|bugfix|refactor|perf|chore|breaking|deprecate';
|
|
43
|
+
const patterns = [
|
|
44
|
+
new RegExp(`^[a-f0-9]+\\s+(${prefixes})(\\(.+?\\))?:?\\s+(.+)`, 'i'),
|
|
45
|
+
new RegExp(`^(${prefixes})(\\(.+?\\))?:?\\s+(.+)`, 'i'),
|
|
46
|
+
/^(Fix|Revert|Bug|Hotfix|Bugfix|Refactor|Perf)\s+(.+)/,
|
|
47
|
+
/\b(fixed|reverted|corrected|resolved|refactored|optimized|deprecated)\b.{3,100}/i,
|
|
48
|
+
];
|
|
49
|
+
for (const line of lines) {
|
|
50
|
+
const trimmed = line.trim();
|
|
51
|
+
if (!trimmed || trimmed.startsWith('commit ') || trimmed.startsWith('Author:') || trimmed.startsWith('Date:')) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
// Strip leading git hash if present (real hashes are hex, but be lenient with alphanumeric prefixes)
|
|
55
|
+
const subject = trimmed.replace(/^[a-z0-9]{6,40}\s+/i, '');
|
|
56
|
+
for (const pat of patterns) {
|
|
57
|
+
const m = subject.match(pat);
|
|
58
|
+
if (m) {
|
|
59
|
+
// For conventional commits: use group 3 (message after prefix), group 2, or full match
|
|
60
|
+
const lesson = (m[3] ?? m[2] ?? m[0]).trim();
|
|
61
|
+
if (lesson.length > 5 && lesson.length < 500) {
|
|
62
|
+
lessons.push(lesson);
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Deduplicate exact matches at extraction time
|
|
69
|
+
return [...new Set(lessons)];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Check if a substantially similar memory already exists.
|
|
73
|
+
* Returns true if overlap > threshold (default 0.7).
|
|
74
|
+
*/
|
|
75
|
+
export function deduplicateLesson(hippoRootOrEntries, lesson, threshold = 0.7) {
|
|
76
|
+
const entries = typeof hippoRootOrEntries === 'string'
|
|
77
|
+
? loadAllEntries(hippoRootOrEntries)
|
|
78
|
+
: hippoRootOrEntries;
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
const overlap = textOverlap(lesson, entry.content);
|
|
81
|
+
if (overlap > threshold)
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Run a command, streaming stdout/stderr to the terminal in real time.
|
|
88
|
+
* Returns: { exitCode, stderr }.
|
|
89
|
+
*/
|
|
90
|
+
export function runWatched(command) {
|
|
91
|
+
return new Promise((resolve) => {
|
|
92
|
+
// Use shell: true so the command string is handled by the shell as-is
|
|
93
|
+
const child = spawn(command, { shell: true, stdio: ['inherit', 'inherit', 'pipe'] });
|
|
94
|
+
const stderrChunks = [];
|
|
95
|
+
child.stderr.on('data', (chunk) => {
|
|
96
|
+
stderrChunks.push(chunk);
|
|
97
|
+
// Also pass through to terminal
|
|
98
|
+
process.stderr.write(chunk);
|
|
99
|
+
});
|
|
100
|
+
child.on('close', (code) => {
|
|
101
|
+
resolve({
|
|
102
|
+
exitCode: code ?? 1,
|
|
103
|
+
stderr: Buffer.concat(stderrChunks).toString('utf8'),
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
child.on('error', (err) => {
|
|
107
|
+
resolve({ exitCode: 1, stderr: err.message });
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Check whether a directory is a git work tree.
|
|
113
|
+
*/
|
|
114
|
+
export function isGitRepo(cwd) {
|
|
115
|
+
try {
|
|
116
|
+
const raw = execSync('git rev-parse --is-inside-work-tree', {
|
|
117
|
+
encoding: 'utf8',
|
|
118
|
+
cwd,
|
|
119
|
+
timeout: 10000,
|
|
120
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
121
|
+
});
|
|
122
|
+
return raw.trim() === 'true';
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Fetch recent git log lines (subject lines only).
|
|
130
|
+
* days: how many days of history to include.
|
|
131
|
+
*/
|
|
132
|
+
export function fetchGitLog(cwd, days) {
|
|
133
|
+
try {
|
|
134
|
+
const raw = execFileSync('git', [
|
|
135
|
+
'log', `--since=${days} days ago`, '--pretty=format:%s',
|
|
136
|
+
], { encoding: 'utf8', cwd, timeout: 10000, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
137
|
+
return typeof raw === 'string' ? raw : '';
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return '';
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=autolearn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autolearn.js","sourceRoot":"","sources":["../../src/autolearn.ts"],"names":[],"mappings":"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"}
|