clawvault 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/command-registration.test.js +2 -1
- package/bin/help-contract.test.js +2 -0
- package/bin/register-maintenance-commands.js +27 -1
- package/bin/register-query-commands.js +35 -0
- package/bin/register-query-commands.test.js +15 -0
- package/dist/chunk-35JCYSRR.js +158 -0
- package/dist/{chunk-TDWFBDAQ.js → chunk-D5U3Q4N5.js} +7 -151
- package/dist/{chunk-YCUVAOFC.js → chunk-DCF4KMFD.js} +4 -4
- package/dist/chunk-NSXYM6EZ.js +255 -0
- package/dist/chunk-QYQAGBTM.js +2097 -0
- package/dist/chunk-RL2L6I6K.js +223 -0
- package/dist/chunk-YTRZNA64.js +37 -0
- package/dist/cli/index.js +6 -5
- package/dist/commands/entities.d.ts +8 -1
- package/dist/commands/entities.js +44 -1
- package/dist/commands/link.js +5 -5
- package/dist/commands/maintain.js +2 -1
- package/dist/commands/recall.d.ts +14 -0
- package/dist/commands/recall.js +15 -0
- package/dist/index.d.ts +59 -1
- package/dist/index.js +56 -11
- package/dist/openclaw-plugin--gqA2BZw.d.ts +267 -0
- package/dist/openclaw-plugin.d.ts +4 -8
- package/dist/openclaw-plugin.js +16 -10
- package/dist/types-CbL-wIKi.d.ts +36 -0
- package/openclaw.plugin.json +39 -0
- package/package.json +4 -4
|
@@ -49,7 +49,7 @@ describe('CLI command registration modules', () => {
|
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
const names = listCommandNames(program);
|
|
52
|
-
expect(names).toEqual(expect.arrayContaining(['search', 'vsearch', 'context', 'inject', 'observe', 'reflect', 'session-recap']));
|
|
52
|
+
expect(names).toEqual(expect.arrayContaining(['search', 'vsearch', 'context', 'recall', 'inject', 'observe', 'reflect', 'session-recap']));
|
|
53
53
|
|
|
54
54
|
const contextCommand = program.commands.find((command) => command.name() === 'context');
|
|
55
55
|
const profileOption = contextCommand?.options.find((option) => option.flags.includes('--profile <profile>'));
|
|
@@ -127,6 +127,7 @@ describe('CLI command registration modules', () => {
|
|
|
127
127
|
'compat',
|
|
128
128
|
'graph',
|
|
129
129
|
'entities',
|
|
130
|
+
'entity',
|
|
130
131
|
'link',
|
|
131
132
|
'rebuild',
|
|
132
133
|
'archive',
|
|
@@ -6,6 +6,7 @@ describe('CLI help contract', () => {
|
|
|
6
6
|
const help = registerAllCommandModules().helpInformation();
|
|
7
7
|
expect(help).toContain('init');
|
|
8
8
|
expect(help).toContain('context');
|
|
9
|
+
expect(help).toContain('recall');
|
|
9
10
|
expect(help).toContain('inject');
|
|
10
11
|
expect(help).toContain('doctor');
|
|
11
12
|
expect(help).toContain('benchmark');
|
|
@@ -22,6 +23,7 @@ describe('CLI help contract', () => {
|
|
|
22
23
|
expect(help).toContain('template');
|
|
23
24
|
expect(help).toContain('config');
|
|
24
25
|
expect(help).toContain('route');
|
|
26
|
+
expect(help).toContain('entity');
|
|
25
27
|
});
|
|
26
28
|
|
|
27
29
|
it('documents context/compat/inject/project help details', () => {
|
|
@@ -174,11 +174,37 @@ export function registerMaintenanceCommands(program, { chalk }) {
|
|
|
174
174
|
.command('entities')
|
|
175
175
|
.description('List all linkable entities in the vault')
|
|
176
176
|
.option('-v, --vault <path>', 'Vault path')
|
|
177
|
+
.option('--refresh', 'Regenerate entity profiles before listing')
|
|
177
178
|
.option('--json', 'Output as JSON')
|
|
178
179
|
.action(async (options) => {
|
|
179
180
|
try {
|
|
180
181
|
const { entitiesCommand } = await import('../dist/commands/entities.js');
|
|
181
|
-
await entitiesCommand({
|
|
182
|
+
await entitiesCommand({
|
|
183
|
+
json: options.json,
|
|
184
|
+
vaultPath: options.vault,
|
|
185
|
+
refresh: options.refresh
|
|
186
|
+
});
|
|
187
|
+
} catch (err) {
|
|
188
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// === ENTITY ===
|
|
194
|
+
program
|
|
195
|
+
.command('entity <name>')
|
|
196
|
+
.description('Show synthesized profile for one entity')
|
|
197
|
+
.option('-v, --vault <path>', 'Vault path')
|
|
198
|
+
.option('--refresh', 'Regenerate entity profiles before lookup')
|
|
199
|
+
.option('--json', 'Output as JSON')
|
|
200
|
+
.action(async (name, options) => {
|
|
201
|
+
try {
|
|
202
|
+
const { entityCommand } = await import('../dist/commands/entities.js');
|
|
203
|
+
await entityCommand(name, {
|
|
204
|
+
json: options.json,
|
|
205
|
+
vaultPath: options.vault,
|
|
206
|
+
refresh: options.refresh
|
|
207
|
+
});
|
|
182
208
|
} catch (err) {
|
|
183
209
|
console.error(chalk.red(`Error: ${err.message}`));
|
|
184
210
|
process.exit(1);
|
|
@@ -202,6 +202,41 @@ export function registerQueryCommands(
|
|
|
202
202
|
}
|
|
203
203
|
});
|
|
204
204
|
|
|
205
|
+
// === INJECT ===
|
|
206
|
+
program
|
|
207
|
+
.command('recall <query>')
|
|
208
|
+
.description('Recall memory context with strategy classification (quick|entity|temporal|verification|relationship)')
|
|
209
|
+
.option('-n, --limit <n>', 'Max results (default: 6)', '6')
|
|
210
|
+
.option('--strategy <strategy>', 'Override strategy (quick|entity|temporal|verification|relationship)')
|
|
211
|
+
.option('--json', 'Output as JSON')
|
|
212
|
+
.option('--no-sources', 'Hide source paths in recall context')
|
|
213
|
+
.option('-v, --vault <path>', 'Vault path')
|
|
214
|
+
.action(async (query, options) => {
|
|
215
|
+
try {
|
|
216
|
+
const parsedLimit = Number.parseInt(options.limit, 10);
|
|
217
|
+
if (!Number.isFinite(parsedLimit) || parsedLimit <= 0) {
|
|
218
|
+
throw new Error(`Invalid --limit value: ${options.limit}`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const allowedStrategies = new Set(['quick', 'entity', 'temporal', 'verification', 'relationship']);
|
|
222
|
+
if (options.strategy && !allowedStrategies.has(options.strategy)) {
|
|
223
|
+
throw new Error(`Invalid --strategy value: ${options.strategy}`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const { recallCommand } = await import('../dist/commands/recall.js');
|
|
227
|
+
await recallCommand(query, {
|
|
228
|
+
vaultPath: resolveVaultPath(options.vault),
|
|
229
|
+
limit: parsedLimit,
|
|
230
|
+
strategy: options.strategy,
|
|
231
|
+
json: options.json,
|
|
232
|
+
includeSources: options.sources
|
|
233
|
+
});
|
|
234
|
+
} catch (err) {
|
|
235
|
+
console.error(chalk.red(`Error: ${err.message}`));
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
205
240
|
// === INJECT ===
|
|
206
241
|
program
|
|
207
242
|
.command('inject <message>')
|
|
@@ -20,6 +20,21 @@ function buildProgram() {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
describe('register-query-commands', () => {
|
|
23
|
+
it('registers recall command with strategy options', () => {
|
|
24
|
+
const program = buildProgram();
|
|
25
|
+
const recallCommand = program.commands.find((command) => command.name() === 'recall');
|
|
26
|
+
expect(recallCommand).toBeDefined();
|
|
27
|
+
|
|
28
|
+
const flags = recallCommand?.options.map((option) => option.flags) ?? [];
|
|
29
|
+
expect(flags).toEqual(expect.arrayContaining([
|
|
30
|
+
'-n, --limit <n>',
|
|
31
|
+
'--strategy <strategy>',
|
|
32
|
+
'--json',
|
|
33
|
+
'--no-sources',
|
|
34
|
+
'-v, --vault <path>'
|
|
35
|
+
]));
|
|
36
|
+
});
|
|
37
|
+
|
|
23
38
|
it('documents inject command options and config-backed defaults', () => {
|
|
24
39
|
const program = buildProgram();
|
|
25
40
|
const injectCommand = program.commands.find((command) => command.name() === 'inject');
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// src/lib/maintenance/heuristics.ts
|
|
2
|
+
var CATEGORY_PATTERNS = [
|
|
3
|
+
{
|
|
4
|
+
category: "decisions",
|
|
5
|
+
patterns: [
|
|
6
|
+
/\b(decid(?:e|ed|ing|ion)|chose|selected|opted|trade[- ]?off)\b/i,
|
|
7
|
+
/\b(approved|agreed|consensus)\b/i
|
|
8
|
+
]
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
category: "lessons",
|
|
12
|
+
patterns: [
|
|
13
|
+
/\b(learn(?:ed|ing|t)|lesson|insight|realized|retrospective)\b/i,
|
|
14
|
+
/\b(next time|note to self|mistake)\b/i
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
category: "commitments",
|
|
19
|
+
patterns: [
|
|
20
|
+
/\b(todo|task|action item|follow[- ]?up|deadline|due)\b/i,
|
|
21
|
+
/\b(i will|we will|must|need to)\b/i
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
category: "people",
|
|
26
|
+
patterns: [
|
|
27
|
+
/\b(met with|talked to|spoke with|emailed|called|messaged)\b/i,
|
|
28
|
+
/\b(client|customer|partner|colleague|contact)\b/i
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
category: "projects",
|
|
33
|
+
patterns: [
|
|
34
|
+
/\b(project|feature|release|deployment|deploy|service|api|repo)\b/i,
|
|
35
|
+
/\b(shipped|launched|merged|rolled out)\b/i
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
category: "preferences",
|
|
40
|
+
patterns: [
|
|
41
|
+
/\b(prefer(?:s|red|ence)?|like(?:s|d)?|dislike|style|convention)\b/i,
|
|
42
|
+
/\b(always use|never use|default to)\b/i
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
category: "facts",
|
|
47
|
+
patterns: [
|
|
48
|
+
/\b(is|are|was|were|has|have|contains|includes)\b/i
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
];
|
|
52
|
+
function splitSentences(content) {
|
|
53
|
+
return content.split(/\r?\n|(?<=[.?!])\s+/).map((sentence) => sentence.trim()).filter(Boolean);
|
|
54
|
+
}
|
|
55
|
+
function compactWhitespace(value) {
|
|
56
|
+
return value.toLowerCase().replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
57
|
+
}
|
|
58
|
+
var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
59
|
+
"the",
|
|
60
|
+
"a",
|
|
61
|
+
"an",
|
|
62
|
+
"and",
|
|
63
|
+
"or",
|
|
64
|
+
"to",
|
|
65
|
+
"of",
|
|
66
|
+
"for",
|
|
67
|
+
"in",
|
|
68
|
+
"on",
|
|
69
|
+
"is",
|
|
70
|
+
"are",
|
|
71
|
+
"was",
|
|
72
|
+
"were",
|
|
73
|
+
"be",
|
|
74
|
+
"this",
|
|
75
|
+
"that",
|
|
76
|
+
"it",
|
|
77
|
+
"with",
|
|
78
|
+
"as",
|
|
79
|
+
"at",
|
|
80
|
+
"by",
|
|
81
|
+
"from",
|
|
82
|
+
"we",
|
|
83
|
+
"i",
|
|
84
|
+
"you",
|
|
85
|
+
"they",
|
|
86
|
+
"he",
|
|
87
|
+
"she"
|
|
88
|
+
]);
|
|
89
|
+
function classifyInboxItemHeuristic(item) {
|
|
90
|
+
const sample = `${item.title}
|
|
91
|
+
${item.content.slice(0, 2400)}`;
|
|
92
|
+
for (const rule of CATEGORY_PATTERNS) {
|
|
93
|
+
if (rule.patterns.some((pattern) => pattern.test(sample))) {
|
|
94
|
+
return rule.category;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return "inbox";
|
|
98
|
+
}
|
|
99
|
+
function normalizeForDedup(content) {
|
|
100
|
+
return compactWhitespace(content.replace(/\[\[[^\]]+\]\]/g, ""));
|
|
101
|
+
}
|
|
102
|
+
function wordSet(content) {
|
|
103
|
+
const words = compactWhitespace(content).split(" ").filter(Boolean);
|
|
104
|
+
const filtered = words.filter((word) => !STOP_WORDS.has(word) && word.length > 2);
|
|
105
|
+
return new Set(filtered);
|
|
106
|
+
}
|
|
107
|
+
function similarityScore(left, right) {
|
|
108
|
+
const leftWords = wordSet(left);
|
|
109
|
+
const rightWords = wordSet(right);
|
|
110
|
+
if (leftWords.size === 0 || rightWords.size === 0) {
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
let intersection = 0;
|
|
114
|
+
for (const word of leftWords) {
|
|
115
|
+
if (rightWords.has(word)) {
|
|
116
|
+
intersection += 1;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const union = leftWords.size + rightWords.size - intersection;
|
|
120
|
+
return union === 0 ? 0 : intersection / union;
|
|
121
|
+
}
|
|
122
|
+
function extractHeuristicInsights(content) {
|
|
123
|
+
const sentences = splitSentences(content);
|
|
124
|
+
const facts = sentences.filter((line) => /\b(is|are|was|were|has|have|contains|includes)\b/i.test(line)).slice(0, 8);
|
|
125
|
+
const decisions = sentences.filter((line) => /\b(decid(?:e|ed|ing|ion)|chose|selected|opted|agreed)\b/i.test(line)).slice(0, 8);
|
|
126
|
+
const lessons = sentences.filter((line) => /\b(learn(?:ed|ing|t)|lesson|insight|realized|next time|mistake)\b/i.test(line)).slice(0, 8);
|
|
127
|
+
if (facts.length === 0 && sentences.length > 0) {
|
|
128
|
+
facts.push(sentences[0]);
|
|
129
|
+
}
|
|
130
|
+
return { facts, decisions, lessons };
|
|
131
|
+
}
|
|
132
|
+
function buildHeuristicSurveyRecommendations(params) {
|
|
133
|
+
const recommendations = [];
|
|
134
|
+
if (params.inboxCount > 20) {
|
|
135
|
+
recommendations.push(`Inbox backlog is high (${params.inboxCount}); run \`clawvault maintain --worker curator\` more frequently.`);
|
|
136
|
+
}
|
|
137
|
+
if (params.linkedRatio < 0.25) {
|
|
138
|
+
recommendations.push("Graph connectivity is low; add wiki-links between related notes to improve context traversal.");
|
|
139
|
+
}
|
|
140
|
+
if ((params.categoryCounts.lessons ?? 0) < 5) {
|
|
141
|
+
recommendations.push("Lessons are sparse; run distillation on long-form captures to keep reusable learnings explicit.");
|
|
142
|
+
}
|
|
143
|
+
if ((params.categoryCounts.decisions ?? 0) < 5) {
|
|
144
|
+
recommendations.push("Decision coverage is light; capture major choices and rationale in decisions/.");
|
|
145
|
+
}
|
|
146
|
+
if (recommendations.length === 0) {
|
|
147
|
+
recommendations.push("Vault health looks balanced. Keep regular maintenance cadence and continue linking related notes.");
|
|
148
|
+
}
|
|
149
|
+
return recommendations;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export {
|
|
153
|
+
classifyInboxItemHeuristic,
|
|
154
|
+
normalizeForDedup,
|
|
155
|
+
similarityScore,
|
|
156
|
+
extractHeuristicInsights,
|
|
157
|
+
buildHeuristicSurveyRecommendations
|
|
158
|
+
};
|
|
@@ -5,6 +5,13 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
readInboxItems
|
|
7
7
|
} from "./chunk-2PKBIKDH.js";
|
|
8
|
+
import {
|
|
9
|
+
buildHeuristicSurveyRecommendations,
|
|
10
|
+
classifyInboxItemHeuristic,
|
|
11
|
+
extractHeuristicInsights,
|
|
12
|
+
normalizeForDedup,
|
|
13
|
+
similarityScore
|
|
14
|
+
} from "./chunk-35JCYSRR.js";
|
|
8
15
|
import {
|
|
9
16
|
resolveVaultPath
|
|
10
17
|
} from "./chunk-GJO3CFUN.js";
|
|
@@ -173,157 +180,6 @@ function writeMaintenanceState(vaultPath, state) {
|
|
|
173
180
|
import * as path5 from "path";
|
|
174
181
|
import matter from "gray-matter";
|
|
175
182
|
|
|
176
|
-
// src/lib/maintenance/heuristics.ts
|
|
177
|
-
var CATEGORY_PATTERNS = [
|
|
178
|
-
{
|
|
179
|
-
category: "decisions",
|
|
180
|
-
patterns: [
|
|
181
|
-
/\b(decid(?:e|ed|ing|ion)|chose|selected|opted|trade[- ]?off)\b/i,
|
|
182
|
-
/\b(approved|agreed|consensus)\b/i
|
|
183
|
-
]
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
category: "lessons",
|
|
187
|
-
patterns: [
|
|
188
|
-
/\b(learn(?:ed|ing|t)|lesson|insight|realized|retrospective)\b/i,
|
|
189
|
-
/\b(next time|note to self|mistake)\b/i
|
|
190
|
-
]
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
category: "commitments",
|
|
194
|
-
patterns: [
|
|
195
|
-
/\b(todo|task|action item|follow[- ]?up|deadline|due)\b/i,
|
|
196
|
-
/\b(i will|we will|must|need to)\b/i
|
|
197
|
-
]
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
category: "people",
|
|
201
|
-
patterns: [
|
|
202
|
-
/\b(met with|talked to|spoke with|emailed|called|messaged)\b/i,
|
|
203
|
-
/\b(client|customer|partner|colleague|contact)\b/i
|
|
204
|
-
]
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
category: "projects",
|
|
208
|
-
patterns: [
|
|
209
|
-
/\b(project|feature|release|deployment|deploy|service|api|repo)\b/i,
|
|
210
|
-
/\b(shipped|launched|merged|rolled out)\b/i
|
|
211
|
-
]
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
category: "preferences",
|
|
215
|
-
patterns: [
|
|
216
|
-
/\b(prefer(?:s|red|ence)?|like(?:s|d)?|dislike|style|convention)\b/i,
|
|
217
|
-
/\b(always use|never use|default to)\b/i
|
|
218
|
-
]
|
|
219
|
-
},
|
|
220
|
-
{
|
|
221
|
-
category: "facts",
|
|
222
|
-
patterns: [
|
|
223
|
-
/\b(is|are|was|were|has|have|contains|includes)\b/i
|
|
224
|
-
]
|
|
225
|
-
}
|
|
226
|
-
];
|
|
227
|
-
function splitSentences(content) {
|
|
228
|
-
return content.split(/\r?\n|(?<=[.?!])\s+/).map((sentence) => sentence.trim()).filter(Boolean);
|
|
229
|
-
}
|
|
230
|
-
function compactWhitespace(value) {
|
|
231
|
-
return value.toLowerCase().replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
232
|
-
}
|
|
233
|
-
var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
234
|
-
"the",
|
|
235
|
-
"a",
|
|
236
|
-
"an",
|
|
237
|
-
"and",
|
|
238
|
-
"or",
|
|
239
|
-
"to",
|
|
240
|
-
"of",
|
|
241
|
-
"for",
|
|
242
|
-
"in",
|
|
243
|
-
"on",
|
|
244
|
-
"is",
|
|
245
|
-
"are",
|
|
246
|
-
"was",
|
|
247
|
-
"were",
|
|
248
|
-
"be",
|
|
249
|
-
"this",
|
|
250
|
-
"that",
|
|
251
|
-
"it",
|
|
252
|
-
"with",
|
|
253
|
-
"as",
|
|
254
|
-
"at",
|
|
255
|
-
"by",
|
|
256
|
-
"from",
|
|
257
|
-
"we",
|
|
258
|
-
"i",
|
|
259
|
-
"you",
|
|
260
|
-
"they",
|
|
261
|
-
"he",
|
|
262
|
-
"she"
|
|
263
|
-
]);
|
|
264
|
-
function classifyInboxItemHeuristic(item) {
|
|
265
|
-
const sample = `${item.title}
|
|
266
|
-
${item.content.slice(0, 2400)}`;
|
|
267
|
-
for (const rule of CATEGORY_PATTERNS) {
|
|
268
|
-
if (rule.patterns.some((pattern) => pattern.test(sample))) {
|
|
269
|
-
return rule.category;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
return "inbox";
|
|
273
|
-
}
|
|
274
|
-
function normalizeForDedup(content) {
|
|
275
|
-
return compactWhitespace(content.replace(/\[\[[^\]]+\]\]/g, ""));
|
|
276
|
-
}
|
|
277
|
-
function wordSet(content) {
|
|
278
|
-
const words = compactWhitespace(content).split(" ").filter(Boolean);
|
|
279
|
-
const filtered = words.filter((word) => !STOP_WORDS.has(word) && word.length > 2);
|
|
280
|
-
return new Set(filtered);
|
|
281
|
-
}
|
|
282
|
-
function similarityScore(left, right) {
|
|
283
|
-
const leftWords = wordSet(left);
|
|
284
|
-
const rightWords = wordSet(right);
|
|
285
|
-
if (leftWords.size === 0 || rightWords.size === 0) {
|
|
286
|
-
return 0;
|
|
287
|
-
}
|
|
288
|
-
let intersection = 0;
|
|
289
|
-
for (const word of leftWords) {
|
|
290
|
-
if (rightWords.has(word)) {
|
|
291
|
-
intersection += 1;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
const union = leftWords.size + rightWords.size - intersection;
|
|
295
|
-
return union === 0 ? 0 : intersection / union;
|
|
296
|
-
}
|
|
297
|
-
function extractHeuristicInsights(content) {
|
|
298
|
-
const sentences = splitSentences(content);
|
|
299
|
-
const facts = sentences.filter((line) => /\b(is|are|was|were|has|have|contains|includes)\b/i.test(line)).slice(0, 8);
|
|
300
|
-
const decisions = sentences.filter((line) => /\b(decid(?:e|ed|ing|ion)|chose|selected|opted|agreed)\b/i.test(line)).slice(0, 8);
|
|
301
|
-
const lessons = sentences.filter((line) => /\b(learn(?:ed|ing|t)|lesson|insight|realized|next time|mistake)\b/i.test(line)).slice(0, 8);
|
|
302
|
-
if (facts.length === 0 && sentences.length > 0) {
|
|
303
|
-
facts.push(sentences[0]);
|
|
304
|
-
}
|
|
305
|
-
return { facts, decisions, lessons };
|
|
306
|
-
}
|
|
307
|
-
function buildHeuristicSurveyRecommendations(params) {
|
|
308
|
-
const recommendations = [];
|
|
309
|
-
if (params.inboxCount > 20) {
|
|
310
|
-
recommendations.push(`Inbox backlog is high (${params.inboxCount}); run \`clawvault maintain --worker curator\` more frequently.`);
|
|
311
|
-
}
|
|
312
|
-
if (params.linkedRatio < 0.25) {
|
|
313
|
-
recommendations.push("Graph connectivity is low; add wiki-links between related notes to improve context traversal.");
|
|
314
|
-
}
|
|
315
|
-
if ((params.categoryCounts.lessons ?? 0) < 5) {
|
|
316
|
-
recommendations.push("Lessons are sparse; run distillation on long-form captures to keep reusable learnings explicit.");
|
|
317
|
-
}
|
|
318
|
-
if ((params.categoryCounts.decisions ?? 0) < 5) {
|
|
319
|
-
recommendations.push("Decision coverage is light; capture major choices and rationale in decisions/.");
|
|
320
|
-
}
|
|
321
|
-
if (recommendations.length === 0) {
|
|
322
|
-
recommendations.push("Vault health looks balanced. Keep regular maintenance cadence and continue linking related notes.");
|
|
323
|
-
}
|
|
324
|
-
return recommendations;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
183
|
// src/lib/maintenance/worker-utils.ts
|
|
328
184
|
import * as fs4 from "fs";
|
|
329
185
|
import * as path4 from "path";
|
|
@@ -9,22 +9,22 @@ import {
|
|
|
9
9
|
} from "./chunk-OFOCU2V4.js";
|
|
10
10
|
import {
|
|
11
11
|
registerMaintainCommand
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-D5U3Q4N5.js";
|
|
13
13
|
import {
|
|
14
14
|
registerObserveCommand
|
|
15
15
|
} from "./chunk-BLQXXX7Q.js";
|
|
16
16
|
import {
|
|
17
17
|
registerContextCommand
|
|
18
18
|
} from "./chunk-GFCHWMGD.js";
|
|
19
|
-
import {
|
|
20
|
-
ClawVault
|
|
21
|
-
} from "./chunk-ECGJYWNA.js";
|
|
22
19
|
import {
|
|
23
20
|
registerEmbedCommand
|
|
24
21
|
} from "./chunk-T7E764W3.js";
|
|
25
22
|
import {
|
|
26
23
|
registerInboxCommand
|
|
27
24
|
} from "./chunk-HEHO7SMV.js";
|
|
25
|
+
import {
|
|
26
|
+
ClawVault
|
|
27
|
+
} from "./chunk-ECGJYWNA.js";
|
|
28
28
|
import {
|
|
29
29
|
resolveVaultPath
|
|
30
30
|
} from "./chunk-GJO3CFUN.js";
|