@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.
Files changed (210) hide show
  1. package/dist/agency/agency-manager.d.ts +27 -1
  2. package/dist/agency/agency-manager.d.ts.map +1 -1
  3. package/dist/agency/agency-manager.js +180 -9
  4. package/dist/agency/agency-manager.js.map +1 -1
  5. package/dist/agency/default-rules.d.ts +7 -0
  6. package/dist/agency/default-rules.d.ts.map +1 -0
  7. package/dist/agency/default-rules.js +79 -0
  8. package/dist/agency/default-rules.js.map +1 -0
  9. package/dist/agency/types.d.ts +48 -0
  10. package/dist/agency/types.d.ts.map +1 -1
  11. package/dist/brain/brain.d.ts +17 -2
  12. package/dist/brain/brain.d.ts.map +1 -1
  13. package/dist/brain/brain.js +118 -8
  14. package/dist/brain/brain.js.map +1 -1
  15. package/dist/brain/knowledge-synthesizer.d.ts +37 -0
  16. package/dist/brain/knowledge-synthesizer.d.ts.map +1 -0
  17. package/dist/brain/knowledge-synthesizer.js +161 -0
  18. package/dist/brain/knowledge-synthesizer.js.map +1 -0
  19. package/dist/brain/learning-radar.d.ts +96 -0
  20. package/dist/brain/learning-radar.d.ts.map +1 -0
  21. package/dist/brain/learning-radar.js +202 -0
  22. package/dist/brain/learning-radar.js.map +1 -0
  23. package/dist/brain/types.d.ts +15 -0
  24. package/dist/brain/types.d.ts.map +1 -1
  25. package/dist/context/context-engine.d.ts.map +1 -1
  26. package/dist/context/context-engine.js +82 -17
  27. package/dist/context/context-engine.js.map +1 -1
  28. package/dist/context/types.d.ts +5 -0
  29. package/dist/context/types.d.ts.map +1 -1
  30. package/dist/control/intent-router.d.ts +12 -1
  31. package/dist/control/intent-router.d.ts.map +1 -1
  32. package/dist/control/intent-router.js +68 -0
  33. package/dist/control/intent-router.js.map +1 -1
  34. package/dist/control/types.d.ts +17 -0
  35. package/dist/control/types.d.ts.map +1 -1
  36. package/dist/curator/classifier.d.ts +18 -0
  37. package/dist/curator/classifier.d.ts.map +1 -0
  38. package/dist/curator/classifier.js +61 -0
  39. package/dist/curator/classifier.js.map +1 -0
  40. package/dist/curator/quality-gate.d.ts +29 -0
  41. package/dist/curator/quality-gate.d.ts.map +1 -0
  42. package/dist/curator/quality-gate.js +88 -0
  43. package/dist/curator/quality-gate.js.map +1 -0
  44. package/dist/engine/bin/soleri-engine.js +1 -0
  45. package/dist/engine/bin/soleri-engine.js.map +1 -1
  46. package/dist/events/event-bus.d.ts +30 -0
  47. package/dist/events/event-bus.d.ts.map +1 -0
  48. package/dist/events/event-bus.js +51 -0
  49. package/dist/events/event-bus.js.map +1 -0
  50. package/dist/flows/chain-runner.d.ts +46 -0
  51. package/dist/flows/chain-runner.d.ts.map +1 -0
  52. package/dist/flows/chain-runner.js +271 -0
  53. package/dist/flows/chain-runner.js.map +1 -0
  54. package/dist/flows/chain-types.d.ts +103 -0
  55. package/dist/flows/chain-types.d.ts.map +1 -0
  56. package/dist/flows/chain-types.js +23 -0
  57. package/dist/flows/chain-types.js.map +1 -0
  58. package/dist/health/doctor-checks.d.ts +15 -0
  59. package/dist/health/doctor-checks.d.ts.map +1 -0
  60. package/dist/health/doctor-checks.js +98 -0
  61. package/dist/health/doctor-checks.js.map +1 -0
  62. package/dist/intake/text-ingester.d.ts +52 -0
  63. package/dist/intake/text-ingester.d.ts.map +1 -0
  64. package/dist/intake/text-ingester.js +181 -0
  65. package/dist/intake/text-ingester.js.map +1 -0
  66. package/dist/llm/llm-client.d.ts.map +1 -1
  67. package/dist/llm/llm-client.js +37 -1
  68. package/dist/llm/llm-client.js.map +1 -1
  69. package/dist/llm/oauth-discovery.d.ts +26 -0
  70. package/dist/llm/oauth-discovery.d.ts.map +1 -0
  71. package/dist/llm/oauth-discovery.js +149 -0
  72. package/dist/llm/oauth-discovery.js.map +1 -0
  73. package/dist/planning/evidence-collector.d.ts +41 -0
  74. package/dist/planning/evidence-collector.d.ts.map +1 -0
  75. package/dist/planning/evidence-collector.js +194 -0
  76. package/dist/planning/evidence-collector.js.map +1 -0
  77. package/dist/planning/planner.d.ts +4 -0
  78. package/dist/planning/planner.d.ts.map +1 -1
  79. package/dist/planning/planner.js +11 -0
  80. package/dist/planning/planner.js.map +1 -1
  81. package/dist/queue/job-queue.d.ts +92 -0
  82. package/dist/queue/job-queue.d.ts.map +1 -0
  83. package/dist/queue/job-queue.js +180 -0
  84. package/dist/queue/job-queue.js.map +1 -0
  85. package/dist/queue/pipeline-runner.d.ts +62 -0
  86. package/dist/queue/pipeline-runner.d.ts.map +1 -0
  87. package/dist/queue/pipeline-runner.js +126 -0
  88. package/dist/queue/pipeline-runner.js.map +1 -0
  89. package/dist/runtime/admin-setup-ops.d.ts +20 -0
  90. package/dist/runtime/admin-setup-ops.d.ts.map +1 -0
  91. package/dist/runtime/admin-setup-ops.js +583 -0
  92. package/dist/runtime/admin-setup-ops.js.map +1 -0
  93. package/dist/runtime/chain-ops.d.ts +9 -0
  94. package/dist/runtime/chain-ops.d.ts.map +1 -0
  95. package/dist/runtime/chain-ops.js +107 -0
  96. package/dist/runtime/chain-ops.js.map +1 -0
  97. package/dist/runtime/claude-md-helpers.d.ts +65 -0
  98. package/dist/runtime/claude-md-helpers.d.ts.map +1 -0
  99. package/dist/runtime/claude-md-helpers.js +173 -0
  100. package/dist/runtime/claude-md-helpers.js.map +1 -0
  101. package/dist/runtime/curator-extra-ops.d.ts +3 -2
  102. package/dist/runtime/curator-extra-ops.d.ts.map +1 -1
  103. package/dist/runtime/curator-extra-ops.js +81 -3
  104. package/dist/runtime/curator-extra-ops.js.map +1 -1
  105. package/dist/runtime/facades/admin-facade.d.ts.map +1 -1
  106. package/dist/runtime/facades/admin-facade.js +4 -0
  107. package/dist/runtime/facades/admin-facade.js.map +1 -1
  108. package/dist/runtime/facades/agency-facade.d.ts.map +1 -1
  109. package/dist/runtime/facades/agency-facade.js +64 -0
  110. package/dist/runtime/facades/agency-facade.js.map +1 -1
  111. package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
  112. package/dist/runtime/facades/brain-facade.js +122 -1
  113. package/dist/runtime/facades/brain-facade.js.map +1 -1
  114. package/dist/runtime/facades/control-facade.d.ts.map +1 -1
  115. package/dist/runtime/facades/control-facade.js +42 -0
  116. package/dist/runtime/facades/control-facade.js.map +1 -1
  117. package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
  118. package/dist/runtime/facades/memory-facade.js +20 -2
  119. package/dist/runtime/facades/memory-facade.js.map +1 -1
  120. package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
  121. package/dist/runtime/facades/plan-facade.js +2 -0
  122. package/dist/runtime/facades/plan-facade.js.map +1 -1
  123. package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
  124. package/dist/runtime/facades/vault-facade.js +25 -5
  125. package/dist/runtime/facades/vault-facade.js.map +1 -1
  126. package/dist/runtime/intake-ops.d.ts +7 -5
  127. package/dist/runtime/intake-ops.d.ts.map +1 -1
  128. package/dist/runtime/intake-ops.js +98 -5
  129. package/dist/runtime/intake-ops.js.map +1 -1
  130. package/dist/runtime/memory-extra-ops.d.ts +6 -3
  131. package/dist/runtime/memory-extra-ops.d.ts.map +1 -1
  132. package/dist/runtime/memory-extra-ops.js +292 -4
  133. package/dist/runtime/memory-extra-ops.js.map +1 -1
  134. package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
  135. package/dist/runtime/planning-extra-ops.js +85 -0
  136. package/dist/runtime/planning-extra-ops.js.map +1 -1
  137. package/dist/runtime/playbook-ops.js +1 -1
  138. package/dist/runtime/playbook-ops.js.map +1 -1
  139. package/dist/runtime/runtime.d.ts.map +1 -1
  140. package/dist/runtime/runtime.js +143 -2
  141. package/dist/runtime/runtime.js.map +1 -1
  142. package/dist/runtime/session-briefing.d.ts +23 -0
  143. package/dist/runtime/session-briefing.d.ts.map +1 -0
  144. package/dist/runtime/session-briefing.js +140 -0
  145. package/dist/runtime/session-briefing.js.map +1 -0
  146. package/dist/runtime/types.d.ts +23 -0
  147. package/dist/runtime/types.d.ts.map +1 -1
  148. package/dist/runtime/vault-linking-ops.d.ts.map +1 -1
  149. package/dist/runtime/vault-linking-ops.js +1 -3
  150. package/dist/runtime/vault-linking-ops.js.map +1 -1
  151. package/dist/vault/vault.d.ts +25 -0
  152. package/dist/vault/vault.d.ts.map +1 -1
  153. package/dist/vault/vault.js +67 -3
  154. package/dist/vault/vault.js.map +1 -1
  155. package/package.json +1 -1
  156. package/src/__tests__/admin-setup-ops.test.ts +355 -0
  157. package/src/__tests__/async-infrastructure.test.ts +307 -0
  158. package/src/__tests__/cognee-client-gaps.test.ts +6 -2
  159. package/src/__tests__/cognee-hybrid-search.test.ts +49 -35
  160. package/src/__tests__/cognee-sync-manager-deep.test.ts +89 -65
  161. package/src/__tests__/curator-extra-ops.test.ts +6 -2
  162. package/src/__tests__/curator-pipeline-e2e.test.ts +358 -0
  163. package/src/__tests__/memory-extra-ops.test.ts +2 -2
  164. package/src/__tests__/planning-extra-ops.test.ts +2 -2
  165. package/src/__tests__/second-brain-features.test.ts +583 -0
  166. package/src/agency/agency-manager.ts +217 -9
  167. package/src/agency/default-rules.ts +83 -0
  168. package/src/agency/types.ts +61 -0
  169. package/src/brain/brain.ts +110 -8
  170. package/src/brain/knowledge-synthesizer.ts +218 -0
  171. package/src/brain/learning-radar.ts +340 -0
  172. package/src/brain/types.ts +16 -0
  173. package/src/context/context-engine.ts +114 -15
  174. package/src/context/types.ts +5 -0
  175. package/src/control/intent-router.ts +107 -0
  176. package/src/control/types.ts +10 -0
  177. package/src/curator/classifier.ts +88 -0
  178. package/src/curator/quality-gate.ts +129 -0
  179. package/src/engine/bin/soleri-engine.ts +1 -0
  180. package/src/events/event-bus.ts +58 -0
  181. package/src/flows/chain-runner.ts +369 -0
  182. package/src/flows/chain-types.ts +57 -0
  183. package/src/health/doctor-checks.ts +115 -0
  184. package/src/intake/text-ingester.ts +234 -0
  185. package/src/llm/llm-client.ts +38 -1
  186. package/src/llm/oauth-discovery.ts +169 -0
  187. package/src/planning/evidence-collector.ts +247 -0
  188. package/src/planning/planner.ts +11 -0
  189. package/src/queue/job-queue.ts +281 -0
  190. package/src/queue/pipeline-runner.ts +149 -0
  191. package/src/runtime/admin-setup-ops.ts +664 -0
  192. package/src/runtime/chain-ops.ts +121 -0
  193. package/src/runtime/claude-md-helpers.ts +236 -0
  194. package/src/runtime/curator-extra-ops.ts +86 -3
  195. package/src/runtime/facades/admin-facade.ts +4 -0
  196. package/src/runtime/facades/agency-facade.ts +68 -0
  197. package/src/runtime/facades/brain-facade.ts +142 -1
  198. package/src/runtime/facades/control-facade.ts +45 -0
  199. package/src/runtime/facades/memory-facade.ts +20 -2
  200. package/src/runtime/facades/plan-facade.ts +2 -0
  201. package/src/runtime/facades/vault-facade.ts +28 -5
  202. package/src/runtime/intake-ops.ts +107 -5
  203. package/src/runtime/memory-extra-ops.ts +312 -4
  204. package/src/runtime/planning-extra-ops.ts +94 -0
  205. package/src/runtime/playbook-ops.ts +1 -1
  206. package/src/runtime/runtime.ts +138 -2
  207. package/src/runtime/session-briefing.ts +161 -0
  208. package/src/runtime/types.ts +23 -0
  209. package/src/runtime/vault-linking-ops.ts +1 -3
  210. package/src/vault/vault.ts +79 -4
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Session Briefing — proactive context loading on session start.
3
+ *
4
+ * Gathers data from all subsystems (sessions, plans, vault, brain, curator)
5
+ * and produces a concise, structured briefing for the agent.
6
+ *
7
+ * Design: gather all data in parallel, skip sections with nothing to report.
8
+ * Target: < 15 lines of output, < 3 seconds latency.
9
+ */
10
+
11
+ import { z } from 'zod';
12
+ import type { OpDefinition } from '../facades/types.js';
13
+ import type { AgentRuntime } from './types.js';
14
+
15
+ export interface BriefingSection {
16
+ label: string;
17
+ content: string;
18
+ }
19
+
20
+ export interface SessionBriefing {
21
+ sections: BriefingSection[];
22
+ generatedAt: number;
23
+ /** Total entries consulted across all data sources. */
24
+ dataPointsConsulted: number;
25
+ }
26
+
27
+ export function createSessionBriefingOps(runtime: AgentRuntime): OpDefinition[] {
28
+ const { brainIntelligence, planner, vault, curator } = runtime;
29
+
30
+ return [
31
+ {
32
+ name: 'session_briefing',
33
+ description:
34
+ 'Proactive session briefing — gathers last session, active plans, recent vault captures, brain recommendations, and stale knowledge warnings into a concise summary.',
35
+ auth: 'read',
36
+ schema: z.object({
37
+ maxSections: z.number().optional().default(6).describe('Max sections to include'),
38
+ recencyHours: z.number().optional().default(48).describe('Look back window in hours'),
39
+ }),
40
+ handler: async (params) => {
41
+ const maxSections = params.maxSections as number;
42
+ const sections: BriefingSection[] = [];
43
+ let dataPoints = 0;
44
+
45
+ // 1. Last session
46
+ try {
47
+ const sessions = brainIntelligence.listSessions({ limit: 1, active: false });
48
+ dataPoints += sessions.length;
49
+ if (sessions.length > 0) {
50
+ const last = sessions[0];
51
+ const ago = formatTimeAgo(last.endedAt ? new Date(last.endedAt).getTime() : Date.now());
52
+ const domain = last.domain ? ` [${last.domain}]` : '';
53
+ const context = last.context ? `: ${last.context.slice(0, 80)}` : '';
54
+ const tools = last.toolsUsed.length > 0 ? `, used ${last.toolsUsed.length} tools` : '';
55
+ const files =
56
+ last.filesModified.length > 0 ? `, modified ${last.filesModified.length} files` : '';
57
+ sections.push({
58
+ label: 'Last session',
59
+ content: `(${ago})${domain}${context}${tools}${files}`,
60
+ });
61
+ }
62
+ } catch {
63
+ // Session data unavailable — skip
64
+ }
65
+
66
+ // 2. Active plans
67
+ try {
68
+ const plans = planner.list();
69
+ const active = plans.filter(
70
+ (p) =>
71
+ p.status === 'executing' ||
72
+ p.status === 'approved' ||
73
+ p.status === 'reconciling' ||
74
+ p.status === 'validating',
75
+ );
76
+ dataPoints += plans.length;
77
+ if (active.length > 0) {
78
+ const summaries = active.map((p) => {
79
+ const tasksDone = p.tasks.filter((t) => t.status === 'completed').length;
80
+ return `${p.objective?.slice(0, 40) || p.id} (${p.status}, ${tasksDone}/${p.tasks.length} tasks)`;
81
+ });
82
+ sections.push({
83
+ label: active.length === 1 ? 'Active plan' : `Active plans (${active.length})`,
84
+ content: summaries.join('; '),
85
+ });
86
+ }
87
+ } catch {
88
+ // Planner unavailable — skip
89
+ }
90
+
91
+ // 3. Recent vault captures
92
+ try {
93
+ const recent = vault.getRecent(10);
94
+ dataPoints += recent.length;
95
+ if (recent.length > 0) {
96
+ const count = Math.min(recent.length, 5);
97
+ const titles = recent.slice(0, 3).map((e) => e.title.slice(0, 50));
98
+ sections.push({
99
+ label: 'Recent captures',
100
+ content: `${count} entries — ${titles.join(', ')}${count > 3 ? '...' : ''}`,
101
+ });
102
+ }
103
+ } catch {
104
+ // Vault unavailable — skip
105
+ }
106
+
107
+ // 4. Brain recommendations
108
+ try {
109
+ const recs = brainIntelligence.recommend({ limit: 3 });
110
+ dataPoints += recs.length;
111
+ if (recs.length > 0) {
112
+ const items = recs.map((r) => `"${r.pattern}" (strength: ${r.strength.toFixed(2)})`);
113
+ sections.push({
114
+ label: 'Brain recommends',
115
+ content: items.join(', '),
116
+ });
117
+ }
118
+ } catch {
119
+ // Brain unavailable — skip
120
+ }
121
+
122
+ // 5. Stale knowledge / health warnings
123
+ try {
124
+ const health = curator.healthAudit();
125
+ dataPoints += 1;
126
+ const warnings: string[] = [];
127
+ if (health.score < 70) {
128
+ warnings.push(`vault health: ${health.score}/100`);
129
+ }
130
+ if (health.recommendations && health.recommendations.length > 0) {
131
+ warnings.push(health.recommendations[0]);
132
+ }
133
+ if (warnings.length > 0) {
134
+ sections.push({
135
+ label: 'Attention',
136
+ content: warnings.join('. '),
137
+ });
138
+ }
139
+ } catch {
140
+ // Curator unavailable — skip
141
+ }
142
+
143
+ return {
144
+ sections: sections.slice(0, maxSections),
145
+ generatedAt: Date.now(),
146
+ dataPointsConsulted: dataPoints,
147
+ } satisfies SessionBriefing;
148
+ },
149
+ },
150
+ ];
151
+ }
152
+
153
+ function formatTimeAgo(timestamp: number): string {
154
+ const diff = Date.now() - timestamp;
155
+ const minutes = Math.floor(diff / 60000);
156
+ if (minutes < 60) return `${minutes}m ago`;
157
+ const hours = Math.floor(minutes / 60);
158
+ if (hours < 24) return `${hours}h ago`;
159
+ const days = Math.floor(hours / 24);
160
+ return `${days}d ago`;
161
+ }
@@ -28,6 +28,13 @@ import type { VaultBranching } from '../vault/vault-branching.js';
28
28
  import type { ContextEngine } from '../context/context-engine.js';
