@veewo/claw-core 0.2.14 → 0.2.16
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 -16
- package/dist/src/memory.js +28 -147
- package/dist/src/memory.js.map +1 -1
- package/dist/src/resources/cindy-delegate-writer/TEMPLATE.json +1 -1
- package/dist/src/resources/delegate-writer/TEMPLATE.json +1 -1
- package/dist/src/resources/doc-updater/FALLBACK.md +16 -16
- package/dist/src/resources/doc-updater/SKILL.md +19 -19
- package/dist/src/resources/doc-updater/TEMPLATE.json +1 -1
- package/dist/src/resources/knowledge-writer/CONTENT-COVERAGE.md +30 -30
- package/dist/src/resources/knowledge-writer/SKILL.md +6 -6
- package/dist/src/resources/knowledge-writer/TEMPLATE.json +1 -1
- package/dist/src/resources/knowledge-writer/non-claw-fallback.md +53 -53
- package/dist/src/templates/plans/default.js +1 -1
- package/dist/src/types.d.ts +2 -5
- package/dist/src/workflow-guidance.codex.config.json +363 -0
- package/dist/src/workflow-guidance.config.json +365 -365
- package/dist/src/workflow-guidance.qoder.config.json +362 -0
- package/package.json +48 -48
- package/dist/src/embedding-config.d.ts +0 -9
- package/dist/src/embedding-config.js +0 -21
- package/dist/src/embedding-config.js.map +0 -1
- package/dist/src/project-config-defaults.d.ts +0 -6
- package/dist/src/project-config-defaults.js +0 -5
- package/dist/src/project-config-defaults.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
# @veewo/claw-core
|
|
2
|
-
|
|
3
|
-
`@veewo/claw-core` is the shared workflow engine behind `claw-kit`.
|
|
4
|
-
|
|
5
|
-
It provides the core primitives that let `.claw` act as a project-level working surface for config resolution, planning, project recall, truth ingestion, and task retention.
|
|
6
|
-
|
|
7
|
-
## Responsibilities
|
|
8
|
-
|
|
9
|
-
- project config normalization and runtime resolution
|
|
10
|
-
- plan lifecycle and workflow guidance primitives
|
|
11
|
-
- project memory and search indexing behavior
|
|
12
|
-
- truth ingestion and retention mechanics
|
|
13
|
-
|
|
14
|
-
## Repository
|
|
15
|
-
|
|
16
|
-
- [claw-kit](https://github.com/chanyuenpang/claw-kit)
|
|
1
|
+
# @veewo/claw-core
|
|
2
|
+
|
|
3
|
+
`@veewo/claw-core` is the shared workflow engine behind `claw-kit`.
|
|
4
|
+
|
|
5
|
+
It provides the core primitives that let `.claw` act as a project-level working surface for config resolution, planning, project recall, truth ingestion, and task retention.
|
|
6
|
+
|
|
7
|
+
## Responsibilities
|
|
8
|
+
|
|
9
|
+
- project config normalization and runtime resolution
|
|
10
|
+
- plan lifecycle and workflow guidance primitives
|
|
11
|
+
- project memory and search indexing behavior
|
|
12
|
+
- truth ingestion and retention mechanics
|
|
13
|
+
|
|
14
|
+
## Repository
|
|
15
|
+
|
|
16
|
+
- [claw-kit](https://github.com/chanyuenpang/claw-kit)
|
package/dist/src/memory.js
CHANGED
|
@@ -5,11 +5,11 @@ import { spawnSync } from "node:child_process";
|
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
6
|
import { DatabaseSync } from "node:sqlite";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
|
-
import { resolveProjectContext
|
|
8
|
+
import { resolveProjectContext } from "./context.js";
|
|
9
9
|
import { resolveDefaultLocalEmbeddingDimensions } from "./embedding-defaults.js";
|
|
10
10
|
import { requestPersistentEmbedding } from "./embedding-daemon-protocol.js";
|
|
11
11
|
import { ClawError } from "./errors.js";
|
|
12
|
-
import {
|
|
12
|
+
import { readTextFile } from "./io.js";
|
|
13
13
|
import { analyzeKnowledgeDocument } from "./knowledge-document.js";
|
|
14
14
|
import { buildProjectKeywordSearchPlan, buildProjectQueryIntent } from "./memory-query.js";
|
|
15
15
|
const DEFAULT_PROJECT_REFRESH_FILE_LIMIT = 100;
|
|
@@ -28,32 +28,27 @@ const DEFAULT_PERSISTENT_SEARCH_DATABASE_LIMIT = 2;
|
|
|
28
28
|
const persistentMemoryDatabases = new Map();
|
|
29
29
|
const projectVectorRowsByDatabase = new WeakMap();
|
|
30
30
|
export function buildMemoryIndex(input) {
|
|
31
|
-
const
|
|
31
|
+
const project = resolveProjectContext(input.cwd);
|
|
32
32
|
if (!isProjectMemoryEnabled(project)) {
|
|
33
33
|
return {
|
|
34
|
-
scope,
|
|
35
|
-
storePath: getMemoryStorePath(project
|
|
34
|
+
scope: "project",
|
|
35
|
+
storePath: getMemoryStorePath(project),
|
|
36
36
|
indexedCount: 0,
|
|
37
37
|
processedFileCount: 0,
|
|
38
38
|
pendingFileCount: 0,
|
|
39
39
|
sources: [],
|
|
40
|
-
|
|
40
|
+
embedding: null,
|
|
41
|
+
vectorIndex: null,
|
|
41
42
|
};
|
|
42
43
|
}
|
|
43
|
-
const storePath = getMemoryStorePath(project
|
|
44
|
-
const sources =
|
|
45
|
-
const embedding =
|
|
44
|
+
const storePath = getMemoryStorePath(project);
|
|
45
|
+
const sources = collectProjectMemorySources(project);
|
|
46
|
+
const embedding = resolveProjectMemoryEmbeddingConfig(project);
|
|
46
47
|
fs.mkdirSync(path.dirname(storePath), { recursive: true });
|
|
47
48
|
return withMemoryDatabase(storePath, "index refresh", "write", (db) => {
|
|
48
49
|
prepareSchema(db);
|
|
49
|
-
const syncResult =
|
|
50
|
-
|
|
51
|
-
: {
|
|
52
|
-
vectorIndex: rebuildTaskMemoryIndex(db, sources),
|
|
53
|
-
processedFileCount: sources.length,
|
|
54
|
-
pendingFileCount: 0,
|
|
55
|
-
};
|
|
56
|
-
upsertMetadata(db, "scope", scope);
|
|
50
|
+
const syncResult = syncProjectMemoryIndex(db, sources, embedding ?? null, input.maxFiles ?? DEFAULT_PROJECT_REFRESH_FILE_LIMIT);
|
|
51
|
+
upsertMetadata(db, "scope", "project");
|
|
57
52
|
upsertMetadata(db, "indexed_at", new Date().toISOString());
|
|
58
53
|
if (embedding) {
|
|
59
54
|
upsertMetadata(db, "embedding_config", JSON.stringify(embedding));
|
|
@@ -70,29 +65,17 @@ export function buildMemoryIndex(input) {
|
|
|
70
65
|
deleteMetadata(db, "vector_index");
|
|
71
66
|
}
|
|
72
67
|
return {
|
|
73
|
-
scope,
|
|
68
|
+
scope: "project",
|
|
74
69
|
storePath,
|
|
75
70
|
indexedCount: sources.length,
|
|
76
71
|
processedFileCount: syncResult.processedFileCount,
|
|
77
72
|
pendingFileCount: syncResult.pendingFileCount,
|
|
78
73
|
sources: sources.map((entry) => entry.sourcePath),
|
|
79
|
-
|
|
74
|
+
embedding,
|
|
75
|
+
vectorIndex: syncResult.vectorIndex,
|
|
80
76
|
};
|
|
81
77
|
});
|
|
82
78
|
}
|
|
83
|
-
function rebuildTaskMemoryIndex(db, sources) {
|
|
84
|
-
db.exec("DELETE FROM docs;");
|
|
85
|
-
db.exec("DELETE FROM docs_fts;");
|
|
86
|
-
db.exec("DELETE FROM doc_embeddings;");
|
|
87
|
-
db.exec("DELETE FROM doc_embedding_vectors;");
|
|
88
|
-
const insertDoc = db.prepare("INSERT INTO docs (source_path, kind, content, content_hash) VALUES (?, ?, ?, ?)");
|
|
89
|
-
const insertFts = db.prepare("INSERT INTO docs_fts (rowid, source_path, kind, content) VALUES (?, ?, ?, ?)");
|
|
90
|
-
for (const source of sources) {
|
|
91
|
-
const result = insertDoc.run(source.sourcePath, source.kind, source.content, hashMemoryContent(source.content));
|
|
92
|
-
insertFts.run(Number(result.lastInsertRowid), source.sourcePath, source.kind, source.content);
|
|
93
|
-
}
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
79
|
function syncProjectMemoryIndex(db, sources, embedding, maxFiles) {
|
|
97
80
|
const currentEmbeddingConfig = embedding ? JSON.stringify(embedding) : null;
|
|
98
81
|
const storedEmbeddingConfig = getMetadata(db, "embedding_config");
|
|
@@ -226,37 +209,22 @@ export function searchMemory(input) {
|
|
|
226
209
|
if (!input.query.trim()) {
|
|
227
210
|
throw new ClawError("MEMORY_QUERY_REQUIRED", "memory search requires a non-empty query.");
|
|
228
211
|
}
|
|
229
|
-
const
|
|
212
|
+
const project = resolveProjectContext(input.cwd);
|
|
230
213
|
if (!isProjectMemoryEnabled(project)) {
|
|
231
214
|
throw new ClawError("MEMORY_DISABLED", "Project memory is disabled by .claw/project.json `memory.enabled = false`.", {
|
|
232
|
-
scope,
|
|
215
|
+
scope: "project",
|
|
233
216
|
projectRoot: project.projectRoot,
|
|
234
217
|
});
|
|
235
218
|
}
|
|
236
|
-
const storePath = getMemoryStorePath(project
|
|
219
|
+
const storePath = getMemoryStorePath(project);
|
|
237
220
|
if (!fs.existsSync(storePath)) {
|
|
238
|
-
|
|
239
|
-
throw new ClawError("MEMORY_VECTOR_INDEX_REQUIRED", "Project search requires a refreshed vector index. Run `claw search index --refresh` first.");
|
|
240
|
-
}
|
|
241
|
-
buildMemoryIndex({
|
|
242
|
-
cwd: input.cwd,
|
|
243
|
-
scope,
|
|
244
|
-
...(task ? { taskName: task.taskName } : {}),
|
|
245
|
-
});
|
|
221
|
+
throw new ClawError("MEMORY_VECTOR_INDEX_REQUIRED", "Project search requires a refreshed vector index. Run `claw search index --refresh` first.");
|
|
246
222
|
}
|
|
247
223
|
return withMemoryDatabase(storePath, "search", "read", (db) => {
|
|
248
224
|
prepareSchema(db);
|
|
249
|
-
const searchResult =
|
|
250
|
-
? searchProjectMemoryHybrid(db, input.query, input.limit ?? 10, project)
|
|
251
|
-
: {
|
|
252
|
-
results: searchTaskMemoryFts(db, input.query, input.limit ?? 10),
|
|
253
|
-
telemetry: {
|
|
254
|
-
route: "task_fts",
|
|
255
|
-
queryEmbedding: "skipped",
|
|
256
|
-
},
|
|
257
|
-
};
|
|
225
|
+
const searchResult = searchProjectMemoryHybrid(db, input.query, input.limit ?? 10, project);
|
|
258
226
|
return {
|
|
259
|
-
scope,
|
|
227
|
+
scope: "project",
|
|
260
228
|
storePath,
|
|
261
229
|
results: searchResult.results,
|
|
262
230
|
telemetry: {
|
|
@@ -278,15 +246,14 @@ export async function searchMemoryAsync(input) {
|
|
|
278
246
|
return result;
|
|
279
247
|
}
|
|
280
248
|
async function primePersistentProjectQueryEmbedding(input) {
|
|
281
|
-
if (
|
|
282
|
-
|| process.env.CLAW_EMBEDDING_MOCK === "1"
|
|
249
|
+
if (process.env.CLAW_EMBEDDING_MOCK === "1"
|
|
283
250
|
|| process.env.CLAW_EMBEDDING_PERSISTENT_WORKER === "0"
|
|
284
251
|
|| !input.query.trim()) {
|
|
285
252
|
return null;
|
|
286
253
|
}
|
|
287
254
|
const project = resolveProjectContext(input.cwd);
|
|
288
255
|
const embedding = resolveProjectMemoryEmbeddingConfig(project);
|
|
289
|
-
const storePath = getMemoryStorePath(project
|
|
256
|
+
const storePath = getMemoryStorePath(project);
|
|
290
257
|
if (embedding?.provider !== "local" || !fs.existsSync(storePath)) {
|
|
291
258
|
return null;
|
|
292
259
|
}
|
|
@@ -321,34 +288,16 @@ async function primePersistentProjectQueryEmbedding(input) {
|
|
|
321
288
|
return "persistent_daemon";
|
|
322
289
|
}
|
|
323
290
|
export function getMemory(input) {
|
|
324
|
-
const
|
|
325
|
-
const storePath = getMemoryStorePath(project
|
|
326
|
-
const sources = isProjectMemoryEnabled(project) ?
|
|
291
|
+
const project = resolveProjectContext(input.cwd);
|
|
292
|
+
const storePath = getMemoryStorePath(project);
|
|
293
|
+
const sources = isProjectMemoryEnabled(project) ? collectProjectMemorySources(project) : [];
|
|
327
294
|
return {
|
|
328
|
-
scope,
|
|
295
|
+
scope: "project",
|
|
329
296
|
storePath,
|
|
330
297
|
sources,
|
|
331
298
|
};
|
|
332
299
|
}
|
|
333
|
-
function
|
|
334
|
-
const project = resolveProjectContext(input.cwd);
|
|
335
|
-
const scope = input.scope ?? "project";
|
|
336
|
-
if (scope === "task") {
|
|
337
|
-
if (!input.taskName) {
|
|
338
|
-
throw new ClawError("TASK_NOT_FOUND", "Task scope memory commands require --task.", { scope });
|
|
339
|
-
}
|
|
340
|
-
return {
|
|
341
|
-
scope,
|
|
342
|
-
project,
|
|
343
|
-
task: resolveTaskContext(project, input.taskName),
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
return { scope, project };
|
|
347
|
-
}
|
|
348
|
-
function getMemoryStorePath(project, scope, task) {
|
|
349
|
-
if (scope === "task" && task) {
|
|
350
|
-
return path.join(task.taskDir, "memory.sqlite");
|
|
351
|
-
}
|
|
300
|
+
function getMemoryStorePath(project) {
|
|
352
301
|
return path.join(project.clawDir, "memory.sqlite");
|
|
353
302
|
}
|
|
354
303
|
function withMemoryDatabase(storePath, operation, access, callback) {
|
|
@@ -431,12 +380,6 @@ function buildMemoryStoreBusyError(storePath, operation, cause) {
|
|
|
431
380
|
cause: causeMessage,
|
|
432
381
|
});
|
|
433
382
|
}
|
|
434
|
-
function collectMemorySources(project, scope, task) {
|
|
435
|
-
if (scope === "task" && task) {
|
|
436
|
-
return collectTaskMemorySources(task);
|
|
437
|
-
}
|
|
438
|
-
return collectProjectMemorySources(project);
|
|
439
|
-
}
|
|
440
383
|
function collectProjectMemorySources(project) {
|
|
441
384
|
const sources = [];
|
|
442
385
|
addTextSourceIfExists(sources, path.join(project.clawDir, "memory.md"), "project_memory");
|
|
@@ -451,17 +394,6 @@ function collectProjectMemorySources(project) {
|
|
|
451
394
|
}
|
|
452
395
|
return sources;
|
|
453
396
|
}
|
|
454
|
-
function collectTaskMemorySources(task) {
|
|
455
|
-
const sources = [];
|
|
456
|
-
const plan = readJsonFile(task.activePlanPath);
|
|
457
|
-
sources.push({
|
|
458
|
-
sourcePath: task.activePlanPath,
|
|
459
|
-
kind: "active_plan",
|
|
460
|
-
content: renderStructuredPlanMemory(plan),
|
|
461
|
-
});
|
|
462
|
-
addTextSourceIfExists(sources, path.join(task.taskDir, "memory.md"), "task_memory");
|
|
463
|
-
return sources;
|
|
464
|
-
}
|
|
465
397
|
function addTextSourceIfExists(sources, sourcePath, kind) {
|
|
466
398
|
if (!fs.existsSync(sourcePath) || !fs.statSync(sourcePath).isFile()) {
|
|
467
399
|
return;
|
|
@@ -491,40 +423,6 @@ function addExternalDocSources(sources, projectRoot, externalPath) {
|
|
|
491
423
|
addTextSourceIfExists(sources, filePath, "external_doc");
|
|
492
424
|
}
|
|
493
425
|
}
|
|
494
|
-
function renderStructuredPlanMemory(plan) {
|
|
495
|
-
const parts = [
|
|
496
|
-
`# ${plan.title}`,
|
|
497
|
-
`Status: ${plan.status}`,
|
|
498
|
-
`Goal: ${plan.goal.text}`,
|
|
499
|
-
];
|
|
500
|
-
if (plan.rules?.length) {
|
|
501
|
-
parts.push("Rules:");
|
|
502
|
-
parts.push(...plan.rules.map((rule) => `- ${rule}`));
|
|
503
|
-
}
|
|
504
|
-
if (plan.references?.length) {
|
|
505
|
-
parts.push("References:");
|
|
506
|
-
parts.push(...plan.references.map((reference) => `- ${reference.why}: ${reference.path}`));
|
|
507
|
-
}
|
|
508
|
-
if (plan.keyDecisions?.length) {
|
|
509
|
-
parts.push("Key Decisions:");
|
|
510
|
-
parts.push(...plan.keyDecisions.map((decision) => `- ${decision}`));
|
|
511
|
-
}
|
|
512
|
-
if (plan.retrospective) {
|
|
513
|
-
parts.push("Retrospective:");
|
|
514
|
-
parts.push(`- Summary: ${plan.retrospective.summary}`);
|
|
515
|
-
for (const item of plan.retrospective.whatWorked ?? []) {
|
|
516
|
-
parts.push(`- Worked: ${item}`);
|
|
517
|
-
}
|
|
518
|
-
for (const item of plan.retrospective.issues ?? []) {
|
|
519
|
-
parts.push(`- Issue: ${item}`);
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
if (plan.tasks.length) {
|
|
523
|
-
parts.push("Tasks:");
|
|
524
|
-
parts.push(...plan.tasks.map((task) => `- [${task.status}] ${task.id}: ${task.title}`));
|
|
525
|
-
}
|
|
526
|
-
return `${parts.join("\n")}\n`;
|
|
527
|
-
}
|
|
528
426
|
function prepareSchema(db) {
|
|
529
427
|
db.exec([
|
|
530
428
|
"CREATE TABLE IF NOT EXISTS docs (",
|
|
@@ -1084,23 +982,6 @@ function resolveEmbeddingDimensions(embedding, fallback) {
|
|
|
1084
982
|
}
|
|
1085
983
|
return fallback > 0 ? fallback : 1536;
|
|
1086
984
|
}
|
|
1087
|
-
function searchTaskMemoryFts(db, query, limit) {
|
|
1088
|
-
const rows = db
|
|
1089
|
-
.prepare([
|
|
1090
|
-
"SELECT source_path, kind, snippet(docs_fts, 2, '[', ']', ' ... ', 18) AS snippet, bm25(docs_fts) AS score",
|
|
1091
|
-
"FROM docs_fts",
|
|
1092
|
-
"WHERE docs_fts MATCH ?",
|
|
1093
|
-
"ORDER BY score ASC",
|
|
1094
|
-
"LIMIT ?",
|
|
1095
|
-
].join(" "))
|
|
1096
|
-
.all(query, limit);
|
|
1097
|
-
return rows.map((row) => ({
|
|
1098
|
-
sourcePath: row.source_path,
|
|
1099
|
-
kind: row.kind,
|
|
1100
|
-
snippet: row.snippet,
|
|
1101
|
-
score: row.score,
|
|
1102
|
-
}));
|
|
1103
|
-
}
|
|
1104
985
|
function searchProjectMemoryHybrid(db, query, limit, project) {
|
|
1105
986
|
const embedding = resolveProjectMemoryEmbeddingConfig(project);
|
|
1106
987
|
if (!embedding) {
|