@grec0/memory-bank-mcp 0.1.21 → 0.1.22
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/common/projectKnowledgeService.js +23 -10
- package/dist/common/sessionState.js +24 -0
- package/dist/common/version.js +1 -1
- package/dist/index.js +6 -6
- package/dist/tools/generateProjectDocs.js +32 -5
- package/dist/tools/getProjectDocs.js +8 -7
- package/dist/tools/indexCode.js +25 -0
- package/dist/tools/manageAgents.js +3 -0
- package/dist/tools/readFile.js +24 -0
- package/dist/tools/searchMemory.js +5 -3
- package/dist/tools/writeFile.js +37 -0
- package/package.json +1 -1
|
@@ -152,14 +152,18 @@ Generate a markdown document useful for setting up the development environment.`
|
|
|
152
152
|
filename: "activeContext.md",
|
|
153
153
|
title: "Active Context",
|
|
154
154
|
description: "Current development state, recent changes, and work in progress",
|
|
155
|
-
promptTemplate: `Analyze the following recently modified code chunks and generate an Active Context document.
|
|
155
|
+
promptTemplate: `Analyze the following recently modified code chunks and current session history to generate an Active Context document.
|
|
156
156
|
|
|
157
157
|
Document:
|
|
158
|
-
1. **
|
|
159
|
-
2. **
|
|
160
|
-
3. **
|
|
161
|
-
4. **
|
|
162
|
-
5. **
|
|
158
|
+
1. **Current Session Status**: Summary of actions performed in the current session (from history).
|
|
159
|
+
2. **Recent Changes**: What parts of the code were recently modified?
|
|
160
|
+
3. **Work in Progress**: Features or fixes that appear incomplete
|
|
161
|
+
4. **Hot Areas**: Parts of the code with high activity
|
|
162
|
+
5. **Potential Issues**: Code that might need attention (TODOs, FIXMEs)
|
|
163
|
+
6. **Current Focus**: What seems to be the current development focus?
|
|
164
|
+
|
|
165
|
+
Recent session history:
|
|
166
|
+
{sessionHistory}
|
|
163
167
|
|
|
164
168
|
Recent code chunks:
|
|
165
169
|
{chunks}
|
|
@@ -320,6 +324,9 @@ export class ProjectKnowledgeService {
|
|
|
320
324
|
.join("|");
|
|
321
325
|
return crypto.createHash("md5").update(content).digest("hex");
|
|
322
326
|
}
|
|
327
|
+
hashString(str) {
|
|
328
|
+
return crypto.createHash("md5").update(str).digest("hex");
|
|
329
|
+
}
|
|
323
330
|
/**
|
|
324
331
|
* Prepares chunks for inclusion in a prompt
|
|
325
332
|
* Uses Map-Reduce summarization if content exceeds context window threshold
|
|
@@ -603,9 +610,9 @@ ${chunk.content}
|
|
|
603
610
|
/**
|
|
604
611
|
* Generates a single document for a specific project
|
|
605
612
|
*/
|
|
606
|
-
async generateDocument(projectId, type, chunks, force = false, previousProgress) {
|
|
613
|
+
async generateDocument(projectId, type, chunks, force = false, previousProgress, sessionHistory) {
|
|
607
614
|
const definition = DOC_DEFINITIONS[type];
|
|
608
|
-
const inputHash = this.hashChunks(chunks);
|
|
615
|
+
const inputHash = this.hashChunks(chunks) + (sessionHistory ? this.hashString(sessionHistory) : 0);
|
|
609
616
|
const docsPath = this.ensureProjectDocsDirectory(projectId);
|
|
610
617
|
const metadataCache = this.loadProjectMetadata(projectId);
|
|
611
618
|
// Check if regeneration is needed
|
|
@@ -620,6 +627,12 @@ ${chunk.content}
|
|
|
620
627
|
const preparedChunks = await this.prepareChunksForPrompt(chunks, this.options.maxChunksPerDoc);
|
|
621
628
|
console.error(` Chunks text length: ${preparedChunks.text.length} chars${preparedChunks.usedMapReduce ? ' (after Map-Reduce)' : ''}`);
|
|
622
629
|
let prompt = definition.promptTemplate.replace("{chunks}", preparedChunks.text);
|
|
630
|
+
if (sessionHistory) {
|
|
631
|
+
prompt = prompt.replace("{sessionHistory}", sessionHistory);
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
prompt = prompt.replace("{sessionHistory}", "No recent session history available.");
|
|
635
|
+
}
|
|
623
636
|
if (type === "progress" && previousProgress) {
|
|
624
637
|
prompt = prompt.replace("{previousProgress}", previousProgress);
|
|
625
638
|
}
|
|
@@ -655,7 +668,7 @@ ${chunk.content}
|
|
|
655
668
|
/**
|
|
656
669
|
* Generates all project documents (in parallel for speed)
|
|
657
670
|
*/
|
|
658
|
-
async generateAllDocuments(projectId, chunks, force = false) {
|
|
671
|
+
async generateAllDocuments(projectId, chunks, force = false, sessionHistory) {
|
|
659
672
|
const result = {
|
|
660
673
|
success: true,
|
|
661
674
|
documentsGenerated: [],
|
|
@@ -694,7 +707,7 @@ ${chunk.content}
|
|
|
694
707
|
const docChunks = docType === "activeContext" ? recentChunks : chunks;
|
|
695
708
|
const existingMetadata = metadataCache.get(docType);
|
|
696
709
|
const isNew = !existingMetadata;
|
|
697
|
-
const doc = await this.generateDocument(projectId, docType, docChunks, force, docType === "progress" ? previousProgress : undefined);
|
|
710
|
+
const doc = await this.generateDocument(projectId, docType, docChunks, force, docType === "progress" ? previousProgress : undefined, sessionHistory);
|
|
698
711
|
return { docType, doc, isNew, error: null };
|
|
699
712
|
}
|
|
700
713
|
catch (error) {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export class SessionState {
|
|
2
|
+
static instance;
|
|
3
|
+
currentAgentId = null;
|
|
4
|
+
currentProjectId = null;
|
|
5
|
+
constructor() { }
|
|
6
|
+
static getInstance() {
|
|
7
|
+
if (!SessionState.instance) {
|
|
8
|
+
SessionState.instance = new SessionState();
|
|
9
|
+
}
|
|
10
|
+
return SessionState.instance;
|
|
11
|
+
}
|
|
12
|
+
setCurrentAgent(agentId, projectId) {
|
|
13
|
+
this.currentAgentId = agentId;
|
|
14
|
+
this.currentProjectId = projectId;
|
|
15
|
+
console.error(`[SessionState] Set Active Agent: ${agentId} for Project: ${projectId}`);
|
|
16
|
+
}
|
|
17
|
+
getCurrentAgentId() {
|
|
18
|
+
return this.currentAgentId;
|
|
19
|
+
}
|
|
20
|
+
getCurrentProjectId() {
|
|
21
|
+
return this.currentProjectId;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export const sessionState = SessionState.getInstance();
|
package/dist/common/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Version of the MCP Kanban server
|
|
2
|
-
export const VERSION = "0.1.
|
|
2
|
+
export const VERSION = "0.1.22";
|
package/dist/index.js
CHANGED
|
@@ -159,10 +159,6 @@ server.tool("memorybank_search", "Busca código relevante mediante búsqueda sem
|
|
|
159
159
|
.string()
|
|
160
160
|
.optional()
|
|
161
161
|
.describe("Filtrar resultados por lenguaje de programación (ej: 'typescript', 'python')"),
|
|
162
|
-
agentId: z
|
|
163
|
-
.string()
|
|
164
|
-
.optional()
|
|
165
|
-
.describe("Identificador del agente (para logging de sesión)"),
|
|
166
162
|
}, async (args) => {
|
|
167
163
|
const result = await searchMemory({
|
|
168
164
|
projectId: args.projectId,
|
|
@@ -171,7 +167,6 @@ server.tool("memorybank_search", "Busca código relevante mediante búsqueda sem
|
|
|
171
167
|
minScore: args.minScore,
|
|
172
168
|
filterByFile: args.filterByFile,
|
|
173
169
|
filterByLanguage: args.filterByLanguage,
|
|
174
|
-
agentId: args.agentId,
|
|
175
170
|
}, indexManager, workspaceRoot);
|
|
176
171
|
return {
|
|
177
172
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
@@ -193,11 +188,16 @@ Ejemplo: "C:/workspaces/proyecto/src/index.ts"`, {
|
|
|
193
188
|
.number()
|
|
194
189
|
.optional()
|
|
195
190
|
.describe("Línea final (opcional)"),
|
|
191
|
+
projectId: z
|
|
192
|
+
.string()
|
|
193
|
+
.optional()
|
|
194
|
+
.describe("Identificador del proyecto (Opcional, pero necesario para logging de sesión)"),
|
|
196
195
|
}, async (args) => {
|
|
197
196
|
const result = await readFile({
|
|
198
197
|
path: args.path,
|
|
199
198
|
startLine: args.startLine,
|
|
200
199
|
endLine: args.endLine,
|
|
200
|
+
projectId: args.projectId,
|
|
201
201
|
}, workspaceRoot);
|
|
202
202
|
return {
|
|
203
203
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
@@ -314,7 +314,7 @@ server.tool(generateProjectDocsToolDefinition.name, generateProjectDocsToolDefin
|
|
|
314
314
|
const result = await generateProjectDocs({
|
|
315
315
|
projectId: args.projectId,
|
|
316
316
|
force: args.force,
|
|
317
|
-
}, projectKnowledgeService, vectorStore);
|
|
317
|
+
}, projectKnowledgeService, vectorStore, workspaceRoot);
|
|
318
318
|
return {
|
|
319
319
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
320
320
|
};
|
|
@@ -2,15 +2,43 @@
|
|
|
2
2
|
* @fileoverview Tool for generating project documentation
|
|
3
3
|
* Uses the Project Knowledge Service to create structured markdown docs
|
|
4
4
|
*/
|
|
5
|
+
import { AgentBoard } from "../common/agentBoard.js";
|
|
6
|
+
import { sessionLogger } from "../common/sessionLogger.js";
|
|
7
|
+
import { sessionState } from "../common/sessionState.js";
|
|
5
8
|
/**
|
|
6
9
|
* Generates project documentation using AI reasoning
|
|
7
10
|
*/
|
|
8
|
-
export async function generateProjectDocs(params, projectKnowledgeService, vectorStore)
|
|
11
|
+
export async function generateProjectDocs(params, projectKnowledgeService, vectorStore, workspaceRoot = process.cwd() // Add workspaceRoot
|
|
12
|
+
) {
|
|
9
13
|
try {
|
|
10
14
|
console.error("\n=== Generating Project Documentation ===");
|
|
11
|
-
|
|
15
|
+
const projectId = params.projectId || "default";
|
|
16
|
+
console.error(`Project ID: ${projectId}`);
|
|
17
|
+
// Fetch Session History via Session State
|
|
18
|
+
let sessionHistory;
|
|
19
|
+
const activeAgentId = sessionState.getCurrentAgentId();
|
|
20
|
+
if (activeAgentId) {
|
|
21
|
+
try {
|
|
22
|
+
const board = new AgentBoard(workspaceRoot, projectId);
|
|
23
|
+
const sessionId = await board.getSessionId(activeAgentId);
|
|
24
|
+
if (sessionId) {
|
|
25
|
+
console.error(`Fetching session history for session: ${sessionId}`);
|
|
26
|
+
const history = await sessionLogger.getSessionHistory(projectId, sessionId);
|
|
27
|
+
if (history && history.length > 0) {
|
|
28
|
+
// Summarize last 20 events
|
|
29
|
+
const recentEvents = history.slice(-20);
|
|
30
|
+
sessionHistory = recentEvents.map(e => {
|
|
31
|
+
const dataStr = JSON.stringify(e.data).slice(0, 200); // Truncate data
|
|
32
|
+
return `- [${e.timestamp.split('T')[1].split('.')[0]}] ${e.type}: ${dataStr}`;
|
|
33
|
+
}).join('\n');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
console.error(`Warning: Failed to fetch session history: ${e}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
12
41
|
console.error(`Force regeneration: ${params.force || false}`);
|
|
13
|
-
// Get all chunks from the vector store
|
|
14
42
|
const chunks = await vectorStore.getAllChunks(params.projectId);
|
|
15
43
|
if (chunks.length === 0) {
|
|
16
44
|
return {
|
|
@@ -34,8 +62,7 @@ export async function generateProjectDocs(params, projectKnowledgeService, vecto
|
|
|
34
62
|
}
|
|
35
63
|
console.error(`Found ${chunks.length} code chunks to analyze`);
|
|
36
64
|
// Generate documents - projectId is required
|
|
37
|
-
const
|
|
38
|
-
const result = await projectKnowledgeService.generateAllDocuments(projectId, chunks, params.force || false);
|
|
65
|
+
const result = await projectKnowledgeService.generateAllDocuments(projectId, chunks, params.force || false, sessionHistory);
|
|
39
66
|
// Calculate estimated cost (approximate rates for gpt-5-mini)
|
|
40
67
|
// Reasoning tokens are typically more expensive
|
|
41
68
|
const reasoningCostPer1K = 0.003; // $0.003 per 1K reasoning tokens
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { AgentBoard } from "../common/agentBoard.js";
|
|
6
6
|
import { sessionLogger } from "../common/sessionLogger.js";
|
|
7
|
+
import { sessionState } from "../common/sessionState.js";
|
|
7
8
|
const VALID_DOC_TYPES = [
|
|
8
9
|
"projectBrief",
|
|
9
10
|
"productContext",
|
|
@@ -17,25 +18,25 @@ const VALID_DOC_TYPES = [
|
|
|
17
18
|
*/
|
|
18
19
|
export async function getProjectDocs(params, projectKnowledgeService, workspaceRoot) {
|
|
19
20
|
const logSession = async (outputSummary) => {
|
|
20
|
-
|
|
21
|
+
const activeAgentId = sessionState.getCurrentAgentId();
|
|
22
|
+
if (activeAgentId && workspaceRoot) {
|
|
21
23
|
try {
|
|
22
24
|
const board = new AgentBoard(workspaceRoot, params.projectId);
|
|
23
|
-
const sessionId = await board.getSessionId(
|
|
25
|
+
const sessionId = await board.getSessionId(activeAgentId);
|
|
24
26
|
if (sessionId) {
|
|
25
|
-
// Use singleton sessionLogger
|
|
26
27
|
await sessionLogger.logSessionEvent(params.projectId, sessionId, {
|
|
27
28
|
timestamp: new Date().toISOString(),
|
|
28
29
|
type: 'read_doc',
|
|
29
30
|
data: {
|
|
30
|
-
document: params.document
|
|
31
|
-
format: params.format
|
|
31
|
+
document: params.document,
|
|
32
|
+
format: params.format,
|
|
32
33
|
summary: outputSummary
|
|
33
34
|
}
|
|
34
35
|
});
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
|
-
catch (
|
|
38
|
-
console.error(`Failed to log
|
|
38
|
+
catch (logError) {
|
|
39
|
+
console.error(`Failed to log read_doc session: ${logError}`);
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
};
|
package/dist/tools/indexCode.js
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
* Indexes code files semantically
|
|
4
4
|
*/
|
|
5
5
|
import * as path from "path";
|
|
6
|
+
import { AgentBoard } from "../common/agentBoard.js";
|
|
7
|
+
import { sessionLogger } from "../common/sessionLogger.js";
|
|
8
|
+
import { sessionState } from "../common/sessionState.js";
|
|
6
9
|
/**
|
|
7
10
|
* Indexes code from a directory or file
|
|
8
11
|
*/
|
|
@@ -16,6 +19,28 @@ export async function indexCode(params, indexManager, workspaceRoot) {
|
|
|
16
19
|
: workspaceRoot;
|
|
17
20
|
console.error(`\nIndexing code at: ${targetPath}`);
|
|
18
21
|
console.error(`Project ID: ${params.projectId}`);
|
|
22
|
+
// Session Logging via Session State
|
|
23
|
+
const activeAgentId = sessionState.getCurrentAgentId();
|
|
24
|
+
if (activeAgentId) {
|
|
25
|
+
try {
|
|
26
|
+
const board = new AgentBoard(workspaceRoot, params.projectId);
|
|
27
|
+
const sessionId = await board.getSessionId(activeAgentId);
|
|
28
|
+
if (sessionId) {
|
|
29
|
+
await sessionLogger.logSessionEvent(params.projectId, sessionId, {
|
|
30
|
+
timestamp: new Date().toISOString(),
|
|
31
|
+
type: 'index',
|
|
32
|
+
data: {
|
|
33
|
+
path: targetPath,
|
|
34
|
+
recursive: params.recursive !== false,
|
|
35
|
+
force: params.forceReindex || false
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (logError) {
|
|
41
|
+
console.error(`Failed to log session event: ${logError}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
19
44
|
console.error(`Workspace root: ${workspaceRoot}`);
|
|
20
45
|
console.error(`Recursive: ${params.recursive !== false}`);
|
|
21
46
|
console.error(`Force reindex: ${params.forceReindex || false}`);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AgentBoard } from '../common/agentBoard.js';
|
|
2
2
|
import { RegistryManager } from '../common/registryManager.js';
|
|
3
|
+
import { sessionState } from '../common/sessionState.js';
|
|
3
4
|
import * as crypto from 'crypto';
|
|
4
5
|
const WORKSPACE_ROOT = process.cwd(); // Will be overridden by actual workspace logic if passed
|
|
5
6
|
export async function manageAgentsTool(params, workspaceRoot = WORKSPACE_ROOT) {
|
|
@@ -10,6 +11,8 @@ export async function manageAgentsTool(params, workspaceRoot = WORKSPACE_ROOT) {
|
|
|
10
11
|
case 'register':
|
|
11
12
|
if (!agentId)
|
|
12
13
|
throw new Error('agentId is required for register');
|
|
14
|
+
// Set Global Session State
|
|
15
|
+
sessionState.setCurrentAgent(agentId, projectId);
|
|
13
16
|
// Auto-generate session ID if not provided.
|
|
14
17
|
const effectiveSessionId = sessionId || crypto.randomUUID();
|
|
15
18
|
// 1. Register agent on local board
|
package/dist/tools/readFile.js
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as fs from "fs";
|
|
6
6
|
import * as path from "path";
|
|
7
|
+
import { AgentBoard } from "../common/agentBoard.js";
|
|
8
|
+
import { sessionLogger } from "../common/sessionLogger.js";
|
|
9
|
+
import { sessionState } from "../common/sessionState.js";
|
|
7
10
|
/**
|
|
8
11
|
* Reads a file from the workspace
|
|
9
12
|
*/
|
|
@@ -13,6 +16,27 @@ export async function readFile(params, workspaceRoot) {
|
|
|
13
16
|
const filePath = path.isAbsolute(params.path)
|
|
14
17
|
? params.path
|
|
15
18
|
: path.join(workspaceRoot, params.path);
|
|
19
|
+
// Session Logging via Session State
|
|
20
|
+
const activeAgentId = sessionState.getCurrentAgentId();
|
|
21
|
+
if (activeAgentId && params.projectId) {
|
|
22
|
+
try {
|
|
23
|
+
const board = new AgentBoard(workspaceRoot, params.projectId);
|
|
24
|
+
const sessionId = await board.getSessionId(activeAgentId);
|
|
25
|
+
if (sessionId) {
|
|
26
|
+
await sessionLogger.logSessionEvent(params.projectId, sessionId, {
|
|
27
|
+
timestamp: new Date().toISOString(),
|
|
28
|
+
type: 'read_file',
|
|
29
|
+
data: {
|
|
30
|
+
path: params.path,
|
|
31
|
+
lines: params.startLine && params.endLine ? `${params.startLine}-${params.endLine}` : 'all'
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (logError) {
|
|
37
|
+
console.error(`Failed to log session event: ${logError}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
16
40
|
// Check if file exists
|
|
17
41
|
if (!fs.existsSync(filePath)) {
|
|
18
42
|
return {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { AgentBoard } from "../common/agentBoard.js";
|
|
6
6
|
import { sessionLogger } from "../common/sessionLogger.js";
|
|
7
|
+
import { sessionState } from "../common/sessionState.js";
|
|
7
8
|
/**
|
|
8
9
|
* Searches the Memory Bank for relevant code
|
|
9
10
|
*/
|
|
@@ -36,11 +37,12 @@ export async function searchMemory(params, indexManager, workspaceRoot) {
|
|
|
36
37
|
filterByFile: params.filterByFile,
|
|
37
38
|
filterByLanguage: params.filterByLanguage,
|
|
38
39
|
});
|
|
39
|
-
// Session Logging
|
|
40
|
-
|
|
40
|
+
// Session Logging via Session State
|
|
41
|
+
const activeAgentId = sessionState.getCurrentAgentId();
|
|
42
|
+
if (activeAgentId && workspaceRoot) {
|
|
41
43
|
try {
|
|
42
44
|
const board = new AgentBoard(workspaceRoot, params.projectId);
|
|
43
|
-
const sessionId = await board.getSessionId(
|
|
45
|
+
const sessionId = await board.getSessionId(activeAgentId);
|
|
44
46
|
if (sessionId) {
|
|
45
47
|
await sessionLogger.logSessionEvent(params.projectId, sessionId, {
|
|
46
48
|
timestamp: new Date().toISOString(),
|
package/dist/tools/writeFile.js
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as fs from "fs";
|
|
6
6
|
import * as path from "path";
|
|
7
|
+
import { AgentBoard } from "../common/agentBoard.js";
|
|
8
|
+
import { sessionLogger } from "../common/sessionLogger.js";
|
|
9
|
+
import { sessionState } from "../common/sessionState.js";
|
|
7
10
|
/**
|
|
8
11
|
* Writes a file and optionally reindexes it
|
|
9
12
|
*/
|
|
@@ -13,6 +16,40 @@ export async function writeFile(params, indexManager, workspaceRoot) {
|
|
|
13
16
|
const filePath = path.isAbsolute(params.path)
|
|
14
17
|
? params.path
|
|
15
18
|
: path.join(workspaceRoot, params.path);
|
|
19
|
+
// Auto-Locking & Logging via Session State
|
|
20
|
+
const activeAgentId = sessionState.getCurrentAgentId();
|
|
21
|
+
if (activeAgentId) {
|
|
22
|
+
const board = new AgentBoard(workspaceRoot, params.projectId);
|
|
23
|
+
// 1. Check/Claim Lock
|
|
24
|
+
// Normalize path for locking (relative to workspace)
|
|
25
|
+
const relativePath = path.relative(workspaceRoot, filePath).replace(/\\/g, '/');
|
|
26
|
+
const canWrite = await board.claimResource(activeAgentId, relativePath);
|
|
27
|
+
if (!canWrite) {
|
|
28
|
+
return {
|
|
29
|
+
success: false,
|
|
30
|
+
filePath: params.path,
|
|
31
|
+
message: `File is locked by another agent. Write rejected.`
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
// 2. Log Session Event
|
|
35
|
+
try {
|
|
36
|
+
const sessionId = await board.getSessionId(activeAgentId);
|
|
37
|
+
if (sessionId) {
|
|
38
|
+
await sessionLogger.logSessionEvent(params.projectId, sessionId, {
|
|
39
|
+
timestamp: new Date().toISOString(),
|
|
40
|
+
type: 'decision',
|
|
41
|
+
data: {
|
|
42
|
+
action: 'write_file',
|
|
43
|
+
path: params.path,
|
|
44
|
+
byteSize: Buffer.byteLength(params.content, "utf-8")
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
console.error("Failed to log session event:", e);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
16
53
|
// Ensure directory exists
|
|
17
54
|
const dir = path.dirname(filePath);
|
|
18
55
|
if (!fs.existsSync(dir)) {
|