29
29
  import type { AgencyManager } from '../agency/agency-manager.js';
30
30
  import type { KnowledgeReview } from '../vault/knowledge-review.js';
31
+ import type { LinkManager } from '../vault/linking.js';
32
+ import type { LearningRadar } from '../brain/learning-radar.js';
33
+ import type { TextIngester } from '../intake/text-ingester.js';
34
+ import type { KnowledgeSynthesizer } from '../brain/knowledge-synthesizer.js';
35
+ import type { ChainRunner } from '../flows/chain-runner.js';
36
+ import type { JobQueue } from '../queue/job-queue.js';
37
+ import type { PipelineRunner } from '../queue/pipeline-runner.js';
31
38
 
32
39
  /**
33
40
  * Configuration for creating an agent runtime.
@@ -50,6 +57,8 @@ export interface AgentRuntimeConfig {
50
57
  sharedVaultPath?: string;
51
58
  /** Enable Cognee vector search integration. Default: false (opt-in). */
52
59
  cognee?: boolean;
60
+ /** Path to the agent's root directory (containing agent.yaml, instructions/, etc.). Optional — set by engine binary. */
61
+ agentDir?: string;
53
62
  }
54
63
 
55
64
  /**
@@ -100,6 +109,20 @@ export interface AgentRuntime {
100
109
  agencyManager: AgencyManager;
101
110
  /** Knowledge review — team review workflows (submit/approve/reject). */
