agileflow 2.96.0 → 2.96.2
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/CHANGELOG.md +10 -0
- package/lib/claude-cli-bridge.js +18 -24
- package/lib/dashboard-protocol.js +48 -48
- package/lib/drivers/claude-driver.ts +62 -60
- package/lib/drivers/codex-driver.ts +98 -88
- package/lib/drivers/driver-manager.ts +8 -7
- package/lib/drivers/gemini-driver.ts +121 -108
- package/lib/drivers/index.ts +4 -4
- package/lib/flag-detection.js +10 -9
- package/lib/merge-operations.js +8 -1
- package/lib/protocol/driver.ts +76 -82
- package/lib/protocol/index.ts +2 -2
- package/lib/protocol/ir.ts +40 -40
- package/lib/session-display.js +7 -6
- package/lib/yaml-utils.js +28 -1
- package/package.json +1 -1
- package/scripts/agileflow-welcome.js +2 -6
- package/scripts/automation-run-due.js +3 -1
- package/scripts/backfill-ideation-status.js +6 -2
- package/scripts/dashboard-serve.js +28 -15
- package/scripts/lib/concurrency-limiter.js +1 -3
- package/scripts/lib/context-formatter.js +3 -1
- package/scripts/lib/ideation-index.js +18 -6
- package/scripts/lib/process-cleanup.js +6 -1
- package/scripts/lib/sync-ideation-status.js +4 -4
- package/scripts/migrate-ideation-index.js +28 -13
- package/scripts/session-manager.js +471 -119
- package/scripts/spawn-parallel.js +3 -1
- package/tools/cli/commands/serve.js +54 -27
- package/tools/cli/installers/core/installer.js +9 -1
- package/tools/cli/installers/ide/claude-code.js +4 -2
- package/tools/cli/lib/content-injector.js +7 -5
- package/tools/cli/lib/docs-setup.js +27 -7
- package/tools/cli/lib/ui.js +12 -5
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
CLICommand,
|
|
21
21
|
IREventHandler,
|
|
22
22
|
CODEX_CAPABILITIES,
|
|
23
|
-
} from
|
|
23
|
+
} from '../protocol/driver';
|
|
24
24
|
import {
|
|
25
25
|
IREnvelope,
|
|
26
26
|
IRSource,
|
|
@@ -33,19 +33,19 @@ import {
|
|
|
33
33
|
IRError,
|
|
34
34
|
IRFileOp,
|
|
35
35
|
IRShell,
|
|
36
|
-
} from
|
|
36
|
+
} from '../protocol/ir';
|
|
37
37
|
|
|
38
38
|
// ============================================================================
|
|
39
39
|
// Tool Name Mapping (Codex -> IR normalized names)
|
|
40
40
|
// ============================================================================
|
|
41
41
|
|
|
42
42
|
const CODEX_TOOL_MAPPING: Record<string, string> = {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
exec_command: 'shell_exec', // Used for both shell and file reads
|
|
44
|
+
apply_patch: 'file_edit',
|
|
45
|
+
web_search: 'web_search',
|
|
46
|
+
read_file: 'file_read',
|
|
47
|
+
write_file: 'file_write',
|
|
48
|
+
container_exec: 'shell_exec',
|
|
49
49
|
};
|
|
50
50
|
|
|
51
51
|
/**
|
|
@@ -59,8 +59,8 @@ function normalizeToolName(codexName: string): string {
|
|
|
59
59
|
* Determine if an exec_command is a file read operation
|
|
60
60
|
*/
|
|
61
61
|
function isFileReadCommand(params: CodexExecCommandParams): boolean {
|
|
62
|
-
const cmd = params.command?.trim() ||
|
|
63
|
-
return cmd.startsWith(
|
|
62
|
+
const cmd = params.command?.trim() || '';
|
|
63
|
+
return cmd.startsWith('cat ') || cmd.startsWith('head ') || cmd.startsWith('tail ');
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/**
|
|
@@ -70,11 +70,11 @@ function extractFilePath(command: string): string {
|
|
|
70
70
|
const parts = command.trim().split(/\s+/);
|
|
71
71
|
// Skip command and flags, find the file path
|
|
72
72
|
for (let i = 1; i < parts.length; i++) {
|
|
73
|
-
if (!parts[i].startsWith(
|
|
74
|
-
return parts[i].replace(/^['"]|['"]$/g,
|
|
73
|
+
if (!parts[i].startsWith('-')) {
|
|
74
|
+
return parts[i].replace(/^['"]|['"]$/g, ''); // Remove quotes
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
-
return
|
|
77
|
+
return '';
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
// ============================================================================
|
|
@@ -82,22 +82,25 @@ function extractFilePath(command: string): string {
|
|
|
82
82
|
// ============================================================================
|
|
83
83
|
|
|
84
84
|
export class CodexDriver implements Driver {
|
|
85
|
-
readonly id: IRSource =
|
|
86
|
-
readonly name =
|
|
85
|
+
readonly id: IRSource = 'codex';
|
|
86
|
+
readonly name = 'Codex CLI';
|
|
87
87
|
|
|
88
88
|
private _status: DriverStatus = {
|
|
89
|
-
state:
|
|
90
|
-
provider:
|
|
89
|
+
state: 'stopped',
|
|
90
|
+
provider: 'codex',
|
|
91
91
|
};
|
|
92
92
|
|
|
93
93
|
private _capabilities: Capability[] = [...CODEX_CAPABILITIES];
|
|
94
94
|
private _eventHandlers: Set<IREventHandler> = new Set();
|
|
95
|
-
private _sessions: Map<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
private _sessions: Map<
|
|
96
|
+
string,
|
|
97
|
+
{
|
|
98
|
+
config: DriverConfig;
|
|
99
|
+
seqCounter: number;
|
|
100
|
+
threadId?: string;
|
|
101
|
+
parentThreadId?: string;
|
|
102
|
+
}
|
|
103
|
+
> = new Map();
|
|
101
104
|
|
|
102
105
|
// Rate limiting
|
|
103
106
|
private _lastRequestTime = 0;
|
|
@@ -119,21 +122,21 @@ export class CodexDriver implements Driver {
|
|
|
119
122
|
this._sessions.set(sessionId, { config, seqCounter: 0 });
|
|
120
123
|
|
|
121
124
|
this._status = {
|
|
122
|
-
state:
|
|
123
|
-
provider:
|
|
124
|
-
model: config.model ||
|
|
125
|
+
state: 'ready',
|
|
126
|
+
provider: 'codex',
|
|
127
|
+
model: config.model || 'codex-1',
|
|
125
128
|
contextMax: config.maxTokens || 128000,
|
|
126
129
|
};
|
|
127
130
|
|
|
128
131
|
// Emit init event
|
|
129
132
|
const initPayload: IRInit = {
|
|
130
|
-
provider:
|
|
131
|
-
version:
|
|
133
|
+
provider: 'codex',
|
|
134
|
+
version: '1.0.0',
|
|
132
135
|
capabilities: this._capabilities.filter(c => c.available).map(c => c.name),
|
|
133
136
|
maxContext: config.maxTokens || 128000,
|
|
134
137
|
};
|
|
135
138
|
|
|
136
|
-
this._emit(createIREnvelope(
|
|
139
|
+
this._emit(createIREnvelope('init', sessionId, 'codex', initPayload));
|
|
137
140
|
}
|
|
138
141
|
|
|
139
142
|
async stop(sessionId: string): Promise<void> {
|
|
@@ -142,7 +145,7 @@ export class CodexDriver implements Driver {
|
|
|
142
145
|
if (this._sessions.size === 0) {
|
|
143
146
|
this._status = {
|
|
144
147
|
...this._status,
|
|
145
|
-
state:
|
|
148
|
+
state: 'stopped',
|
|
146
149
|
};
|
|
147
150
|
}
|
|
148
151
|
}
|
|
@@ -171,12 +174,12 @@ export class CodexDriver implements Driver {
|
|
|
171
174
|
// -------------------------------------------------------------------------
|
|
172
175
|
|
|
173
176
|
async send(sessionId: string, command: CLICommand): Promise<void> {
|
|
174
|
-
this._status = { ...this._status, state:
|
|
177
|
+
this._status = { ...this._status, state: 'busy' };
|
|
175
178
|
|
|
176
179
|
const sessionPayload: IRSession = {
|
|
177
|
-
state:
|
|
180
|
+
state: 'thinking',
|
|
178
181
|
};
|
|
179
|
-
this._emit(createIREnvelope(
|
|
182
|
+
this._emit(createIREnvelope('session', sessionId, 'codex', sessionPayload));
|
|
180
183
|
}
|
|
181
184
|
|
|
182
185
|
// -------------------------------------------------------------------------
|
|
@@ -199,10 +202,12 @@ export class CodexDriver implements Driver {
|
|
|
199
202
|
});
|
|
200
203
|
|
|
201
204
|
// Emit session fork event
|
|
202
|
-
this._emit(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
205
|
+
this._emit(
|
|
206
|
+
createIREnvelope<IRSession>('session', newSessionId, 'codex', {
|
|
207
|
+
state: 'connected',
|
|
208
|
+
message: `Forked from ${sessionId}`,
|
|
209
|
+
})
|
|
210
|
+
);
|
|
206
211
|
}
|
|
207
212
|
|
|
208
213
|
/**
|
|
@@ -213,10 +218,12 @@ export class CodexDriver implements Driver {
|
|
|
213
218
|
if (!session) return;
|
|
214
219
|
|
|
215
220
|
// In a real implementation, this would call the Codex CLI rollback command
|
|
216
|
-
this._emit(
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
221
|
+
this._emit(
|
|
222
|
+
createIREnvelope<IRSession>('session', sessionId, 'codex', {
|
|
223
|
+
state: 'idle',
|
|
224
|
+
message: `Rolled back to sequence ${targetSeq}`,
|
|
225
|
+
})
|
|
226
|
+
);
|
|
220
227
|
}
|
|
221
228
|
|
|
222
229
|
// -------------------------------------------------------------------------
|
|
@@ -245,39 +252,42 @@ export class CodexDriver implements Driver {
|
|
|
245
252
|
|
|
246
253
|
private _translateMethod(sessionId: string, msg: CodexJsonRpcMessage): IREnvelope | null {
|
|
247
254
|
switch (msg.method) {
|
|
248
|
-
case
|
|
255
|
+
case 'item/agentMessage/delta':
|
|
249
256
|
// Streaming text delta
|
|
250
|
-
return createIREnvelope<IRTextDelta>(
|
|
251
|
-
text: msg.params?.content ||
|
|
257
|
+
return createIREnvelope<IRTextDelta>('text_delta', sessionId, 'codex', {
|
|
258
|
+
text: msg.params?.content || '',
|
|
252
259
|
done: false,
|
|
253
260
|
});
|
|
254
261
|
|
|
255
|
-
case
|
|
262
|
+
case 'item/agentMessage':
|
|
256
263
|
// Complete text message
|
|
257
|
-
return createIREnvelope<IRTextDelta>(
|
|
258
|
-
text: msg.params?.content ||
|
|
264
|
+
return createIREnvelope<IRTextDelta>('text_delta', sessionId, 'codex', {
|
|
265
|
+
text: msg.params?.content || '',
|
|
259
266
|
done: true,
|
|
260
267
|
});
|
|
261
268
|
|
|
262
|
-
case
|
|
269
|
+
case 'item/started':
|
|
263
270
|
// Tool call started
|
|
264
|
-
if (msg.params?.item?.type ===
|
|
265
|
-
const toolName = msg.params.item.name ||
|
|
271
|
+
if (msg.params?.item?.type === 'function_call') {
|
|
272
|
+
const toolName = msg.params.item.name || 'unknown';
|
|
266
273
|
const toolInput = msg.params.item.arguments || {};
|
|
267
274
|
|
|
268
275
|
// Check if this is exec_command being used as file_read
|
|
269
|
-
if (
|
|
270
|
-
|
|
276
|
+
if (
|
|
277
|
+
toolName === 'exec_command' &&
|
|
278
|
+
isFileReadCommand(toolInput as CodexExecCommandParams)
|
|
279
|
+
) {
|
|
280
|
+
return createIREnvelope<IRToolStart>('tool_start', sessionId, 'codex', {
|
|
271
281
|
id: msg.params.item.id || `tool_${Date.now()}`,
|
|
272
|
-
name:
|
|
273
|
-
nativeName:
|
|
282
|
+
name: 'file_read',
|
|
283
|
+
nativeName: 'exec_command',
|
|
274
284
|
input: {
|
|
275
|
-
path: extractFilePath((toolInput as CodexExecCommandParams).command ||
|
|
285
|
+
path: extractFilePath((toolInput as CodexExecCommandParams).command || ''),
|
|
276
286
|
},
|
|
277
287
|
});
|
|
278
288
|
}
|
|
279
289
|
|
|
280
|
-
return createIREnvelope<IRToolStart>(
|
|
290
|
+
return createIREnvelope<IRToolStart>('tool_start', sessionId, 'codex', {
|
|
281
291
|
id: msg.params.item.id || `tool_${Date.now()}`,
|
|
282
292
|
name: normalizeToolName(toolName),
|
|
283
293
|
nativeName: toolName,
|
|
@@ -286,17 +296,17 @@ export class CodexDriver implements Driver {
|
|
|
286
296
|
}
|
|
287
297
|
return null;
|
|
288
298
|
|
|
289
|
-
case
|
|
299
|
+
case 'item/completed':
|
|
290
300
|
// Tool call completed
|
|
291
301
|
const output = msg.params?.item?.output;
|
|
292
|
-
const isError = msg.params?.item?.status ===
|
|
302
|
+
const isError = msg.params?.item?.status === 'error';
|
|
293
303
|
|
|
294
304
|
// Check if this was a file operation
|
|
295
|
-
if (msg.params?.item?.name ===
|
|
305
|
+
if (msg.params?.item?.name === 'exec_command' && msg.params?.item?.arguments) {
|
|
296
306
|
const args = msg.params.item.arguments as CodexExecCommandParams;
|
|
297
307
|
if (isFileReadCommand(args)) {
|
|
298
|
-
return createIREnvelope<IRToolResult>(
|
|
299
|
-
id: msg.params.item.id ||
|
|
308
|
+
return createIREnvelope<IRToolResult>('tool_result', sessionId, 'codex', {
|
|
309
|
+
id: msg.params.item.id || '',
|
|
300
310
|
ok: !isError,
|
|
301
311
|
output: output,
|
|
302
312
|
error: isError ? String(output) : undefined,
|
|
@@ -305,49 +315,49 @@ export class CodexDriver implements Driver {
|
|
|
305
315
|
}
|
|
306
316
|
|
|
307
317
|
// Check if this was apply_patch (file edit)
|
|
308
|
-
if (msg.params?.item?.name ===
|
|
318
|
+
if (msg.params?.item?.name === 'apply_patch') {
|
|
309
319
|
const patchArgs = msg.params.item.arguments as CodexApplyPatchParams;
|
|
310
|
-
return createIREnvelope<IRFileOp>(
|
|
311
|
-
action:
|
|
312
|
-
path: patchArgs.path ||
|
|
320
|
+
return createIREnvelope<IRFileOp>('file_op', sessionId, 'codex', {
|
|
321
|
+
action: 'edit',
|
|
322
|
+
path: patchArgs.path || '',
|
|
313
323
|
diff: {
|
|
314
|
-
before:
|
|
315
|
-
after:
|
|
324
|
+
before: '', // Would need to parse from patch
|
|
325
|
+
after: '',
|
|
316
326
|
},
|
|
317
327
|
});
|
|
318
328
|
}
|
|
319
329
|
|
|
320
|
-
return createIREnvelope<IRToolResult>(
|
|
321
|
-
id: msg.params?.item?.id ||
|
|
330
|
+
return createIREnvelope<IRToolResult>('tool_result', sessionId, 'codex', {
|
|
331
|
+
id: msg.params?.item?.id || '',
|
|
322
332
|
ok: !isError,
|
|
323
333
|
output: output,
|
|
324
334
|
error: isError ? String(output) : undefined,
|
|
325
335
|
});
|
|
326
336
|
|
|
327
|
-
case
|
|
328
|
-
return createIREnvelope<IRSession>(
|
|
329
|
-
state:
|
|
337
|
+
case 'turn/started':
|
|
338
|
+
return createIREnvelope<IRSession>('session', sessionId, 'codex', {
|
|
339
|
+
state: 'thinking',
|
|
330
340
|
});
|
|
331
341
|
|
|
332
|
-
case
|
|
333
|
-
this._status = { ...this._status, state:
|
|
334
|
-
return createIREnvelope<IRSession>(
|
|
335
|
-
state:
|
|
342
|
+
case 'turn/completed':
|
|
343
|
+
this._status = { ...this._status, state: 'ready' };
|
|
344
|
+
return createIREnvelope<IRSession>('session', sessionId, 'codex', {
|
|
345
|
+
state: 'idle',
|
|
336
346
|
});
|
|
337
347
|
|
|
338
|
-
case
|
|
348
|
+
case 'thread/created':
|
|
339
349
|
const session = this._sessions.get(sessionId);
|
|
340
350
|
if (session) {
|
|
341
351
|
session.threadId = msg.params?.threadId;
|
|
342
352
|
}
|
|
343
|
-
return createIREnvelope<IRSession>(
|
|
344
|
-
state:
|
|
353
|
+
return createIREnvelope<IRSession>('session', sessionId, 'codex', {
|
|
354
|
+
state: 'connected',
|
|
345
355
|
message: `Thread created: ${msg.params?.threadId}`,
|
|
346
356
|
});
|
|
347
357
|
|
|
348
|
-
case
|
|
349
|
-
return createIREnvelope<IRSession>(
|
|
350
|
-
state:
|
|
358
|
+
case 'thread/forked':
|
|
359
|
+
return createIREnvelope<IRSession>('session', sessionId, 'codex', {
|
|
360
|
+
state: 'connected',
|
|
351
361
|
message: `Thread forked from ${msg.params?.parentThreadId}`,
|
|
352
362
|
});
|
|
353
363
|
|
|
@@ -358,9 +368,9 @@ export class CodexDriver implements Driver {
|
|
|
358
368
|
|
|
359
369
|
private _translateResult(sessionId: string, msg: CodexJsonRpcMessage): IREnvelope | null {
|
|
360
370
|
if (msg.error) {
|
|
361
|
-
return createIREnvelope<IRError>(
|
|
362
|
-
code: String(msg.error.code ||
|
|
363
|
-
message: msg.error.message ||
|
|
371
|
+
return createIREnvelope<IRError>('error', sessionId, 'codex', {
|
|
372
|
+
code: String(msg.error.code || 'UNKNOWN'),
|
|
373
|
+
message: msg.error.message || 'Unknown error',
|
|
364
374
|
details: msg.error.data,
|
|
365
375
|
recoverable: true,
|
|
366
376
|
});
|
|
@@ -390,11 +400,11 @@ export class CodexDriver implements Driver {
|
|
|
390
400
|
}
|
|
391
401
|
|
|
392
402
|
private _emit(envelope: IREnvelope): void {
|
|
393
|
-
Array.from(this._eventHandlers).forEach(
|
|
403
|
+
Array.from(this._eventHandlers).forEach(handler => {
|
|
394
404
|
try {
|
|
395
405
|
handler(envelope);
|
|
396
406
|
} catch (error) {
|
|
397
|
-
console.error(
|
|
407
|
+
console.error('[CodexDriver] Event handler error:', error);
|
|
398
408
|
}
|
|
399
409
|
});
|
|
400
410
|
}
|
|
@@ -405,7 +415,7 @@ export class CodexDriver implements Driver {
|
|
|
405
415
|
// ============================================================================
|
|
406
416
|
|
|
407
417
|
export interface CodexJsonRpcMessage {
|
|
408
|
-
jsonrpc?:
|
|
418
|
+
jsonrpc?: '2.0';
|
|
409
419
|
id?: string | number;
|
|
410
420
|
method?: string;
|
|
411
421
|
params?: {
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* for the dashboard to interact with any supported CLI.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { Driver, DriverManager, IREventHandler } from
|
|
9
|
-
import { IRSource, IREnvelope } from
|
|
8
|
+
import { Driver, DriverManager, IREventHandler } from '../protocol/driver';
|
|
9
|
+
import { IRSource, IREnvelope } from '../protocol/ir';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Default driver manager implementation
|
|
@@ -29,7 +29,7 @@ export class DefaultDriverManager implements DriverManager {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
// Forward driver events to global handlers
|
|
32
|
-
driver.onEvent(
|
|
32
|
+
driver.onEvent(envelope => {
|
|
33
33
|
this._emitGlobal(envelope);
|
|
34
34
|
});
|
|
35
35
|
|
|
@@ -99,11 +99,11 @@ export class DefaultDriverManager implements DriverManager {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
private _emitGlobal(envelope: IREnvelope): void {
|
|
102
|
-
Array.from(this._globalHandlers).forEach(
|
|
102
|
+
Array.from(this._globalHandlers).forEach(handler => {
|
|
103
103
|
try {
|
|
104
104
|
handler(envelope);
|
|
105
105
|
} catch (error) {
|
|
106
|
-
console.error(
|
|
106
|
+
console.error('[DriverManager] Global handler error:', error);
|
|
107
107
|
}
|
|
108
108
|
});
|
|
109
109
|
}
|
|
@@ -126,8 +126,9 @@ export class DefaultDriverManager implements DriverManager {
|
|
|
126
126
|
id: driver.id,
|
|
127
127
|
name: driver.name,
|
|
128
128
|
status: driver.status.state,
|
|
129
|
-
available: driver.status.state !==
|
|
130
|
-
capabilities: driver
|
|
129
|
+
available: driver.status.state !== 'error',
|
|
130
|
+
capabilities: driver
|
|
131
|
+
.capabilities()
|
|
131
132
|
.filter(c => c.available)
|
|
132
133
|
.map(c => c.name),
|
|
133
134
|
}));
|