@syntesseraai/opencode-feature-factory 0.4.3 → 0.4.4

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 (47) hide show
  1. package/package.json +2 -2
  2. package/dist/discovery.test.d.ts +0 -10
  3. package/dist/discovery.test.js +0 -97
  4. package/dist/local-recall/daemon-controller.d.ts +0 -51
  5. package/dist/local-recall/daemon-controller.js +0 -166
  6. package/dist/local-recall/daemon.d.ts +0 -35
  7. package/dist/local-recall/daemon.js +0 -262
  8. package/dist/local-recall/index-state.d.ts +0 -14
  9. package/dist/local-recall/index-state.js +0 -76
  10. package/dist/local-recall/index.d.ts +0 -20
  11. package/dist/local-recall/index.js +0 -27
  12. package/dist/local-recall/mcp-server.d.ts +0 -34
  13. package/dist/local-recall/mcp-server.js +0 -194
  14. package/dist/local-recall/mcp-stdio-server.d.ts +0 -4
  15. package/dist/local-recall/mcp-stdio-server.js +0 -225
  16. package/dist/local-recall/mcp-tools.d.ts +0 -103
  17. package/dist/local-recall/mcp-tools.js +0 -187
  18. package/dist/local-recall/memory-service.d.ts +0 -32
  19. package/dist/local-recall/memory-service.js +0 -156
  20. package/dist/local-recall/model-router.d.ts +0 -23
  21. package/dist/local-recall/model-router.js +0 -41
  22. package/dist/local-recall/processed-log.d.ts +0 -41
  23. package/dist/local-recall/processed-log.js +0 -85
  24. package/dist/local-recall/prompt-injection.d.ts +0 -2
  25. package/dist/local-recall/prompt-injection.js +0 -194
  26. package/dist/local-recall/session-extractor.d.ts +0 -19
  27. package/dist/local-recall/session-extractor.js +0 -172
  28. package/dist/local-recall/storage-reader.d.ts +0 -40
  29. package/dist/local-recall/storage-reader.js +0 -157
  30. package/dist/local-recall/thinking-extractor.d.ts +0 -16
  31. package/dist/local-recall/thinking-extractor.js +0 -132
  32. package/dist/local-recall/types.d.ts +0 -152
  33. package/dist/local-recall/types.js +0 -7
  34. package/dist/local-recall/vector/embedding-provider.d.ts +0 -37
  35. package/dist/local-recall/vector/embedding-provider.js +0 -184
  36. package/dist/local-recall/vector/orama-index.d.ts +0 -39
  37. package/dist/local-recall/vector/orama-index.js +0 -408
  38. package/dist/local-recall/vector/types.d.ts +0 -33
  39. package/dist/local-recall/vector/types.js +0 -1
  40. package/dist/output.test.d.ts +0 -8
  41. package/dist/output.test.js +0 -205
  42. package/dist/plugins/ff-reviews-delete-plugin.d.ts +0 -2
  43. package/dist/plugins/ff-reviews-delete-plugin.js +0 -32
  44. package/dist/quality-gate-config.test.d.ts +0 -9
  45. package/dist/quality-gate-config.test.js +0 -164
  46. package/dist/stop-quality-gate.test.d.ts +0 -8
  47. package/dist/stop-quality-gate.test.js +0 -549