102
111
  knowledgeReview: KnowledgeReview;
112
+ /** Link manager — Zettelkasten bidirectional linking with auto-link on ingestion. */
113
+ linkManager: LinkManager;
114
+ /** Learning radar — automatic pattern detection from session signals. */
115
+ learningRadar: LearningRadar;
116
+ /** Text ingester — ingest articles, transcripts, and plain text into vault. */
117
+ textIngester: TextIngester;
118
+ /** Knowledge synthesizer — turn vault knowledge into briefs, outlines, posts. */
119
+ knowledgeSynthesizer: KnowledgeSynthesizer;
120
+ /** Chain runner — composable multi-step workflows with data flow and gates. */
121
+ chainRunner: ChainRunner;
122
+ /** Job queue — SQLite-backed async job processing with DAG dependencies. */
123
+ jobQueue: JobQueue;
124
+ /** Pipeline runner — background polling loop for job execution. */
125
+ pipelineRunner: PipelineRunner;
103
126
  /** Timestamp (ms since epoch) when this runtime was created. */
104
127
  createdAt: number;
105
128
  /** Close the vault database connection. Call on shutdown. */
@@ -11,7 +11,6 @@
11
11
  import { z } from 'zod';
12
12
  import type { OpDefinition } from '../facades/types.js';
