@soleri/core 7.0.0 → 8.0.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/dist/agency/agency-manager.d.ts +27 -1
- package/dist/agency/agency-manager.d.ts.map +1 -1
- package/dist/agency/agency-manager.js +180 -9
- package/dist/agency/agency-manager.js.map +1 -1
- package/dist/agency/default-rules.d.ts +7 -0
- package/dist/agency/default-rules.d.ts.map +1 -0
- package/dist/agency/default-rules.js +79 -0
- package/dist/agency/default-rules.js.map +1 -0
- package/dist/agency/types.d.ts +48 -0
- package/dist/agency/types.d.ts.map +1 -1
- package/dist/brain/brain.d.ts +17 -2
- package/dist/brain/brain.d.ts.map +1 -1
- package/dist/brain/brain.js +118 -8
- package/dist/brain/brain.js.map +1 -1
- package/dist/brain/knowledge-synthesizer.d.ts +37 -0
- package/dist/brain/knowledge-synthesizer.d.ts.map +1 -0
- package/dist/brain/knowledge-synthesizer.js +161 -0
- package/dist/brain/knowledge-synthesizer.js.map +1 -0
- package/dist/brain/learning-radar.d.ts +96 -0
- package/dist/brain/learning-radar.d.ts.map +1 -0
- package/dist/brain/learning-radar.js +202 -0
- package/dist/brain/learning-radar.js.map +1 -0
- package/dist/brain/types.d.ts +15 -0
- package/dist/brain/types.d.ts.map +1 -1
- package/dist/context/context-engine.d.ts.map +1 -1
- package/dist/context/context-engine.js +82 -17
- package/dist/context/context-engine.js.map +1 -1
- package/dist/context/types.d.ts +5 -0
- package/dist/context/types.d.ts.map +1 -1
- package/dist/control/intent-router.d.ts +12 -1
- package/dist/control/intent-router.d.ts.map +1 -1
- package/dist/control/intent-router.js +68 -0
- package/dist/control/intent-router.js.map +1 -1
- package/dist/control/types.d.ts +17 -0
- package/dist/control/types.d.ts.map +1 -1
- package/dist/curator/classifier.d.ts +18 -0
- package/dist/curator/classifier.d.ts.map +1 -0
- package/dist/curator/classifier.js +61 -0
- package/dist/curator/classifier.js.map +1 -0
- package/dist/curator/quality-gate.d.ts +29 -0
- package/dist/curator/quality-gate.d.ts.map +1 -0
- package/dist/curator/quality-gate.js +88 -0
- package/dist/curator/quality-gate.js.map +1 -0
- package/dist/engine/bin/soleri-engine.js +1 -0
- package/dist/engine/bin/soleri-engine.js.map +1 -1
- package/dist/events/event-bus.d.ts +30 -0
- package/dist/events/event-bus.d.ts.map +1 -0
- package/dist/events/event-bus.js +51 -0
- package/dist/events/event-bus.js.map +1 -0
- package/dist/flows/chain-runner.d.ts +46 -0
- package/dist/flows/chain-runner.d.ts.map +1 -0
- package/dist/flows/chain-runner.js +271 -0
- package/dist/flows/chain-runner.js.map +1 -0
- package/dist/flows/chain-types.d.ts +103 -0
- package/dist/flows/chain-types.d.ts.map +1 -0
- package/dist/flows/chain-types.js +23 -0
- package/dist/flows/chain-types.js.map +1 -0
- package/dist/health/doctor-checks.d.ts +15 -0
- package/dist/health/doctor-checks.d.ts.map +1 -0
- package/dist/health/doctor-checks.js +98 -0
- package/dist/health/doctor-checks.js.map +1 -0
- package/dist/intake/text-ingester.d.ts +52 -0
- package/dist/intake/text-ingester.d.ts.map +1 -0
- package/dist/intake/text-ingester.js +181 -0
- package/dist/intake/text-ingester.js.map +1 -0
- package/dist/llm/llm-client.d.ts.map +1 -1
- package/dist/llm/llm-client.js +37 -1
- package/dist/llm/llm-client.js.map +1 -1
- package/dist/llm/oauth-discovery.d.ts +26 -0
- package/dist/llm/oauth-discovery.d.ts.map +1 -0
- package/dist/llm/oauth-discovery.js +149 -0
- package/dist/llm/oauth-discovery.js.map +1 -0
- package/dist/planning/evidence-collector.d.ts +41 -0
- package/dist/planning/evidence-collector.d.ts.map +1 -0
- package/dist/planning/evidence-collector.js +194 -0
- package/dist/planning/evidence-collector.js.map +1 -0
- package/dist/planning/planner.d.ts +4 -0
- package/dist/planning/planner.d.ts.map +1 -1
- package/dist/planning/planner.js +11 -0
- package/dist/planning/planner.js.map +1 -1
- package/dist/queue/job-queue.d.ts +92 -0
- package/dist/queue/job-queue.d.ts.map +1 -0
- package/dist/queue/job-queue.js +180 -0
- package/dist/queue/job-queue.js.map +1 -0
- package/dist/queue/pipeline-runner.d.ts +62 -0
- package/dist/queue/pipeline-runner.d.ts.map +1 -0
- package/dist/queue/pipeline-runner.js +126 -0
- package/dist/queue/pipeline-runner.js.map +1 -0
- package/dist/runtime/admin-setup-ops.d.ts +20 -0
- package/dist/runtime/admin-setup-ops.d.ts.map +1 -0
- package/dist/runtime/admin-setup-ops.js +583 -0
- package/dist/runtime/admin-setup-ops.js.map +1 -0
- package/dist/runtime/chain-ops.d.ts +9 -0
- package/dist/runtime/chain-ops.d.ts.map +1 -0
- package/dist/runtime/chain-ops.js +107 -0
- package/dist/runtime/chain-ops.js.map +1 -0
- package/dist/runtime/claude-md-helpers.d.ts +65 -0
- package/dist/runtime/claude-md-helpers.d.ts.map +1 -0
- package/dist/runtime/claude-md-helpers.js +173 -0
- package/dist/runtime/claude-md-helpers.js.map +1 -0
- package/dist/runtime/curator-extra-ops.d.ts +3 -2
- package/dist/runtime/curator-extra-ops.d.ts.map +1 -1
- package/dist/runtime/curator-extra-ops.js +81 -3
- package/dist/runtime/curator-extra-ops.js.map +1 -1
- package/dist/runtime/facades/admin-facade.d.ts.map +1 -1
- package/dist/runtime/facades/admin-facade.js +4 -0
- package/dist/runtime/facades/admin-facade.js.map +1 -1
- package/dist/runtime/facades/agency-facade.d.ts.map +1 -1
- package/dist/runtime/facades/agency-facade.js +64 -0
- package/dist/runtime/facades/agency-facade.js.map +1 -1
- package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
- package/dist/runtime/facades/brain-facade.js +122 -1
- package/dist/runtime/facades/brain-facade.js.map +1 -1
- package/dist/runtime/facades/control-facade.d.ts.map +1 -1
- package/dist/runtime/facades/control-facade.js +42 -0
- package/dist/runtime/facades/control-facade.js.map +1 -1
- package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
- package/dist/runtime/facades/memory-facade.js +20 -2
- package/dist/runtime/facades/memory-facade.js.map +1 -1
- package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
- package/dist/runtime/facades/plan-facade.js +2 -0
- package/dist/runtime/facades/plan-facade.js.map +1 -1
- package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
- package/dist/runtime/facades/vault-facade.js +25 -5
- package/dist/runtime/facades/vault-facade.js.map +1 -1
- package/dist/runtime/intake-ops.d.ts +7 -5
- package/dist/runtime/intake-ops.d.ts.map +1 -1
- package/dist/runtime/intake-ops.js +98 -5
- package/dist/runtime/intake-ops.js.map +1 -1
- package/dist/runtime/memory-extra-ops.d.ts +6 -3
- package/dist/runtime/memory-extra-ops.d.ts.map +1 -1
- package/dist/runtime/memory-extra-ops.js +292 -4
- package/dist/runtime/memory-extra-ops.js.map +1 -1
- package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
- package/dist/runtime/planning-extra-ops.js +85 -0
- package/dist/runtime/planning-extra-ops.js.map +1 -1
- package/dist/runtime/playbook-ops.js +1 -1
- package/dist/runtime/playbook-ops.js.map +1 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +143 -2
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/session-briefing.d.ts +23 -0
- package/dist/runtime/session-briefing.d.ts.map +1 -0
- package/dist/runtime/session-briefing.js +140 -0
- package/dist/runtime/session-briefing.js.map +1 -0
- package/dist/runtime/types.d.ts +23 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/vault-linking-ops.d.ts.map +1 -1
- package/dist/runtime/vault-linking-ops.js +1 -3
- package/dist/runtime/vault-linking-ops.js.map +1 -1
- package/dist/vault/vault.d.ts +25 -0
- package/dist/vault/vault.d.ts.map +1 -1
- package/dist/vault/vault.js +67 -3
- package/dist/vault/vault.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/admin-setup-ops.test.ts +355 -0
- package/src/__tests__/async-infrastructure.test.ts +307 -0
- package/src/__tests__/cognee-client-gaps.test.ts +6 -2
- package/src/__tests__/cognee-hybrid-search.test.ts +49 -35
- package/src/__tests__/cognee-sync-manager-deep.test.ts +89 -65
- package/src/__tests__/curator-extra-ops.test.ts +6 -2
- package/src/__tests__/curator-pipeline-e2e.test.ts +358 -0
- package/src/__tests__/memory-extra-ops.test.ts +2 -2
- package/src/__tests__/planning-extra-ops.test.ts +2 -2
- package/src/__tests__/second-brain-features.test.ts +583 -0
- package/src/agency/agency-manager.ts +217 -9
- package/src/agency/default-rules.ts +83 -0
- package/src/agency/types.ts +61 -0
- package/src/brain/brain.ts +110 -8
- package/src/brain/knowledge-synthesizer.ts +218 -0
- package/src/brain/learning-radar.ts +340 -0
- package/src/brain/types.ts +16 -0
- package/src/context/context-engine.ts +114 -15
- package/src/context/types.ts +5 -0
- package/src/control/intent-router.ts +107 -0
- package/src/control/types.ts +10 -0
- package/src/curator/classifier.ts +88 -0
- package/src/curator/quality-gate.ts +129 -0
- package/src/engine/bin/soleri-engine.ts +1 -0
- package/src/events/event-bus.ts +58 -0
- package/src/flows/chain-runner.ts +369 -0
- package/src/flows/chain-types.ts +57 -0
- package/src/health/doctor-checks.ts +115 -0
- package/src/intake/text-ingester.ts +234 -0
- package/src/llm/llm-client.ts +38 -1
- package/src/llm/oauth-discovery.ts +169 -0
- package/src/planning/evidence-collector.ts +247 -0
- package/src/planning/planner.ts +11 -0
- package/src/queue/job-queue.ts +281 -0
- package/src/queue/pipeline-runner.ts +149 -0
- package/src/runtime/admin-setup-ops.ts +664 -0
- package/src/runtime/chain-ops.ts +121 -0
- package/src/runtime/claude-md-helpers.ts +236 -0
- package/src/runtime/curator-extra-ops.ts +86 -3
- package/src/runtime/facades/admin-facade.ts +4 -0
- package/src/runtime/facades/agency-facade.ts +68 -0
- package/src/runtime/facades/brain-facade.ts +142 -1
- package/src/runtime/facades/control-facade.ts +45 -0
- package/src/runtime/facades/memory-facade.ts +20 -2
- package/src/runtime/facades/plan-facade.ts +2 -0
- package/src/runtime/facades/vault-facade.ts +28 -5
- package/src/runtime/intake-ops.ts +107 -5
- package/src/runtime/memory-extra-ops.ts +312 -4
- package/src/runtime/planning-extra-ops.ts +94 -0
- package/src/runtime/playbook-ops.ts +1 -1
- package/src/runtime/runtime.ts +138 -2
- package/src/runtime/session-briefing.ts +161 -0
- package/src/runtime/types.ts +23 -0
- package/src/runtime/vault-linking-ops.ts +1 -3
- package/src/vault/vault.ts +79 -4
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Extended memory operations —
|
|
2
|
+
* Extended memory operations — 18 ops for advanced memory management.
|
|
3
3
|
*
|
|
4
4
|
* These complement the 4 base memory ops in core-ops.ts:
|
|
5
5
|
* memory_search, memory_capture, memory_list, session_capture
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* CRUD: memory_delete, memory_stats, memory_export, memory_import,
|
|
8
|
+
* memory_prune, memory_deduplicate, memory_topics, memory_by_project
|
|
9
|
+
* Governance (#213): memory_get, session_search, knowledge_audit, smart_capture,
|
|
10
|
+
* knowledge_health, merge_patterns, knowledge_reorganize,
|
|
11
|
+
* list_project_knowledge, list_projects, knowledge_debug
|
|
9
12
|
*/
|
|
10
13
|
|
|
11
14
|
import { z } from 'zod';
|
|
@@ -13,7 +16,7 @@ import type { OpDefinition } from '../facades/types.js';
|
|
|
13
16
|
import type { AgentRuntime } from './types.js';
|
|
14
17
|
|
|
15
18
|
export function createMemoryExtraOps(runtime: AgentRuntime): OpDefinition[] {
|
|
16
|
-
const { vault } = runtime;
|
|
19
|
+
const { vault, brain, curator, linkManager } = runtime;
|
|
17
20
|
|
|
18
21
|
return [
|
|
19
22
|
{
|
|
@@ -116,6 +119,11 @@ export function createMemoryExtraOps(runtime: AgentRuntime): OpDefinition[] {
|
|
|
116
119
|
topics: (m.topics as string[]) ?? [],
|
|
117
120
|
filesModified: (m.filesModified as string[]) ?? [],
|
|
118
121
|
toolsUsed: (m.toolsUsed as string[]) ?? [],
|
|
122
|
+
intent: (m.intent as string) ?? null,
|
|
123
|
+
decisions: (m.decisions as string[]) ?? [],
|
|
124
|
+
currentState: (m.currentState as string) ?? null,
|
|
125
|
+
nextSteps: (m.nextSteps as string[]) ?? [],
|
|
126
|
+
vaultEntriesReferenced: (m.vaultEntriesReferenced as string[]) ?? [],
|
|
119
127
|
createdAt: m.createdAt as number,
|
|
120
128
|
archivedAt: (m.archivedAt as number | null) ?? null,
|
|
121
129
|
}));
|
|
@@ -182,5 +190,305 @@ export function createMemoryExtraOps(runtime: AgentRuntime): OpDefinition[] {
|
|
|
182
190
|
return { count: groups.length, projects: groups };
|
|
183
191
|
},
|
|
184
192
|
},
|
|
193
|
+
|
|
194
|
+
// ─── Knowledge Governance (#213) ─────────────────────────────────
|
|
195
|
+
|
|
196
|
+
{
|
|
197
|
+
name: 'memory_get',
|
|
198
|
+
description: 'Get a single memory entry by ID.',
|
|
199
|
+
auth: 'read',
|
|
200
|
+
schema: z.object({
|
|
201
|
+
id: z.string().describe('Memory ID'),
|
|
202
|
+
}),
|
|
203
|
+
handler: async (params) => {
|
|
204
|
+
const memory = vault.getMemory(params.id as string);
|
|
205
|
+
if (!memory) return { found: false, id: params.id };
|
|
206
|
+
return memory;
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
name: 'session_search',
|
|
211
|
+
description: 'Search session memories with optional includeArchived flag.',
|
|
212
|
+
auth: 'read',
|
|
213
|
+
schema: z.object({
|
|
214
|
+
query: z.string().describe('Search query'),
|
|
215
|
+
includeArchived: z.boolean().optional().default(false),
|
|
216
|
+
intent: z.string().optional().describe('Filter by session intent'),
|
|
217
|
+
limit: z.number().optional().default(10),
|
|
218
|
+
}),
|
|
219
|
+
handler: async (params) => {
|
|
220
|
+
// Use searchMemories with type=session
|
|
221
|
+
const results = vault.searchMemories(params.query as string, {
|
|
222
|
+
type: 'session',
|
|
223
|
+
intent: params.intent as string | undefined,
|
|
224
|
+
limit: params.limit as number,
|
|
225
|
+
});
|
|
226
|
+
// If includeArchived, also search archived
|
|
227
|
+
if (params.includeArchived) {
|
|
228
|
+
try {
|
|
229
|
+
const archived = vault
|
|
230
|
+
.getProvider()
|
|
231
|
+
.all<Record<string, unknown>>(
|
|
232
|
+
"SELECT * FROM memories WHERE type = 'session' AND archived_at IS NOT NULL AND summary LIKE @q ORDER BY created_at DESC LIMIT @limit",
|
|
233
|
+
{ q: `%${params.query}%`, limit: params.limit as number },
|
|
234
|
+
);
|
|
235
|
+
// Minimal parsing for archived results
|
|
236
|
+
const archivedMemories = archived.map((r) => ({
|
|
237
|
+
id: r.id,
|
|
238
|
+
summary: r.summary,
|
|
239
|
+
intent: r.intent ?? null,
|
|
240
|
+
createdAt: r.created_at,
|
|
241
|
+
archived: true,
|
|
242
|
+
}));
|
|
243
|
+
return { active: results, archived: archivedMemories };
|
|
244
|
+
} catch {
|
|
245
|
+
return { active: results, archived: [] };
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return { results };
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
name: 'knowledge_audit',
|
|
253
|
+
description:
|
|
254
|
+
'Audit vault knowledge quality — coverage, freshness, tag health, recommendations.',
|
|
255
|
+
auth: 'read',
|
|
256
|
+
handler: async () => {
|
|
257
|
+
const healthAudit = curator.healthAudit();
|
|
258
|
+
const vaultStats = vault.stats();
|
|
259
|
+
const brainStats = brain.getStats();
|
|
260
|
+
return {
|
|
261
|
+
vault: {
|
|
262
|
+
totalEntries: vaultStats.totalEntries,
|
|
263
|
+
byType: vaultStats.byType,
|
|
264
|
+
byDomain: vaultStats.byDomain,
|
|
265
|
+
},
|
|
266
|
+
health: healthAudit,
|
|
267
|
+
brain: brainStats,
|
|
268
|
+
};
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
name: 'smart_capture',
|
|
273
|
+
description:
|
|
274
|
+
'Capture knowledge with auto-classification — infers type, tags, and severity from content.',
|
|
275
|
+
auth: 'write',
|
|
276
|
+
schema: z.object({
|
|
277
|
+
title: z.string(),
|
|
278
|
+
description: z.string(),
|
|
279
|
+
domain: z.string().optional().default('general'),
|
|
280
|
+
context: z.string().optional(),
|
|
281
|
+
why: z.string().optional(),
|
|
282
|
+
}),
|
|
283
|
+
handler: async (params) => {
|
|
284
|
+
const id = `smart-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;
|
|
285
|
+
// Auto-infer type from keywords
|
|
286
|
+
const desc = (params.description as string).toLowerCase();
|
|
287
|
+
const inferredType: 'pattern' | 'anti-pattern' =
|
|
288
|
+
desc.includes('never') ||
|
|
289
|
+
desc.includes("don't") ||
|
|
290
|
+
desc.includes('avoid') ||
|
|
291
|
+
desc.includes('anti')
|
|
292
|
+
? 'anti-pattern'
|
|
293
|
+
: 'pattern';
|
|
294
|
+
const inferredSeverity: 'critical' | 'warning' | 'suggestion' =
|
|
295
|
+
desc.includes('must') || desc.includes('critical') || desc.includes('always')
|
|
296
|
+
? 'critical'
|
|
297
|
+
: desc.includes('should') || desc.includes('important')
|
|
298
|
+
? 'warning'
|
|
299
|
+
: 'suggestion';
|
|
300
|
+
|
|
301
|
+
const result = brain.enrichAndCapture({
|
|
302
|
+
id,
|
|
303
|
+
type: inferredType,
|
|
304
|
+
domain: params.domain as string,
|
|
305
|
+
title: params.title as string,
|
|
306
|
+
description: params.description as string,
|
|
307
|
+
severity: inferredSeverity,
|
|
308
|
+
context: params.context as string | undefined,
|
|
309
|
+
why: params.why as string | undefined,
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
...result,
|
|
314
|
+
inferred: { type: inferredType, severity: inferredSeverity },
|
|
315
|
+
};
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
name: 'knowledge_health',
|
|
320
|
+
description: 'Knowledge base health — freshness, staleness, contradictions, coverage gaps.',
|
|
321
|
+
auth: 'read',
|
|
322
|
+
handler: async () => {
|
|
323
|
+
const audit = curator.healthAudit();
|
|
324
|
+
const ageReport = vault.getAgeReport();
|
|
325
|
+
const contradictions = curator.detectContradictions();
|
|
326
|
+
return {
|
|
327
|
+
score: audit.score,
|
|
328
|
+
metrics: audit.metrics,
|
|
329
|
+
ageDistribution: ageReport,
|
|
330
|
+
openContradictions: contradictions.filter((c) => c.status === 'open').length,
|
|
331
|
+
recommendations: audit.recommendations,
|
|
332
|
+
};
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
name: 'merge_patterns',
|
|
337
|
+
description: 'Merge two vault entries into one — combines tags, preserves links from both.',
|
|
338
|
+
auth: 'write',
|
|
339
|
+
schema: z.object({
|
|
340
|
+
keepId: z.string().describe('Entry ID to keep (survives the merge)'),
|
|
341
|
+
removeId: z.string().describe('Entry ID to remove (merged into keepId)'),
|
|
342
|
+
}),
|
|
343
|
+
handler: async (params) => {
|
|
344
|
+
const keepEntry = vault.get(params.keepId as string);
|
|
345
|
+
const removeEntry = vault.get(params.removeId as string);
|
|
346
|
+
if (!keepEntry) return { error: `Entry not found: ${params.keepId}` };
|
|
347
|
+
if (!removeEntry) return { error: `Entry not found: ${params.removeId}` };
|
|
348
|
+
|
|
349
|
+
// Merge tags
|
|
350
|
+
const mergedTags = [...new Set([...keepEntry.tags, ...removeEntry.tags])];
|
|
351
|
+
|
|
352
|
+
// Update the kept entry with merged tags and enriched description
|
|
353
|
+
vault.update(params.keepId as string, {
|
|
354
|
+
tags: mergedTags,
|
|
355
|
+
description: keepEntry.description.includes(removeEntry.title)
|
|
356
|
+
? keepEntry.description
|
|
357
|
+
: `${keepEntry.description}\n\n[Merged from: ${removeEntry.title}] ${removeEntry.description}`,
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// Transfer links from removed entry to kept entry
|
|
361
|
+
if (linkManager) {
|
|
362
|
+
try {
|
|
363
|
+
const links = linkManager.getLinks(params.removeId as string);
|
|
364
|
+
for (const link of links) {
|
|
365
|
+
const otherId = link.sourceId === params.removeId ? link.targetId : link.sourceId;
|
|
366
|
+
if (otherId !== params.keepId) {
|
|
367
|
+
try {
|
|
368
|
+
linkManager.addLink(
|
|
369
|
+
params.keepId as string,
|
|
370
|
+
otherId,
|
|
371
|
+
link.linkType,
|
|
372
|
+
`merged from ${params.removeId}`,
|
|
373
|
+
);
|
|
374
|
+
} catch {
|
|
375
|
+
/* duplicate link — skip */
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
} catch {
|
|
380
|
+
/* link manager ops failed — non-critical */
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Remove the merged entry
|
|
385
|
+
vault.remove(params.removeId as string);
|
|
386
|
+
|
|
387
|
+
return {
|
|
388
|
+
merged: true,
|
|
389
|
+
keptId: params.keepId,
|
|
390
|
+
removedId: params.removeId,
|
|
391
|
+
mergedTags,
|
|
392
|
+
};
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
name: 'knowledge_reorganize',
|
|
397
|
+
description: 'Re-categorize vault entries — change domain, retag, with dry-run preview.',
|
|
398
|
+
auth: 'write',
|
|
399
|
+
schema: z.object({
|
|
400
|
+
fromDomain: z.string().describe('Current domain to reorganize'),
|
|
401
|
+
toDomain: z.string().describe('Target domain'),
|
|
402
|
+
addTags: z.array(z.string()).optional().describe('Tags to add to all affected entries'),
|
|
403
|
+
removeTags: z
|
|
404
|
+
.array(z.string())
|
|
405
|
+
.optional()
|
|
406
|
+
.describe('Tags to remove from all affected entries'),
|
|
407
|
+
dryRun: z.boolean().optional().default(true).describe('Preview without applying'),
|
|
408
|
+
}),
|
|
409
|
+
handler: async (params) => {
|
|
410
|
+
const entries = vault.list({ limit: 10000 }).filter((e) => e.domain === params.fromDomain);
|
|
411
|
+
const addTags = (params.addTags as string[]) ?? [];
|
|
412
|
+
const removeTags = new Set((params.removeTags as string[]) ?? []);
|
|
413
|
+
const toDomain = params.toDomain as string;
|
|
414
|
+
|
|
415
|
+
if (params.dryRun) {
|
|
416
|
+
return {
|
|
417
|
+
dryRun: true,
|
|
418
|
+
affected: entries.length,
|
|
419
|
+
fromDomain: params.fromDomain,
|
|
420
|
+
toDomain,
|
|
421
|
+
entries: entries.slice(0, 20).map((e) => ({ id: e.id, title: e.title })),
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
let updated = 0;
|
|
426
|
+
for (const entry of entries) {
|
|
427
|
+
const newTags = [...entry.tags.filter((t) => !removeTags.has(t)), ...addTags];
|
|
428
|
+
vault.update(entry.id, { domain: toDomain, tags: [...new Set(newTags)] });
|
|
429
|
+
updated++;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return { applied: true, updated, fromDomain: params.fromDomain, toDomain };
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
name: 'list_project_knowledge',
|
|
437
|
+
description: 'List vault entries scoped to a project (by tier tag or domain).',
|
|
438
|
+
auth: 'read',
|
|
439
|
+
schema: z.object({
|
|
440
|
+
project: z.string().describe('Project name or path to filter by'),
|
|
441
|
+
limit: z.number().optional().default(50),
|
|
442
|
+
}),
|
|
443
|
+
handler: async () => {
|
|
444
|
+
// Entries with tier='project' or tagged with project name
|
|
445
|
+
const all = vault.list({ limit: 10000 });
|
|
446
|
+
const projectEntries = all.filter((e) => e.tier === 'project' || e.origin === 'user');
|
|
447
|
+
return {
|
|
448
|
+
count: projectEntries.length,
|
|
449
|
+
entries: projectEntries.slice(0, 50).map((e) => ({
|
|
450
|
+
id: e.id,
|
|
451
|
+
title: e.title,
|
|
452
|
+
type: e.type,
|
|
453
|
+
domain: e.domain,
|
|
454
|
+
tier: e.tier,
|
|
455
|
+
})),
|
|
456
|
+
};
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
name: 'list_projects',
|
|
461
|
+
description:
|
|
462
|
+
'List all distinct domains and tiers in the vault — shows knowledge distribution.',
|
|
463
|
+
auth: 'read',
|
|
464
|
+
handler: async () => {
|
|
465
|
+
const stats = vault.stats();
|
|
466
|
+
return {
|
|
467
|
+
domains: Object.entries(stats.byDomain ?? {}).map(([domain, count]) => ({
|
|
468
|
+
domain,
|
|
469
|
+
count,
|
|
470
|
+
})),
|
|
471
|
+
types: Object.entries(stats.byType ?? {}).map(([type, count]) => ({ type, count })),
|
|
472
|
+
total: stats.totalEntries,
|
|
473
|
+
};
|
|
474
|
+
},
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
name: 'knowledge_debug',
|
|
478
|
+
description:
|
|
479
|
+
'Debug knowledge system internals — vault DB stats, brain state, curator state, memory counts.',
|
|
480
|
+
auth: 'admin',
|
|
481
|
+
handler: async () => {
|
|
482
|
+
return {
|
|
483
|
+
vault: {
|
|
484
|
+
stats: vault.stats(),
|
|
485
|
+
recentCount: vault.getRecent(1).length > 0 ? 'has entries' : 'empty',
|
|
486
|
+
},
|
|
487
|
+
brain: brain.getStats(),
|
|
488
|
+
curator: curator.getStatus(),
|
|
489
|
+
memory: vault.memoryStats(),
|
|
490
|
+
};
|
|
491
|
+
},
|
|
492
|
+
},
|
|
185
493
|
];
|
|
186
494
|
}
|
|
@@ -13,6 +13,7 @@ import { z } from 'zod';
|
|
|
13
13
|
import type { OpDefinition } from '../facades/types.js';
|
|
14
14
|
import type { AgentRuntime } from './types.js';
|
|
15
15
|
import type { DriftItem, TaskEvidence } from '../planning/planner.js';
|
|
16
|
+
import { collectGitEvidence } from '../planning/evidence-collector.js';
|
|
16
17
|
import { matchPlaybooks, type PlaybookMatchResult } from '../playbooks/index.js';
|
|
17
18
|
import { entryToPlaybookDefinition } from '../playbooks/index.js';
|
|
18
19
|
|
|
@@ -714,5 +715,98 @@ export function createPlanningExtraOps(runtime: AgentRuntime): OpDefinition[] {
|
|
|
714
715
|
}
|
|
715
716
|
},
|
|
716
717
|
},
|
|
718
|
+
|
|
719
|
+
// ─── Evidence-Based Reconciliation (#206) ─────────────────────
|
|
720
|
+
{
|
|
721
|
+
name: 'plan_reconcile_with_evidence',
|
|
722
|
+
description:
|
|
723
|
+
'Cross-reference plan tasks against git diff to produce an evidence-based drift report. ' +
|
|
724
|
+
'Shows which tasks have matching file changes, which are missing, and what unplanned work was done.',
|
|
725
|
+
auth: 'read',
|
|
726
|
+
schema: z.object({
|
|
727
|
+
planId: z.string().describe('Plan ID to verify against git'),
|
|
728
|
+
projectPath: z.string().describe('Project root (must be a git repo)'),
|
|
729
|
+
baseBranch: z
|
|
730
|
+
.string()
|
|
731
|
+
.optional()
|
|
732
|
+
.default('main')
|
|
733
|
+
.describe('Branch to diff against (default: main)'),
|
|
734
|
+
}),
|
|
735
|
+
handler: async (params) => {
|
|
736
|
+
try {
|
|
737
|
+
const plan = planner.get(params.planId as string);
|
|
738
|
+
if (!plan) return { error: `Plan not found: ${params.planId}` };
|
|
739
|
+
|
|
740
|
+
return collectGitEvidence(
|
|
741
|
+
plan,
|
|
742
|
+
params.projectPath as string,
|
|
743
|
+
params.baseBranch as string,
|
|
744
|
+
);
|
|
745
|
+
} catch (err) {
|
|
746
|
+
return { error: (err as Error).message };
|
|
747
|
+
}
|
|
748
|
+
},
|
|
749
|
+
},
|
|
750
|
+
|
|
751
|
+
// ─── Purge Plans (#215) ──────────────────────────────────────────
|
|
752
|
+
{
|
|
753
|
+
name: 'plan_purge',
|
|
754
|
+
description:
|
|
755
|
+
'Permanently delete plans by mode: "archived" (only archived), "completed" (completed + archived), ' +
|
|
756
|
+
'"stale" (draft/approved older than 24h), or "specific" (by IDs). Use dryRun to preview.',
|
|
757
|
+
auth: 'admin',
|
|
758
|
+
schema: z.object({
|
|
759
|
+
mode: z.enum(['archived', 'completed', 'stale', 'specific']).describe('Purge mode'),
|
|
760
|
+
planIds: z.array(z.string()).optional().describe('Plan IDs for specific mode'),
|
|
761
|
+
dryRun: z.boolean().optional().default(false).describe('Preview without deleting'),
|
|
762
|
+
}),
|
|
763
|
+
handler: async (params) => {
|
|
764
|
+
const mode = params.mode as string;
|
|
765
|
+
const dryRun = params.dryRun as boolean;
|
|
766
|
+
const plans = planner.list();
|
|
767
|
+
const now = Date.now();
|
|
768
|
+
const staleThresholdMs = 24 * 60 * 60 * 1000;
|
|
769
|
+
|
|
770
|
+
let toPurge: typeof plans;
|
|
771
|
+
if (mode === 'archived') {
|
|
772
|
+
toPurge = plans.filter((p) => p.status === 'archived');
|
|
773
|
+
} else if (mode === 'completed') {
|
|
774
|
+
toPurge = plans.filter((p) => p.status === 'completed' || p.status === 'archived');
|
|
775
|
+
} else if (mode === 'stale') {
|
|
776
|
+
toPurge = plans.filter(
|
|
777
|
+
(p) =>
|
|
778
|
+
(p.status === 'draft' || p.status === 'approved' || p.status === 'brainstorming') &&
|
|
779
|
+
p.createdAt &&
|
|
780
|
+
now - p.createdAt > staleThresholdMs,
|
|
781
|
+
);
|
|
782
|
+
} else if (mode === 'specific') {
|
|
783
|
+
const ids = new Set((params.planIds as string[]) ?? []);
|
|
784
|
+
toPurge = plans.filter((p) => ids.has(p.id));
|
|
785
|
+
} else {
|
|
786
|
+
return { error: `Unknown purge mode: ${mode}` };
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
if (dryRun) {
|
|
790
|
+
return {
|
|
791
|
+
dryRun: true,
|
|
792
|
+
mode,
|
|
793
|
+
wouldPurge: toPurge.length,
|
|
794
|
+
plans: toPurge.map((p) => ({ id: p.id, status: p.status, objective: p.objective })),
|
|
795
|
+
};
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
let purged = 0;
|
|
799
|
+
for (const p of toPurge) {
|
|
800
|
+
try {
|
|
801
|
+
planner.remove(p.id);
|
|
802
|
+
purged++;
|
|
803
|
+
} catch {
|
|
804
|
+
// Skip plans that can't be removed
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
return { purged, mode };
|
|
809
|
+
},
|
|
810
|
+
},
|
|
717
811
|
];
|
|
718
812
|
}
|
|
@@ -88,7 +88,7 @@ export function createPlaybookOps(runtime: AgentRuntime): OpDefinition[] {
|
|
|
88
88
|
validation?: string;
|
|
89
89
|
}>;
|
|
90
90
|
|
|
91
|
-
const steps = rawSteps.map((s, i) => ({
|
|
91
|
+
const steps = rawSteps.map((s, i) => Object.assign({}, s, { order: i + 1 }));
|
|
92
92
|
const id =
|
|
93
93
|
(params.id as string | undefined) ??
|
|
94
94
|
`playbook-${domain}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
package/src/runtime/runtime.ts
CHANGED
|
@@ -19,10 +19,12 @@ import { LoopManager } from '../loop/loop-manager.js';
|
|
|
19
19
|
import { IdentityManager } from '../control/identity-manager.js';
|
|
20
20
|
import { IntentRouter } from '../control/intent-router.js';
|
|
21
21
|
import { KeyPool, loadKeyPoolConfig } from '../llm/key-pool.js';
|
|
22
|
+
import { discoverAnthropicToken } from '../llm/oauth-discovery.js';
|
|
22
23
|
import { loadIntelligenceData } from '../intelligence/loader.js';
|
|
23
24
|
import { LLMClient } from '../llm/llm-client.js';
|
|
24
25
|
import { CogneeSyncManager } from '../cognee/sync-manager.js';
|
|
25
26
|
import { IntakePipeline } from '../intake/intake-pipeline.js';
|
|
27
|
+
import { TextIngester } from '../intake/text-ingester.js';
|
|
26
28
|
import { Telemetry } from '../telemetry/telemetry.js';
|
|
27
29
|
import { ProjectRegistry } from '../project/project-registry.js';
|
|
28
30
|
import { TemplateManager } from '../prompts/template-manager.js';
|
|
@@ -39,6 +41,14 @@ import { VaultBranching } from '../vault/vault-branching.js';
|
|
|
39
41
|
import { ContextEngine } from '../context/context-engine.js';
|
|
40
42
|
import { AgencyManager } from '../agency/agency-manager.js';
|
|
41
43
|
import { KnowledgeReview } from '../vault/knowledge-review.js';
|
|
44
|
+
import { LinkManager } from '../vault/linking.js';
|
|
45
|
+
import { LearningRadar } from '../brain/learning-radar.js';
|
|
46
|
+
import { KnowledgeSynthesizer } from '../brain/knowledge-synthesizer.js';
|
|
47
|
+
import { ChainRunner } from '../flows/chain-runner.js';
|
|
48
|
+
import { JobQueue } from '../queue/job-queue.js';
|
|
49
|
+
import { PipelineRunner } from '../queue/pipeline-runner.js';
|
|
50
|
+
import { evaluateQuality } from '../curator/quality-gate.js';
|
|
51
|
+
import { classifyEntry } from '../curator/classifier.js';
|
|
42
52
|
import type { AgentRuntimeConfig, AgentRuntime } from './types.js';
|
|
43
53
|
|
|
44
54
|
/**
|
|
@@ -96,7 +106,8 @@ export function createAgentRuntime(config: AgentRuntimeConfig): AgentRuntime {
|
|
|
96
106
|
}
|
|
97
107
|
|
|
98
108
|
// Brain — intelligence layer (TF-IDF scoring, auto-tagging, dedup)
|
|
99
|
-
|
|
109
|
+
// Pass vaultManager so intelligentSearch queries all connected sources (not just agent tier)
|
|
110
|
+
const brain = new Brain(vault, cognee ?? undefined, vaultManager);
|
|
100
111
|
|
|
101
112
|
// Brain Intelligence — pattern strengths, session knowledge, intelligence pipeline
|
|
102
113
|
const brainIntelligence = new BrainIntelligence(vault, brain);
|
|
@@ -130,9 +141,15 @@ export function createAgentRuntime(config: AgentRuntimeConfig): AgentRuntime {
|
|
|
130
141
|
}
|
|
131
142
|
|
|
132
143
|
// LLM key pools and client
|
|
144
|
+
// Try OAuth token discovery for Anthropic (Claude Code subscription → free API access)
|
|
133
145
|
const keyPoolFiles = loadKeyPoolConfig(agentId);
|
|
146
|
+
const oauthToken = discoverAnthropicToken();
|
|
147
|
+
const anthropicConfig = keyPoolFiles.anthropic;
|
|
148
|
+
if (oauthToken && anthropicConfig.keys.length === 0) {
|
|
149
|
+
anthropicConfig.keys.push(oauthToken);
|
|
150
|
+
}
|
|
134
151
|
const openaiKeyPool = new KeyPool(keyPoolFiles.openai);
|
|
135
|
-
const anthropicKeyPool = new KeyPool(
|
|
152
|
+
const anthropicKeyPool = new KeyPool(anthropicConfig);
|
|
136
153
|
const llmClient = new LLMClient(openaiKeyPool, anthropicKeyPool, agentId);
|
|
137
154
|
|
|
138
155
|
// Cognee Sync Manager — queue-based dirty tracking with offline resilience (only when Cognee enabled)
|
|
@@ -146,8 +163,13 @@ export function createAgentRuntime(config: AgentRuntimeConfig): AgentRuntime {
|
|
|
146
163
|
vault.setSyncManager(syncManager);
|
|
147
164
|
}
|
|
148
165
|
|
|
166
|
+
// Link Manager — Zettelkasten auto-linking on vault ingestion
|
|
167
|
+
const linkManager = new LinkManager(vault.getProvider());
|
|
168
|
+
vault.setLinkManager(linkManager, { enabled: true, maxLinks: 3 });
|
|
169
|
+
|
|
149
170
|
// Intake Pipeline — PDF/book ingestion with LLM classification
|
|
150
171
|
const intakePipeline = new IntakePipeline(vault.getProvider(), vault, llmClient);
|
|
172
|
+
const textIngester = new TextIngester(vault, llmClient);
|
|
151
173
|
|
|
152
174
|
// Playbook Executor — in-memory step-by-step workflow sessions
|
|
153
175
|
const playbookExecutor = new PlaybookExecutor();
|
|
@@ -217,6 +239,7 @@ export function createAgentRuntime(config: AgentRuntimeConfig): AgentRuntime {
|
|
|
217
239
|
templateManager,
|
|
218
240
|
syncManager,
|
|
219
241
|
intakePipeline,
|
|
242
|
+
textIngester,
|
|
220
243
|
authPolicy: { mode: 'permissive', callerLevel: 'admin' },
|
|
221
244
|
flags: new FeatureFlags(join(agentHome, 'flags.json')),
|
|
222
245
|
health,
|
|
@@ -228,6 +251,119 @@ export function createAgentRuntime(config: AgentRuntimeConfig): AgentRuntime {
|
|
|
228
251
|
contextEngine,
|
|
229
252
|
agencyManager,
|
|
230
253
|
knowledgeReview,
|
|
254
|
+
linkManager,
|
|
255
|
+
learningRadar: new LearningRadar(vault, brain),
|
|
256
|
+
knowledgeSynthesizer: new KnowledgeSynthesizer(brain, llmClient),
|
|
257
|
+
chainRunner: new ChainRunner(vault.getProvider()),
|
|
258
|
+
jobQueue: new JobQueue(vault.getProvider()),
|
|
259
|
+
pipelineRunner: (() => {
|
|
260
|
+
const jq = new JobQueue(vault.getProvider());
|
|
261
|
+
const pr = new PipelineRunner(jq);
|
|
262
|
+
// Register default job handlers for curator pipeline
|
|
263
|
+
pr.registerHandler('tag-normalize', async (job) => {
|
|
264
|
+
const entry = vault.get(job.entryId ?? '');
|
|
265
|
+
if (!entry) return { skipped: true, reason: 'entry not found' };
|
|
266
|
+
const result = curator.normalizeTag(entry.tags[0] ?? '');
|
|
267
|
+
return result;
|
|
268
|
+
});
|
|
269
|
+
pr.registerHandler('dedup-check', async (job) => {
|
|
270
|
+
const entry = vault.get(job.entryId ?? '');
|
|
271
|
+
if (!entry) return { skipped: true, reason: 'entry not found' };
|
|
272
|
+
return curator.detectDuplicates(entry.id);
|
|
273
|
+
});
|
|
274
|
+
pr.registerHandler('auto-link', async (job) => {
|
|
275
|
+
if (linkManager) {
|
|
276
|
+
const suggestions = linkManager.suggestLinks(job.entryId ?? '', 3);
|
|
277
|
+
for (const s of suggestions) {
|
|
278
|
+
linkManager.addLink(
|
|
279
|
+
job.entryId ?? '',
|
|
280
|
+
s.entryId,
|
|
281
|
+
s.suggestedType,
|
|
282
|
+
`pipeline: ${s.reason}`,
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
return { linked: suggestions.length };
|
|
286
|
+
}
|
|
287
|
+
return { skipped: true, reason: 'link manager not available' };
|
|
288
|
+
});
|
|
289
|
+
pr.registerHandler('quality-gate', async (job) => {
|
|
290
|
+
const entry = vault.get(job.entryId ?? '');
|
|
291
|
+
if (!entry) return { skipped: true, reason: 'entry not found' };
|
|
292
|
+
return evaluateQuality(entry, llmClient);
|
|
293
|
+
});
|
|
294
|
+
pr.registerHandler('classify', async (job) => {
|
|
295
|
+
const entry = vault.get(job.entryId ?? '');
|
|
296
|
+
if (!entry) return { skipped: true, reason: 'entry not found' };
|
|
297
|
+
return classifyEntry(entry, llmClient);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// ─── 9 additional handlers for full Salvador parity (#216) ────
|
|
301
|
+
pr.registerHandler('enrich-frontmatter', async (job) => {
|
|
302
|
+
const entry = vault.get(job.entryId ?? '');
|
|
303
|
+
if (!entry) return { skipped: true, reason: 'entry not found' };
|
|
304
|
+
return curator.enrichMetadata(entry.id);
|
|
305
|
+
});
|
|
306
|
+
pr.registerHandler('detect-staleness', async (job) => {
|
|
307
|
+
const entry = vault.get(job.entryId ?? '');
|
|
308
|
+
if (!entry) return { skipped: true, reason: 'entry not found' };
|
|
309
|
+
// Check if entry is older than 90 days (using validFrom or fallback to 0)
|
|
310
|
+
const entryTimestamp = (entry.validFrom ?? 0) * 1000 || Date.now();
|
|
311
|
+
const ageMs = Date.now() - entryTimestamp;
|
|
312
|
+
const staleDays = 90;
|
|
313
|
+
const isStale = ageMs > staleDays * 86400000;
|
|
314
|
+
return { stale: isStale, ageDays: Math.floor(ageMs / 86400000), entryId: entry.id };
|
|
315
|
+
});
|
|
316
|
+
pr.registerHandler('detect-duplicate', async (job) => {
|
|
317
|
+
const entry = vault.get(job.entryId ?? '');
|
|
318
|
+
if (!entry) return { skipped: true, reason: 'entry not found' };
|
|
319
|
+
return curator.detectDuplicates(entry.id);
|
|
320
|
+
});
|
|
321
|
+
pr.registerHandler('detect-contradiction', async (job) => {
|
|
322
|
+
const entry = vault.get(job.entryId ?? '');
|
|
323
|
+
if (!entry) return { skipped: true, reason: 'entry not found' };
|
|
324
|
+
const contradictions = curator.detectContradictions(0.4);
|
|
325
|
+
const relevant = contradictions.filter(
|
|
326
|
+
(c) => c.patternId === job.entryId || c.antipatternId === job.entryId,
|
|
327
|
+
);
|
|
328
|
+
return { found: relevant.length, contradictions: relevant };
|
|
329
|
+
});
|
|
330
|
+
pr.registerHandler('consolidate-duplicates', async (_job) => {
|
|
331
|
+
return curator.consolidate({ dryRun: false, staleDaysThreshold: 90 });
|
|
332
|
+
});
|
|
333
|
+
pr.registerHandler('archive-stale', async (_job) => {
|
|
334
|
+
// Run consolidation with stale detection
|
|
335
|
+
const result = curator.consolidate({ dryRun: false, staleDaysThreshold: 90 });
|
|
336
|
+
return { archived: result.staleEntries.length, result };
|
|
337
|
+
});
|
|
338
|
+
pr.registerHandler('cognee-ingest', async (job) => {
|
|
339
|
+
if (!cognee) return { skipped: true, reason: 'cognee not available' };
|
|
340
|
+
const entry = vault.get(job.entryId ?? '');
|
|
341
|
+
if (!entry) return { skipped: true, reason: 'entry not found' };
|
|
342
|
+
try {
|
|
343
|
+
const result = await cognee.addEntries([entry]);
|
|
344
|
+
return { ingested: result.added };
|
|
345
|
+
} catch {
|
|
346
|
+
return { skipped: true, reason: 'cognee ingestion failed' };
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
pr.registerHandler('cognee-cognify', async (_job) => {
|
|
350
|
+
if (!cognee) return { skipped: true, reason: 'cognee not available' };
|
|
351
|
+
try {
|
|
352
|
+
const result = await cognee.cognify();
|
|
353
|
+
return result;
|
|
354
|
+
} catch {
|
|
355
|
+
return { skipped: true, reason: 'cognee cognify failed' };
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
pr.registerHandler('verify-searchable', async (job) => {
|
|
359
|
+
const entry = vault.get(job.entryId ?? '');
|
|
360
|
+
if (!entry) return { skipped: true, reason: 'entry not found' };
|
|
361
|
+
const searchResults = vault.search(entry.title, { limit: 1 });
|
|
362
|
+
const found = searchResults.some((r) => r.entry.id === entry.id);
|
|
363
|
+
return { searchable: found, entryId: entry.id };
|
|
364
|
+
});
|
|
365
|
+
return pr;
|
|
366
|
+
})(),
|
|
231
367
|
createdAt: Date.now(),
|
|
232
368
|
close: () => {
|
|
233
369
|
syncManager?.close();
|