sam-coder-cli 2.0.4 → 2.0.5
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/README.md +36 -43
- package/bin/agi-cli.js +132 -294
- package/bin/ui.js +8 -1
- package/package.json +11 -20
- package/bin/core/brainstorm.js +0 -198
- package/bin/core/edit_finished_brainstorm.js +0 -294
- package/bin/core/finish_brainstorm.js +0 -217
- package/bin/core/index.js +0 -37
- package/bin/core/models.js +0 -290
- package/bin/core/templates.js +0 -567
package/bin/core/brainstorm.js
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Brainstorm Module - Start a New Brainstorm Session
|
|
3
|
-
*
|
|
4
|
-
* Initializes a new brainstorm session and generates all project coordination files.
|
|
5
|
-
* Ported from Python to JavaScript.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const fs = require('fs').promises;
|
|
9
|
-
const path = require('path');
|
|
10
|
-
const { ProjectConfig, BrainstormSession } = require('./models');
|
|
11
|
-
const templates = require('./templates');
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* File templates mapping
|
|
15
|
-
*/
|
|
16
|
-
const FILE_TEMPLATES = {
|
|
17
|
-
'CLAUDE.md': templates.generateClaudeMd,
|
|
18
|
-
'PROJECT_STATUS.md': templates.generateProjectStatusMd,
|
|
19
|
-
'PROGRESS_REPORT.md': templates.generateProgressReportMd,
|
|
20
|
-
'GETTING_STARTED.md': templates.generateGettingStartedMd,
|
|
21
|
-
'SELF_IMPROVEMENT.md': templates.generateSelfImprovementMd,
|
|
22
|
-
'CEO-UPDATES-TODAY.md': templates.generateCeoUpdatesMd,
|
|
23
|
-
'CODE_OF_CONDUCT_OF_AI_WORKERS.md': templates.generateCodeOfConductMd
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const MULTI_AGENT_TEMPLATES = {
|
|
27
|
-
'SECONDARY-AI-CHAT.md': templates.generateSecondaryAiChatMd
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Start a new brainstorm session
|
|
32
|
-
*
|
|
33
|
-
* @param {Object} options
|
|
34
|
-
* @param {ProjectConfig|Object} options.config - Project configuration
|
|
35
|
-
* @param {string} options.outputDir - Directory where files will be generated
|
|
36
|
-
* @param {string[]} options.agents - List of agent identities (e.g., ["CLAUDE-1", "CLAUDE-2"])
|
|
37
|
-
* @returns {Promise<BrainstormSession>}
|
|
38
|
-
*/
|
|
39
|
-
async function startBrainstorm({ config, outputDir, agents = ['CLAUDE-1'] }) {
|
|
40
|
-
// Convert to ProjectConfig if needed
|
|
41
|
-
const project = config instanceof ProjectConfig ? config : new ProjectConfig(config);
|
|
42
|
-
|
|
43
|
-
// Create output directory
|
|
44
|
-
await fs.mkdir(outputDir, { recursive: true });
|
|
45
|
-
|
|
46
|
-
// Create new session
|
|
47
|
-
const session = BrainstormSession.create({
|
|
48
|
-
project,
|
|
49
|
-
outputDirectory: outputDir,
|
|
50
|
-
agents
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
const generatedFiles = [];
|
|
54
|
-
|
|
55
|
-
// Generate standard files
|
|
56
|
-
for (const [fileName, templateFn] of Object.entries(FILE_TEMPLATES)) {
|
|
57
|
-
const content = templateFn({ project, agents, session });
|
|
58
|
-
const filePath = path.join(outputDir, fileName);
|
|
59
|
-
await fs.writeFile(filePath, content, 'utf-8');
|
|
60
|
-
generatedFiles.push(fileName);
|
|
61
|
-
session.fileVersions[fileName] = 1;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Generate multi-agent files if more than one agent
|
|
65
|
-
if (agents.length > 1) {
|
|
66
|
-
for (const [fileName, templateFn] of Object.entries(MULTI_AGENT_TEMPLATES)) {
|
|
67
|
-
const content = templateFn({ project, agents, session });
|
|
68
|
-
const filePath = path.join(outputDir, fileName);
|
|
69
|
-
await fs.writeFile(filePath, content, 'utf-8');
|
|
70
|
-
generatedFiles.push(fileName);
|
|
71
|
-
session.fileVersions[fileName] = 1;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Create directory structure if defined
|
|
76
|
-
if (project.directoryStructure && Object.keys(project.directoryStructure).length > 0) {
|
|
77
|
-
await createDirectoryStructure(outputDir, project.directoryStructure);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Add event for file generation
|
|
81
|
-
session.addEvent({
|
|
82
|
-
eventType: 'UPDATED',
|
|
83
|
-
actor: 'BRAINSTORM',
|
|
84
|
-
description: `Generated ${generatedFiles.length} project files`,
|
|
85
|
-
affectedFiles: generatedFiles
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
// Save session state
|
|
89
|
-
await session.save();
|
|
90
|
-
|
|
91
|
-
return session;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Create directory structure recursively
|
|
96
|
-
*/
|
|
97
|
-
async function createDirectoryStructure(baseDir, structure, currentPath = null) {
|
|
98
|
-
const current = currentPath || baseDir;
|
|
99
|
-
|
|
100
|
-
for (const [name, children] of Object.entries(structure)) {
|
|
101
|
-
const itemPath = path.join(current, name);
|
|
102
|
-
|
|
103
|
-
if (typeof children === 'object' && children !== null && Object.keys(children).length > 0) {
|
|
104
|
-
// Directory with children
|
|
105
|
-
await fs.mkdir(itemPath, { recursive: true });
|
|
106
|
-
await createDirectoryStructure(baseDir, children, itemPath);
|
|
107
|
-
} else if (children === null || (typeof children === 'object' && Object.keys(children).length === 0)) {
|
|
108
|
-
// Empty directory
|
|
109
|
-
await fs.mkdir(itemPath, { recursive: true });
|
|
110
|
-
} else {
|
|
111
|
-
// File placeholder
|
|
112
|
-
await fs.mkdir(path.dirname(itemPath), { recursive: true });
|
|
113
|
-
try {
|
|
114
|
-
await fs.access(itemPath);
|
|
115
|
-
} catch {
|
|
116
|
-
await fs.writeFile(itemPath, '', 'utf-8');
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Load an existing session from a directory
|
|
124
|
-
*
|
|
125
|
-
* @param {string} sessionDir - Directory containing SESSION.json
|
|
126
|
-
* @returns {Promise<BrainstormSession|null>}
|
|
127
|
-
*/
|
|
128
|
-
async function getSession(sessionDir) {
|
|
129
|
-
const sessionFile = path.join(sessionDir, 'SESSION.json');
|
|
130
|
-
|
|
131
|
-
try {
|
|
132
|
-
await fs.access(sessionFile);
|
|
133
|
-
return await BrainstormSession.load(sessionFile);
|
|
134
|
-
} catch {
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* List all files in a brainstorm session with their versions
|
|
141
|
-
*
|
|
142
|
-
* @param {BrainstormSession} session
|
|
143
|
-
* @returns {Array<Object>}
|
|
144
|
-
*/
|
|
145
|
-
async function listFiles(session) {
|
|
146
|
-
const files = [];
|
|
147
|
-
|
|
148
|
-
for (const [fileName, version] of Object.entries(session.fileVersions)) {
|
|
149
|
-
const filePath = path.join(session.outputDirectory, fileName);
|
|
150
|
-
let exists = false;
|
|
151
|
-
|
|
152
|
-
try {
|
|
153
|
-
await fs.access(filePath);
|
|
154
|
-
exists = true;
|
|
155
|
-
} catch { }
|
|
156
|
-
|
|
157
|
-
files.push({
|
|
158
|
-
name: fileName,
|
|
159
|
-
path: filePath,
|
|
160
|
-
version,
|
|
161
|
-
exists
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return files;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Quick start function for creating a brainstorm session
|
|
170
|
-
*
|
|
171
|
-
* @param {string} name - Project name
|
|
172
|
-
* @param {string} description - Project description
|
|
173
|
-
* @param {string} outputDir - Output directory
|
|
174
|
-
* @param {string[]} agents - List of agent identities
|
|
175
|
-
* @param {Object} options - Additional ProjectConfig fields
|
|
176
|
-
* @returns {Promise<BrainstormSession>}
|
|
177
|
-
*/
|
|
178
|
-
async function quickStart(name, description, outputDir, agents = ['CLAUDE-1'], options = {}) {
|
|
179
|
-
const config = new ProjectConfig({
|
|
180
|
-
name,
|
|
181
|
-
description,
|
|
182
|
-
...options
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
return startBrainstorm({
|
|
186
|
-
config,
|
|
187
|
-
outputDir,
|
|
188
|
-
agents
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
module.exports = {
|
|
193
|
-
startBrainstorm,
|
|
194
|
-
getSession,
|
|
195
|
-
listFiles,
|
|
196
|
-
quickStart,
|
|
197
|
-
createDirectoryStructure
|
|
198
|
-
};
|
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Edit Finished Brainstorm Module - Version-Tracked Edits
|
|
3
|
-
*
|
|
4
|
-
* Allows editing of completed brainstorm files with full version tracking and audit trail.
|
|
5
|
-
* Ported from Python to JavaScript.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const fs = require('fs').promises;
|
|
9
|
-
const path = require('path');
|
|
10
|
-
const { BrainstormSession, EditInfo } = require('./models');
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Result of an edit operation
|
|
14
|
-
*/
|
|
15
|
-
class EditResult {
|
|
16
|
-
constructor({
|
|
17
|
-
success,
|
|
18
|
-
fileName,
|
|
19
|
-
versionBefore,
|
|
20
|
-
versionAfter,
|
|
21
|
-
backupPath = null,
|
|
22
|
-
error = null
|
|
23
|
-
}) {
|
|
24
|
-
this.success = success;
|
|
25
|
-
this.fileName = fileName;
|
|
26
|
-
this.versionBefore = versionBefore;
|
|
27
|
-
this.versionAfter = versionAfter;
|
|
28
|
-
this.backupPath = backupPath;
|
|
29
|
-
this.error = error;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Edit a file in a completed brainstorm session
|
|
35
|
-
*
|
|
36
|
-
* @param {Object} options
|
|
37
|
-
* @param {string} options.sessionDir - Directory containing the session
|
|
38
|
-
* @param {string} options.fileName - Name of the file to edit
|
|
39
|
-
* @param {string} options.newContent - New content for the file
|
|
40
|
-
* @param {string} options.description - Description of what was changed
|
|
41
|
-
* @param {string} options.editor - Who is making the edit
|
|
42
|
-
* @returns {Promise<EditResult>}
|
|
43
|
-
*/
|
|
44
|
-
async function editBrainstormFile({ sessionDir, fileName, newContent, description, editor = 'HUMAN' }) {
|
|
45
|
-
const sessionFile = path.join(sessionDir, 'SESSION.json');
|
|
46
|
-
|
|
47
|
-
// Check if session exists
|
|
48
|
-
try {
|
|
49
|
-
await fs.access(sessionFile);
|
|
50
|
-
} catch {
|
|
51
|
-
return new EditResult({
|
|
52
|
-
success: false,
|
|
53
|
-
fileName,
|
|
54
|
-
versionBefore: 0,
|
|
55
|
-
versionAfter: 0,
|
|
56
|
-
error: 'SESSION.json not found'
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Load session
|
|
61
|
-
const session = await BrainstormSession.load(sessionFile);
|
|
62
|
-
const filePath = path.join(session.outputDirectory, fileName);
|
|
63
|
-
|
|
64
|
-
// Check if file exists
|
|
65
|
-
try {
|
|
66
|
-
await fs.access(filePath);
|
|
67
|
-
} catch {
|
|
68
|
-
return new EditResult({
|
|
69
|
-
success: false,
|
|
70
|
-
fileName,
|
|
71
|
-
versionBefore: 0,
|
|
72
|
-
versionAfter: 0,
|
|
73
|
-
error: `File ${fileName} does not exist in session`
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Get current version
|
|
78
|
-
const versionBefore = session.getFileVersion(fileName);
|
|
79
|
-
|
|
80
|
-
// Create backup
|
|
81
|
-
const backupPath = await createBackup(session, filePath, versionBefore);
|
|
82
|
-
|
|
83
|
-
// Write new content
|
|
84
|
-
await fs.writeFile(filePath, newContent, 'utf-8');
|
|
85
|
-
|
|
86
|
-
// Increment version
|
|
87
|
-
const versionAfter = session.incrementFileVersion(fileName);
|
|
88
|
-
|
|
89
|
-
// Add event to session history
|
|
90
|
-
session.addEvent({
|
|
91
|
-
eventType: 'EDITED',
|
|
92
|
-
actor: editor,
|
|
93
|
-
description: `Edited ${fileName}: ${description}`,
|
|
94
|
-
affectedFiles: [fileName]
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// Save updated session
|
|
98
|
-
await session.save();
|
|
99
|
-
|
|
100
|
-
return new EditResult({
|
|
101
|
-
success: true,
|
|
102
|
-
fileName,
|
|
103
|
-
versionBefore,
|
|
104
|
-
versionAfter,
|
|
105
|
-
backupPath
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Create a versioned backup of a file
|
|
111
|
-
*
|
|
112
|
-
* @param {BrainstormSession} session
|
|
113
|
-
* @param {string} filePath - Path to the file
|
|
114
|
-
* @param {number} version - Current version number
|
|
115
|
-
* @returns {Promise<string|null>}
|
|
116
|
-
*/
|
|
117
|
-
async function createBackup(session, filePath, version) {
|
|
118
|
-
const backupsDir = path.join(session.outputDirectory, '.backups');
|
|
119
|
-
|
|
120
|
-
try {
|
|
121
|
-
await fs.mkdir(backupsDir, { recursive: true });
|
|
122
|
-
} catch { }
|
|
123
|
-
|
|
124
|
-
const fileName = path.basename(filePath);
|
|
125
|
-
const backupName = `${fileName}.v${version}`;
|
|
126
|
-
const backupPath = path.join(backupsDir, backupName);
|
|
127
|
-
|
|
128
|
-
try {
|
|
129
|
-
await fs.copyFile(filePath, backupPath);
|
|
130
|
-
return backupPath;
|
|
131
|
-
} catch (error) {
|
|
132
|
-
console.error(`Failed to create backup: ${error.message}`);
|
|
133
|
-
return null;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Get edit history for a session or specific file
|
|
139
|
-
*
|
|
140
|
-
* @param {string} sessionDir - Directory containing the session
|
|
141
|
-
* @param {string|null} fileName - Optional file name to filter by
|
|
142
|
-
* @returns {Promise<Array>}
|
|
143
|
-
*/
|
|
144
|
-
async function getHistory(sessionDir, fileName = null) {
|
|
145
|
-
const sessionFile = path.join(sessionDir, 'SESSION.json');
|
|
146
|
-
|
|
147
|
-
try {
|
|
148
|
-
await fs.access(sessionFile);
|
|
149
|
-
} catch {
|
|
150
|
-
return [];
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const session = await BrainstormSession.load(sessionFile);
|
|
154
|
-
|
|
155
|
-
// Filter for EDITED events
|
|
156
|
-
let edits = session.history
|
|
157
|
-
.filter(e => e.eventType === 'EDITED')
|
|
158
|
-
.map(e => e.toJSON ? e.toJSON() : e);
|
|
159
|
-
|
|
160
|
-
// Filter by file name if specified
|
|
161
|
-
if (fileName) {
|
|
162
|
-
edits = edits.filter(e =>
|
|
163
|
-
(e.affectedFiles || []).includes(fileName)
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return edits;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Get current versions of all files in a session
|
|
172
|
-
*
|
|
173
|
-
* @param {string} sessionDir - Directory containing the session
|
|
174
|
-
* @returns {Promise<Object>}
|
|
175
|
-
*/
|
|
176
|
-
async function getVersions(sessionDir) {
|
|
177
|
-
const sessionFile = path.join(sessionDir, 'SESSION.json');
|
|
178
|
-
|
|
179
|
-
try {
|
|
180
|
-
await fs.access(sessionFile);
|
|
181
|
-
} catch {
|
|
182
|
-
return {};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const session = await BrainstormSession.load(sessionFile);
|
|
186
|
-
return { ...session.fileVersions };
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Restore a file to a previous version
|
|
191
|
-
*
|
|
192
|
-
* @param {Object} options
|
|
193
|
-
* @param {string} options.sessionDir - Directory containing the session
|
|
194
|
-
* @param {string} options.fileName - Name of the file to restore
|
|
195
|
-
* @param {number} options.version - Version number to restore to
|
|
196
|
-
* @param {string} options.editor - Who is making the restore
|
|
197
|
-
* @returns {Promise<EditResult>}
|
|
198
|
-
*/
|
|
199
|
-
async function restoreVersion({ sessionDir, fileName, version, editor = 'HUMAN' }) {
|
|
200
|
-
const sessionFile = path.join(sessionDir, 'SESSION.json');
|
|
201
|
-
|
|
202
|
-
try {
|
|
203
|
-
await fs.access(sessionFile);
|
|
204
|
-
} catch {
|
|
205
|
-
return new EditResult({
|
|
206
|
-
success: false,
|
|
207
|
-
fileName,
|
|
208
|
-
versionBefore: 0,
|
|
209
|
-
versionAfter: 0,
|
|
210
|
-
error: 'SESSION.json not found'
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const session = await BrainstormSession.load(sessionFile);
|
|
215
|
-
|
|
216
|
-
// Find backup file
|
|
217
|
-
const backupsDir = path.join(session.outputDirectory, '.backups');
|
|
218
|
-
const backupPath = path.join(backupsDir, `${fileName}.v${version}`);
|
|
219
|
-
|
|
220
|
-
try {
|
|
221
|
-
await fs.access(backupPath);
|
|
222
|
-
} catch {
|
|
223
|
-
return new EditResult({
|
|
224
|
-
success: false,
|
|
225
|
-
fileName,
|
|
226
|
-
versionBefore: session.getFileVersion(fileName),
|
|
227
|
-
versionAfter: session.getFileVersion(fileName),
|
|
228
|
-
error: `Backup version ${version} not found for ${fileName}`
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Read backup content
|
|
233
|
-
const content = await fs.readFile(backupPath, 'utf-8');
|
|
234
|
-
|
|
235
|
-
// Use edit to restore (this creates a new version)
|
|
236
|
-
return editBrainstormFile({
|
|
237
|
-
sessionDir,
|
|
238
|
-
fileName,
|
|
239
|
-
newContent: content,
|
|
240
|
-
description: `Restored to version ${version}`,
|
|
241
|
-
editor
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* List all backup files in a session
|
|
247
|
-
*
|
|
248
|
-
* @param {string} sessionDir - Directory containing the session
|
|
249
|
-
* @returns {Promise<Array>}
|
|
250
|
-
*/
|
|
251
|
-
async function listBackups(sessionDir) {
|
|
252
|
-
const backupsDir = path.join(sessionDir, '.backups');
|
|
253
|
-
|
|
254
|
-
try {
|
|
255
|
-
await fs.access(backupsDir);
|
|
256
|
-
} catch {
|
|
257
|
-
return [];
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const entries = await fs.readdir(backupsDir, { withFileTypes: true });
|
|
261
|
-
const backups = [];
|
|
262
|
-
|
|
263
|
-
for (const entry of entries) {
|
|
264
|
-
if (entry.isFile()) {
|
|
265
|
-
const match = entry.name.match(/^(.+)\.v(\d+)$/);
|
|
266
|
-
if (match) {
|
|
267
|
-
const filePath = path.join(backupsDir, entry.name);
|
|
268
|
-
const stats = await fs.stat(filePath);
|
|
269
|
-
|
|
270
|
-
backups.push({
|
|
271
|
-
fileName: match[1],
|
|
272
|
-
version: parseInt(match[2], 10),
|
|
273
|
-
backupPath: filePath,
|
|
274
|
-
size: stats.size,
|
|
275
|
-
modified: stats.mtime.toISOString()
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return backups.sort((a, b) => {
|
|
282
|
-
if (a.fileName !== b.fileName) return a.fileName.localeCompare(b.fileName);
|
|
283
|
-
return a.version - b.version;
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
module.exports = {
|
|
288
|
-
EditResult,
|
|
289
|
-
editBrainstormFile,
|
|
290
|
-
getHistory,
|
|
291
|
-
getVersions,
|
|
292
|
-
restoreVersion,
|
|
293
|
-
listBackups
|
|
294
|
-
};
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Finish Brainstorm Module - Complete a Brainstorm Session
|
|
3
|
-
*
|
|
4
|
-
* Finalizes a brainstorm session, generates mutual summaries,
|
|
5
|
-
* and marks the session as completed.
|
|
6
|
-
* Ported from Python to JavaScript.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const fs = require('fs').promises;
|
|
10
|
-
const path = require('path');
|
|
11
|
-
const { BrainstormSession, SessionResult } = require('./models');
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Complete a brainstorm session
|
|
15
|
-
*
|
|
16
|
-
* @param {Object} options
|
|
17
|
-
* @param {string} options.sessionDir - Directory containing the session
|
|
18
|
-
* @param {string} options.summary - Summary of what was accomplished
|
|
19
|
-
* @param {string} options.actor - Who is completing the session
|
|
20
|
-
* @param {string[]} options.nextSteps - Optional list of next steps
|
|
21
|
-
* @returns {Promise<SessionResult>}
|
|
22
|
-
*/
|
|
23
|
-
async function finishBrainstorm({ sessionDir, summary, actor = 'CLAUDE-1', nextSteps = [] }) {
|
|
24
|
-
const sessionFile = path.join(sessionDir, 'SESSION.json');
|
|
25
|
-
|
|
26
|
-
// Check if session exists
|
|
27
|
-
try {
|
|
28
|
-
await fs.access(sessionFile);
|
|
29
|
-
} catch {
|
|
30
|
-
return new SessionResult({
|
|
31
|
-
success: false,
|
|
32
|
-
sessionId: '',
|
|
33
|
-
status: 'FAILED',
|
|
34
|
-
summary: 'Session file not found',
|
|
35
|
-
errors: ['SESSION.json not found in the specified directory']
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Load session
|
|
40
|
-
const session = await BrainstormSession.load(sessionFile);
|
|
41
|
-
|
|
42
|
-
// Check if already completed
|
|
43
|
-
if (session.status === 'COMPLETED') {
|
|
44
|
-
return new SessionResult({
|
|
45
|
-
success: false,
|
|
46
|
-
sessionId: session.id,
|
|
47
|
-
status: 'ALREADY_COMPLETED',
|
|
48
|
-
summary: 'Session was already completed',
|
|
49
|
-
errors: ['Session is already in COMPLETED status']
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// Generate mutual summary
|
|
54
|
-
const mutualSummary = generateMutualSummary({ session, summary, actor, nextSteps });
|
|
55
|
-
|
|
56
|
-
// Update PROGRESS_REPORT.md with completion info
|
|
57
|
-
await updateProgressReport({ session, mutualSummary, actor });
|
|
58
|
-
|
|
59
|
-
// Update SECONDARY-AI-CHAT.md if it exists
|
|
60
|
-
const secondaryChatPath = path.join(session.outputDirectory, 'SECONDARY-AI-CHAT.md');
|
|
61
|
-
try {
|
|
62
|
-
await fs.access(secondaryChatPath);
|
|
63
|
-
await updateSecondaryChat({ session, summary, actor });
|
|
64
|
-
} catch { }
|
|
65
|
-
|
|
66
|
-
// Mark session as completed
|
|
67
|
-
session.status = 'COMPLETED';
|
|
68
|
-
session.mutualSummary = summary;
|
|
69
|
-
|
|
70
|
-
// Add completion event
|
|
71
|
-
session.addEvent({
|
|
72
|
-
eventType: 'COMPLETED',
|
|
73
|
-
actor,
|
|
74
|
-
description: `Session completed: ${summary}`,
|
|
75
|
-
affectedFiles: Object.keys(session.fileVersions)
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// Save updated session
|
|
79
|
-
await session.save();
|
|
80
|
-
|
|
81
|
-
return new SessionResult({
|
|
82
|
-
success: true,
|
|
83
|
-
sessionId: session.id,
|
|
84
|
-
status: 'COMPLETED',
|
|
85
|
-
summary,
|
|
86
|
-
filesGenerated: Object.keys(session.fileVersions)
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Generate the mutual summary text
|
|
92
|
-
*/
|
|
93
|
-
function generateMutualSummary({ session, summary, actor, nextSteps }) {
|
|
94
|
-
const timestamp = new Date().toISOString();
|
|
95
|
-
|
|
96
|
-
let result = `
|
|
97
|
-
## 🏁 MUTUAL SUMMARY
|
|
98
|
-
|
|
99
|
-
**Session ID**: ${session.id}
|
|
100
|
-
**Completed At**: ${timestamp}
|
|
101
|
-
**Completed By**: ${actor}
|
|
102
|
-
|
|
103
|
-
### What Was Accomplished:
|
|
104
|
-
${summary}
|
|
105
|
-
|
|
106
|
-
`;
|
|
107
|
-
|
|
108
|
-
if (nextSteps && nextSteps.length > 0) {
|
|
109
|
-
result += '### Next Steps:\n';
|
|
110
|
-
nextSteps.forEach((step, i) => {
|
|
111
|
-
result += `${i + 1}. ${step}\n`;
|
|
112
|
-
});
|
|
113
|
-
result += '\n';
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Add history summary (last 5 events)
|
|
117
|
-
result += '### Session History:\n';
|
|
118
|
-
const recentEvents = session.history.slice(-5);
|
|
119
|
-
recentEvents.forEach(event => {
|
|
120
|
-
result += `- [${event.eventType}] ${event.description} (${event.actor})\n`;
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
return result;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Update PROGRESS_REPORT.md with completion information
|
|
128
|
-
*/
|
|
129
|
-
async function updateProgressReport({ session, mutualSummary, actor }) {
|
|
130
|
-
const progressFile = path.join(session.outputDirectory, 'PROGRESS_REPORT.md');
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
await fs.access(progressFile);
|
|
134
|
-
} catch {
|
|
135
|
-
return; // File doesn't exist
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Read current content
|
|
139
|
-
let content = await fs.readFile(progressFile, 'utf-8');
|
|
140
|
-
|
|
141
|
-
// Add completion block
|
|
142
|
-
const completionBlock = `
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
${mutualSummary}
|
|
147
|
-
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
**Final Status**: COMPLETED
|
|
151
|
-
**Last Updated**: ${new Date().toISOString().replace('T', ' ').split('.')[0]} by ${actor}
|
|
152
|
-
`;
|
|
153
|
-
|
|
154
|
-
content += completionBlock;
|
|
155
|
-
await fs.writeFile(progressFile, content, 'utf-8');
|
|
156
|
-
|
|
157
|
-
// Increment version
|
|
158
|
-
session.incrementFileVersion('PROGRESS_REPORT.md');
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Update SECONDARY-AI-CHAT.md with completion log
|
|
163
|
-
*/
|
|
164
|
-
async function updateSecondaryChat({ session, summary, actor }) {
|
|
165
|
-
const chatFile = path.join(session.outputDirectory, 'SECONDARY-AI-CHAT.md');
|
|
166
|
-
|
|
167
|
-
try {
|
|
168
|
-
await fs.access(chatFile);
|
|
169
|
-
} catch {
|
|
170
|
-
return; // File doesn't exist
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Read current content
|
|
174
|
-
let content = await fs.readFile(chatFile, 'utf-8');
|
|
175
|
-
|
|
176
|
-
// Add completion entry
|
|
177
|
-
const completionEntry = `
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
[${actor}] COMPLETED: Session completed
|
|
181
|
-
Timestamp: ${new Date().toISOString()}
|
|
182
|
-
Summary: ${summary}
|
|
183
|
-
Status: SUCCESS ✅
|
|
184
|
-
Notes: All brainstorm files finalized. Session ready for execution phase.
|
|
185
|
-
|
|
186
|
-
---
|
|
187
|
-
`;
|
|
188
|
-
|
|
189
|
-
content += completionEntry;
|
|
190
|
-
await fs.writeFile(chatFile, content, 'utf-8');
|
|
191
|
-
|
|
192
|
-
// Increment version
|
|
193
|
-
session.incrementFileVersion('SECONDARY-AI-CHAT.md');
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Get the current status of a session
|
|
198
|
-
*
|
|
199
|
-
* @param {string} sessionDir - Directory containing the session
|
|
200
|
-
* @returns {Promise<string>}
|
|
201
|
-
*/
|
|
202
|
-
async function getStatus(sessionDir) {
|
|
203
|
-
const sessionFile = path.join(sessionDir, 'SESSION.json');
|
|
204
|
-
|
|
205
|
-
try {
|
|
206
|
-
await fs.access(sessionFile);
|
|
207
|
-
const session = await BrainstormSession.load(sessionFile);
|
|
208
|
-
return session.status;
|
|
209
|
-
} catch {
|
|
210
|
-
return 'NOT_FOUND';
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
module.exports = {
|
|
215
|
-
finishBrainstorm,
|
|
216
|
-
getStatus
|
|
217
|
-
};
|