@@ -1,76 +0,0 @@
1
- import { createHash } from 'node:crypto';
2
- import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
3
- import path from 'node:path';
4
- const EMPTY_STATE = {
5
- version: 1,
6
- entries: {},
7
- updatedAt: 0,
8
- };
9
- function getIndexDir(directory) {
10
- return path.join(directory, 'ff-memories', 'index');
11
- }
12
- export function getIndexStatePath(directory) {
13
- return path.join(getIndexDir(directory), 'state.json');
14
- }
15
- function normalizeState(raw) {
16
- if (!raw || typeof raw !== 'object') {
17
- return { ...EMPTY_STATE };
18
- }
19
- const value = raw;
20
- const entries = {};
21
- if (value.entries && typeof value.entries === 'object') {
22
- for (const [id, entry] of Object.entries(value.entries)) {
23
- if (!entry || typeof entry !== 'object') {
24
- continue;
25
- }
26
- const candidate = entry;
27
- if (typeof candidate.hash !== 'string') {
28
- continue;
29
- }
30
- entries[id] = {
31
- hash: candidate.hash,
32
- updatedAt: typeof candidate.updatedAt === 'number' ? candidate.updatedAt : 0,
33
- };
34
- }
35
- }
36
- return {
37
- version: value.version === 1 ? 1 : 1,
38
- entries,
39
- updatedAt: typeof value.updatedAt === 'number' ? value.updatedAt : 0,
40
- };
41
- }
42
- async function writeAtomic(filePath, value) {
43
- const tmpPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
44
- await writeFile(tmpPath, JSON.stringify(value, null, 2), 'utf-8');
45
- await rename(tmpPath, filePath);
46
- }
47
- export async function readIndexState(directory) {
48
- const filePath = getIndexStatePath(directory);
49
- try {
50
- const raw = await readFile(filePath, 'utf-8');
51
- return normalizeState(JSON.parse(raw));
52
- }
53
- catch {
54
- return { ...EMPTY_STATE };
55
- }
56
- }
57
- export async function writeIndexState(directory, state) {
58
- const filePath = getIndexStatePath(directory);
59
- await mkdir(path.dirname(filePath), { recursive: true });
60
- await writeAtomic(filePath, state);
61
- }
62
- export function computeMemoryHash(memory) {
63
- const stable = JSON.stringify({
64
- id: memory.id,
65
- sessionID: memory.sessionID,
66
- messageID: memory.messageID,
67
- category: memory.category,
68
- title: memory.title,
69
- body: memory.body,
70
- tags: [...memory.tags].sort(),
71
- importance: memory.importance,
72
- createdAt: memory.createdAt,
73
- extractedBy: memory.extractedBy,
74
- });
75
- return createHash('sha256').update(stable).digest('hex');
76
- }
@@ -1,20 +0,0 @@
1
- /**
2
- * local-recall/index.ts — Barrel export for the local-recall module.
3
- *
4
- * Re-exports all public APIs from the local-recall memory system.
5
- */
6
- export type { Memory, MemoryCategory, SearchCriteria, MemorySearchResult, ExtractionInput, ExtractionResult, ProcessedEntry, OCProject, OCSession, OCMessage, OCPart, } from './types.js';
7
- export { findProject, listProjects, listSessions, getSession, listMessages, getMessage, listParts, getPart, } from './storage-reader.js';
8
- export { storeMemory, storeMemories, getMemory, listAllMemories, searchMemories, } from './memory-service.js';
9
- export { extractFromMessage, extractFromParts } from './session-extractor.js';
10
- export { extractThinkingFromMessage, extractFromThinkingParts } from './thinking-extractor.js';
11
- export { isProcessed, isContentProcessed, markProcessed, readProcessedLog, contentHash, getProcessedMessageIDs, getProcessedHashes, } from './processed-log.js';
12
- export { runExtraction, type ExtractionStats } from './daemon.js';
13
- export { LocalRecallDaemonController, type DaemonStatus, type DaemonRunReport, } from './daemon-controller.js';
14
- export { readIndexState, writeIndexState, computeMemoryHash, getIndexStatePath, type IndexState, type IndexStateEntry, } from './index-state.js';
15
- export { createEmbeddingProvider, OllamaEmbeddingProvider, OpenAIEmbeddingProvider, } from './vector/embedding-provider.js';
16
- export { OramaMemoryIndex } from './vector/orama-index.js';
17
- export type { EmbeddingProvider, EmbeddingProviderName, VectorIndexManifest, VectorIndexDocument, VectorSearchResponse, } from './vector/types.js';
18
- export { initLocalRecall, isInitialized, getDirectory, triggerExtraction, getLastExtractionStats, shutdownLocalRecall, storeLearningMemory, searchLearningMemories, getLearningMemory, startIndexingDaemon, stopIndexingDaemon, getIndexingStatus, rebuildIndex, listLearningMemories, type LearningStoreInput, type IndexingStatus, } from './mcp-server.js';
19
- export { runLocalRecallMCPServer, type LocalRecallMCPServerOptions } from './mcp-stdio-server.js';
20
- export { createLearningStoreTool, createLearningSearchTool, createLearningGetTool, createLearningIndexStartTool, createLearningIndexStatusTool, createLearningIndexStopTool, createLearningIndexRebuildTool, } from './mcp-tools.js';
@@ -1,27 +0,0 @@
1
- /**
2
- * local-recall/index.ts — Barrel export for the local-recall module.
3
- *
4
- * Re-exports all public APIs from the local-recall memory system.
5
- */
6
- // Storage reader
7
- export { findProject, listProjects, listSessions, getSession, listMessages, getMessage, listParts, getPart, } from './storage-reader.js';
8
- // Memory service
9
- export { storeMemory, storeMemories, getMemory, listAllMemories, searchMemories, } from './memory-service.js';
10
- // Extractors
11
- export { extractFromMessage, extractFromParts } from './session-extractor.js';
12
- export { extractThinkingFromMessage, extractFromThinkingParts } from './thinking-extractor.js';
13
- // Processed log
14
- export { isProcessed, isContentProcessed, markProcessed, readProcessedLog, contentHash, getProcessedMessageIDs, getProcessedHashes, } from './processed-log.js';
15
- // Daemon
16
- export { runExtraction } from './daemon.js';
17
- export { LocalRecallDaemonController, } from './daemon-controller.js';
18
- // Index state
19
- export { readIndexState, writeIndexState, computeMemoryHash, getIndexStatePath, } from './index-state.js';
20
- // Vector index
21
- export { createEmbeddingProvider, OllamaEmbeddingProvider, OpenAIEmbeddingProvider, } from './vector/embedding-provider.js';
22
- export { OramaMemoryIndex } from './vector/orama-index.js';
23
- // MCP server lifecycle
24
- export { initLocalRecall, isInitialized, getDirectory, triggerExtraction, getLastExtractionStats, shutdownLocalRecall, storeLearningMemory, searchLearningMemories, getLearningMemory, startIndexingDaemon, stopIndexingDaemon, getIndexingStatus, rebuildIndex, listLearningMemories, } from './mcp-server.js';
25
- export { runLocalRecallMCPServer } from './mcp-stdio-server.js';
26
- // MCP tools (plugin tool creators)
27
- export { createLearningStoreTool, createLearningSearchTool, createLearningGetTool, createLearningIndexStartTool, createLearningIndexStatusTool, createLearningIndexStopTool, createLearningIndexRebuildTool, } from './mcp-tools.js';
@@ -1,34 +0,0 @@
1
- import type { ExtractionStats } from './daemon.js';
2
- import { type DaemonStatus } from './daemon-controller.js';
3
- import type { Memory, MemoryCategory, MemorySearchResult, SearchCriteria } from './types.js';
4
- import { OramaMemoryIndex } from './vector/orama-index.js';
5
- import type { VectorSearchResponse } from './vector/types.js';
6
- export interface LearningStoreInput {
7
- title: string;
8
- description: string;
9
- category: MemoryCategory;
10
- tags: string[];
11
- importance?: number;
12
- content?: string;
13
- }
14
- export interface IndexingStatus {
15
- daemon: DaemonStatus;
16
- index: ReturnType<OramaMemoryIndex['getStatus']>;
17
- }
18
- export declare function initLocalRecall(directory: string): void;
19
- export declare function isInitialized(): boolean;
20
- export declare function getDirectory(): string | null;
21
- export declare function triggerExtraction(directory?: string): Promise<ExtractionStats | null>;
22
- export declare function getLastExtractionStats(): ExtractionStats | null;
23
- export declare function shutdownLocalRecall(): void;
24
- export declare function storeLearningMemory(directory: string, args: LearningStoreInput): Promise<{
25
- memoryId: string;
26
- daemon: DaemonStatus;
27
- }>;
28
- export declare function searchLearningMemories(directory: string, criteria: SearchCriteria): Promise<VectorSearchResponse>;
29
- export declare function getLearningMemory(directory: string, memoryID: string): Promise<Memory | null>;
30
- export declare function startIndexingDaemon(directory: string, intervalMs?: number): Promise<IndexingStatus>;
31
- export declare function stopIndexingDaemon(directory: string): Promise<IndexingStatus>;
32
- export declare function getIndexingStatus(directory: string): Promise<IndexingStatus>;
33
- export declare function rebuildIndex(directory: string): Promise<IndexingStatus>;
34
- export declare function listLearningMemories(directory: string, criteria: SearchCriteria): Promise<MemorySearchResult[]>;
@@ -1,194 +0,0 @@
1
- import crypto from 'node:crypto';
2
- import { LocalRecallDaemonController } from './daemon-controller.js';
3
- import { getMemory, searchMemories, storeMemory } from './memory-service.js';
4
- import { createEmbeddingProvider } from './vector/embedding-provider.js';
5
- import { OramaMemoryIndex } from './vector/orama-index.js';
6
- let _initialized = false;
7
- let _directory = null;
8
- let _runtime = null;
9
- let _initPromise = null;
10
- function parseBoolean(value, fallback) {
11
- if (value === undefined) {
12
- return fallback;
13
- }
14
- const normalized = value.trim().toLowerCase();
15
- return !['0', 'false', 'off', 'no'].includes(normalized);
16
- }
17
- function parseInterval(value, fallback) {
18
- if (!value) {
19
- return fallback;
20
- }
21
- const parsed = Number(value);
22
- if (!Number.isFinite(parsed) || parsed <= 0) {
23
- return fallback;
24
- }
25
- return Math.round(parsed);
26
- }
27
- function createRuntime(directory) {
28
- const provider = (() => {
29
- try {
30
- return createEmbeddingProvider();
31
- }
32
- catch {
33
- return createEmbeddingProvider({
34
- ...process.env,
35
- FF_LOCAL_RECALL_EMBEDDING_PROVIDER: 'ollama',
36
- });
37
- }
38
- })();
39
- const index = new OramaMemoryIndex(directory, provider);
40
- const daemon = new LocalRecallDaemonController({
41
- directory,
42
- index,
43
- intervalMs: parseInterval(process.env.FF_LOCAL_RECALL_INDEX_INTERVAL_MS, 15_000),
44
- extractionEnabled: parseBoolean(process.env.FF_LOCAL_RECALL_EXTRACTION_ENABLED, true),
45
- });
46
- return index.initialize().then(() => {
47
- const autoStart = parseBoolean(process.env.FF_LOCAL_RECALL_DAEMON_AUTOSTART, true);
48
- if (autoStart) {
49
- daemon.start();
50
- }
51
- else {
52
- daemon.requestRun('startup');
53
- }
54
- return {
55
- directory,
56
- index,
57
- daemon,
58
- };
59
- });
60
- }
61
- async function ensureRuntime(directory) {
62
- if (directory && directory !== _directory) {
63
- initLocalRecall(directory);
64
- }
65
- if (!_initialized || !_directory) {
66
- throw new Error('local-recall is not initialized');
67
- }
68
- if (!_initPromise) {
69
- _initPromise = createRuntime(_directory).then((runtime) => {
70
- _runtime = runtime;
71
- });
72
- }
73
- await _initPromise;
74
- if (!_runtime) {
75
- throw new Error('local-recall runtime failed to initialize');
76
- }
77
- return _runtime;
78
- }
79
- export function initLocalRecall(directory) {
80
- if (_directory === directory && _initialized) {
81
- return;
82
- }
83
- if (_runtime) {
84
- _runtime.daemon.stop();
85
- }
86
- _initialized = true;
87
- _directory = directory;
88
- _runtime = null;
89
- _initPromise = createRuntime(directory).then((runtime) => {
90
- _runtime = runtime;
91
- });
92
- }
93
- export function isInitialized() {
94
- return _initialized;
95
- }
96
- export function getDirectory() {
97
- return _directory;
98
- }
99
- export async function triggerExtraction(directory) {
100
- const runtime = await ensureRuntime(directory);
101
- const status = await runtime.daemon.runNow('trigger-extraction');
102
- return status.lastRun?.extraction ?? null;
103
- }
104
- export function getLastExtractionStats() {
105
- return _runtime?.daemon.getStatus().lastRun?.extraction ?? null;
106
- }
107
- export function shutdownLocalRecall() {
108
- _runtime?.daemon.stop();
109
- _initialized = false;
110
- _directory = null;
111
- _runtime = null;
112
- _initPromise = null;
113
- }
114
- function toMemory(args) {
115
- return {
116
- id: crypto.randomUUID(),
117
- sessionID: 'agent-explicit',
118
- messageID: 'agent-explicit',
119
- category: args.category,
120
- title: args.title,
121
- body: args.content ?? args.description,
122
- tags: args.tags,
123
- importance: args.importance ?? 0.7,
124
- createdAt: Date.now(),
125
- extractedBy: 'agent-explicit',
126
- };
127
- }
128
- export async function storeLearningMemory(directory, args) {
129
- const runtime = await ensureRuntime(directory);
130
- const memory = toMemory(args);
131
- await storeMemory(runtime.directory, memory);
132
- runtime.daemon.requestRun('store');
133
- return {
134
- memoryId: memory.id,
135
- daemon: runtime.daemon.getStatus(),
136
- };
137
- }
138
- export async function searchLearningMemories(directory, criteria) {
139
- const runtime = await ensureRuntime(directory);
140
- try {
141
- const vectorResults = await runtime.index.search(criteria);
142
- return {
143
- backend: 'vector',
144
- results: vectorResults,
145
- };
146
- }
147
- catch (error) {
148
- const lexicalResults = await searchMemories(runtime.directory, criteria);
149
- return {
150
- backend: 'lexical',
151
- results: lexicalResults,
152
- fallbackReason: error instanceof Error ? error.message : String(error),
153
- };
154
- }
155
- }
156
- export async function getLearningMemory(directory, memoryID) {
157
- await ensureRuntime(directory);
158
- return getMemory(directory, memoryID);
159
- }
160
- export async function startIndexingDaemon(directory, intervalMs) {
161
- const runtime = await ensureRuntime(directory);
162
- const daemon = runtime.daemon.start(intervalMs);
163
- return {
164
- daemon,
165
- index: runtime.index.getStatus(),
166
- };
167
- }
168
- export async function stopIndexingDaemon(directory) {
169
- const runtime = await ensureRuntime(directory);
170
- const daemon = runtime.daemon.stop();
171
- return {
172
- daemon,
173
- index: runtime.index.getStatus(),
174
- };
175
- }
176
- export async function getIndexingStatus(directory) {
177
- const runtime = await ensureRuntime(directory);
178
- return {
179
- daemon: runtime.daemon.getStatus(),
180
- index: runtime.index.getStatus(),
181
- };
182
- }
183
- export async function rebuildIndex(directory) {
184
- const runtime = await ensureRuntime(directory);
185
- const daemon = await runtime.daemon.rebuild();
186
- return {
187
- daemon,
188
- index: runtime.index.getStatus(),
189
- };
190
- }
191
- export async function listLearningMemories(directory, criteria) {
192
- const searchResults = await searchLearningMemories(directory, criteria);
193
- return searchResults.results;
194
- }
@@ -1,4 +0,0 @@
1
- export interface LocalRecallMCPServerOptions {
2
- directory?: string;
3
- }
4
- export declare function runLocalRecallMCPServer(options?: LocalRecallMCPServerOptions): Promise<void>;
@@ -1,225 +0,0 @@
1
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
- import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
4
- import { getIndexingStatus, getLearningMemory, rebuildIndex, searchLearningMemories, shutdownLocalRecall, startIndexingDaemon, stopIndexingDaemon, storeLearningMemory, initLocalRecall, } from './mcp-server.js';
5
- const CATEGORIES = [
6
- 'pattern',
7
- 'decision',
8
- 'debugging',
9
- 'preference',
10
- 'context',
11
- 'procedure',
12
- ];
13
- function toCallResult(payload, isError = false) {
14
- return {
15
- isError,
16
- content: [
17
- {
18
- type: 'text',
19
- text: JSON.stringify(payload),
20
- },
21
- ],
22
- };
23
- }
24
- function asObject(value) {
25
- if (!value || typeof value !== 'object') {
26
- return {};
27
- }
28
- return value;
29
- }
30
- function asString(value) {
31
- return typeof value === 'string' ? value : undefined;
32
- }
33
- function asNumber(value) {
34
- return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
35
- }
36
- function asStringArray(value) {
37
- if (!Array.isArray(value) || !value.every((item) => typeof item === 'string')) {
38
- return undefined;
39
- }
40
- return value;
41
- }
42
- export async function runLocalRecallMCPServer(options = {}) {
43
- const directory = options.directory ?? process.env.FF_LOCAL_RECALL_DIRECTORY ?? process.cwd();
44
- initLocalRecall(directory);
45
- const server = new Server({
46
- name: 'ff-local-recall',
47
- version: '1.0.0',
48
- }, {
49
- capabilities: {
50
- tools: {},
51
- },
52
- });
53
- server.setRequestHandler(ListToolsRequestSchema, async () => ({
54
- tools: [
55
- {
56
- name: 'local_recall.search',
57
- description: 'Search local-recall memories with vector retrieval and lexical fallback.',
58
- inputSchema: {
59
- type: 'object',
60
- properties: {
61
- query: { type: 'string' },
62
- category: { type: 'string', enum: CATEGORIES },
63
- tags: { type: 'array', items: { type: 'string' } },
64
- minImportance: { type: 'number' },
65
- limit: { type: 'number' },
66
- },
67
- required: ['query'],
68
- },
69
- },
70
- {
71
- name: 'local_recall.get',
72
- description: 'Get a memory by unique ID.',
73
- inputSchema: {
74
- type: 'object',
75
- properties: {
76
- memoryId: { type: 'string' },
77
- },
78
- required: ['memoryId'],
79
- },
80
- },
81
- {
82
- name: 'local_recall.store',
83
- description: 'Store a memory and enqueue async indexing.',
84
- inputSchema: {
85
- type: 'object',
86
- properties: {
87
- title: { type: 'string' },
88
- description: { type: 'string' },
89
- category: { type: 'string', enum: CATEGORIES },
90
- tags: { type: 'array', items: { type: 'string' } },
91
- importance: { type: 'number' },
92
- content: { type: 'string' },
93
- },
94
- required: ['title', 'description', 'category', 'tags'],
95
- },
96
- },
97
- {
98
- name: 'local_recall.index.start',
99
- description: 'Start the local-recall daemon.',
100
- inputSchema: {
101
- type: 'object',
102
- properties: {
103
- intervalMs: { type: 'number' },
104
- },
105
- },
106
- },
107
- {
108
- name: 'local_recall.index.status',
109
- description: 'Get local-recall daemon status.',
110
- inputSchema: {
111
- type: 'object',
112
- properties: {},
113
- },
114
- },
115
- {
116
- name: 'local_recall.index.stop',
117
- description: 'Stop local-recall daemon.',
118
- inputSchema: {
119
- type: 'object',
120
- properties: {},
121
- },
122
- },
123
- {
124
- name: 'local_recall.index.rebuild',
125
- description: 'Perform a full rebuild of the local-recall index.',
126
- inputSchema: {
127
- type: 'object',
128
- properties: {},
129
- },
130
- },
131
- ],
132
- }));
133
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
134
- const toolName = request.params.name;
135
- const args = asObject(request.params.arguments);
136
- try {
137
- switch (toolName) {
138
- case 'local_recall.search': {
139
- const query = asString(args.query);
140
- if (!query) {
141
- return toCallResult({ error: 'query is required' }, true);
142
- }
143
- const result = await searchLearningMemories(directory, {
144
- query,
145
- category: asString(args.category),
146
- tags: asStringArray(args.tags),
147
- minImportance: asNumber(args.minImportance),
148
- limit: asNumber(args.limit),
149
- });
150
- return toCallResult(result);
151
- }
152
- case 'local_recall.get': {
153
- const memoryId = asString(args.memoryId);
154
- if (!memoryId) {
155
- return toCallResult({ error: 'memoryId is required' }, true);
156
- }
157
- const memory = await getLearningMemory(directory, memoryId);
158
- if (!memory) {
159
- return toCallResult({ error: `Memory not found: ${memoryId}` }, true);
160
- }
161
- return toCallResult({ success: true, memory });
162
- }
163
- case 'local_recall.store': {
164
- const title = asString(args.title);
165
- const description = asString(args.description);
166
- const category = asString(args.category);
167
- const tags = asStringArray(args.tags);
168
- if (!title || !description || !category || !tags) {
169
- return toCallResult({
170
- error: 'title, description, category, and tags are required',
171
- }, true);
172
- }
173
- if (!CATEGORIES.includes(category)) {
174
- return toCallResult({
175
- error: `Invalid category: ${category}`,
176
- }, true);
177
- }
178
- const result = await storeLearningMemory(directory, {
179
- title,
180
- description,
181
- category: category,
182
- tags,
183
- importance: asNumber(args.importance),
184
- content: asString(args.content),
185
- });
186
- return toCallResult({
187
- success: true,
188
- memoryId: result.memoryId,
189
- daemon: result.daemon,
190
- });
191
- }
192
- case 'local_recall.index.start': {
193
- const result = await startIndexingDaemon(directory, asNumber(args.intervalMs));
194
- return toCallResult({ success: true, ...result });
195
- }
196
- case 'local_recall.index.status': {
197
- const result = await getIndexingStatus(directory);
198
- return toCallResult({ success: true, ...result });
199
- }
200
- case 'local_recall.index.stop': {
201
- const result = await stopIndexingDaemon(directory);
202
- return toCallResult({ success: true, ...result });
203
- }
204
- case 'local_recall.index.rebuild': {
205
- const result = await rebuildIndex(directory);
206
- return toCallResult({ success: true, ...result });
207
- }
208
- default:
209
- return toCallResult({ error: `Unknown tool: ${toolName}` }, true);
210
- }
211
- }
212
- catch (error) {
213
- return toCallResult({
214
- error: error instanceof Error ? error.message : String(error),
215
- }, true);
216
- }
217
- });
218
- const transport = new StdioServerTransport();
219
- await server.connect(transport);
220
- const shutdown = () => {
221
- shutdownLocalRecall();
222
- };
223
- process.on('SIGINT', shutdown);
224
- process.on('SIGTERM', shutdown);
225
- }