ac-framework 1.9.7 → 1.9.9
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 +37 -11
- package/package.json +1 -1
- package/src/agents/collab-summary.js +120 -0
- package/src/agents/config-store.js +3 -0
- package/src/agents/constants.js +3 -1
- package/src/agents/opencode-client.js +101 -5
- package/src/agents/orchestrator.js +225 -6
- package/src/agents/role-prompts.js +34 -1
- package/src/agents/run-state.js +113 -0
- package/src/agents/runtime.js +75 -3
- package/src/agents/state-store.js +73 -0
- package/src/commands/agents.js +616 -60
- package/src/commands/init.js +9 -5
- package/src/mcp/collab-server.js +378 -24
- package/src/mcp/test-harness.mjs +410 -0
- package/src/services/dependency-installer.js +72 -4
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
SESSION_ROOT_DIR,
|
|
9
9
|
CURRENT_SESSION_FILE,
|
|
10
10
|
} from './constants.js';
|
|
11
|
+
import { createRunState } from './run-state.js';
|
|
11
12
|
import { sanitizeRoleModels } from './model-selection.js';
|
|
12
13
|
|
|
13
14
|
function sleep(ms) {
|
|
@@ -38,6 +39,22 @@ function getTranscriptPath(sessionId) {
|
|
|
38
39
|
return join(getSessionDir(sessionId), 'transcript.jsonl');
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
function getTurnsDir(sessionId) {
|
|
43
|
+
return join(getSessionDir(sessionId), 'turns');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getMeetingLogPath(sessionId) {
|
|
47
|
+
return join(getSessionDir(sessionId), 'meeting-log.md');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function getMeetingLogJsonlPath(sessionId) {
|
|
51
|
+
return join(getSessionDir(sessionId), 'meeting-log.jsonl');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function getMeetingSummaryPath(sessionId) {
|
|
55
|
+
return join(getSessionDir(sessionId), 'meeting-summary.md');
|
|
56
|
+
}
|
|
57
|
+
|
|
41
58
|
function initialState(task, options = {}) {
|
|
42
59
|
const sessionId = randomUUID();
|
|
43
60
|
const createdAt = new Date().toISOString();
|
|
@@ -56,7 +73,10 @@ function initialState(task, options = {}) {
|
|
|
56
73
|
model: options.model || null,
|
|
57
74
|
roleModels: sanitizeRoleModels(options.roleModels),
|
|
58
75
|
opencodeBin: options.opencodeBin || null,
|
|
76
|
+
multiplexer: options.multiplexer || 'auto',
|
|
77
|
+
multiplexerSessionName: options.multiplexerSessionName || null,
|
|
59
78
|
tmuxSessionName: options.tmuxSessionName || null,
|
|
79
|
+
run: createRunState(options.runPolicy, Number.isInteger(options.maxRounds) ? options.maxRounds : DEFAULT_MAX_ROUNDS),
|
|
60
80
|
messages: [
|
|
61
81
|
{
|
|
62
82
|
from: 'user',
|
|
@@ -91,6 +111,57 @@ export async function appendTranscript(sessionId, message) {
|
|
|
91
111
|
await appendFile(transcriptPath, line, 'utf8');
|
|
92
112
|
}
|
|
93
113
|
|
|
114
|
+
export async function appendMeetingTurn(sessionId, turnRecord) {
|
|
115
|
+
const sessionDir = getSessionDir(sessionId);
|
|
116
|
+
const turnsDir = getTurnsDir(sessionId);
|
|
117
|
+
await mkdir(sessionDir, { recursive: true });
|
|
118
|
+
await mkdir(turnsDir, { recursive: true });
|
|
119
|
+
|
|
120
|
+
const safeRole = String(turnRecord?.role || 'unknown').replace(/[^a-z0-9_-]/gi, '_');
|
|
121
|
+
const safeRound = Number.isInteger(turnRecord?.round) ? turnRecord.round : 0;
|
|
122
|
+
const turnFilePath = join(turnsDir, `${String(safeRound).padStart(3, '0')}-${safeRole}.json`);
|
|
123
|
+
await writeFile(turnFilePath, JSON.stringify(turnRecord, null, 2) + '\n', 'utf8');
|
|
124
|
+
|
|
125
|
+
const mdPath = getMeetingLogPath(sessionId);
|
|
126
|
+
const jsonlPath = getMeetingLogJsonlPath(sessionId);
|
|
127
|
+
const snippet = (turnRecord?.snippet || '').trim() || '(empty output)';
|
|
128
|
+
const keyPoints = Array.isArray(turnRecord?.keyPoints) ? turnRecord.keyPoints : [];
|
|
129
|
+
|
|
130
|
+
const mdBlock = [
|
|
131
|
+
`## Round ${safeRound} - ${safeRole}`,
|
|
132
|
+
`- timestamp: ${turnRecord?.timestamp || new Date().toISOString()}`,
|
|
133
|
+
`- model: ${turnRecord?.model || '(default)'}`,
|
|
134
|
+
`- events: ${turnRecord?.eventCount ?? 0}`,
|
|
135
|
+
'',
|
|
136
|
+
'### Output snippet',
|
|
137
|
+
snippet,
|
|
138
|
+
'',
|
|
139
|
+
'### Key points',
|
|
140
|
+
...(keyPoints.length > 0 ? keyPoints.map((line) => `- ${line.replace(/^[-*]\s+/, '')}`) : ['- (none)']),
|
|
141
|
+
'',
|
|
142
|
+
].join('\n');
|
|
143
|
+
|
|
144
|
+
if (!existsSync(mdPath)) {
|
|
145
|
+
const header = `# SynapseGrid Meeting Log\n\nSession: ${sessionId}\n\n`;
|
|
146
|
+
await writeFile(mdPath, header + mdBlock, 'utf8');
|
|
147
|
+
} else {
|
|
148
|
+
await appendFile(mdPath, mdBlock, 'utf8');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
await appendFile(jsonlPath, JSON.stringify(turnRecord) + '\n', 'utf8');
|
|
152
|
+
return {
|
|
153
|
+
turnFilePath,
|
|
154
|
+
meetingLogPath: mdPath,
|
|
155
|
+
meetingJsonlPath: jsonlPath,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export async function writeMeetingSummary(sessionId, summaryMarkdown) {
|
|
160
|
+
const outputPath = getMeetingSummaryPath(sessionId);
|
|
161
|
+
await writeFile(outputPath, String(summaryMarkdown || '').trimEnd() + '\n', 'utf8');
|
|
162
|
+
return outputPath;
|
|
163
|
+
}
|
|
164
|
+
|
|
94
165
|
export async function loadCurrentSessionId() {
|
|
95
166
|
if (!existsSync(CURRENT_SESSION_FILE)) return null;
|
|
96
167
|
const raw = await readFile(CURRENT_SESSION_FILE, 'utf8');
|
|
@@ -139,6 +210,8 @@ export async function listSessions(limit = 20) {
|
|
|
139
210
|
round: state.round,
|
|
140
211
|
maxRounds: state.maxRounds,
|
|
141
212
|
tmuxSessionName: state.tmuxSessionName || null,
|
|
213
|
+
multiplexer: state.multiplexer || 'auto',
|
|
214
|
+
multiplexerSessionName: state.multiplexerSessionName || null,
|
|
142
215
|
createdAt: state.createdAt,
|
|
143
216
|
updatedAt: state.updatedAt,
|
|
144
217
|
mtime: stateStats.mtimeMs,
|