kiro-memory 2.1.0 → 3.0.1
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 +5 -1
- package/package.json +3 -3
- package/plugin/dist/cli/contextkit.js +2342 -183
- package/plugin/dist/hooks/agentSpawn.js +575 -52
- package/plugin/dist/hooks/kiro-hooks.js +575 -52
- package/plugin/dist/hooks/postToolUse.js +583 -59
- package/plugin/dist/hooks/stop.js +575 -52
- package/plugin/dist/hooks/userPromptSubmit.js +578 -53
- package/plugin/dist/index.js +576 -53
- package/plugin/dist/plugins/github/github-client.js +152 -0
- package/plugin/dist/plugins/github/index.js +412 -0
- package/plugin/dist/plugins/github/issue-parser.js +54 -0
- package/plugin/dist/plugins/slack/formatter.js +90 -0
- package/plugin/dist/plugins/slack/index.js +215 -0
- package/plugin/dist/sdk/index.js +575 -52
- package/plugin/dist/servers/mcp-server.js +4461 -397
- package/plugin/dist/services/search/EmbeddingService.js +64 -20
- package/plugin/dist/services/search/HybridSearch.js +380 -38
- package/plugin/dist/services/search/VectorSearch.js +65 -21
- package/plugin/dist/services/search/index.js +380 -38
- package/plugin/dist/services/sqlite/Backup.js +416 -0
- package/plugin/dist/services/sqlite/Database.js +98 -3
- package/plugin/dist/services/sqlite/ImportExport.js +452 -0
- package/plugin/dist/services/sqlite/Observations.js +291 -7
- package/plugin/dist/services/sqlite/Prompts.js +1 -1
- package/plugin/dist/services/sqlite/Search.js +10 -10
- package/plugin/dist/services/sqlite/Summaries.js +4 -4
- package/plugin/dist/services/sqlite/index.js +1350 -31
- package/plugin/dist/viewer.css +1 -1
- package/plugin/dist/viewer.js +16 -8
- package/plugin/dist/viewer.js.map +4 -4
- package/plugin/dist/worker-service.js +326 -75
- package/plugin/dist/worker-service.js.map +4 -4
|
@@ -15,6 +15,290 @@ var __export = (target, all) => {
|
|
|
15
15
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
// src/utils/secrets.ts
|
|
19
|
+
function redactSecrets(text) {
|
|
20
|
+
if (!text) return text;
|
|
21
|
+
let redacted = text;
|
|
22
|
+
for (const { pattern } of SECRET_PATTERNS) {
|
|
23
|
+
pattern.lastIndex = 0;
|
|
24
|
+
redacted = redacted.replace(pattern, (match) => {
|
|
25
|
+
const prefix = match.substring(0, Math.min(4, match.length));
|
|
26
|
+
return `${prefix}***REDACTED***`;
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return redacted;
|
|
30
|
+
}
|
|
31
|
+
var SECRET_PATTERNS;
|
|
32
|
+
var init_secrets = __esm({
|
|
33
|
+
"src/utils/secrets.ts"() {
|
|
34
|
+
"use strict";
|
|
35
|
+
SECRET_PATTERNS = [
|
|
36
|
+
// AWS Access Keys (AKIA, ABIA, ACCA, ASIA prefixes + 16 alphanumeric chars)
|
|
37
|
+
{ name: "aws-key", pattern: /(?:AKIA|ABIA|ACCA|ASIA)[A-Z0-9]{16}/g },
|
|
38
|
+
// JWT tokens (three base64url segments separated by dots)
|
|
39
|
+
{ name: "jwt", pattern: /eyJ[a-zA-Z0-9_-]{10,}\.eyJ[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}/g },
|
|
40
|
+
// Generic API keys in key=value or key: value assignments
|
|
41
|
+
{ name: "api-key", pattern: /(?:api[_-]?key|apikey|api[_-]?secret)\s*[:=]\s*['"]?([a-zA-Z0-9_\-]{20,})['"]?/gi },
|
|
42
|
+
// Password/secret/token in variable assignments
|
|
43
|
+
{ name: "credential", pattern: /(?:password|passwd|pwd|secret|token|auth[_-]?token|access[_-]?token|bearer)\s*[:=]\s*['"]?([^\s'"]{8,})['"]?/gi },
|
|
44
|
+
// Credentials embedded in URLs (user:pass@host)
|
|
45
|
+
{ name: "url-credential", pattern: /(?:https?:\/\/)([^:]+):([^@]+)@/g },
|
|
46
|
+
// PEM-encoded private keys (RSA, EC, DSA, OpenSSH)
|
|
47
|
+
{ name: "private-key", pattern: /-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g },
|
|
48
|
+
// GitHub personal access tokens (ghp_, gho_, ghu_, ghs_, ghr_ prefixes)
|
|
49
|
+
{ name: "github-token", pattern: /gh[pousr]_[a-zA-Z0-9]{36,}/g },
|
|
50
|
+
// Slack bot/user/app tokens
|
|
51
|
+
{ name: "slack-token", pattern: /xox[bpoas]-[a-zA-Z0-9-]{10,}/g },
|
|
52
|
+
// HTTP Authorization Bearer header values
|
|
53
|
+
{ name: "bearer-header", pattern: /\bBearer\s+([a-zA-Z0-9_\-\.]{20,})/g },
|
|
54
|
+
// Generic hex secrets (32+ hex chars after a key/secret/token/password label)
|
|
55
|
+
{ name: "hex-secret", pattern: /(?:key|secret|token|password)\s*[:=]\s*['"]?([0-9a-f]{32,})['"]?/gi }
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// src/utils/categorizer.ts
|
|
61
|
+
function categorize(input) {
|
|
62
|
+
const scores = /* @__PURE__ */ new Map();
|
|
63
|
+
const searchText = [
|
|
64
|
+
input.title,
|
|
65
|
+
input.text || "",
|
|
66
|
+
input.narrative || "",
|
|
67
|
+
input.concepts || ""
|
|
68
|
+
].join(" ").toLowerCase();
|
|
69
|
+
const allFiles = [input.filesModified || "", input.filesRead || ""].join(",");
|
|
70
|
+
for (const rule of CATEGORY_RULES) {
|
|
71
|
+
let score = 0;
|
|
72
|
+
for (const kw of rule.keywords) {
|
|
73
|
+
if (searchText.includes(kw.toLowerCase())) {
|
|
74
|
+
score += rule.weight;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (rule.types && rule.types.includes(input.type)) {
|
|
78
|
+
score += rule.weight * 2;
|
|
79
|
+
}
|
|
80
|
+
if (rule.filePatterns && allFiles) {
|
|
81
|
+
for (const pattern of rule.filePatterns) {
|
|
82
|
+
if (pattern.test(allFiles)) {
|
|
83
|
+
score += rule.weight;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (score > 0) {
|
|
88
|
+
scores.set(rule.category, (scores.get(rule.category) || 0) + score);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
let bestCategory = "general";
|
|
92
|
+
let bestScore = 0;
|
|
93
|
+
for (const [category, score] of scores) {
|
|
94
|
+
if (score > bestScore) {
|
|
95
|
+
bestScore = score;
|
|
96
|
+
bestCategory = category;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return bestCategory;
|
|
100
|
+
}
|
|
101
|
+
var CATEGORY_RULES;
|
|
102
|
+
var init_categorizer = __esm({
|
|
103
|
+
"src/utils/categorizer.ts"() {
|
|
104
|
+
"use strict";
|
|
105
|
+
CATEGORY_RULES = [
|
|
106
|
+
{
|
|
107
|
+
category: "security",
|
|
108
|
+
keywords: [
|
|
109
|
+
"security",
|
|
110
|
+
"vulnerability",
|
|
111
|
+
"cve",
|
|
112
|
+
"xss",
|
|
113
|
+
"csrf",
|
|
114
|
+
"injection",
|
|
115
|
+
"sanitize",
|
|
116
|
+
"escape",
|
|
117
|
+
"auth",
|
|
118
|
+
"authentication",
|
|
119
|
+
"authorization",
|
|
120
|
+
"permission",
|
|
121
|
+
"helmet",
|
|
122
|
+
"cors",
|
|
123
|
+
"rate-limit",
|
|
124
|
+
"token",
|
|
125
|
+
"encrypt",
|
|
126
|
+
"decrypt",
|
|
127
|
+
"secret",
|
|
128
|
+
"redact",
|
|
129
|
+
"owasp"
|
|
130
|
+
],
|
|
131
|
+
filePatterns: [/security/i, /auth/i, /secrets?\.ts/i],
|
|
132
|
+
weight: 10
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
category: "testing",
|
|
136
|
+
keywords: [
|
|
137
|
+
"test",
|
|
138
|
+
"spec",
|
|
139
|
+
"expect",
|
|
140
|
+
"assert",
|
|
141
|
+
"mock",
|
|
142
|
+
"stub",
|
|
143
|
+
"fixture",
|
|
144
|
+
"coverage",
|
|
145
|
+
"jest",
|
|
146
|
+
"vitest",
|
|
147
|
+
"bun test",
|
|
148
|
+
"unit test",
|
|
149
|
+
"integration test",
|
|
150
|
+
"e2e"
|
|
151
|
+
],
|
|
152
|
+
types: ["test"],
|
|
153
|
+
filePatterns: [/\.test\./i, /\.spec\./i, /tests?\//i, /__tests__/i],
|
|
154
|
+
weight: 8
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
category: "debugging",
|
|
158
|
+
keywords: [
|
|
159
|
+
"debug",
|
|
160
|
+
"fix",
|
|
161
|
+
"bug",
|
|
162
|
+
"error",
|
|
163
|
+
"crash",
|
|
164
|
+
"stacktrace",
|
|
165
|
+
"stack trace",
|
|
166
|
+
"exception",
|
|
167
|
+
"breakpoint",
|
|
168
|
+
"investigate",
|
|
169
|
+
"root cause",
|
|
170
|
+
"troubleshoot",
|
|
171
|
+
"diagnose",
|
|
172
|
+
"bisect",
|
|
173
|
+
"regression"
|
|
174
|
+
],
|
|
175
|
+
types: ["bugfix"],
|
|
176
|
+
weight: 8
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
category: "architecture",
|
|
180
|
+
keywords: [
|
|
181
|
+
"architect",
|
|
182
|
+
"design",
|
|
183
|
+
"pattern",
|
|
184
|
+
"modular",
|
|
185
|
+
"migration",
|
|
186
|
+
"schema",
|
|
187
|
+
"database",
|
|
188
|
+
"api design",
|
|
189
|
+
"abstract",
|
|
190
|
+
"dependency injection",
|
|
191
|
+
"singleton",
|
|
192
|
+
"factory",
|
|
193
|
+
"observer",
|
|
194
|
+
"middleware",
|
|
195
|
+
"pipeline",
|
|
196
|
+
"microservice",
|
|
197
|
+
"monolith"
|
|
198
|
+
],
|
|
199
|
+
types: ["decision", "constraint"],
|
|
200
|
+
weight: 7
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
category: "refactoring",
|
|
204
|
+
keywords: [
|
|
205
|
+
"refactor",
|
|
206
|
+
"rename",
|
|
207
|
+
"extract",
|
|
208
|
+
"inline",
|
|
209
|
+
"move",
|
|
210
|
+
"split",
|
|
211
|
+
"merge",
|
|
212
|
+
"simplify",
|
|
213
|
+
"cleanup",
|
|
214
|
+
"clean up",
|
|
215
|
+
"dead code",
|
|
216
|
+
"consolidate",
|
|
217
|
+
"reorganize",
|
|
218
|
+
"restructure",
|
|
219
|
+
"decouple"
|
|
220
|
+
],
|
|
221
|
+
weight: 6
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
category: "config",
|
|
225
|
+
keywords: [
|
|
226
|
+
"config",
|
|
227
|
+
"configuration",
|
|
228
|
+
"env",
|
|
229
|
+
"environment",
|
|
230
|
+
"dotenv",
|
|
231
|
+
".env",
|
|
232
|
+
"settings",
|
|
233
|
+
"tsconfig",
|
|
234
|
+
"eslint",
|
|
235
|
+
"prettier",
|
|
236
|
+
"webpack",
|
|
237
|
+
"vite",
|
|
238
|
+
"esbuild",
|
|
239
|
+
"docker",
|
|
240
|
+
"ci/cd",
|
|
241
|
+
"github actions",
|
|
242
|
+
"deploy",
|
|
243
|
+
"build",
|
|
244
|
+
"bundle",
|
|
245
|
+
"package.json"
|
|
246
|
+
],
|
|
247
|
+
filePatterns: [
|
|
248
|
+
/\.config\./i,
|
|
249
|
+
/\.env/i,
|
|
250
|
+
/tsconfig/i,
|
|
251
|
+
/\.ya?ml/i,
|
|
252
|
+
/Dockerfile/i,
|
|
253
|
+
/docker-compose/i
|
|
254
|
+
],
|
|
255
|
+
weight: 5
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
category: "docs",
|
|
259
|
+
keywords: [
|
|
260
|
+
"document",
|
|
261
|
+
"readme",
|
|
262
|
+
"changelog",
|
|
263
|
+
"jsdoc",
|
|
264
|
+
"comment",
|
|
265
|
+
"explain",
|
|
266
|
+
"guide",
|
|
267
|
+
"tutorial",
|
|
268
|
+
"api doc",
|
|
269
|
+
"openapi",
|
|
270
|
+
"swagger"
|
|
271
|
+
],
|
|
272
|
+
types: ["docs"],
|
|
273
|
+
filePatterns: [/\.md$/i, /docs?\//i, /readme/i, /changelog/i],
|
|
274
|
+
weight: 5
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
category: "feature-dev",
|
|
278
|
+
keywords: [
|
|
279
|
+
"feature",
|
|
280
|
+
"implement",
|
|
281
|
+
"add",
|
|
282
|
+
"create",
|
|
283
|
+
"new",
|
|
284
|
+
"endpoint",
|
|
285
|
+
"component",
|
|
286
|
+
"module",
|
|
287
|
+
"service",
|
|
288
|
+
"handler",
|
|
289
|
+
"route",
|
|
290
|
+
"hook",
|
|
291
|
+
"plugin",
|
|
292
|
+
"integration"
|
|
293
|
+
],
|
|
294
|
+
types: ["feature", "file-write"],
|
|
295
|
+
weight: 3
|
|
296
|
+
// lowest — generic catch-all for development
|
|
297
|
+
}
|
|
298
|
+
];
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
|
|
18
302
|
// src/services/sqlite/Observations.ts
|
|
19
303
|
var Observations_exports = {};
|
|
20
304
|
__export(Observations_exports, {
|
|
@@ -40,11 +324,23 @@ function isDuplicateObservation(db, contentHash, windowMs = 3e4) {
|
|
|
40
324
|
}
|
|
41
325
|
function createObservation(db, memorySessionId, project, type, title, subtitle, text, narrative, facts, concepts, filesRead, filesModified, promptNumber, contentHash = null, discoveryTokens = 0) {
|
|
42
326
|
const now = /* @__PURE__ */ new Date();
|
|
327
|
+
const safeTitle = redactSecrets(title);
|
|
328
|
+
const safeText = text ? redactSecrets(text) : text;
|
|
329
|
+
const safeNarrative = narrative ? redactSecrets(narrative) : narrative;
|
|
330
|
+
const autoCategory = categorize({
|
|
331
|
+
type,
|
|
332
|
+
title: safeTitle,
|
|
333
|
+
text: safeText,
|
|
334
|
+
narrative: safeNarrative,
|
|
335
|
+
concepts,
|
|
336
|
+
filesModified,
|
|
337
|
+
filesRead
|
|
338
|
+
});
|
|
43
339
|
const result = db.run(
|
|
44
340
|
`INSERT INTO observations
|
|
45
|
-
(memory_session_id, project, type, title, subtitle, text, narrative, facts, concepts, files_read, files_modified, prompt_number, created_at, created_at_epoch, content_hash, discovery_tokens)
|
|
46
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
47
|
-
[memorySessionId, project, type,
|
|
341
|
+
(memory_session_id, project, type, title, subtitle, text, narrative, facts, concepts, files_read, files_modified, prompt_number, created_at, created_at_epoch, content_hash, discovery_tokens, auto_category)
|
|
342
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
343
|
+
[memorySessionId, project, type, safeTitle, subtitle, safeText, safeNarrative, facts, concepts, filesRead, filesModified, promptNumber, now.toISOString(), now.getTime(), contentHash, discoveryTokens, autoCategory]
|
|
48
344
|
);
|
|
49
345
|
return Number(result.lastInsertRowid);
|
|
50
346
|
}
|
|
@@ -56,16 +352,16 @@ function getObservationsBySession(db, memorySessionId) {
|
|
|
56
352
|
}
|
|
57
353
|
function getObservationsByProject(db, project, limit = 100) {
|
|
58
354
|
const query = db.query(
|
|
59
|
-
"SELECT * FROM observations WHERE project = ? ORDER BY created_at_epoch DESC LIMIT ?"
|
|
355
|
+
"SELECT * FROM observations WHERE project = ? ORDER BY created_at_epoch DESC, id DESC LIMIT ?"
|
|
60
356
|
);
|
|
61
357
|
return query.all(project, limit);
|
|
62
358
|
}
|
|
63
359
|
function searchObservations(db, searchTerm, project) {
|
|
64
360
|
const sql = project ? `SELECT * FROM observations
|
|
65
361
|
WHERE project = ? AND (title LIKE ? ESCAPE '\\' OR text LIKE ? ESCAPE '\\' OR narrative LIKE ? ESCAPE '\\')
|
|
66
|
-
ORDER BY created_at_epoch DESC` : `SELECT * FROM observations
|
|
362
|
+
ORDER BY created_at_epoch DESC, id DESC` : `SELECT * FROM observations
|
|
67
363
|
WHERE title LIKE ? ESCAPE '\\' OR text LIKE ? ESCAPE '\\' OR narrative LIKE ? ESCAPE '\\'
|
|
68
|
-
ORDER BY created_at_epoch DESC`;
|
|
364
|
+
ORDER BY created_at_epoch DESC, id DESC`;
|
|
69
365
|
const pattern = `%${escapeLikePattern(searchTerm)}%`;
|
|
70
366
|
const query = db.query(sql);
|
|
71
367
|
if (project) {
|
|
@@ -121,7 +417,7 @@ function consolidateObservations(db, project, options = {}) {
|
|
|
121
417
|
const obsIds = group.ids.split(",").map(Number);
|
|
122
418
|
const placeholders = obsIds.map(() => "?").join(",");
|
|
123
419
|
const observations = db.query(
|
|
124
|
-
`SELECT * FROM observations WHERE id IN (${placeholders}) ORDER BY created_at_epoch DESC`
|
|
420
|
+
`SELECT * FROM observations WHERE id IN (${placeholders}) ORDER BY created_at_epoch DESC, id DESC`
|
|
125
421
|
).all(...obsIds);
|
|
126
422
|
if (observations.length < minGroupSize) continue;
|
|
127
423
|
const keeper = observations[0];
|
|
@@ -152,6 +448,8 @@ function consolidateObservations(db, project, options = {}) {
|
|
|
152
448
|
var init_Observations = __esm({
|
|
153
449
|
"src/services/sqlite/Observations.ts"() {
|
|
154
450
|
"use strict";
|
|
451
|
+
init_secrets();
|
|
452
|
+
init_categorizer();
|
|
155
453
|
}
|
|
156
454
|
});
|
|
157
455
|
|
|
@@ -271,7 +569,7 @@ function searchObservationsLIKE(db, query, filters = {}) {
|
|
|
271
569
|
sql += " AND created_at_epoch <= ?";
|
|
272
570
|
params.push(filters.dateEnd);
|
|
273
571
|
}
|
|
274
|
-
sql += " ORDER BY created_at_epoch DESC LIMIT ?";
|
|
572
|
+
sql += " ORDER BY created_at_epoch DESC, id DESC LIMIT ?";
|
|
275
573
|
params.push(limit);
|
|
276
574
|
const stmt = db.query(sql);
|
|
277
575
|
return stmt.all(...params);
|
|
@@ -296,7 +594,7 @@ function searchSummariesFiltered(db, query, filters = {}) {
|
|
|
296
594
|
sql += " AND created_at_epoch <= ?";
|
|
297
595
|
params.push(filters.dateEnd);
|
|
298
596
|
}
|
|
299
|
-
sql += " ORDER BY created_at_epoch DESC LIMIT ?";
|
|
597
|
+
sql += " ORDER BY created_at_epoch DESC, id DESC LIMIT ?";
|
|
300
598
|
params.push(limit);
|
|
301
599
|
const stmt = db.query(sql);
|
|
302
600
|
return stmt.all(...params);
|
|
@@ -306,7 +604,7 @@ function getObservationsByIds(db, ids) {
|
|
|
306
604
|
const validIds = ids.filter((id) => typeof id === "number" && Number.isInteger(id) && id > 0).slice(0, 500);
|
|
307
605
|
if (validIds.length === 0) return [];
|
|
308
606
|
const placeholders = validIds.map(() => "?").join(",");
|
|
309
|
-
const sql = `SELECT * FROM observations WHERE id IN (${placeholders}) ORDER BY created_at_epoch DESC`;
|
|
607
|
+
const sql = `SELECT * FROM observations WHERE id IN (${placeholders}) ORDER BY created_at_epoch DESC, id DESC`;
|
|
310
608
|
const stmt = db.query(sql);
|
|
311
609
|
return stmt.all(...validIds);
|
|
312
610
|
}
|
|
@@ -318,11 +616,11 @@ function getTimeline(db, anchorId, depthBefore = 5, depthAfter = 5) {
|
|
|
318
616
|
const beforeStmt = db.query(`
|
|
319
617
|
SELECT id, 'observation' as type, title, text as content, project, created_at, created_at_epoch
|
|
320
618
|
FROM observations
|
|
321
|
-
WHERE created_at_epoch < ?
|
|
322
|
-
ORDER BY created_at_epoch DESC
|
|
619
|
+
WHERE (created_at_epoch < ? OR (created_at_epoch = ? AND id < ?))
|
|
620
|
+
ORDER BY created_at_epoch DESC, id DESC
|
|
323
621
|
LIMIT ?
|
|
324
622
|
`);
|
|
325
|
-
const before = beforeStmt.all(anchorEpoch, depthBefore).reverse();
|
|
623
|
+
const before = beforeStmt.all(anchorEpoch, anchorEpoch, anchorId, depthBefore).reverse();
|
|
326
624
|
const selfStmt = db.query(`
|
|
327
625
|
SELECT id, 'observation' as type, title, text as content, project, created_at, created_at_epoch
|
|
328
626
|
FROM observations WHERE id = ?
|
|
@@ -331,11 +629,11 @@ function getTimeline(db, anchorId, depthBefore = 5, depthAfter = 5) {
|
|
|
331
629
|
const afterStmt = db.query(`
|
|
332
630
|
SELECT id, 'observation' as type, title, text as content, project, created_at, created_at_epoch
|
|
333
631
|
FROM observations
|
|
334
|
-
WHERE created_at_epoch > ?
|
|
335
|
-
ORDER BY created_at_epoch ASC
|
|
632
|
+
WHERE (created_at_epoch > ? OR (created_at_epoch = ? AND id > ?))
|
|
633
|
+
ORDER BY created_at_epoch ASC, id ASC
|
|
336
634
|
LIMIT ?
|
|
337
635
|
`);
|
|
338
|
-
const after = afterStmt.all(anchorEpoch, depthAfter);
|
|
636
|
+
const after = afterStmt.all(anchorEpoch, anchorEpoch, anchorId, depthAfter);
|
|
339
637
|
return [...before, ...self, ...after];
|
|
340
638
|
}
|
|
341
639
|
function getProjectStats(db, project) {
|
|
@@ -378,7 +676,7 @@ function getStaleObservations(db, project) {
|
|
|
378
676
|
const rows = db.query(`
|
|
379
677
|
SELECT * FROM observations
|
|
380
678
|
WHERE project = ? AND files_modified IS NOT NULL AND files_modified != ''
|
|
381
|
-
ORDER BY created_at_epoch DESC
|
|
679
|
+
ORDER BY created_at_epoch DESC, id DESC
|
|
382
680
|
LIMIT 500
|
|
383
681
|
`).all(project);
|
|
384
682
|
const staleObs = [];
|
|
@@ -471,23 +769,47 @@ var BunQueryCompat = class {
|
|
|
471
769
|
constructor(db, sql) {
|
|
472
770
|
this._stmt = db.prepare(sql);
|
|
473
771
|
}
|
|
772
|
+
/**
|
|
773
|
+
* Adatta parametri named da formato bun:sqlite a better-sqlite3.
|
|
774
|
+
* bun:sqlite: chiavi CON prefisso (es. { $todayStart: 123 })
|
|
775
|
+
* better-sqlite3: chiavi SENZA prefisso (es. { todayStart: 123 })
|
|
776
|
+
*/
|
|
777
|
+
_adaptParams(params) {
|
|
778
|
+
if (params.length !== 1 || typeof params[0] !== "object" || params[0] === null || Array.isArray(params[0])) {
|
|
779
|
+
return params;
|
|
780
|
+
}
|
|
781
|
+
const obj = params[0];
|
|
782
|
+
const keys = Object.keys(obj);
|
|
783
|
+
if (keys.length === 0) return params;
|
|
784
|
+
if (!keys[0].startsWith("$") && !keys[0].startsWith("@") && !keys[0].startsWith(":")) {
|
|
785
|
+
return params;
|
|
786
|
+
}
|
|
787
|
+
const adapted = {};
|
|
788
|
+
for (const key of keys) {
|
|
789
|
+
adapted[key.slice(1)] = obj[key];
|
|
790
|
+
}
|
|
791
|
+
return [adapted];
|
|
792
|
+
}
|
|
474
793
|
/**
|
|
475
794
|
* Returns all rows
|
|
476
795
|
*/
|
|
477
796
|
all(...params) {
|
|
478
|
-
|
|
797
|
+
if (params.length === 0) return this._stmt.all();
|
|
798
|
+
return this._stmt.all(...this._adaptParams(params));
|
|
479
799
|
}
|
|
480
800
|
/**
|
|
481
801
|
* Returns the first row or null
|
|
482
802
|
*/
|
|
483
803
|
get(...params) {
|
|
484
|
-
|
|
804
|
+
if (params.length === 0) return this._stmt.get();
|
|
805
|
+
return this._stmt.get(...this._adaptParams(params));
|
|
485
806
|
}
|
|
486
807
|
/**
|
|
487
808
|
* Execute without results
|
|
488
809
|
*/
|
|
489
810
|
run(...params) {
|
|
490
|
-
|
|
811
|
+
if (params.length === 0) return this._stmt.run();
|
|
812
|
+
return this._stmt.run(...this._adaptParams(params));
|
|
491
813
|
}
|
|
492
814
|
};
|
|
493
815
|
|
|
@@ -1045,11 +1367,104 @@ var MigrationRunner = class {
|
|
|
1045
1367
|
db.run("CREATE INDEX IF NOT EXISTS idx_summaries_project_epoch ON summaries(project, created_at_epoch DESC)");
|
|
1046
1368
|
db.run("CREATE INDEX IF NOT EXISTS idx_prompts_project_epoch ON prompts(project, created_at_epoch DESC)");
|
|
1047
1369
|
}
|
|
1370
|
+
},
|
|
1371
|
+
{
|
|
1372
|
+
version: 10,
|
|
1373
|
+
up: (db) => {
|
|
1374
|
+
db.run(`
|
|
1375
|
+
CREATE TABLE IF NOT EXISTS job_queue (
|
|
1376
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1377
|
+
type TEXT NOT NULL,
|
|
1378
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
1379
|
+
payload TEXT,
|
|
1380
|
+
result TEXT,
|
|
1381
|
+
error TEXT,
|
|
1382
|
+
retry_count INTEGER DEFAULT 0,
|
|
1383
|
+
max_retries INTEGER DEFAULT 3,
|
|
1384
|
+
priority INTEGER DEFAULT 0,
|
|
1385
|
+
created_at TEXT NOT NULL,
|
|
1386
|
+
created_at_epoch INTEGER NOT NULL,
|
|
1387
|
+
started_at_epoch INTEGER,
|
|
1388
|
+
completed_at_epoch INTEGER
|
|
1389
|
+
)
|
|
1390
|
+
`);
|
|
1391
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_jobs_status ON job_queue(status)");
|
|
1392
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_jobs_type ON job_queue(type)");
|
|
1393
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_jobs_priority ON job_queue(status, priority DESC, created_at_epoch ASC)");
|
|
1394
|
+
}
|
|
1395
|
+
},
|
|
1396
|
+
{
|
|
1397
|
+
version: 11,
|
|
1398
|
+
up: (db) => {
|
|
1399
|
+
db.run("ALTER TABLE observations ADD COLUMN auto_category TEXT");
|
|
1400
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_observations_category ON observations(auto_category)");
|
|
1401
|
+
}
|
|
1402
|
+
},
|
|
1403
|
+
{
|
|
1404
|
+
version: 12,
|
|
1405
|
+
up: (db) => {
|
|
1406
|
+
db.run(`
|
|
1407
|
+
CREATE TABLE IF NOT EXISTS github_links (
|
|
1408
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1409
|
+
observation_id INTEGER,
|
|
1410
|
+
session_id TEXT,
|
|
1411
|
+
repo TEXT NOT NULL,
|
|
1412
|
+
issue_number INTEGER,
|
|
1413
|
+
pr_number INTEGER,
|
|
1414
|
+
event_type TEXT NOT NULL,
|
|
1415
|
+
action TEXT,
|
|
1416
|
+
title TEXT,
|
|
1417
|
+
url TEXT,
|
|
1418
|
+
author TEXT,
|
|
1419
|
+
created_at TEXT NOT NULL,
|
|
1420
|
+
created_at_epoch INTEGER NOT NULL,
|
|
1421
|
+
FOREIGN KEY (observation_id) REFERENCES observations(id)
|
|
1422
|
+
)
|
|
1423
|
+
`);
|
|
1424
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_github_links_repo ON github_links(repo)");
|
|
1425
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_github_links_obs ON github_links(observation_id)");
|
|
1426
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_github_links_event ON github_links(event_type)");
|
|
1427
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_github_links_repo_issue ON github_links(repo, issue_number)");
|
|
1428
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_github_links_repo_pr ON github_links(repo, pr_number)");
|
|
1429
|
+
}
|
|
1430
|
+
},
|
|
1431
|
+
{
|
|
1432
|
+
version: 13,
|
|
1433
|
+
up: (db) => {
|
|
1434
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_observations_keyset ON observations(created_at_epoch DESC, id DESC)");
|
|
1435
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_observations_project_keyset ON observations(project, created_at_epoch DESC, id DESC)");
|
|
1436
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_summaries_keyset ON summaries(created_at_epoch DESC, id DESC)");
|
|
1437
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_summaries_project_keyset ON summaries(project, created_at_epoch DESC, id DESC)");
|
|
1438
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_prompts_keyset ON prompts(created_at_epoch DESC, id DESC)");
|
|
1439
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_prompts_project_keyset ON prompts(project, created_at_epoch DESC, id DESC)");
|
|
1440
|
+
}
|
|
1048
1441
|
}
|
|
1049
1442
|
];
|
|
1050
1443
|
}
|
|
1051
1444
|
};
|
|
1052
1445
|
|
|
1446
|
+
// src/services/sqlite/cursor.ts
|
|
1447
|
+
function encodeCursor(id, epoch) {
|
|
1448
|
+
const raw = `${epoch}:${id}`;
|
|
1449
|
+
return Buffer.from(raw, "utf8").toString("base64url");
|
|
1450
|
+
}
|
|
1451
|
+
function decodeCursor(cursor) {
|
|
1452
|
+
try {
|
|
1453
|
+
const raw = Buffer.from(cursor, "base64url").toString("utf8");
|
|
1454
|
+
const colonIdx = raw.indexOf(":");
|
|
1455
|
+
if (colonIdx === -1) return null;
|
|
1456
|
+
const epochStr = raw.substring(0, colonIdx);
|
|
1457
|
+
const idStr = raw.substring(colonIdx + 1);
|
|
1458
|
+
const epoch = parseInt(epochStr, 10);
|
|
1459
|
+
const id = parseInt(idStr, 10);
|
|
1460
|
+
if (!Number.isInteger(epoch) || epoch <= 0) return null;
|
|
1461
|
+
if (!Number.isInteger(id) || id <= 0) return null;
|
|
1462
|
+
return { epoch, id };
|
|
1463
|
+
} catch {
|
|
1464
|
+
return null;
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1053
1468
|
// src/services/sqlite/Sessions.ts
|
|
1054
1469
|
function createSession(db, contentSessionId, project, userPrompt) {
|
|
1055
1470
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -1093,16 +1508,16 @@ function createSummary(db, sessionId, project, request, investigated, learned, c
|
|
|
1093
1508
|
}
|
|
1094
1509
|
function getSummariesByProject(db, project, limit = 50) {
|
|
1095
1510
|
const query = db.query(
|
|
1096
|
-
"SELECT * FROM summaries WHERE project = ? ORDER BY created_at_epoch DESC LIMIT ?"
|
|
1511
|
+
"SELECT * FROM summaries WHERE project = ? ORDER BY created_at_epoch DESC, id DESC LIMIT ?"
|
|
1097
1512
|
);
|
|
1098
1513
|
return query.all(project, limit);
|
|
1099
1514
|
}
|
|
1100
1515
|
function searchSummaries(db, searchTerm, project) {
|
|
1101
1516
|
const sql = project ? `SELECT * FROM summaries
|
|
1102
1517
|
WHERE project = ? AND (request LIKE ? ESCAPE '\\' OR learned LIKE ? ESCAPE '\\' OR completed LIKE ? ESCAPE '\\' OR notes LIKE ? ESCAPE '\\')
|
|
1103
|
-
ORDER BY created_at_epoch DESC` : `SELECT * FROM summaries
|
|
1518
|
+
ORDER BY created_at_epoch DESC, id DESC` : `SELECT * FROM summaries
|
|
1104
1519
|
WHERE request LIKE ? ESCAPE '\\' OR learned LIKE ? ESCAPE '\\' OR completed LIKE ? ESCAPE '\\' OR notes LIKE ? ESCAPE '\\'
|
|
1105
|
-
ORDER BY created_at_epoch DESC`;
|
|
1520
|
+
ORDER BY created_at_epoch DESC, id DESC`;
|
|
1106
1521
|
const pattern = `%${escapeLikePattern2(searchTerm)}%`;
|
|
1107
1522
|
const query = db.query(sql);
|
|
1108
1523
|
if (project) {
|
|
@@ -1124,7 +1539,7 @@ function createPrompt(db, contentSessionId, project, promptNumber, promptText) {
|
|
|
1124
1539
|
}
|
|
1125
1540
|
function getPromptsByProject(db, project, limit = 100) {
|
|
1126
1541
|
const query = db.query(
|
|
1127
|
-
"SELECT * FROM prompts WHERE project = ? ORDER BY created_at_epoch DESC LIMIT ?"
|
|
1542
|
+
"SELECT * FROM prompts WHERE project = ? ORDER BY created_at_epoch DESC, id DESC LIMIT ?"
|
|
1128
1543
|
);
|
|
1129
1544
|
return query.all(project, limit);
|
|
1130
1545
|
}
|
|
@@ -1152,13 +1567,13 @@ function createCheckpoint(db, sessionId, project, data) {
|
|
|
1152
1567
|
}
|
|
1153
1568
|
function getLatestCheckpoint(db, sessionId) {
|
|
1154
1569
|
const query = db.query(
|
|
1155
|
-
"SELECT * FROM checkpoints WHERE session_id = ? ORDER BY created_at_epoch DESC LIMIT 1"
|
|
1570
|
+
"SELECT * FROM checkpoints WHERE session_id = ? ORDER BY created_at_epoch DESC, id DESC LIMIT 1"
|
|
1156
1571
|
);
|
|
1157
1572
|
return query.get(sessionId);
|
|
1158
1573
|
}
|
|
1159
1574
|
function getLatestCheckpointByProject(db, project) {
|
|
1160
1575
|
const query = db.query(
|
|
1161
|
-
"SELECT * FROM checkpoints WHERE project = ? ORDER BY created_at_epoch DESC LIMIT 1"
|
|
1576
|
+
"SELECT * FROM checkpoints WHERE project = ? ORDER BY created_at_epoch DESC, id DESC LIMIT 1"
|
|
1162
1577
|
);
|
|
1163
1578
|
return query.get(project);
|
|
1164
1579
|
}
|
|
@@ -1220,9 +1635,9 @@ function getReportData(db, project, startEpoch, endEpoch) {
|
|
|
1220
1635
|
const staleCount = (project ? db.query(staleSql).get(project, startEpoch, endEpoch)?.count : db.query(staleSql).get(startEpoch, endEpoch)?.count) || 0;
|
|
1221
1636
|
const summarySql = project ? `SELECT learned, completed, next_steps FROM summaries
|
|
1222
1637
|
WHERE project = ? AND created_at_epoch >= ? AND created_at_epoch <= ?
|
|
1223
|
-
ORDER BY created_at_epoch DESC` : `SELECT learned, completed, next_steps FROM summaries
|
|
1638
|
+
ORDER BY created_at_epoch DESC, id DESC` : `SELECT learned, completed, next_steps FROM summaries
|
|
1224
1639
|
WHERE created_at_epoch >= ? AND created_at_epoch <= ?
|
|
1225
|
-
ORDER BY created_at_epoch DESC`;
|
|
1640
|
+
ORDER BY created_at_epoch DESC, id DESC`;
|
|
1226
1641
|
const summaryRows = project ? db.query(summarySql).all(project, startEpoch, endEpoch) : db.query(summarySql).all(startEpoch, endEpoch);
|
|
1227
1642
|
const topLearnings = [];
|
|
1228
1643
|
const completedTasks = [];
|
|
@@ -1287,20 +1702,61 @@ function getReportData(db, project, startEpoch, endEpoch) {
|
|
|
1287
1702
|
// src/services/sqlite/index.ts
|
|
1288
1703
|
init_Search();
|
|
1289
1704
|
|
|
1705
|
+
// src/types/worker-types.ts
|
|
1706
|
+
var KNOWLEDGE_TYPES = ["constraint", "decision", "heuristic", "rejected"];
|
|
1707
|
+
|
|
1708
|
+
// src/services/sqlite/Retention.ts
|
|
1709
|
+
var KNOWLEDGE_TYPE_LIST = KNOWLEDGE_TYPES;
|
|
1710
|
+
var KNOWLEDGE_PLACEHOLDERS = KNOWLEDGE_TYPE_LIST.map(() => "?").join(", ");
|
|
1711
|
+
|
|
1290
1712
|
// src/sdk/index.ts
|
|
1291
1713
|
init_Observations();
|
|
1292
1714
|
import { createHash } from "crypto";
|
|
1293
1715
|
init_Search();
|
|
1294
1716
|
|
|
1295
1717
|
// src/services/search/EmbeddingService.ts
|
|
1718
|
+
var MODEL_CONFIGS = {
|
|
1719
|
+
"all-MiniLM-L6-v2": {
|
|
1720
|
+
modelId: "Xenova/all-MiniLM-L6-v2",
|
|
1721
|
+
dimensions: 384
|
|
1722
|
+
},
|
|
1723
|
+
"jina-code-v2": {
|
|
1724
|
+
modelId: "jinaai/jina-embeddings-v2-base-code",
|
|
1725
|
+
dimensions: 768
|
|
1726
|
+
},
|
|
1727
|
+
"bge-small-en": {
|
|
1728
|
+
modelId: "BAAI/bge-small-en-v1.5",
|
|
1729
|
+
dimensions: 384
|
|
1730
|
+
}
|
|
1731
|
+
};
|
|
1732
|
+
var FASTEMBED_COMPATIBLE_MODELS = /* @__PURE__ */ new Set(["all-MiniLM-L6-v2", "bge-small-en"]);
|
|
1296
1733
|
var EmbeddingService = class {
|
|
1297
1734
|
provider = null;
|
|
1298
1735
|
model = null;
|
|
1299
1736
|
initialized = false;
|
|
1300
1737
|
initializing = null;
|
|
1738
|
+
config;
|
|
1739
|
+
configName;
|
|
1740
|
+
constructor() {
|
|
1741
|
+
const envModel = process.env.KIRO_MEMORY_EMBEDDING_MODEL || "all-MiniLM-L6-v2";
|
|
1742
|
+
this.configName = envModel;
|
|
1743
|
+
if (MODEL_CONFIGS[envModel]) {
|
|
1744
|
+
this.config = MODEL_CONFIGS[envModel];
|
|
1745
|
+
} else if (envModel.includes("/")) {
|
|
1746
|
+
const dimensions = parseInt(process.env.KIRO_MEMORY_EMBEDDING_DIMENSIONS || "384", 10);
|
|
1747
|
+
this.config = {
|
|
1748
|
+
modelId: envModel,
|
|
1749
|
+
dimensions: isNaN(dimensions) ? 384 : dimensions
|
|
1750
|
+
};
|
|
1751
|
+
} else {
|
|
1752
|
+
logger.warn("EMBEDDING", `Unknown model name '${envModel}', falling back to 'all-MiniLM-L6-v2'`);
|
|
1753
|
+
this.configName = "all-MiniLM-L6-v2";
|
|
1754
|
+
this.config = MODEL_CONFIGS["all-MiniLM-L6-v2"];
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1301
1757
|
/**
|
|
1302
1758
|
* Initialize the embedding service.
|
|
1303
|
-
* Tries fastembed, then @huggingface/transformers, then
|
|
1759
|
+
* Tries fastembed (when compatible), then @huggingface/transformers, then falls back to null.
|
|
1304
1760
|
*/
|
|
1305
1761
|
async initialize() {
|
|
1306
1762
|
if (this.initialized) return this.provider !== null;
|
|
@@ -1311,32 +1767,35 @@ var EmbeddingService = class {
|
|
|
1311
1767
|
return result;
|
|
1312
1768
|
}
|
|
1313
1769
|
async _doInitialize() {
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1770
|
+
const fastembedCompatible = FASTEMBED_COMPATIBLE_MODELS.has(this.configName);
|
|
1771
|
+
if (fastembedCompatible) {
|
|
1772
|
+
try {
|
|
1773
|
+
const fastembed = await import("fastembed");
|
|
1774
|
+
const EmbeddingModel = fastembed.EmbeddingModel || fastembed.default?.EmbeddingModel;
|
|
1775
|
+
const FlagEmbedding = fastembed.FlagEmbedding || fastembed.default?.FlagEmbedding;
|
|
1776
|
+
if (FlagEmbedding && EmbeddingModel) {
|
|
1777
|
+
this.model = await FlagEmbedding.init({
|
|
1778
|
+
model: EmbeddingModel.BGESmallENV15
|
|
1779
|
+
});
|
|
1780
|
+
this.provider = "fastembed";
|
|
1781
|
+
this.initialized = true;
|
|
1782
|
+
logger.info("EMBEDDING", `Initialized with fastembed (BGE-small-en-v1.5) for model '${this.configName}'`);
|
|
1783
|
+
return true;
|
|
1784
|
+
}
|
|
1785
|
+
} catch (error) {
|
|
1786
|
+
logger.debug("EMBEDDING", `fastembed not available: ${error}`);
|
|
1326
1787
|
}
|
|
1327
|
-
} catch (error) {
|
|
1328
|
-
logger.debug("EMBEDDING", `fastembed not available: ${error}`);
|
|
1329
1788
|
}
|
|
1330
1789
|
try {
|
|
1331
1790
|
const transformers = await import("@huggingface/transformers");
|
|
1332
1791
|
const pipeline = transformers.pipeline || transformers.default?.pipeline;
|
|
1333
1792
|
if (pipeline) {
|
|
1334
|
-
this.model = await pipeline("feature-extraction",
|
|
1793
|
+
this.model = await pipeline("feature-extraction", this.config.modelId, {
|
|
1335
1794
|
quantized: true
|
|
1336
1795
|
});
|
|
1337
1796
|
this.provider = "transformers";
|
|
1338
1797
|
this.initialized = true;
|
|
1339
|
-
logger.info("EMBEDDING",
|
|
1798
|
+
logger.info("EMBEDDING", `Initialized with @huggingface/transformers (${this.config.modelId})`);
|
|
1340
1799
|
return true;
|
|
1341
1800
|
}
|
|
1342
1801
|
} catch (error) {
|
|
@@ -1349,7 +1808,7 @@ var EmbeddingService = class {
|
|
|
1349
1808
|
}
|
|
1350
1809
|
/**
|
|
1351
1810
|
* Generate embedding for a single text.
|
|
1352
|
-
* Returns Float32Array with
|
|
1811
|
+
* Returns Float32Array with configured dimensions, or null if not available.
|
|
1353
1812
|
*/
|
|
1354
1813
|
async embed(text) {
|
|
1355
1814
|
if (!this.initialized) await this.initialize();
|
|
@@ -1400,10 +1859,17 @@ var EmbeddingService = class {
|
|
|
1400
1859
|
return this.provider;
|
|
1401
1860
|
}
|
|
1402
1861
|
/**
|
|
1403
|
-
* Embedding vector dimensions.
|
|
1862
|
+
* Embedding vector dimensions for the active model configuration.
|
|
1404
1863
|
*/
|
|
1405
1864
|
getDimensions() {
|
|
1406
|
-
return
|
|
1865
|
+
return this.config.dimensions;
|
|
1866
|
+
}
|
|
1867
|
+
/**
|
|
1868
|
+
* Human-readable model name used as identifier in the observation_embeddings table.
|
|
1869
|
+
* Returns the short name (e.g., 'all-MiniLM-L6-v2') or the full HF model ID for custom models.
|
|
1870
|
+
*/
|
|
1871
|
+
getModelName() {
|
|
1872
|
+
return this.configName;
|
|
1407
1873
|
}
|
|
1408
1874
|
// --- Batch implementations ---
|
|
1409
1875
|
/**
|
|
@@ -1622,7 +2088,7 @@ var VectorSearch = class {
|
|
|
1622
2088
|
`).all(batchSize);
|
|
1623
2089
|
if (rows.length === 0) return 0;
|
|
1624
2090
|
let count = 0;
|
|
1625
|
-
const model = embeddingService2.
|
|
2091
|
+
const model = embeddingService2.getModelName();
|
|
1626
2092
|
for (const row of rows) {
|
|
1627
2093
|
const parts = [row.title];
|
|
1628
2094
|
if (row.text) parts.push(row.text);
|
|
@@ -1846,9 +2312,6 @@ function getHybridSearch() {
|
|
|
1846
2312
|
return hybridSearch;
|
|
1847
2313
|
}
|
|
1848
2314
|
|
|
1849
|
-
// src/types/worker-types.ts
|
|
1850
|
-
var KNOWLEDGE_TYPES = ["constraint", "decision", "heuristic", "rejected"];
|
|
1851
|
-
|
|
1852
2315
|
// src/sdk/index.ts
|
|
1853
2316
|
var KiroMemorySDK = class {
|
|
1854
2317
|
db;
|
|
@@ -2405,6 +2868,66 @@ var KiroMemorySDK = class {
|
|
|
2405
2868
|
}
|
|
2406
2869
|
return getReportData(this.db.db, this.project, startEpoch, endEpoch);
|
|
2407
2870
|
}
|
|
2871
|
+
/**
|
|
2872
|
+
* Lista osservazioni con keyset pagination.
|
|
2873
|
+
* Restituisce un oggetto { data, next_cursor, has_more }.
|
|
2874
|
+
*
|
|
2875
|
+
* Esempio:
|
|
2876
|
+
* const page1 = await sdk.listObservations({ limit: 50 });
|
|
2877
|
+
* const page2 = await sdk.listObservations({ cursor: page1.next_cursor });
|
|
2878
|
+
*/
|
|
2879
|
+
async listObservations(options = {}) {
|
|
2880
|
+
const limit = Math.min(Math.max(options.limit ?? 50, 1), 200);
|
|
2881
|
+
const project = options.project ?? this.project;
|
|
2882
|
+
let rows;
|
|
2883
|
+
if (options.cursor) {
|
|
2884
|
+
const decoded = decodeCursor(options.cursor);
|
|
2885
|
+
if (!decoded) throw new Error("Cursor non valido");
|
|
2886
|
+
const sql = project ? `SELECT * FROM observations
|
|
2887
|
+
WHERE project = ? AND (created_at_epoch < ? OR (created_at_epoch = ? AND id < ?))
|
|
2888
|
+
ORDER BY created_at_epoch DESC, id DESC
|
|
2889
|
+
LIMIT ?` : `SELECT * FROM observations
|
|
2890
|
+
WHERE (created_at_epoch < ? OR (created_at_epoch = ? AND id < ?))
|
|
2891
|
+
ORDER BY created_at_epoch DESC, id DESC
|
|
2892
|
+
LIMIT ?`;
|
|
2893
|
+
rows = project ? this.db.db.query(sql).all(project, decoded.epoch, decoded.epoch, decoded.id, limit) : this.db.db.query(sql).all(decoded.epoch, decoded.epoch, decoded.id, limit);
|
|
2894
|
+
} else {
|
|
2895
|
+
const sql = project ? "SELECT * FROM observations WHERE project = ? ORDER BY created_at_epoch DESC, id DESC LIMIT ?" : "SELECT * FROM observations ORDER BY created_at_epoch DESC, id DESC LIMIT ?";
|
|
2896
|
+
rows = project ? this.db.db.query(sql).all(project, limit) : this.db.db.query(sql).all(limit);
|
|
2897
|
+
}
|
|
2898
|
+
const next_cursor = rows.length >= limit ? encodeCursor(rows[rows.length - 1].id, rows[rows.length - 1].created_at_epoch) : null;
|
|
2899
|
+
return { data: rows, next_cursor, has_more: next_cursor !== null };
|
|
2900
|
+
}
|
|
2901
|
+
/**
|
|
2902
|
+
* Lista sommari con keyset pagination.
|
|
2903
|
+
* Restituisce un oggetto { data, next_cursor, has_more }.
|
|
2904
|
+
*
|
|
2905
|
+
* Esempio:
|
|
2906
|
+
* const page1 = await sdk.listSummaries({ limit: 20 });
|
|
2907
|
+
* const page2 = await sdk.listSummaries({ cursor: page1.next_cursor });
|
|
2908
|
+
*/
|
|
2909
|
+
async listSummaries(options = {}) {
|
|
2910
|
+
const limit = Math.min(Math.max(options.limit ?? 20, 1), 200);
|
|
2911
|
+
const project = options.project ?? this.project;
|
|
2912
|
+
let rows;
|
|
2913
|
+
if (options.cursor) {
|
|
2914
|
+
const decoded = decodeCursor(options.cursor);
|
|
2915
|
+
if (!decoded) throw new Error("Cursor non valido");
|
|
2916
|
+
const sql = project ? `SELECT * FROM summaries
|
|
2917
|
+
WHERE project = ? AND (created_at_epoch < ? OR (created_at_epoch = ? AND id < ?))
|
|
2918
|
+
ORDER BY created_at_epoch DESC, id DESC
|
|
2919
|
+
LIMIT ?` : `SELECT * FROM summaries
|
|
2920
|
+
WHERE (created_at_epoch < ? OR (created_at_epoch = ? AND id < ?))
|
|
2921
|
+
ORDER BY created_at_epoch DESC, id DESC
|
|
2922
|
+
LIMIT ?`;
|
|
2923
|
+
rows = project ? this.db.db.query(sql).all(project, decoded.epoch, decoded.epoch, decoded.id, limit) : this.db.db.query(sql).all(decoded.epoch, decoded.epoch, decoded.id, limit);
|
|
2924
|
+
} else {
|
|
2925
|
+
const sql = project ? "SELECT * FROM summaries WHERE project = ? ORDER BY created_at_epoch DESC, id DESC LIMIT ?" : "SELECT * FROM summaries ORDER BY created_at_epoch DESC, id DESC LIMIT ?";
|
|
2926
|
+
rows = project ? this.db.db.query(sql).all(project, limit) : this.db.db.query(sql).all(limit);
|
|
2927
|
+
}
|
|
2928
|
+
const next_cursor = rows.length >= limit ? encodeCursor(rows[rows.length - 1].id, rows[rows.length - 1].created_at_epoch) : null;
|
|
2929
|
+
return { data: rows, next_cursor, has_more: next_cursor !== null };
|
|
2930
|
+
}
|
|
2408
2931
|
/**
|
|
2409
2932
|
* Getter for direct database access (for API routes)
|
|
2410
2933
|
*/
|