13
13
  import type { AgentRuntime } from './types.js';
14
- import { LinkManager } from '../vault/linking.js';
15
14
 
16
15
  const EVAL_SYSTEM_PROMPT = `You evaluate pairs of knowledge entries to determine if they should be linked in a Zettelkasten vault. For EACH pair, decide:
17
16
  - If meaningfully related → return { "link": true, "type": "<type>", "note": "<1 sentence why>" }
@@ -26,8 +25,7 @@ Link types:
26
25
  Rules: Same category alone is NOT enough. Be selective. Return a JSON array.`;
27
26
 
28
27
  export function createVaultLinkingOps(runtime: AgentRuntime): OpDefinition[] {
29
- const { vault } = runtime;
30
- const linkManager = new LinkManager(vault.getProvider());
28
+ const { vault, linkManager } = runtime;
31
29
 
32
30
  return [
33
31
  {
@@ -2,6 +2,7 @@ import type { PersistenceProvider } from '../persistence/types.js';
2
2
  import { SQLitePersistenceProvider } from '../persistence/sqlite-provider.js';
3
3
  import type { IntelligenceEntry } from '../intelligence/types.js';
4
4
  import { computeContentHash } from './content-hash.js';
5
+ import type { LinkManager } from './linking.js';
5
6
 
6
7
  export interface SearchResult {
7
8
  entry: IntelligenceEntry;
@@ -29,6 +30,16 @@ export interface Memory {
29
30
  topics: string[];
30
31
  filesModified: string[];
31
32
  toolsUsed: string[];
33
+ /** What the user was trying to accomplish. */
34
+ intent: string | null;
35
+ /** Key decisions made and their rationale. */
36
+ decisions: string[];
37
+ /** Where things stand at capture time. */
38
+ currentState: string | null;
39
+ /** What should happen next session. */
40
+ nextSteps: string[];
41
+ /** Vault entries that informed this session. */
42
+ vaultEntriesReferenced: string[];
32
43
  createdAt: number;
33
44
  archivedAt: number | null;
34
45
  }
@@ -42,6 +53,10 @@ export class Vault {
42
53
  private provider: PersistenceProvider;
43
54
  private sqliteProvider: SQLitePersistenceProvider | null;
44
55
  private syncManager: import('../cognee/sync-manager.js').CogneeSyncManager | null = null;
56
+ private linkManager: LinkManager | null = null;
57
+ private autoLinkEnabled = true;
58
+ /** Minimum number of FTS5 suggestions to auto-link. Top N are linked. */
59
+ private autoLinkMaxLinks = 3;
45
60
 
46
61
  /**
47
62
  * Create a Vault with a PersistenceProvider or a SQLite path (backward compat).
@@ -67,6 +82,28 @@ export class Vault {
67
82
  this.syncManager = mgr;
68
83
  }
69
84
 
85
+ setLinkManager(mgr: LinkManager, opts?: { enabled?: boolean; maxLinks?: number }): void {
86
+ this.linkManager = mgr;
87
+ if (opts?.enabled !== undefined) this.autoLinkEnabled = opts.enabled;
88
+ if (opts?.maxLinks !== undefined) this.autoLinkMaxLinks = opts.maxLinks;
89
+ }
90
+
91
+ /**
92
+ * Auto-link a newly added entry using FTS5 suggestions.
93
+ * Called after seed() for each entry. Creates links for top N suggestions.
94
+ */
95
+ private autoLink(entryId: string): void {
96
+ if (!this.linkManager || !this.autoLinkEnabled) return;
97
+ try {
98
+ const suggestions = this.linkManager.suggestLinks(entryId, this.autoLinkMaxLinks);
99
+ for (const s of suggestions) {
100
+ this.linkManager.addLink(entryId, s.entryId, s.suggestedType, `auto: ${s.reason}`);
101
+ }
102
+ } catch {
103
+ // Auto-linking is best-effort — never block ingestion
104
+ }
105
+ }
106
+
70
107
  /** Backward-compatible factory. */
71
108
  static createWithSQLite(dbPath: string = ':memory:'): Vault {
72
109
  return new Vault(dbPath);
@@ -140,7 +177,23 @@ export class Vault {
140
177
  CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
141
178
  id, context, summary, topics,
142
179
  content='memories', content_rowid='rowid', tokenize='porter unicode61'
143
- );
180
+ );`);
181
+
182
+ // Add new columns if they don't exist (backward-compatible migration)
183
+ const memCols = this.provider
184
+ .all<{ name: string }>(`PRAGMA table_info(memories)`)
185
+ .map((r) => r.name);
186
+ if (!memCols.includes('intent')) {
187
+ this.provider.execSql(`
188
+ ALTER TABLE memories ADD COLUMN intent TEXT;
189
+ ALTER TABLE memories ADD COLUMN decisions TEXT NOT NULL DEFAULT '[]';
190
+ ALTER TABLE memories ADD COLUMN current_state TEXT;
191
+ ALTER TABLE memories ADD COLUMN next_steps TEXT NOT NULL DEFAULT '[]';
192
+ ALTER TABLE memories ADD COLUMN vault_entries_referenced TEXT NOT NULL DEFAULT '[]';
193
+ `);
194
+ }
195
+
196
+ this.provider.execSql(`
144
197
  CREATE TRIGGER IF NOT EXISTS memories_ai AFTER INSERT ON memories BEGIN
145
198
  INSERT INTO memories_fts(rowid,id,context,summary,topics) VALUES(new.rowid,new.id,new.context,new.summary,new.topics);
146
199
  END;
@@ -339,6 +392,13 @@ export class Vault {
339
392
  this.syncManager.enqueue('ingest', entry.id, entry);
340
393
  }
341
394
  }
395
+ // Auto-link after all entries are inserted (so they can link to each other).
396
+ // Skip for large batches (>100) — use relink_vault for bulk imports.
397
+ if (entries.length <= 100) {
398
+ for (const entry of entries) {
399
+ this.autoLink(entry.id);
400
+ }
401
+ }
342
402
  return count;
343
403
  });
344
404
  }
@@ -676,7 +736,7 @@ export class Vault {
676
736
  }
677
737
  return {
678
738
  total: rows.length,
679
- buckets: bucketDefs.map((b, i) => ({ ...b, count: counts[i] })),
739
+ buckets: bucketDefs.map((b, i) => Object.assign({}, b, { count: counts[i] })),
680
740
  oldestTimestamp: oldest,
681
741
  newestTimestamp: newest,
682
742
  };
@@ -727,7 +787,8 @@ export class Vault {
727
787
  captureMemory(memory: Omit<Memory, 'id' | 'createdAt' | 'archivedAt'>): Memory {
728
788
  const id = `mem-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
729
789
  this.provider.run(
730
- `INSERT INTO memories (id, project_path, type, context, summary, topics, files_modified, tools_used) VALUES (@id, @projectPath, @type, @context, @summary, @topics, @filesModified, @toolsUsed)`,
790
+ `INSERT INTO memories (id, project_path, type, context, summary, topics, files_modified, tools_used, intent, decisions, current_state, next_steps, vault_entries_referenced)
791
+ VALUES (@id, @projectPath, @type, @context, @summary, @topics, @filesModified, @toolsUsed, @intent, @decisions, @currentState, @nextSteps, @vaultEntriesReferenced)`,
731
792
  {
732
793
  id,
733
794
  projectPath: memory.projectPath,
@@ -737,6 +798,11 @@ export class Vault {
737
798
  topics: JSON.stringify(memory.topics),
738
799
  filesModified: JSON.stringify(memory.filesModified),
739
800
  toolsUsed: JSON.stringify(memory.toolsUsed),
801
+ intent: memory.intent ?? null,
802
+ decisions: JSON.stringify(memory.decisions ?? []),
803
+ currentState: memory.currentState ?? null,
804
+ nextSteps: JSON.stringify(memory.nextSteps ?? []),
805
+ vaultEntriesReferenced: JSON.stringify(memory.vaultEntriesReferenced ?? []),
740
806
  },
741
807
  );
742
808
  return this.getMemory(id)!;
@@ -744,7 +810,7 @@ export class Vault {
744
810
 
745
811
  searchMemories(
746
812
  query: string,
747
- options?: { type?: string; projectPath?: string; limit?: number },
813
+ options?: { type?: string; projectPath?: string; intent?: string; limit?: number },
748
814
  ): Memory[] {
749
815
  const limit = options?.limit ?? 10;
750
816
  const filters: string[] = ['m.archived_at IS NULL'];
@@ -757,6 +823,10 @@ export class Vault {
757
823
  filters.push('m.project_path = @projectPath');
758
824
  fp.projectPath = options.projectPath;
759
825
  }
826
+ if (options?.intent) {
827
+ filters.push('m.intent = @intent');
828
+ fp.intent = options.intent;
829
+ }
760
830
  const wc = filters.length > 0 ? `AND ${filters.join(' AND ')}` : '';
761
831
  try {
762
832
  const rows = this.provider.all<Record<string, unknown>>(
@@ -1239,6 +1309,11 @@ function rowToMemory(row: Record<string, unknown>): Memory {
1239
1309
  topics: JSON.parse((row.topics as string) || '[]'),
1240
1310
  filesModified: JSON.parse((row.files_modified as string) || '[]'),
1241
1311
  toolsUsed: JSON.parse((row.tools_used as string) || '[]'),
1312
+ intent: (row.intent as string) ?? null,
1313
+ decisions: JSON.parse((row.decisions as string) || '[]'),
1314
+ currentState: (row.current_state as string) ?? null,
1315
+ nextSteps: JSON.parse((row.next_steps as string) || '[]'),
1316
+ vaultEntriesReferenced: JSON.parse((row.vault_entries_referenced as string) || '[]'),
1242
1317
  createdAt: row.created_at as number,
1243
1318
  archivedAt: (row.archived_at as number) ?? null,
1244
1319
  };