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
|
@@ -16,6 +16,290 @@ var __export = (target, all) => {
|
|
|
16
16
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
+
// src/utils/secrets.ts
|
|
20
|
+
function redactSecrets(text) {
|
|
21
|
+
if (!text) return text;
|
|
22
|
+
let redacted = text;
|
|
23
|
+
for (const { pattern } of SECRET_PATTERNS) {
|
|
24
|
+
pattern.lastIndex = 0;
|
|
25
|
+
redacted = redacted.replace(pattern, (match) => {
|
|
26
|
+
const prefix = match.substring(0, Math.min(4, match.length));
|
|
27
|
+
return `${prefix}***REDACTED***`;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return redacted;
|
|
31
|
+
}
|
|
32
|
+
var SECRET_PATTERNS;
|
|
33
|
+
var init_secrets = __esm({
|
|
34
|
+
"src/utils/secrets.ts"() {
|
|
35
|
+
"use strict";
|
|
36
|
+
SECRET_PATTERNS = [
|
|
37
|
+
// AWS Access Keys (AKIA, ABIA, ACCA, ASIA prefixes + 16 alphanumeric chars)
|
|
38
|
+
{ name: "aws-key", pattern: /(?:AKIA|ABIA|ACCA|ASIA)[A-Z0-9]{16}/g },
|
|
39
|
+
// JWT tokens (three base64url segments separated by dots)
|
|
40
|
+
{ name: "jwt", pattern: /eyJ[a-zA-Z0-9_-]{10,}\.eyJ[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}/g },
|
|
41
|
+
// Generic API keys in key=value or key: value assignments
|
|
42
|
+
{ name: "api-key", pattern: /(?:api[_-]?key|apikey|api[_-]?secret)\s*[:=]\s*['"]?([a-zA-Z0-9_\-]{20,})['"]?/gi },
|
|
43
|
+
// Password/secret/token in variable assignments
|
|
44
|
+
{ name: "credential", pattern: /(?:password|passwd|pwd|secret|token|auth[_-]?token|access[_-]?token|bearer)\s*[:=]\s*['"]?([^\s'"]{8,})['"]?/gi },
|
|
45
|
+
// Credentials embedded in URLs (user:pass@host)
|
|
46
|
+
{ name: "url-credential", pattern: /(?:https?:\/\/)([^:]+):([^@]+)@/g },
|
|
47
|
+
// PEM-encoded private keys (RSA, EC, DSA, OpenSSH)
|
|
48
|
+
{ name: "private-key", pattern: /-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/g },
|
|
49
|
+
// GitHub personal access tokens (ghp_, gho_, ghu_, ghs_, ghr_ prefixes)
|
|
50
|
+
{ name: "github-token", pattern: /gh[pousr]_[a-zA-Z0-9]{36,}/g },
|
|
51
|
+
// Slack bot/user/app tokens
|
|
52
|
+
{ name: "slack-token", pattern: /xox[bpoas]-[a-zA-Z0-9-]{10,}/g },
|
|
53
|
+
// HTTP Authorization Bearer header values
|
|
54
|
+
{ name: "bearer-header", pattern: /\bBearer\s+([a-zA-Z0-9_\-\.]{20,})/g },
|
|
55
|
+
// Generic hex secrets (32+ hex chars after a key/secret/token/password label)
|
|
56
|
+
{ name: "hex-secret", pattern: /(?:key|secret|token|password)\s*[:=]\s*['"]?([0-9a-f]{32,})['"]?/gi }
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// src/utils/categorizer.ts
|
|
62
|
+
function categorize(input) {
|
|
63
|
+
const scores = /* @__PURE__ */ new Map();
|
|
64
|
+
const searchText = [
|
|
65
|
+
input.title,
|
|
66
|
+
input.text || "",
|
|
67
|
+
input.narrative || "",
|
|
68
|
+
input.concepts || ""
|
|
69
|
+
].join(" ").toLowerCase();
|
|
70
|
+
const allFiles = [input.filesModified || "", input.filesRead || ""].join(",");
|
|
71
|
+
for (const rule of CATEGORY_RULES) {
|
|
72
|
+
let score = 0;
|
|
73
|
+
for (const kw of rule.keywords) {
|
|
74
|
+
if (searchText.includes(kw.toLowerCase())) {
|
|
75
|
+
score += rule.weight;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (rule.types && rule.types.includes(input.type)) {
|
|
79
|
+
score += rule.weight * 2;
|
|
80
|
+
}
|
|
81
|
+
if (rule.filePatterns && allFiles) {
|
|
82
|
+
for (const pattern of rule.filePatterns) {
|
|
83
|
+
if (pattern.test(allFiles)) {
|
|
84
|
+
score += rule.weight;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (score > 0) {
|
|
89
|
+
scores.set(rule.category, (scores.get(rule.category) || 0) + score);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
let bestCategory = "general";
|
|
93
|
+
let bestScore = 0;
|
|
94
|
+
for (const [category, score] of scores) {
|
|
95
|
+
if (score > bestScore) {
|
|
96
|
+
bestScore = score;
|
|
97
|
+
bestCategory = category;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return bestCategory;
|
|
101
|
+
}
|
|
102
|
+
var CATEGORY_RULES;
|
|
103
|
+
var init_categorizer = __esm({
|
|
104
|
+
"src/utils/categorizer.ts"() {
|
|
105
|
+
"use strict";
|
|
106
|
+
CATEGORY_RULES = [
|
|
107
|
+
{
|
|
108
|
+
category: "security",
|
|
109
|
+
keywords: [
|
|
110
|
+
"security",
|
|
111
|
+
"vulnerability",
|
|
112
|
+
"cve",
|
|
113
|
+
"xss",
|
|
114
|
+
"csrf",
|
|
115
|
+
"injection",
|
|
116
|
+
"sanitize",
|
|
117
|
+
"escape",
|
|
118
|
+
"auth",
|
|
119
|
+
"authentication",
|
|
120
|
+
"authorization",
|
|
121
|
+
"permission",
|
|
122
|
+
"helmet",
|
|
123
|
+
"cors",
|
|
124
|
+
"rate-limit",
|
|
125
|
+
"token",
|
|
126
|
+
"encrypt",
|
|
127
|
+
"decrypt",
|
|
128
|
+
"secret",
|
|
129
|
+
"redact",
|
|
130
|
+
"owasp"
|
|
131
|
+
],
|
|
132
|
+
filePatterns: [/security/i, /auth/i, /secrets?\.ts/i],
|
|
133
|
+
weight: 10
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
category: "testing",
|
|
137
|
+
keywords: [
|
|
138
|
+
"test",
|
|
139
|
+
"spec",
|
|
140
|
+
"expect",
|
|
141
|
+
"assert",
|
|
142
|
+
"mock",
|
|
143
|
+
"stub",
|
|
144
|
+
"fixture",
|
|
145
|
+
"coverage",
|
|
146
|
+
"jest",
|
|
147
|
+
"vitest",
|
|
148
|
+
"bun test",
|
|
149
|
+
"unit test",
|
|
150
|
+
"integration test",
|
|
151
|
+
"e2e"
|
|
152
|
+
],
|
|
153
|
+
types: ["test"],
|
|
154
|
+
filePatterns: [/\.test\./i, /\.spec\./i, /tests?\//i, /__tests__/i],
|
|
155
|
+
weight: 8
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
category: "debugging",
|
|
159
|
+
keywords: [
|
|
160
|
+
"debug",
|
|
161
|
+
"fix",
|
|
162
|
+
"bug",
|
|
163
|
+
"error",
|
|
164
|
+
"crash",
|
|
165
|
+
"stacktrace",
|
|
166
|
+
"stack trace",
|
|
167
|
+
"exception",
|
|
168
|
+
"breakpoint",
|
|
169
|
+
"investigate",
|
|
170
|
+
"root cause",
|
|
171
|
+
"troubleshoot",
|
|
172
|
+
"diagnose",
|
|
173
|
+
"bisect",
|
|
174
|
+
"regression"
|
|
175
|
+
],
|
|
176
|
+
types: ["bugfix"],
|
|
177
|
+
weight: 8
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
category: "architecture",
|
|
181
|
+
keywords: [
|
|
182
|
+
"architect",
|
|
183
|
+
"design",
|
|
184
|
+
"pattern",
|
|
185
|
+
"modular",
|
|
186
|
+
"migration",
|
|
187
|
+
"schema",
|
|
188
|
+
"database",
|
|
189
|
+
"api design",
|
|
190
|
+
"abstract",
|
|
191
|
+
"dependency injection",
|
|
192
|
+
"singleton",
|
|
193
|
+
"factory",
|
|
194
|
+
"observer",
|
|
195
|
+
"middleware",
|
|
196
|
+
"pipeline",
|
|
197
|
+
"microservice",
|
|
198
|
+
"monolith"
|
|
199
|
+
],
|
|
200
|
+
types: ["decision", "constraint"],
|
|
201
|
+
weight: 7
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
category: "refactoring",
|
|
205
|
+
keywords: [
|
|
206
|
+
"refactor",
|
|
207
|
+
"rename",
|
|
208
|
+
"extract",
|
|
209
|
+
"inline",
|
|
210
|
+
"move",
|
|
211
|
+
"split",
|
|
212
|
+
"merge",
|
|
213
|
+
"simplify",
|
|
214
|
+
"cleanup",
|
|
215
|
+
"clean up",
|
|
216
|
+
"dead code",
|
|
217
|
+
"consolidate",
|
|
218
|
+
"reorganize",
|
|
219
|
+
"restructure",
|
|
220
|
+
"decouple"
|
|
221
|
+
],
|
|
222
|
+
weight: 6
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
category: "config",
|
|
226
|
+
keywords: [
|
|
227
|
+
"config",
|
|
228
|
+
"configuration",
|
|
229
|
+
"env",
|
|
230
|
+
"environment",
|
|
231
|
+
"dotenv",
|
|
232
|
+
".env",
|
|
233
|
+
"settings",
|
|
234
|
+
"tsconfig",
|
|
235
|
+
"eslint",
|
|
236
|
+
"prettier",
|
|
237
|
+
"webpack",
|
|
238
|
+
"vite",
|
|
239
|
+
"esbuild",
|
|
240
|
+
"docker",
|
|
241
|
+
"ci/cd",
|
|
242
|
+
"github actions",
|
|
243
|
+
"deploy",
|
|
244
|
+
"build",
|
|
245
|
+
"bundle",
|
|
246
|
+
"package.json"
|
|
247
|
+
],
|
|
248
|
+
filePatterns: [
|
|
249
|
+
/\.config\./i,
|
|
250
|
+
/\.env/i,
|
|
251
|
+
/tsconfig/i,
|
|
252
|
+
/\.ya?ml/i,
|
|
253
|
+
/Dockerfile/i,
|
|
254
|
+
/docker-compose/i
|
|
255
|
+
],
|
|
256
|
+
weight: 5
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
category: "docs",
|
|
260
|
+
keywords: [
|
|
261
|
+
"document",
|
|
262
|
+
"readme",
|
|
263
|
+
"changelog",
|
|
264
|
+
"jsdoc",
|
|
265
|
+
"comment",
|
|
266
|
+
"explain",
|
|
267
|
+
"guide",
|
|
268
|
+
"tutorial",
|
|
269
|
+
"api doc",
|
|
270
|
+
"openapi",
|
|
271
|
+
"swagger"
|
|
272
|
+
],
|
|
273
|
+
types: ["docs"],
|
|
274
|
+
filePatterns: [/\.md$/i, /docs?\//i, /readme/i, /changelog/i],
|
|
275
|
+
weight: 5
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
category: "feature-dev",
|
|
279
|
+
keywords: [
|
|
280
|
+
"feature",
|
|
281
|
+
"implement",
|
|
282
|
+
"add",
|
|
283
|
+
"create",
|
|
284
|
+
"new",
|
|
285
|
+
"endpoint",
|
|
286
|
+
"component",
|
|
287
|
+
"module",
|
|
288
|
+
"service",
|
|
289
|
+
"handler",
|
|
290
|
+
"route",
|
|
291
|
+
"hook",
|
|
292
|
+
"plugin",
|
|
293
|
+
"integration"
|
|
294
|
+
],
|
|
295
|
+
types: ["feature", "file-write"],
|
|
296
|
+
weight: 3
|
|
297
|
+
// lowest — generic catch-all for development
|
|
298
|
+
}
|
|
299
|
+
];
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
19
303
|
// src/services/sqlite/Observations.ts
|
|
20
304
|
var Observations_exports = {};
|
|
21
305
|
__export(Observations_exports, {
|
|
@@ -41,11 +325,23 @@ function isDuplicateObservation(db, contentHash, windowMs = 3e4) {
|
|
|
41
325
|
}
|
|
42
326
|
function createObservation(db, memorySessionId, project, type, title, subtitle, text, narrative, facts, concepts, filesRead, filesModified, promptNumber, contentHash = null, discoveryTokens = 0) {
|
|
43
327
|
const now = /* @__PURE__ */ new Date();
|
|
328
|
+
const safeTitle = redactSecrets(title);
|
|
329
|
+
const safeText = text ? redactSecrets(text) : text;
|
|
330
|
+
const safeNarrative = narrative ? redactSecrets(narrative) : narrative;
|
|
331
|
+
const autoCategory = categorize({
|
|
332
|
+
type,
|
|
333
|
+
title: safeTitle,
|
|
334
|
+
text: safeText,
|
|
335
|
+
narrative: safeNarrative,
|
|
336
|
+
concepts,
|
|
337
|
+
filesModified,
|
|
338
|
+
filesRead
|
|
339
|
+
});
|
|
44
340
|
const result = db.run(
|
|
45
341
|
`INSERT INTO observations
|
|
46
|
-
(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)
|
|
47
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
48
|
-
[memorySessionId, project, type,
|
|
342
|
+
(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)
|
|
343
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
344
|
+
[memorySessionId, project, type, safeTitle, subtitle, safeText, safeNarrative, facts, concepts, filesRead, filesModified, promptNumber, now.toISOString(), now.getTime(), contentHash, discoveryTokens, autoCategory]
|
|
49
345
|
);
|
|
50
346
|
return Number(result.lastInsertRowid);
|
|
51
347
|
}
|
|
@@ -57,16 +353,16 @@ function getObservationsBySession(db, memorySessionId) {
|
|
|
57
353
|
}
|
|
58
354
|
function getObservationsByProject(db, project, limit = 100) {
|
|
59
355
|
const query = db.query(
|
|
60
|
-
"SELECT * FROM observations WHERE project = ? ORDER BY created_at_epoch DESC LIMIT ?"
|
|
356
|
+
"SELECT * FROM observations WHERE project = ? ORDER BY created_at_epoch DESC, id DESC LIMIT ?"
|
|
61
357
|
);
|
|
62
358
|
return query.all(project, limit);
|
|
63
359
|
}
|
|
64
360
|
function searchObservations(db, searchTerm, project) {
|
|
65
361
|
const sql = project ? `SELECT * FROM observations
|
|
66
362
|
WHERE project = ? AND (title LIKE ? ESCAPE '\\' OR text LIKE ? ESCAPE '\\' OR narrative LIKE ? ESCAPE '\\')
|
|
67
|
-
ORDER BY created_at_epoch DESC` : `SELECT * FROM observations
|
|
363
|
+
ORDER BY created_at_epoch DESC, id DESC` : `SELECT * FROM observations
|
|
68
364
|
WHERE title LIKE ? ESCAPE '\\' OR text LIKE ? ESCAPE '\\' OR narrative LIKE ? ESCAPE '\\'
|
|
69
|
-
ORDER BY created_at_epoch DESC`;
|
|
365
|
+
ORDER BY created_at_epoch DESC, id DESC`;
|
|
70
366
|
const pattern = `%${escapeLikePattern(searchTerm)}%`;
|
|
71
367
|
const query = db.query(sql);
|
|
72
368
|
if (project) {
|
|
@@ -122,7 +418,7 @@ function consolidateObservations(db, project, options = {}) {
|
|
|
122
418
|
const obsIds = group.ids.split(",").map(Number);
|
|
123
419
|
const placeholders = obsIds.map(() => "?").join(",");
|
|
124
420
|
const observations = db.query(
|
|
125
|
-
`SELECT * FROM observations WHERE id IN (${placeholders}) ORDER BY created_at_epoch DESC`
|
|
421
|
+
`SELECT * FROM observations WHERE id IN (${placeholders}) ORDER BY created_at_epoch DESC, id DESC`
|
|
126
422
|
).all(...obsIds);
|
|
127
423
|
if (observations.length < minGroupSize) continue;
|
|
128
424
|
const keeper = observations[0];
|
|
@@ -153,6 +449,8 @@ function consolidateObservations(db, project, options = {}) {
|
|
|
153
449
|
var init_Observations = __esm({
|
|
154
450
|
"src/services/sqlite/Observations.ts"() {
|
|
155
451
|
"use strict";
|
|
452
|
+
init_secrets();
|
|
453
|
+
init_categorizer();
|
|
156
454
|
}
|
|
157
455
|
});
|
|
158
456
|
|
|
@@ -272,7 +570,7 @@ function searchObservationsLIKE(db, query, filters = {}) {
|
|
|
272
570
|
sql += " AND created_at_epoch <= ?";
|
|
273
571
|
params.push(filters.dateEnd);
|
|
274
572
|
}
|
|
275
|
-
sql += " ORDER BY created_at_epoch DESC LIMIT ?";
|
|
573
|
+
sql += " ORDER BY created_at_epoch DESC, id DESC LIMIT ?";
|
|
276
574
|
params.push(limit);
|
|
277
575
|
const stmt = db.query(sql);
|
|
278
576
|
return stmt.all(...params);
|
|
@@ -297,7 +595,7 @@ function searchSummariesFiltered(db, query, filters = {}) {
|
|
|
297
595
|
sql += " AND created_at_epoch <= ?";
|
|
298
596
|
params.push(filters.dateEnd);
|
|
299
597
|
}
|
|
300
|
-
sql += " ORDER BY created_at_epoch DESC LIMIT ?";
|
|
598
|
+
sql += " ORDER BY created_at_epoch DESC, id DESC LIMIT ?";
|
|
301
599
|
params.push(limit);
|
|
302
600
|
const stmt = db.query(sql);
|
|
303
601
|
return stmt.all(...params);
|
|
@@ -307,7 +605,7 @@ function getObservationsByIds(db, ids) {
|
|
|
307
605
|
const validIds = ids.filter((id) => typeof id === "number" && Number.isInteger(id) && id > 0).slice(0, 500);
|
|
308
606
|
if (validIds.length === 0) return [];
|
|
309
607
|
const placeholders = validIds.map(() => "?").join(",");
|
|
310
|
-
const sql = `SELECT * FROM observations WHERE id IN (${placeholders}) ORDER BY created_at_epoch DESC`;
|
|
608
|
+
const sql = `SELECT * FROM observations WHERE id IN (${placeholders}) ORDER BY created_at_epoch DESC, id DESC`;
|
|
311
609
|
const stmt = db.query(sql);
|
|
312
610
|
return stmt.all(...validIds);
|
|
313
611
|
}
|
|
@@ -319,11 +617,11 @@ function getTimeline(db, anchorId, depthBefore = 5, depthAfter = 5) {
|
|
|
319
617
|
const beforeStmt = db.query(`
|
|
320
618
|
SELECT id, 'observation' as type, title, text as content, project, created_at, created_at_epoch
|
|
321
619
|
FROM observations
|
|
322
|
-
WHERE created_at_epoch < ?
|
|
323
|
-
ORDER BY created_at_epoch DESC
|
|
620
|
+
WHERE (created_at_epoch < ? OR (created_at_epoch = ? AND id < ?))
|
|
621
|
+
ORDER BY created_at_epoch DESC, id DESC
|
|
324
622
|
LIMIT ?
|
|
325
623
|
`);
|
|
326
|
-
const before = beforeStmt.all(anchorEpoch, depthBefore).reverse();
|
|
624
|
+
const before = beforeStmt.all(anchorEpoch, anchorEpoch, anchorId, depthBefore).reverse();
|
|
327
625
|
const selfStmt = db.query(`
|
|
328
626
|
SELECT id, 'observation' as type, title, text as content, project, created_at, created_at_epoch
|
|
329
627
|
FROM observations WHERE id = ?
|
|
@@ -332,11 +630,11 @@ function getTimeline(db, anchorId, depthBefore = 5, depthAfter = 5) {
|
|
|
332
630
|
const afterStmt = db.query(`
|
|
333
631
|
SELECT id, 'observation' as type, title, text as content, project, created_at, created_at_epoch
|
|
334
632
|
FROM observations
|
|
335
|
-
WHERE created_at_epoch > ?
|
|
336
|
-
ORDER BY created_at_epoch ASC
|
|
633
|
+
WHERE (created_at_epoch > ? OR (created_at_epoch = ? AND id > ?))
|
|
634
|
+
ORDER BY created_at_epoch ASC, id ASC
|
|
337
635
|
LIMIT ?
|
|
338
636
|
`);
|
|
339
|
-
const after = afterStmt.all(anchorEpoch, depthAfter);
|
|
637
|
+
const after = afterStmt.all(anchorEpoch, anchorEpoch, anchorId, depthAfter);
|
|
340
638
|
return [...before, ...self, ...after];
|
|
341
639
|
}
|
|
342
640
|
function getProjectStats(db, project) {
|
|
@@ -379,7 +677,7 @@ function getStaleObservations(db, project) {
|
|
|
379
677
|
const rows = db.query(`
|
|
380
678
|
SELECT * FROM observations
|
|
381
679
|
WHERE project = ? AND files_modified IS NOT NULL AND files_modified != ''
|
|
382
|
-
ORDER BY created_at_epoch DESC
|
|
680
|
+
ORDER BY created_at_epoch DESC, id DESC
|
|
383
681
|
LIMIT 500
|
|
384
682
|
`).all(project);
|
|
385
683
|
const staleObs = [];
|
|
@@ -634,23 +932,47 @@ var BunQueryCompat = class {
|
|
|
634
932
|
constructor(db, sql) {
|
|
635
933
|
this._stmt = db.prepare(sql);
|
|
636
934
|
}
|
|
935
|
+
/**
|
|
936
|
+
* Adatta parametri named da formato bun:sqlite a better-sqlite3.
|
|
937
|
+
* bun:sqlite: chiavi CON prefisso (es. { $todayStart: 123 })
|
|
938
|
+
* better-sqlite3: chiavi SENZA prefisso (es. { todayStart: 123 })
|
|
939
|
+
*/
|
|
940
|
+
_adaptParams(params) {
|
|
941
|
+
if (params.length !== 1 || typeof params[0] !== "object" || params[0] === null || Array.isArray(params[0])) {
|
|
942
|
+
return params;
|
|
943
|
+
}
|
|
944
|
+
const obj = params[0];
|
|
945
|
+
const keys = Object.keys(obj);
|
|
946
|
+
if (keys.length === 0) return params;
|
|
947
|
+
if (!keys[0].startsWith("$") && !keys[0].startsWith("@") && !keys[0].startsWith(":")) {
|
|
948
|
+
return params;
|
|
949
|
+
}
|
|
950
|
+
const adapted = {};
|
|
951
|
+
for (const key of keys) {
|
|
952
|
+
adapted[key.slice(1)] = obj[key];
|
|
953
|
+
}
|
|
954
|
+
return [adapted];
|
|
955
|
+
}
|
|
637
956
|
/**
|
|
638
957
|
* Returns all rows
|
|
639
958
|
*/
|
|
640
959
|
all(...params) {
|
|
641
|
-
|
|
960
|
+
if (params.length === 0) return this._stmt.all();
|
|
961
|
+
return this._stmt.all(...this._adaptParams(params));
|
|
642
962
|
}
|
|
643
963
|
/**
|
|
644
964
|
* Returns the first row or null
|
|
645
965
|
*/
|
|
646
966
|
get(...params) {
|
|
647
|
-
|
|
967
|
+
if (params.length === 0) return this._stmt.get();
|
|
968
|
+
return this._stmt.get(...this._adaptParams(params));
|
|
648
969
|
}
|
|
649
970
|
/**
|
|
650
971
|
* Execute without results
|
|
651
972
|
*/
|
|
652
973
|
run(...params) {
|
|
653
|
-
|
|
974
|
+
if (params.length === 0) return this._stmt.run();
|
|
975
|
+
return this._stmt.run(...this._adaptParams(params));
|
|
654
976
|
}
|
|
655
977
|
};
|
|
656
978
|
|
|
@@ -1208,11 +1530,104 @@ var MigrationRunner = class {
|
|
|
1208
1530
|
db.run("CREATE INDEX IF NOT EXISTS idx_summaries_project_epoch ON summaries(project, created_at_epoch DESC)");
|
|
1209
1531
|
db.run("CREATE INDEX IF NOT EXISTS idx_prompts_project_epoch ON prompts(project, created_at_epoch DESC)");
|
|
1210
1532
|
}
|
|
1533
|
+
},
|
|
1534
|
+
{
|
|
1535
|
+
version: 10,
|
|
1536
|
+
up: (db) => {
|
|
1537
|
+
db.run(`
|
|
1538
|
+
CREATE TABLE IF NOT EXISTS job_queue (
|
|
1539
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1540
|
+
type TEXT NOT NULL,
|
|
1541
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
1542
|
+
payload TEXT,
|
|
1543
|
+
result TEXT,
|
|
1544
|
+
error TEXT,
|
|
1545
|
+
retry_count INTEGER DEFAULT 0,
|
|
1546
|
+
max_retries INTEGER DEFAULT 3,
|
|
1547
|
+
priority INTEGER DEFAULT 0,
|
|
1548
|
+
created_at TEXT NOT NULL,
|
|
1549
|
+
created_at_epoch INTEGER NOT NULL,
|
|
1550
|
+
started_at_epoch INTEGER,
|
|
1551
|
+
completed_at_epoch INTEGER
|
|
1552
|
+
)
|
|
1553
|
+
`);
|
|
1554
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_jobs_status ON job_queue(status)");
|
|
1555
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_jobs_type ON job_queue(type)");
|
|
1556
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_jobs_priority ON job_queue(status, priority DESC, created_at_epoch ASC)");
|
|
1557
|
+
}
|
|
1558
|
+
},
|
|
1559
|
+
{
|
|
1560
|
+
version: 11,
|
|
1561
|
+
up: (db) => {
|
|
1562
|
+
db.run("ALTER TABLE observations ADD COLUMN auto_category TEXT");
|
|
1563
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_observations_category ON observations(auto_category)");
|
|
1564
|
+
}
|
|
1565
|
+
},
|
|
1566
|
+
{
|
|
1567
|
+
version: 12,
|
|
1568
|
+
up: (db) => {
|
|
1569
|
+
db.run(`
|
|
1570
|
+
CREATE TABLE IF NOT EXISTS github_links (
|
|
1571
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1572
|
+
observation_id INTEGER,
|
|
1573
|
+
session_id TEXT,
|
|
1574
|
+
repo TEXT NOT NULL,
|
|
1575
|
+
issue_number INTEGER,
|
|
1576
|
+
pr_number INTEGER,
|
|
1577
|
+
event_type TEXT NOT NULL,
|
|
1578
|
+
action TEXT,
|
|
1579
|
+
title TEXT,
|
|
1580
|
+
url TEXT,
|
|
1581
|
+
author TEXT,
|
|
1582
|
+
created_at TEXT NOT NULL,
|
|
1583
|
+
created_at_epoch INTEGER NOT NULL,
|
|
1584
|
+
FOREIGN KEY (observation_id) REFERENCES observations(id)
|
|
1585
|
+
)
|
|
1586
|
+
`);
|
|
1587
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_github_links_repo ON github_links(repo)");
|
|
1588
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_github_links_obs ON github_links(observation_id)");
|
|
1589
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_github_links_event ON github_links(event_type)");
|
|
1590
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_github_links_repo_issue ON github_links(repo, issue_number)");
|
|
1591
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_github_links_repo_pr ON github_links(repo, pr_number)");
|
|
1592
|
+
}
|
|
1593
|
+
},
|
|
1594
|
+
{
|
|
1595
|
+
version: 13,
|
|
1596
|
+
up: (db) => {
|
|
1597
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_observations_keyset ON observations(created_at_epoch DESC, id DESC)");
|
|
1598
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_observations_project_keyset ON observations(project, created_at_epoch DESC, id DESC)");
|
|
1599
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_summaries_keyset ON summaries(created_at_epoch DESC, id DESC)");
|
|
1600
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_summaries_project_keyset ON summaries(project, created_at_epoch DESC, id DESC)");
|
|
1601
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_prompts_keyset ON prompts(created_at_epoch DESC, id DESC)");
|
|
1602
|
+
db.run("CREATE INDEX IF NOT EXISTS idx_prompts_project_keyset ON prompts(project, created_at_epoch DESC, id DESC)");
|
|
1603
|
+
}
|
|
1211
1604
|
}
|
|
1212
1605
|
];
|
|
1213
1606
|
}
|
|
1214
1607
|
};
|
|
1215
1608
|
|
|
1609
|
+
// src/services/sqlite/cursor.ts
|
|
1610
|
+
function encodeCursor(id, epoch) {
|
|
1611
|
+
const raw = `${epoch}:${id}`;
|
|
1612
|
+
return Buffer.from(raw, "utf8").toString("base64url");
|
|
1613
|
+
}
|
|
1614
|
+
function decodeCursor(cursor) {
|
|
1615
|
+
try {
|
|
1616
|
+
const raw = Buffer.from(cursor, "base64url").toString("utf8");
|
|
1617
|
+
const colonIdx = raw.indexOf(":");
|
|
1618
|
+
if (colonIdx === -1) return null;
|
|
1619
|
+
const epochStr = raw.substring(0, colonIdx);
|
|
1620
|
+
const idStr = raw.substring(colonIdx + 1);
|
|
1621
|
+
const epoch = parseInt(epochStr, 10);
|
|
1622
|
+
const id = parseInt(idStr, 10);
|
|
1623
|
+
if (!Number.isInteger(epoch) || epoch <= 0) return null;
|
|
1624
|
+
if (!Number.isInteger(id) || id <= 0) return null;
|
|
1625
|
+
return { epoch, id };
|
|
1626
|
+
} catch {
|
|
1627
|
+
return null;
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1216
1631
|
// src/services/sqlite/Sessions.ts
|
|
1217
1632
|
function createSession(db, contentSessionId, project, userPrompt) {
|
|
1218
1633
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -1256,16 +1671,16 @@ function createSummary(db, sessionId, project, request, investigated, learned, c
|
|
|
1256
1671
|
}
|
|
1257
1672
|
function getSummariesByProject(db, project, limit = 50) {
|
|
1258
1673
|
const query = db.query(
|
|
1259
|
-
"SELECT * FROM summaries WHERE project = ? ORDER BY created_at_epoch DESC LIMIT ?"
|
|
1674
|
+
"SELECT * FROM summaries WHERE project = ? ORDER BY created_at_epoch DESC, id DESC LIMIT ?"
|
|
1260
1675
|
);
|
|
1261
1676
|
return query.all(project, limit);
|
|
1262
1677
|
}
|
|
1263
1678
|
function searchSummaries(db, searchTerm, project) {
|
|
1264
1679
|
const sql = project ? `SELECT * FROM summaries
|
|
1265
1680
|
WHERE project = ? AND (request LIKE ? ESCAPE '\\' OR learned LIKE ? ESCAPE '\\' OR completed LIKE ? ESCAPE '\\' OR notes LIKE ? ESCAPE '\\')
|
|
1266
|
-
ORDER BY created_at_epoch DESC` : `SELECT * FROM summaries
|
|
1681
|
+
ORDER BY created_at_epoch DESC, id DESC` : `SELECT * FROM summaries
|
|
1267
1682
|
WHERE request LIKE ? ESCAPE '\\' OR learned LIKE ? ESCAPE '\\' OR completed LIKE ? ESCAPE '\\' OR notes LIKE ? ESCAPE '\\'
|
|
1268
|
-
ORDER BY created_at_epoch DESC`;
|
|
1683
|
+
ORDER BY created_at_epoch DESC, id DESC`;
|
|
1269
1684
|
const pattern = `%${escapeLikePattern2(searchTerm)}%`;
|
|
1270
1685
|
const query = db.query(sql);
|
|
1271
1686
|
if (project) {
|
|
@@ -1287,7 +1702,7 @@ function createPrompt(db, contentSessionId, project, promptNumber, promptText) {
|
|
|
1287
1702
|
}
|
|
1288
1703
|
function getPromptsByProject(db, project, limit = 100) {
|
|
1289
1704
|
const query = db.query(
|
|
1290
|
-
"SELECT * FROM prompts WHERE project = ? ORDER BY created_at_epoch DESC LIMIT ?"
|
|
1705
|
+
"SELECT * FROM prompts WHERE project = ? ORDER BY created_at_epoch DESC, id DESC LIMIT ?"
|
|
1291
1706
|
);
|
|
1292
1707
|
return query.all(project, limit);
|
|
1293
1708
|
}
|
|
@@ -1315,13 +1730,13 @@ function createCheckpoint(db, sessionId, project, data) {
|
|
|
1315
1730
|
}
|
|
1316
1731
|
function getLatestCheckpoint(db, sessionId) {
|
|
1317
1732
|
const query = db.query(
|
|
1318
|
-
"SELECT * FROM checkpoints WHERE session_id = ? ORDER BY created_at_epoch DESC LIMIT 1"
|
|
1733
|
+
"SELECT * FROM checkpoints WHERE session_id = ? ORDER BY created_at_epoch DESC, id DESC LIMIT 1"
|
|
1319
1734
|
);
|
|
1320
1735
|
return query.get(sessionId);
|
|
1321
1736
|
}
|
|
1322
1737
|
function getLatestCheckpointByProject(db, project) {
|
|
1323
1738
|
const query = db.query(
|
|
1324
|
-
"SELECT * FROM checkpoints WHERE project = ? ORDER BY created_at_epoch DESC LIMIT 1"
|
|
1739
|
+
"SELECT * FROM checkpoints WHERE project = ? ORDER BY created_at_epoch DESC, id DESC LIMIT 1"
|
|
1325
1740
|
);
|
|
1326
1741
|
return query.get(project);
|
|
1327
1742
|
}
|
|
@@ -1383,9 +1798,9 @@ function getReportData(db, project, startEpoch, endEpoch) {
|
|
|
1383
1798
|
const staleCount = (project ? db.query(staleSql).get(project, startEpoch, endEpoch)?.count : db.query(staleSql).get(startEpoch, endEpoch)?.count) || 0;
|
|
1384
1799
|
const summarySql = project ? `SELECT learned, completed, next_steps FROM summaries
|
|
1385
1800
|
WHERE project = ? AND created_at_epoch >= ? AND created_at_epoch <= ?
|
|
1386
|
-
ORDER BY created_at_epoch DESC` : `SELECT learned, completed, next_steps FROM summaries
|
|
1801
|
+
ORDER BY created_at_epoch DESC, id DESC` : `SELECT learned, completed, next_steps FROM summaries
|
|
1387
1802
|
WHERE created_at_epoch >= ? AND created_at_epoch <= ?
|
|
1388
|
-
ORDER BY created_at_epoch DESC`;
|
|
1803
|
+
ORDER BY created_at_epoch DESC, id DESC`;
|
|
1389
1804
|
const summaryRows = project ? db.query(summarySql).all(project, startEpoch, endEpoch) : db.query(summarySql).all(startEpoch, endEpoch);
|
|
1390
1805
|
const topLearnings = [];
|
|
1391
1806
|
const completedTasks = [];
|
|
@@ -1450,20 +1865,61 @@ function getReportData(db, project, startEpoch, endEpoch) {
|
|
|
1450
1865
|
// src/services/sqlite/index.ts
|
|
1451
1866
|
init_Search();
|
|
1452
1867
|
|
|
1868
|
+
// src/types/worker-types.ts
|
|
1869
|
+
var KNOWLEDGE_TYPES = ["constraint", "decision", "heuristic", "rejected"];
|
|
1870
|
+
|
|
1871
|
+
// src/services/sqlite/Retention.ts
|
|
1872
|
+
var KNOWLEDGE_TYPE_LIST = KNOWLEDGE_TYPES;
|
|
1873
|
+
var KNOWLEDGE_PLACEHOLDERS = KNOWLEDGE_TYPE_LIST.map(() => "?").join(", ");
|
|
1874
|
+
|
|
1453
1875
|
// src/sdk/index.ts
|
|
1454
1876
|
init_Observations();
|
|
1455
1877
|
import { createHash } from "crypto";
|
|
1456
1878
|
init_Search();
|
|
1457
1879
|
|
|
1458
1880
|
// src/services/search/EmbeddingService.ts
|
|
1881
|
+
var MODEL_CONFIGS = {
|
|
1882
|
+
"all-MiniLM-L6-v2": {
|
|
1883
|
+
modelId: "Xenova/all-MiniLM-L6-v2",
|
|
1884
|
+
dimensions: 384
|
|
1885
|
+
},
|
|
1886
|
+
"jina-code-v2": {
|
|
1887
|
+
modelId: "jinaai/jina-embeddings-v2-base-code",
|
|
1888
|
+
dimensions: 768
|
|
1889
|
+
},
|
|
1890
|
+
"bge-small-en": {
|
|
1891
|
+
modelId: "BAAI/bge-small-en-v1.5",
|
|
1892
|
+
dimensions: 384
|
|
1893
|
+
}
|
|
1894
|
+
};
|
|
1895
|
+
var FASTEMBED_COMPATIBLE_MODELS = /* @__PURE__ */ new Set(["all-MiniLM-L6-v2", "bge-small-en"]);
|
|
1459
1896
|
var EmbeddingService = class {
|
|
1460
1897
|
provider = null;
|
|
1461
1898
|
model = null;
|
|
1462
1899
|
initialized = false;
|
|
1463
1900
|
initializing = null;
|
|
1901
|
+
config;
|
|
1902
|
+
configName;
|
|
1903
|
+
constructor() {
|
|
1904
|
+
const envModel = process.env.KIRO_MEMORY_EMBEDDING_MODEL || "all-MiniLM-L6-v2";
|
|
1905
|
+
this.configName = envModel;
|
|
1906
|
+
if (MODEL_CONFIGS[envModel]) {
|
|
1907
|
+
this.config = MODEL_CONFIGS[envModel];
|
|
1908
|
+
} else if (envModel.includes("/")) {
|
|
1909
|
+
const dimensions = parseInt(process.env.KIRO_MEMORY_EMBEDDING_DIMENSIONS || "384", 10);
|
|
1910
|
+
this.config = {
|
|
1911
|
+
modelId: envModel,
|
|
1912
|
+
dimensions: isNaN(dimensions) ? 384 : dimensions
|
|
1913
|
+
};
|
|
1914
|
+
} else {
|
|
1915
|
+
logger.warn("EMBEDDING", `Unknown model name '${envModel}', falling back to 'all-MiniLM-L6-v2'`);
|
|
1916
|
+
this.configName = "all-MiniLM-L6-v2";
|
|
1917
|
+
this.config = MODEL_CONFIGS["all-MiniLM-L6-v2"];
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1464
1920
|
/**
|
|
1465
1921
|
* Initialize the embedding service.
|
|
1466
|
-
* Tries fastembed, then @huggingface/transformers, then
|
|
1922
|
+
* Tries fastembed (when compatible), then @huggingface/transformers, then falls back to null.
|
|
1467
1923
|
*/
|
|
1468
1924
|
async initialize() {
|
|
1469
1925
|
if (this.initialized) return this.provider !== null;
|
|
@@ -1474,32 +1930,35 @@ var EmbeddingService = class {
|
|
|
1474
1930
|
return result;
|
|
1475
1931
|
}
|
|
1476
1932
|
async _doInitialize() {
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1933
|
+
const fastembedCompatible = FASTEMBED_COMPATIBLE_MODELS.has(this.configName);
|
|
1934
|
+
if (fastembedCompatible) {
|
|
1935
|
+
try {
|
|
1936
|
+
const fastembed = await import("fastembed");
|
|
1937
|
+
const EmbeddingModel = fastembed.EmbeddingModel || fastembed.default?.EmbeddingModel;
|
|
1938
|
+
const FlagEmbedding = fastembed.FlagEmbedding || fastembed.default?.FlagEmbedding;
|
|
1939
|
+
if (FlagEmbedding && EmbeddingModel) {
|
|
1940
|
+
this.model = await FlagEmbedding.init({
|
|
1941
|
+
model: EmbeddingModel.BGESmallENV15
|
|
1942
|
+
});
|
|
1943
|
+
this.provider = "fastembed";
|
|
1944
|
+
this.initialized = true;
|
|
1945
|
+
logger.info("EMBEDDING", `Initialized with fastembed (BGE-small-en-v1.5) for model '${this.configName}'`);
|
|
1946
|
+
return true;
|
|
1947
|
+
}
|
|
1948
|
+
} catch (error) {
|
|
1949
|
+
logger.debug("EMBEDDING", `fastembed not available: ${error}`);
|
|
1489
1950
|
}
|
|
1490
|
-
} catch (error) {
|
|
1491
|
-
logger.debug("EMBEDDING", `fastembed not available: ${error}`);
|
|
1492
1951
|
}
|
|
1493
1952
|
try {
|
|
1494
1953
|
const transformers = await import("@huggingface/transformers");
|
|
1495
1954
|
const pipeline = transformers.pipeline || transformers.default?.pipeline;
|
|
1496
1955
|
if (pipeline) {
|
|
1497
|
-
this.model = await pipeline("feature-extraction",
|
|
1956
|
+
this.model = await pipeline("feature-extraction", this.config.modelId, {
|
|
1498
1957
|
quantized: true
|
|
1499
1958
|
});
|
|
1500
1959
|
this.provider = "transformers";
|
|
1501
1960
|
this.initialized = true;
|
|
1502
|
-
logger.info("EMBEDDING",
|
|
1961
|
+
logger.info("EMBEDDING", `Initialized with @huggingface/transformers (${this.config.modelId})`);
|
|
1503
1962
|
return true;
|
|
1504
1963
|
}
|
|
1505
1964
|
} catch (error) {
|
|
@@ -1512,7 +1971,7 @@ var EmbeddingService = class {
|
|
|
1512
1971
|
}
|
|
1513
1972
|
/**
|
|
1514
1973
|
* Generate embedding for a single text.
|
|
1515
|
-
* Returns Float32Array with
|
|
1974
|
+
* Returns Float32Array with configured dimensions, or null if not available.
|
|
1516
1975
|
*/
|
|
1517
1976
|
async embed(text) {
|
|
1518
1977
|
if (!this.initialized) await this.initialize();
|
|
@@ -1563,10 +2022,17 @@ var EmbeddingService = class {
|
|
|
1563
2022
|
return this.provider;
|
|
1564
2023
|
}
|
|
1565
2024
|
/**
|
|
1566
|
-
* Embedding vector dimensions.
|
|
2025
|
+
* Embedding vector dimensions for the active model configuration.
|
|
1567
2026
|
*/
|
|
1568
2027
|
getDimensions() {
|
|
1569
|
-
return
|
|
2028
|
+
return this.config.dimensions;
|
|
2029
|
+
}
|
|
2030
|
+
/**
|
|
2031
|
+
* Human-readable model name used as identifier in the observation_embeddings table.
|
|
2032
|
+
* Returns the short name (e.g., 'all-MiniLM-L6-v2') or the full HF model ID for custom models.
|
|
2033
|
+
*/
|
|
2034
|
+
getModelName() {
|
|
2035
|
+
return this.configName;
|
|
1570
2036
|
}
|
|
1571
2037
|
// --- Batch implementations ---
|
|
1572
2038
|
/**
|
|
@@ -1785,7 +2251,7 @@ var VectorSearch = class {
|
|
|
1785
2251
|
`).all(batchSize);
|
|
1786
2252
|
if (rows.length === 0) return 0;
|
|
1787
2253
|
let count = 0;
|
|
1788
|
-
const model = embeddingService2.
|
|
2254
|
+
const model = embeddingService2.getModelName();
|
|
1789
2255
|
for (const row of rows) {
|
|
1790
2256
|
const parts = [row.title];
|
|
1791
2257
|
if (row.text) parts.push(row.text);
|
|
@@ -1963,9 +2429,6 @@ function getHybridSearch() {
|
|
|
1963
2429
|
return hybridSearch;
|
|
1964
2430
|
}
|
|
1965
2431
|
|
|
1966
|
-
// src/types/worker-types.ts
|
|
1967
|
-
var KNOWLEDGE_TYPES = ["constraint", "decision", "heuristic", "rejected"];
|
|
1968
|
-
|
|
1969
2432
|
// src/sdk/index.ts
|
|
1970
2433
|
var KiroMemorySDK = class {
|
|
1971
2434
|
db;
|
|
@@ -2522,6 +2985,66 @@ var KiroMemorySDK = class {
|
|
|
2522
2985
|
}
|
|
2523
2986
|
return getReportData(this.db.db, this.project, startEpoch, endEpoch);
|
|
2524
2987
|
}
|
|
2988
|
+
/**
|
|
2989
|
+
* Lista osservazioni con keyset pagination.
|
|
2990
|
+
* Restituisce un oggetto { data, next_cursor, has_more }.
|
|
2991
|
+
*
|
|
2992
|
+
* Esempio:
|
|
2993
|
+
* const page1 = await sdk.listObservations({ limit: 50 });
|
|
2994
|
+
* const page2 = await sdk.listObservations({ cursor: page1.next_cursor });
|
|
2995
|
+
*/
|
|
2996
|
+
async listObservations(options = {}) {
|
|
2997
|
+
const limit = Math.min(Math.max(options.limit ?? 50, 1), 200);
|
|
2998
|
+
const project = options.project ?? this.project;
|
|
2999
|
+
let rows;
|
|
3000
|
+
if (options.cursor) {
|
|
3001
|
+
const decoded = decodeCursor(options.cursor);
|
|
3002
|
+
if (!decoded) throw new Error("Cursor non valido");
|
|
3003
|
+
const sql = project ? `SELECT * FROM observations
|
|
3004
|
+
WHERE project = ? AND (created_at_epoch < ? OR (created_at_epoch = ? AND id < ?))
|
|
3005
|
+
ORDER BY created_at_epoch DESC, id DESC
|
|
3006
|
+
LIMIT ?` : `SELECT * FROM observations
|
|
3007
|
+
WHERE (created_at_epoch < ? OR (created_at_epoch = ? AND id < ?))
|
|
3008
|
+
ORDER BY created_at_epoch DESC, id DESC
|
|
3009
|
+
LIMIT ?`;
|
|
3010
|
+
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);
|
|
3011
|
+
} else {
|
|
3012
|
+
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 ?";
|
|
3013
|
+
rows = project ? this.db.db.query(sql).all(project, limit) : this.db.db.query(sql).all(limit);
|
|
3014
|
+
}
|
|
3015
|
+
const next_cursor = rows.length >= limit ? encodeCursor(rows[rows.length - 1].id, rows[rows.length - 1].created_at_epoch) : null;
|
|
3016
|
+
return { data: rows, next_cursor, has_more: next_cursor !== null };
|
|
3017
|
+
}
|
|
3018
|
+
/**
|
|
3019
|
+
* Lista sommari con keyset pagination.
|
|
3020
|
+
* Restituisce un oggetto { data, next_cursor, has_more }.
|
|
3021
|
+
*
|
|
3022
|
+
* Esempio:
|
|
3023
|
+
* const page1 = await sdk.listSummaries({ limit: 20 });
|
|
3024
|
+
* const page2 = await sdk.listSummaries({ cursor: page1.next_cursor });
|
|
3025
|
+
*/
|
|
3026
|
+
async listSummaries(options = {}) {
|
|
3027
|
+
const limit = Math.min(Math.max(options.limit ?? 20, 1), 200);
|
|
3028
|
+
const project = options.project ?? this.project;
|
|
3029
|
+
let rows;
|
|
3030
|
+
if (options.cursor) {
|
|
3031
|
+
const decoded = decodeCursor(options.cursor);
|
|
3032
|
+
if (!decoded) throw new Error("Cursor non valido");
|
|
3033
|
+
const sql = project ? `SELECT * FROM summaries
|
|
3034
|
+
WHERE project = ? AND (created_at_epoch < ? OR (created_at_epoch = ? AND id < ?))
|
|
3035
|
+
ORDER BY created_at_epoch DESC, id DESC
|
|
3036
|
+
LIMIT ?` : `SELECT * FROM summaries
|
|
3037
|
+
WHERE (created_at_epoch < ? OR (created_at_epoch = ? AND id < ?))
|
|
3038
|
+
ORDER BY created_at_epoch DESC, id DESC
|
|
3039
|
+
LIMIT ?`;
|
|
3040
|
+
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);
|
|
3041
|
+
} else {
|
|
3042
|
+
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 ?";
|
|
3043
|
+
rows = project ? this.db.db.query(sql).all(project, limit) : this.db.db.query(sql).all(limit);
|
|
3044
|
+
}
|
|
3045
|
+
const next_cursor = rows.length >= limit ? encodeCursor(rows[rows.length - 1].id, rows[rows.length - 1].created_at_epoch) : null;
|
|
3046
|
+
return { data: rows, next_cursor, has_more: next_cursor !== null };
|
|
3047
|
+
}
|
|
2525
3048
|
/**
|
|
2526
3049
|
* Getter for direct database access (for API routes)
|
|
2527
3050
|
*/
|
|
@@ -2540,6 +3063,7 @@ function createKiroMemory(config) {
|
|
|
2540
3063
|
}
|
|
2541
3064
|
|
|
2542
3065
|
// src/hooks/userPromptSubmit.ts
|
|
3066
|
+
init_secrets();
|
|
2543
3067
|
runHook("userPromptSubmit", async (input) => {
|
|
2544
3068
|
const promptText = input.prompt || input.user_prompt || input.tool_input?.prompt || input.tool_input?.content;
|
|
2545
3069
|
if (!promptText || typeof promptText !== "string" || promptText.trim().length === 0) return;
|
|
@@ -2547,7 +3071,8 @@ runHook("userPromptSubmit", async (input) => {
|
|
|
2547
3071
|
const sdk = createKiroMemory({ project, skipMigrations: true });
|
|
2548
3072
|
try {
|
|
2549
3073
|
const sessionId = input.session_id || `kiro-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}-${project}`;
|
|
2550
|
-
|
|
3074
|
+
const safePromptText = redactSecrets(promptText.trim());
|
|
3075
|
+
await sdk.storePrompt(sessionId, Date.now(), safePromptText);
|
|
2551
3076
|
await notifyWorker("prompt-created", { project });
|
|
2552
3077
|
if (input.hook_event_name === "beforeSubmitPrompt") {
|
|
2553
3078
|
process.stdout.write(JSON.stringify({ continue: true }));
|